LCOV - code coverage report
Current view: top level - layout/style - nsDOMCSSDeclaration.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 54 182 29.7 %
Date: 2017-07-14 16:53:18 Functions: 10 28 35.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /* base class for DOM objects for element.style and cssStyleRule.style */
       7             : 
       8             : #include "nsDOMCSSDeclaration.h"
       9             : 
      10             : #include "nsCSSParser.h"
      11             : #include "mozilla/DeclarationBlockInlines.h"
      12             : #include "mozilla/StyleSheetInlines.h"
      13             : #include "mozilla/css/Rule.h"
      14             : #include "mozilla/dom/CSS2PropertiesBinding.h"
      15             : #include "nsCSSProps.h"
      16             : #include "nsCOMPtr.h"
      17             : #include "mozAutoDocUpdate.h"
      18             : #include "nsIURI.h"
      19             : #include "mozilla/dom/BindingUtils.h"
      20             : #include "nsContentUtils.h"
      21             : #include "nsQueryObject.h"
      22             : #include "mozilla/layers/ScrollLinkedEffectDetector.h"
      23             : 
      24             : using namespace mozilla;
      25             : 
      26           0 : nsDOMCSSDeclaration::~nsDOMCSSDeclaration()
      27             : {
      28           0 : }
      29             : 
      30             : /* virtual */ JSObject*
      31           9 : nsDOMCSSDeclaration::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
      32             : {
      33           9 :   return dom::CSS2PropertiesBinding::Wrap(aCx, this, aGivenProto);
      34             : }
      35             : 
      36           5 : NS_INTERFACE_TABLE_HEAD(nsDOMCSSDeclaration)
      37           5 :   NS_INTERFACE_TABLE(nsDOMCSSDeclaration,
      38             :                      nsICSSDeclaration,
      39             :                      nsIDOMCSSStyleDeclaration)
      40           5 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE
      41           0 : NS_INTERFACE_MAP_END
      42             : 
      43             : NS_IMETHODIMP
      44           0 : nsDOMCSSDeclaration::GetPropertyValue(const nsCSSPropertyID aPropID,
      45             :                                       nsAString& aValue)
      46             : {
      47           0 :   NS_PRECONDITION(aPropID != eCSSProperty_UNKNOWN,
      48             :                   "Should never pass eCSSProperty_UNKNOWN around");
      49             : 
      50           0 :   aValue.Truncate();
      51           0 :   if (DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read)) {
      52           0 :     decl->GetPropertyValueByID(aPropID, aValue);
      53             :   }
      54           0 :   return NS_OK;
      55             : }
      56             : 
      57             : NS_IMETHODIMP
      58          10 : nsDOMCSSDeclaration::SetPropertyValue(const nsCSSPropertyID aPropID,
      59             :                                       const nsAString& aValue)
      60             : {
      61          10 :   switch (aPropID) {
      62             :     case eCSSProperty_background_position:
      63             :     case eCSSProperty_background_position_x:
      64             :     case eCSSProperty_background_position_y:
      65             :     case eCSSProperty_transform:
      66             :     case eCSSProperty_top:
      67             :     case eCSSProperty_left:
      68             :     case eCSSProperty_bottom:
      69             :     case eCSSProperty_right:
      70             :     case eCSSProperty_margin:
      71             :     case eCSSProperty_margin_top:
      72             :     case eCSSProperty_margin_left:
      73             :     case eCSSProperty_margin_bottom:
      74             :     case eCSSProperty_margin_right:
      75             :     case eCSSProperty_margin_inline_start:
      76             :     case eCSSProperty_margin_inline_end:
      77             :     case eCSSProperty_margin_block_start:
      78             :     case eCSSProperty_margin_block_end:
      79           0 :       mozilla::layers::ScrollLinkedEffectDetector::PositioningPropertyMutated();
      80           0 :       break;
      81             :     default:
      82          10 :       break;
      83             :   }
      84             : 
      85          10 :   if (aValue.IsEmpty()) {
      86             :     // If the new value of the property is an empty string we remove the
      87             :     // property.
      88           2 :     return RemovePropertyInternal(aPropID);
      89             :   }
      90             : 
      91           8 :   return ParsePropertyValue(aPropID, aValue, false);
      92             : }
      93             : 
      94             : 
      95             : NS_IMETHODIMP
      96           0 : nsDOMCSSDeclaration::GetCssText(nsAString& aCssText)
      97             : {
      98           0 :   DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read);
      99           0 :   aCssText.Truncate();
     100             : 
     101           0 :   if (decl) {
     102           0 :     decl->ToString(aCssText);
     103             :   }
     104             : 
     105           0 :   return NS_OK;
     106             : }
     107             : 
     108             : NS_IMETHODIMP
     109           0 : nsDOMCSSDeclaration::SetCssText(const nsAString& aCssText)
     110             : {
     111             :   // We don't need to *do* anything with the old declaration, but we need
     112             :   // to ensure that it exists, or else SetCSSDeclaration may crash.
     113           0 :   DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_Modify);
     114           0 :   if (!olddecl) {
     115           0 :     return NS_ERROR_NOT_AVAILABLE;
     116             :   }
     117             : 
     118             :   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
     119             :   // Attribute setting code, which leads in turn to BeginUpdate.  We
     120             :   // need to start the update now so that the old rule doesn't get used
     121             :   // between when we mutate the declaration and when we set the new
     122             :   // rule (see stack in bug 209575).
     123           0 :   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
     124             : 
     125           0 :   RefPtr<DeclarationBlock> newdecl;
     126           0 :   if (olddecl->IsServo()) {
     127           0 :     ServoCSSParsingEnvironment servoEnv = GetServoCSSParsingEnvironment();
     128           0 :     if (!servoEnv.mUrlExtraData) {
     129           0 :       return NS_ERROR_NOT_AVAILABLE;
     130             :     }
     131             : 
     132           0 :     newdecl = ServoDeclarationBlock::FromCssText(aCssText, servoEnv.mUrlExtraData,
     133           0 :                                                  servoEnv.mCompatMode, servoEnv.mLoader);
     134             :   } else {
     135           0 :     CSSParsingEnvironment geckoEnv;
     136           0 :     GetCSSParsingEnvironment(geckoEnv);
     137           0 :     if (!geckoEnv.mPrincipal) {
     138           0 :       return NS_ERROR_NOT_AVAILABLE;
     139             :     }
     140             : 
     141           0 :     RefPtr<css::Declaration> decl(new css::Declaration());
     142           0 :     decl->InitializeEmpty();
     143           0 :     nsCSSParser cssParser(geckoEnv.mCSSLoader);
     144             :     bool changed;
     145           0 :     nsresult result = cssParser.ParseDeclarations(aCssText, geckoEnv.mSheetURI,
     146             :                                                   geckoEnv.mBaseURI, geckoEnv.mPrincipal,
     147           0 :                                                   decl, &changed);
     148           0 :     if (NS_FAILED(result) || !changed) {
     149           0 :       return result;
     150             :     }
     151           0 :     newdecl = decl.forget();
     152             :   }
     153             : 
     154           0 :   return SetCSSDeclaration(newdecl);
     155             : }
     156             : 
     157             : NS_IMETHODIMP
     158           0 : nsDOMCSSDeclaration::GetLength(uint32_t* aLength)
     159             : {
     160           0 :   DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read);
     161             : 
     162           0 :   if (decl) {
     163           0 :     *aLength = decl->Count();
     164             :   } else {
     165           0 :     *aLength = 0;
     166             :   }
     167             : 
     168           0 :   return NS_OK;
     169             : }
     170             : 
     171             : already_AddRefed<dom::CSSValue>
     172           0 : nsDOMCSSDeclaration::GetPropertyCSSValue(const nsAString& aPropertyName, ErrorResult& aRv)
     173             : {
     174             :   // We don't support CSSValue yet so we'll just return null...
     175             : 
     176           0 :   return nullptr;
     177             : }
     178             : 
     179             : void
     180           0 : nsDOMCSSDeclaration::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aPropName)
     181             : {
     182           0 :   DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read);
     183           0 :   aFound = decl && decl->GetNthProperty(aIndex, aPropName);
     184           0 : }
     185             : 
     186             : NS_IMETHODIMP
     187           9 : nsDOMCSSDeclaration::GetPropertyValue(const nsAString& aPropertyName,
     188             :                                       nsAString& aReturn)
     189             : {
     190           9 :   aReturn.Truncate();
     191           9 :   if (DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read)) {
     192           0 :     decl->GetPropertyValue(aPropertyName, aReturn);
     193             :   }
     194           9 :   return NS_OK;
     195             : }
     196             : 
     197             : NS_IMETHODIMP
     198           0 : nsDOMCSSDeclaration::GetAuthoredPropertyValue(const nsAString& aPropertyName,
     199             :                                               nsAString& aReturn)
     200             : {
     201           0 :   if (DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read)) {
     202           0 :     decl->GetAuthoredPropertyValue(aPropertyName, aReturn);
     203             :   }
     204           0 :   return NS_OK;
     205             : }
     206             : 
     207             : NS_IMETHODIMP
     208           0 : nsDOMCSSDeclaration::GetPropertyPriority(const nsAString& aPropertyName,
     209             :                                          nsAString& aReturn)
     210             : {
     211           0 :   DeclarationBlock* decl = GetCSSDeclaration(eOperation_Read);
     212             : 
     213           0 :   aReturn.Truncate();
     214           0 :   if (decl && decl->GetPropertyIsImportant(aPropertyName)) {
     215           0 :     aReturn.AssignLiteral("important");
     216             :   }
     217             : 
     218           0 :   return NS_OK;
     219             : }
     220             : 
     221             : NS_IMETHODIMP
     222           0 : nsDOMCSSDeclaration::SetProperty(const nsAString& aPropertyName,
     223             :                                  const nsAString& aValue,
     224             :                                  const nsAString& aPriority)
     225             : {
     226           0 :   if (aValue.IsEmpty()) {
     227             :     // If the new value of the property is an empty string we remove the
     228             :     // property.
     229             :     // XXX this ignores the priority string, should it?
     230           0 :     return RemovePropertyInternal(aPropertyName);
     231             :   }
     232             : 
     233             :   // In the common (and fast) cases we can use the property id
     234             :   nsCSSPropertyID propID =
     235           0 :     nsCSSProps::LookupProperty(aPropertyName, CSSEnabledState::eForAllContent);
     236           0 :   if (propID == eCSSProperty_UNKNOWN) {
     237           0 :     return NS_OK;
     238             :   }
     239             : 
     240             :   bool important;
     241           0 :   if (aPriority.IsEmpty()) {
     242           0 :     important = false;
     243           0 :   } else if (aPriority.EqualsLiteral("important")) {
     244           0 :     important = true;
     245             :   } else {
     246             :     // XXX silent failure?
     247           0 :     return NS_OK;
     248             :   }
     249             : 
     250           0 :   if (propID == eCSSPropertyExtra_variable) {
     251           0 :     return ParseCustomPropertyValue(aPropertyName, aValue, important);
     252             :   }
     253           0 :   return ParsePropertyValue(propID, aValue, important);
     254             : }
     255             : 
     256             : NS_IMETHODIMP
     257           9 : nsDOMCSSDeclaration::RemoveProperty(const nsAString& aPropertyName,
     258             :                                     nsAString& aReturn)
     259             : {
     260           9 :   nsresult rv = GetPropertyValue(aPropertyName, aReturn);
     261           9 :   NS_ENSURE_SUCCESS(rv, rv);
     262           9 :   return RemovePropertyInternal(aPropertyName);
     263             : }
     264             : 
     265             : /* static */ void
     266           0 : nsDOMCSSDeclaration::GetCSSParsingEnvironmentForRule(css::Rule* aRule,
     267             :                                                      CSSParsingEnvironment& aCSSParseEnv)
     268             : {
     269           0 :   StyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
     270           0 :   if (!sheet) {
     271           0 :     aCSSParseEnv.mPrincipal = nullptr;
     272           0 :     return;
     273             :   }
     274             : 
     275           0 :   nsIDocument* document = sheet->GetAssociatedDocument();
     276           0 :   aCSSParseEnv.mSheetURI = sheet->GetSheetURI();
     277           0 :   aCSSParseEnv.mBaseURI = sheet->GetBaseURI();
     278           0 :   aCSSParseEnv.mPrincipal = sheet->Principal();
     279           0 :   aCSSParseEnv.mCSSLoader = document ? document->CSSLoader() : nullptr;
     280             : }
     281             : 
     282             : /* static */ nsDOMCSSDeclaration::ServoCSSParsingEnvironment
     283           0 : nsDOMCSSDeclaration::GetServoCSSParsingEnvironmentForRule(const css::Rule* aRule)
     284             : {
     285           0 :   StyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
     286           0 :   if (!sheet) {
     287           0 :     return { nullptr, eCompatibility_FullStandards, nullptr };
     288             :   }
     289             : 
     290           0 :   if (nsIDocument* document = aRule->GetDocument()) {
     291             :     return {
     292             :       sheet->AsServo()->URLData(),
     293             :       document->GetCompatibilityMode(),
     294             :       document->CSSLoader(),
     295           0 :     };
     296             :   }
     297             : 
     298             :   return {
     299             :     sheet->AsServo()->URLData(),
     300             :     eCompatibility_FullStandards,
     301             :     nullptr,
     302           0 :   };
     303             : }
     304             : 
     305             : template<typename GeckoFunc, typename ServoFunc>
     306             : nsresult
     307           8 : nsDOMCSSDeclaration::ModifyDeclaration(GeckoFunc aGeckoFunc,
     308             :                                        ServoFunc aServoFunc)
     309             : {
     310           8 :   DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_Modify);
     311           8 :   if (!olddecl) {
     312           0 :     return NS_ERROR_NOT_AVAILABLE;
     313             :   }
     314             : 
     315             :   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
     316             :   // Attribute setting code, which leads in turn to BeginUpdate.  We
     317             :   // need to start the update now so that the old rule doesn't get used
     318             :   // between when we mutate the declaration and when we set the new
     319             :   // rule (see stack in bug 209575).
     320          16 :   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
     321          16 :   RefPtr<DeclarationBlock> decl;
     322           8 :   if (olddecl->IsServo() && !olddecl->IsDirty()) {
     323             :     // In stylo, the old DeclarationBlock is stored in element's rule node tree
     324             :     // directly, to avoid new values replacing the DeclarationBlock in the tree
     325             :     // directly, we need to copy the old one here if we haven't yet copied.
     326             :     // As a result the new value does not replace rule node tree until traversal
     327             :     // happens.
     328           0 :     decl = olddecl->Clone();
     329             :   } else {
     330           8 :     decl = olddecl->EnsureMutable();
     331             :   }
     332             : 
     333             :   bool changed;
     334           8 :   if (decl->IsGecko()) {
     335          16 :     CSSParsingEnvironment geckoEnv;
     336           8 :     GetCSSParsingEnvironment(geckoEnv);
     337           8 :     if (!geckoEnv.mPrincipal) {
     338           0 :       return NS_ERROR_NOT_AVAILABLE;
     339             :     }
     340             : 
     341           8 :     aGeckoFunc(decl->AsGecko(), geckoEnv, &changed);
     342             :   } else {
     343           0 :     ServoCSSParsingEnvironment servoEnv = GetServoCSSParsingEnvironment();
     344           0 :     if (!servoEnv.mUrlExtraData) {
     345           0 :       return NS_ERROR_NOT_AVAILABLE;
     346             :     }
     347             : 
     348           0 :     changed = aServoFunc(decl->AsServo(), servoEnv);
     349             :   }
     350           8 :   if (!changed) {
     351             :     // Parsing failed -- but we don't throw an exception for that.
     352           4 :     return NS_OK;
     353             :   }
     354             : 
     355           4 :   return SetCSSDeclaration(decl);
     356             : }
     357             : 
     358             : nsresult
     359           8 : nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSPropertyID aPropID,
     360             :                                         const nsAString& aPropValue,
     361             :                                         bool aIsImportant)
     362             : {
     363           8 :   return ModifyDeclaration(
     364           8 :     [&](css::Declaration* decl, CSSParsingEnvironment& env, bool* changed) {
     365          16 :       nsCSSParser cssParser(env.mCSSLoader);
     366           8 :       cssParser.ParseProperty(aPropID, aPropValue,
     367             :                               env.mSheetURI, env.mBaseURI, env.mPrincipal,
     368          16 :                               decl, changed, aIsImportant);
     369           8 :     },
     370           0 :     [&](ServoDeclarationBlock* decl, ServoCSSParsingEnvironment& env) {
     371           0 :       NS_ConvertUTF16toUTF8 value(aPropValue);
     372           0 :       return Servo_DeclarationBlock_SetPropertyById(
     373           0 :         decl->Raw(), aPropID, &value, aIsImportant, env.mUrlExtraData,
     374           0 :         ParsingMode::Default, env.mCompatMode, env.mLoader);
     375           8 :     });
     376             : }
     377             : 
     378             : nsresult
     379           0 : nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
     380             :                                               const nsAString& aPropValue,
     381             :                                               bool aIsImportant)
     382             : {
     383           0 :   MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
     384           0 :   return ModifyDeclaration(
     385           0 :     [&](css::Declaration* decl, CSSParsingEnvironment& env, bool* changed) {
     386           0 :       nsCSSParser cssParser(env.mCSSLoader);
     387           0 :       auto propName = Substring(aPropertyName, CSS_CUSTOM_NAME_PREFIX_LENGTH);
     388           0 :       cssParser.ParseVariable(propName, aPropValue, env.mSheetURI,
     389             :                               env.mBaseURI, env.mPrincipal, decl,
     390           0 :                               changed, aIsImportant);
     391           0 :     },
     392           0 :     [&](ServoDeclarationBlock* decl, ServoCSSParsingEnvironment& env) {
     393           0 :       NS_ConvertUTF16toUTF8 property(aPropertyName);
     394           0 :       NS_ConvertUTF16toUTF8 value(aPropValue);
     395           0 :       return Servo_DeclarationBlock_SetProperty(
     396           0 :         decl->Raw(), &property, &value, aIsImportant, env.mUrlExtraData,
     397           0 :         ParsingMode::Default, env.mCompatMode, env.mLoader);
     398           0 :     });
     399             : }
     400             : 
     401             : nsresult
     402           2 : nsDOMCSSDeclaration::RemovePropertyInternal(nsCSSPropertyID aPropID)
     403             : {
     404           2 :   DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_RemoveProperty);
     405           2 :   if (!olddecl) {
     406           1 :     return NS_OK; // no decl, so nothing to remove
     407             :   }
     408             : 
     409             :   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
     410             :   // Attribute setting code, which leads in turn to BeginUpdate.  We
     411             :   // need to start the update now so that the old rule doesn't get used
     412             :   // between when we mutate the declaration and when we set the new
     413             :   // rule (see stack in bug 209575).
     414           2 :   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
     415             : 
     416           2 :   RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
     417           1 :   decl->RemovePropertyByID(aPropID);
     418           1 :   return SetCSSDeclaration(decl);
     419             : }
     420             : 
     421             : nsresult
     422           9 : nsDOMCSSDeclaration::RemovePropertyInternal(const nsAString& aPropertyName)
     423             : {
     424           9 :   DeclarationBlock* olddecl = GetCSSDeclaration(eOperation_RemoveProperty);
     425           9 :   if (!olddecl) {
     426           9 :     return NS_OK; // no decl, so nothing to remove
     427             :   }
     428             : 
     429             :   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
     430             :   // Attribute setting code, which leads in turn to BeginUpdate.  We
     431             :   // need to start the update now so that the old rule doesn't get used
     432             :   // between when we mutate the declaration and when we set the new
     433             :   // rule (see stack in bug 209575).
     434           0 :   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
     435             : 
     436           0 :   RefPtr<DeclarationBlock> decl = olddecl->EnsureMutable();
     437           0 :   decl->RemoveProperty(aPropertyName);
     438           0 :   return SetCSSDeclaration(decl);
     439             : }

Generated by: LCOV version 1.13