layout/style/nsDOMCSSDeclaration.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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/. */
     6 /* base class for DOM objects for element.style and cssStyleRule.style */
     8 #include "nsDOMCSSDeclaration.h"
    10 #include "nsCSSParser.h"
    11 #include "nsCSSStyleSheet.h"
    12 #include "mozilla/css/Rule.h"
    13 #include "mozilla/css/Declaration.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"
    22 using namespace mozilla;
    24 nsDOMCSSDeclaration::~nsDOMCSSDeclaration()
    25 {
    26 }
    28 /* virtual */ JSObject*
    29 nsDOMCSSDeclaration::WrapObject(JSContext* aCx)
    30 {
    31   return dom::CSS2PropertiesBinding::Wrap(aCx, this);
    32 }
    34 NS_INTERFACE_TABLE_HEAD(nsDOMCSSDeclaration)
    35   NS_INTERFACE_TABLE(nsDOMCSSDeclaration,
    36                      nsICSSDeclaration,
    37                      nsIDOMCSSStyleDeclaration)
    38   NS_INTERFACE_TABLE_TO_MAP_SEGUE
    39 NS_INTERFACE_MAP_END
    41 NS_IMETHODIMP
    42 nsDOMCSSDeclaration::GetPropertyValue(const nsCSSProperty aPropID,
    43                                       nsAString& aValue)
    44 {
    45   NS_PRECONDITION(aPropID != eCSSProperty_UNKNOWN,
    46                   "Should never pass eCSSProperty_UNKNOWN around");
    48   css::Declaration* decl = GetCSSDeclaration(false);
    50   aValue.Truncate();
    51   if (decl) {
    52     decl->GetValue(aPropID, aValue);
    53   }
    54   return NS_OK;
    55 }
    57 void
    58 nsDOMCSSDeclaration::GetCustomPropertyValue(const nsAString& aPropertyName,
    59                                             nsAString& aValue)
    60 {
    61   MOZ_ASSERT(Substring(aPropertyName, 0,
    62                        CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--"));
    64   css::Declaration* decl = GetCSSDeclaration(false);
    65   if (!decl) {
    66     aValue.Truncate();
    67     return;
    68   }
    70   decl->GetVariableDeclaration(Substring(aPropertyName,
    71                                          CSS_CUSTOM_NAME_PREFIX_LENGTH),
    72                                aValue);
    73 }
    75 NS_IMETHODIMP
    76 nsDOMCSSDeclaration::SetPropertyValue(const nsCSSProperty aPropID,
    77                                       const nsAString& aValue)
    78 {
    79   if (aValue.IsEmpty()) {
    80     // If the new value of the property is an empty string we remove the
    81     // property.
    82     return RemoveProperty(aPropID);
    83   }
    85   return ParsePropertyValue(aPropID, aValue, false);
    86 }
    89 NS_IMETHODIMP
    90 nsDOMCSSDeclaration::GetCssText(nsAString& aCssText)
    91 {
    92   css::Declaration* decl = GetCSSDeclaration(false);
    93   aCssText.Truncate();
    95   if (decl) {
    96     decl->ToString(aCssText);
    97   }
    99   return NS_OK;
   100 }
   102 NS_IMETHODIMP
   103 nsDOMCSSDeclaration::SetCssText(const nsAString& aCssText)
   104 {
   105   // We don't need to *do* anything with the old declaration, but we need
   106   // to ensure that it exists, or else SetCSSDeclaration may crash.
   107   css::Declaration* olddecl = GetCSSDeclaration(true);
   108   if (!olddecl) {
   109     return NS_ERROR_FAILURE;
   110   }
   112   CSSParsingEnvironment env;
   113   GetCSSParsingEnvironment(env);
   114   if (!env.mPrincipal) {
   115     return NS_ERROR_NOT_AVAILABLE;
   116   }
   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   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
   125   nsAutoPtr<css::Declaration> decl(new css::Declaration());
   126   decl->InitializeEmpty();
   127   nsCSSParser cssParser(env.mCSSLoader);
   128   bool changed;
   129   nsresult result = cssParser.ParseDeclarations(aCssText, env.mSheetURI,
   130                                                 env.mBaseURI,
   131                                                 env.mPrincipal, decl, &changed);
   132   if (NS_FAILED(result) || !changed) {
   133     return result;
   134   }
   136   return SetCSSDeclaration(decl.forget());
   137 }
   139 NS_IMETHODIMP
   140 nsDOMCSSDeclaration::GetLength(uint32_t* aLength)
   141 {
   142   css::Declaration* decl = GetCSSDeclaration(false);
   144   if (decl) {
   145     *aLength = decl->Count();
   146   } else {
   147     *aLength = 0;
   148   }
   150   return NS_OK;
   151 }
   153 already_AddRefed<dom::CSSValue>
   154 nsDOMCSSDeclaration::GetPropertyCSSValue(const nsAString& aPropertyName, ErrorResult& aRv)
   155 {
   156   // We don't support CSSValue yet so we'll just return null...
   158   return nullptr;
   159 }
   161 void
   162 nsDOMCSSDeclaration::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aPropName)
   163 {
   164   css::Declaration* decl = GetCSSDeclaration(false);
   165   aFound = decl && decl->GetNthProperty(aIndex, aPropName);
   166 }
   168 NS_IMETHODIMP
   169 nsDOMCSSDeclaration::GetPropertyValue(const nsAString& aPropertyName,
   170                                       nsAString& aReturn)
   171 {
   172   const nsCSSProperty propID =
   173     nsCSSProps::LookupProperty(aPropertyName,
   174                                nsCSSProps::eEnabledForAllContent);
   175   if (propID == eCSSProperty_UNKNOWN) {
   176     aReturn.Truncate();
   177     return NS_OK;
   178   }
   180   if (propID == eCSSPropertyExtra_variable) {
   181     GetCustomPropertyValue(aPropertyName, aReturn);
   182     return NS_OK;
   183   }
   185   return GetPropertyValue(propID, aReturn);
   186 }
   188 NS_IMETHODIMP
   189 nsDOMCSSDeclaration::GetAuthoredPropertyValue(const nsAString& aPropertyName,
   190                                               nsAString& aReturn)
   191 {
   192   const nsCSSProperty propID =
   193     nsCSSProps::LookupProperty(aPropertyName,
   194                                nsCSSProps::eEnabledForAllContent);
   195   if (propID == eCSSProperty_UNKNOWN) {
   196     aReturn.Truncate();
   197     return NS_OK;
   198   }
   200   if (propID == eCSSPropertyExtra_variable) {
   201     GetCustomPropertyValue(aPropertyName, aReturn);
   202     return NS_OK;
   203   }
   205   css::Declaration* decl = GetCSSDeclaration(false);
   206   if (!decl) {
   207     return NS_ERROR_FAILURE;
   208   }
   210   decl->GetAuthoredValue(propID, aReturn);
   211   return NS_OK;
   212 }
   214 NS_IMETHODIMP
   215 nsDOMCSSDeclaration::GetPropertyPriority(const nsAString& aPropertyName,
   216                                          nsAString& aReturn)
   217 {
   218   css::Declaration* decl = GetCSSDeclaration(false);
   220   aReturn.Truncate();
   221   if (decl && decl->GetValueIsImportant(aPropertyName)) {
   222     aReturn.AssignLiteral("important");
   223   }
   225   return NS_OK;
   226 }
   228 NS_IMETHODIMP
   229 nsDOMCSSDeclaration::SetProperty(const nsAString& aPropertyName,
   230                                  const nsAString& aValue,
   231                                  const nsAString& aPriority)
   232 {
   233   // In the common (and fast) cases we can use the property id
   234   nsCSSProperty propID =
   235     nsCSSProps::LookupProperty(aPropertyName,
   236                                nsCSSProps::eEnabledForAllContent);
   237   if (propID == eCSSProperty_UNKNOWN) {
   238     return NS_OK;
   239   }
   241   if (aValue.IsEmpty()) {
   242     // If the new value of the property is an empty string we remove the
   243     // property.
   244     // XXX this ignores the priority string, should it?
   245     if (propID == eCSSPropertyExtra_variable) {
   246       return RemoveCustomProperty(aPropertyName);
   247     }
   248     return RemoveProperty(propID);
   249   }
   251   bool important;
   252   if (aPriority.IsEmpty()) {
   253     important = false;
   254   } else if (aPriority.EqualsLiteral("important")) {
   255     important = true;
   256   } else {
   257     // XXX silent failure?
   258     return NS_OK;
   259   }
   261   if (propID == eCSSPropertyExtra_variable) {
   262     return ParseCustomPropertyValue(aPropertyName, aValue, important);
   263   }
   264   return ParsePropertyValue(propID, aValue, important);
   265 }
   267 NS_IMETHODIMP
   268 nsDOMCSSDeclaration::RemoveProperty(const nsAString& aPropertyName,
   269                                     nsAString& aReturn)
   270 {
   271   const nsCSSProperty propID =
   272     nsCSSProps::LookupProperty(aPropertyName,
   273                                nsCSSProps::eEnabledForAllContent);
   274   if (propID == eCSSProperty_UNKNOWN) {
   275     aReturn.Truncate();
   276     return NS_OK;
   277   }
   279   if (propID == eCSSPropertyExtra_variable) {
   280     RemoveCustomProperty(aPropertyName);
   281     return NS_OK;
   282   }
   284   nsresult rv = GetPropertyValue(propID, aReturn);
   285   NS_ENSURE_SUCCESS(rv, rv);
   287   return RemoveProperty(propID);
   288 }
   290 /* static */ void
   291 nsDOMCSSDeclaration::GetCSSParsingEnvironmentForRule(css::Rule* aRule,
   292                                                      CSSParsingEnvironment& aCSSParseEnv)
   293 {
   294   nsIStyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
   295   nsRefPtr<nsCSSStyleSheet> cssSheet(do_QueryObject(sheet));
   296   if (!cssSheet) {
   297     aCSSParseEnv.mPrincipal = nullptr;
   298     return;
   299   }
   301   nsIDocument* document = sheet->GetOwningDocument();
   302   aCSSParseEnv.mSheetURI = sheet->GetSheetURI();
   303   aCSSParseEnv.mBaseURI = sheet->GetBaseURI();
   304   aCSSParseEnv.mPrincipal = cssSheet->Principal();
   305   aCSSParseEnv.mCSSLoader = document ? document->CSSLoader() : nullptr;
   306 }
   308 nsresult
   309 nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSProperty aPropID,
   310                                         const nsAString& aPropValue,
   311                                         bool aIsImportant)
   312 {
   313   css::Declaration* olddecl = GetCSSDeclaration(true);
   314   if (!olddecl) {
   315     return NS_ERROR_FAILURE;
   316   }
   318   CSSParsingEnvironment env;
   319   GetCSSParsingEnvironment(env);
   320   if (!env.mPrincipal) {
   321     return NS_ERROR_NOT_AVAILABLE;
   322   }
   324   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   325   // Attribute setting code, which leads in turn to BeginUpdate.  We
   326   // need to start the update now so that the old rule doesn't get used
   327   // between when we mutate the declaration and when we set the new
   328   // rule (see stack in bug 209575).
   329   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
   330   css::Declaration* decl = olddecl->EnsureMutable();
   332   nsCSSParser cssParser(env.mCSSLoader);
   333   bool changed;
   334   nsresult result = cssParser.ParseProperty(aPropID, aPropValue, env.mSheetURI,
   335                                             env.mBaseURI, env.mPrincipal, decl,
   336                                             &changed, aIsImportant);
   337   if (NS_FAILED(result) || !changed) {
   338     if (decl != olddecl) {
   339       delete decl;
   340     }
   341     return result;
   342   }
   344   return SetCSSDeclaration(decl);
   345 }
   347 nsresult
   348 nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
   349                                               const nsAString& aPropValue,
   350                                               bool aIsImportant)
   351 {
   352   MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName));
   354   css::Declaration* olddecl = GetCSSDeclaration(true);
   355   if (!olddecl) {
   356     return NS_ERROR_FAILURE;
   357   }
   359   CSSParsingEnvironment env;
   360   GetCSSParsingEnvironment(env);
   361   if (!env.mPrincipal) {
   362     return NS_ERROR_NOT_AVAILABLE;
   363   }
   365   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   366   // Attribute setting code, which leads in turn to BeginUpdate.  We
   367   // need to start the update now so that the old rule doesn't get used
   368   // between when we mutate the declaration and when we set the new
   369   // rule (see stack in bug 209575).
   370   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
   371   css::Declaration* decl = olddecl->EnsureMutable();
   373   nsCSSParser cssParser(env.mCSSLoader);
   374   bool changed;
   375   nsresult result =
   376     cssParser.ParseVariable(Substring(aPropertyName,
   377                                       CSS_CUSTOM_NAME_PREFIX_LENGTH),
   378                             aPropValue, env.mSheetURI,
   379                             env.mBaseURI, env.mPrincipal, decl,
   380                             &changed, aIsImportant);
   381   if (NS_FAILED(result) || !changed) {
   382     if (decl != olddecl) {
   383       delete decl;
   384     }
   385     return result;
   386   }
   388   return SetCSSDeclaration(decl);
   389 }
   391 nsresult
   392 nsDOMCSSDeclaration::RemoveProperty(const nsCSSProperty aPropID)
   393 {
   394   css::Declaration* decl = GetCSSDeclaration(false);
   395   if (!decl) {
   396     return NS_OK; // no decl, so nothing to remove
   397   }
   399   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   400   // Attribute setting code, which leads in turn to BeginUpdate.  We
   401   // need to start the update now so that the old rule doesn't get used
   402   // between when we mutate the declaration and when we set the new
   403   // rule (see stack in bug 209575).
   404   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
   406   decl = decl->EnsureMutable();
   407   decl->RemoveProperty(aPropID);
   408   return SetCSSDeclaration(decl);
   409 }
   411 nsresult
   412 nsDOMCSSDeclaration::RemoveCustomProperty(const nsAString& aPropertyName)
   413 {
   414   MOZ_ASSERT(Substring(aPropertyName, 0,
   415                        CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--"));
   417   css::Declaration* decl = GetCSSDeclaration(false);
   418   if (!decl) {
   419     return NS_OK; // no decl, so nothing to remove
   420   }
   422   // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to
   423   // Attribute setting code, which leads in turn to BeginUpdate.  We
   424   // need to start the update now so that the old rule doesn't get used
   425   // between when we mutate the declaration and when we set the new
   426   // rule (see stack in bug 209575).
   427   mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true);
   429   decl = decl->EnsureMutable();
   430   decl->RemoveVariableDeclaration(Substring(aPropertyName,
   431                                             CSS_CUSTOM_NAME_PREFIX_LENGTH));
   432   return SetCSSDeclaration(decl);
   433 }
   435 bool IsCSSPropertyExposedToJS(nsCSSProperty aProperty, JSContext* cx, JSObject* obj)
   436 {
   437   nsCSSProps::EnabledState enabledState = nsCSSProps::eEnabledForAllContent;
   439   // Optimization: we skip checking properties of the JSContext
   440   // in the majority case where the property does not have the
   441   // CSS_PROPERTY_ALWAYS_ENABLED_IN_PRIVILEGED_CONTENT flag.
   442   bool isEnabledInChromeOrCertifiedApp
   443     = nsCSSProps::PropHasFlags(aProperty,
   444                                CSS_PROPERTY_ALWAYS_ENABLED_IN_CHROME_OR_CERTIFIED_APP);
   446   if (isEnabledInChromeOrCertifiedApp) {
   447     if (dom::IsInCertifiedApp(cx, obj) ||
   448         nsContentUtils::ThreadsafeIsCallerChrome())
   449     {
   450       enabledState |= nsCSSProps::eEnabledInChromeOrCertifiedApp;
   451     }
   452   }
   453   return nsCSSProps::IsEnabled(aProperty, enabledState);
   454 }

mercurial