Bug 1231682 part 1: When nsCSSParser is parsing a property-alias, keep track of the alias in a member-var. r=heycam draft
authorDaniel Holbert <dholbert@cs.stanford.edu>
Tue, 22 Mar 2016 11:23:35 -0700
changeset 343449 34e1cc00eb4e24a7e42ac4af56dbd202c52b53db
parent 343448 c7a7401fc7e371f9dc9adfc9c93878926c47000b
child 343450 cad52a56be20e66f51e5be398138d1ee61e75971
push id13627
push userdholbert@mozilla.com
push dateTue, 22 Mar 2016 18:23:56 +0000
reviewersheycam
bugs1231682
milestone48.0a1
Bug 1231682 part 1: When nsCSSParser is parsing a property-alias, keep track of the alias in a member-var. r=heycam MozReview-Commit-ID: 6kKrOQsfWnW
layout/style/nsCSSParser.cpp
layout/style/nsCSSProps.cpp
layout/style/nsCSSProps.h
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -361,18 +361,28 @@ public:
       enabledState |= nsCSSProps::eEnabledInUASheets;
     }
     if (mIsChrome) {
       enabledState |= nsCSSProps::eEnabledInChrome;
     }
     return enabledState;
   }
 
-  nsCSSProperty LookupEnabledProperty(const nsAString& aProperty) {
-    return nsCSSProps::LookupProperty(aProperty, PropertyEnabledState());
+  nsCSSProperty LookupEnabledProperty(const nsAString& aProperty,
+                                      nsCSSProperty* aAliasPropID) {
+    nsCSSProperty propID = nsCSSProps::LookupProperty(aProperty,
+                                                      PropertyEnabledState(),
+                                                      aAliasPropID);
+    MOZ_ASSERT(!aAliasPropID ||
+               *aAliasPropID == eCSSProperty_UNKNOWN ||
+               (*aAliasPropID >= eCSSProperty_COUNT &&
+                *aAliasPropID < eCSSProperty_COUNT_with_aliases),
+               "Outparam *aAliasPropID should end up UNKNOWN or a valid alias");
+
+    return propID;
   }
 
 protected:
   class nsAutoParseCompoundProperty;
   friend class nsAutoParseCompoundProperty;
 
   class nsAutoFailingSupportsRule;
   friend class nsAutoFailingSupportsRule;
@@ -1355,16 +1365,23 @@ protected:
   RefPtr<CSSStyleSheet> mSheet;
 
   // Used for @import rules
   css::Loader* mChildLoader; // not ref counted, it owns us
 
   // Any sheets we may reuse when parsing an @import.
   css::LoaderReusableStyleSheets* mReusableSheets;
 
+  // If we're parsing a property-alias, this variable should be set to the ID
+  // of the alias for the duration of the parse operation. (Generally, wherever
+  // we call LookupEnabledProperty() followed by ParseProperty(), this variable
+  // should be set between those two calls & should be cleared after
+  // ParseProperty() completes).
+  nsCSSProperty mAliasBeingParsed;
+
   // Sheet section we're in.  This is used to enforce correct ordering of the
   // various rule types (eg the fact that a @charset rule must come before
   // anything else).  Note that there are checks of similar things in various
   // places in CSSStyleSheet.cpp (e.g in insertRule, RebuildChildList).
   enum nsCSSSection {
     eCSSSection_Charset,
     eCSSSection_Import,
     eCSSSection_NameSpace,
@@ -1511,16 +1528,17 @@ static void AppendRuleToSheet(css::Rule*
   mReporter->ClearError()
 
 CSSParserImpl::CSSParserImpl()
   : mToken(),
     mScanner(nullptr),
     mReporter(nullptr),
     mChildLoader(nullptr),
     mReusableSheets(nullptr),
+    mAliasBeingParsed(eCSSProperty_UNKNOWN),
     mSection(eCSSSection_Charset),
     mNameSpaceMap(nullptr),
     mHavePushBack(false),
     mNavQuirkMode(false),
     mHashlessColorQuirk(false),
     mUnitlessLengthQuirk(false),
     mParsingMode(css::eAuthorSheetFeatures),
     mIsChrome(false),
@@ -2297,17 +2315,18 @@ CSSParserImpl::ParseKeyframeSelectorStri
 
 bool
 CSSParserImpl::EvaluateSupportsDeclaration(const nsAString& aProperty,
                                            const nsAString& aValue,
                                            nsIURI* aDocURL,
                                            nsIURI* aBaseURL,
                                            nsIPrincipal* aDocPrincipal)
 {
-  nsCSSProperty propID = LookupEnabledProperty(aProperty);
+  nsCSSProperty aliasPropID;
+  nsCSSProperty propID = LookupEnabledProperty(aProperty, &aliasPropID);
   if (propID == eCSSProperty_UNKNOWN) {
     return false;
   }
 
   nsCSSScanner scanner(aValue, 0);
   css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURL);
   InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal);
   nsAutoSuppressErrors suppressErrors(this);
@@ -2319,16 +2338,20 @@ CSSParserImpl::EvaluateSupportsDeclarati
                          CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--"));
     const nsDependentSubstring varName =
       Substring(aProperty, CSS_CUSTOM_NAME_PREFIX_LENGTH);  // remove '--'
     CSSVariableDeclarations::Type variableType;
     nsString variableValue;
     parsedOK = ParseVariableDeclaration(&variableType, variableValue) &&
                !GetToken(true);
   } else {
+    AutoRestore<nsCSSProperty> autoRestore(mAliasBeingParsed);
+    if (aliasPropID != eCSSProperty_UNKNOWN) {
+      mAliasBeingParsed = aliasPropID;
+    }
     parsedOK = ParseProperty(propID) && !GetToken(true);
 
     mTempData.ClearProperty(propID);
     mTempData.AssertInitialState();
   }
 
   CLEAR_ERROR();
   ReleaseScanner();
@@ -4586,17 +4609,18 @@ CSSParserImpl::ParseSupportsConditionInP
 
   if (mToken.mType == eCSSToken_Ident) {
     if (!mToken.mIdent.LowerCaseEqualsLiteral("not")) {
       nsAutoString propertyName = mToken.mIdent;
       if (!ExpectSymbol(':', true)) {
         return false;
       }
 
-      nsCSSProperty propID = LookupEnabledProperty(propertyName);
+      nsCSSProperty aliasPropID;
+      nsCSSProperty propID = LookupEnabledProperty(propertyName, &aliasPropID);
       if (propID == eCSSProperty_UNKNOWN) {
         if (ExpectSymbol(')', true)) {
           UngetToken();
           return false;
         }
         aConditionMet = false;
         SkipUntil(')');
         UngetToken();
@@ -4614,16 +4638,20 @@ CSSParserImpl::ParseSupportsConditionInP
           SkipUntil(')');
           UngetToken();
         }
       } else {
         if (ExpectSymbol(')', true)) {
           UngetToken();
           return false;
         }
+        AutoRestore<nsCSSProperty> autoRestore(mAliasBeingParsed);
+        if (aliasPropID != eCSSProperty_UNKNOWN) {
+          mAliasBeingParsed = aliasPropID;
+        }
         aConditionMet = ParseProperty(propID) &&
                         ParsePriority() != ePriority_Error;
         if (!aConditionMet) {
           SkipUntil(')');
           UngetToken();
         }
         mTempData.ClearProperty(propID);
         mTempData.AssertInitialState();
@@ -7185,17 +7213,19 @@ CSSParserImpl::ParseDeclaration(css::Dec
     if (!ParseVariableDeclaration(&variableType, variableValue)) {
       REPORT_UNEXPECTED_P(PEValueParsingError, propertyName);
       REPORT_UNEXPECTED(PEDeclDropped);
       OUTPUT_ERROR();
       return false;
     }
   } else {
     // Map property name to its ID.
-    propID = LookupEnabledProperty(propertyName);
+    nsCSSProperty aliasPropID;
+    propID = LookupEnabledProperty(propertyName, &aliasPropID);
+
     if (eCSSProperty_UNKNOWN == propID ||
         eCSSPropertyExtra_variable == propID ||
         (aContext == eCSSContext_Page &&
          !nsCSSProps::PropHasFlags(propID,
                                    CSS_PROPERTY_APPLIES_TO_PAGE_RULE))) { // unknown property
       if (NonMozillaVendorIdentifier(propertyName)) {
         if (!mInSupportsCondition &&
             aContext == eCSSContext_General &&
@@ -7210,16 +7240,24 @@ CSSParserImpl::ParseDeclaration(css::Dec
         }
       } else {
         REPORT_UNEXPECTED_P(PEUnknownProperty, propertyName);
         REPORT_UNEXPECTED(PEDeclDropped);
         OUTPUT_ERROR();
       }
       return false;
     }
+
+    MOZ_ASSERT(mAliasBeingParsed == eCSSProperty_UNKNOWN,
+               "Someone forgot to clear mAliasBeingParsed");
+    AutoRestore<nsCSSProperty> autoRestore(mAliasBeingParsed);
+    if (aliasPropID != eCSSProperty_UNKNOWN) {
+      mAliasBeingParsed = aliasPropID;
+    }
+
     // Then parse the property.
     if (!ParseProperty(propID)) {
       // XXX Much better to put stuff in the value parsers instead...
       REPORT_UNEXPECTED_P(PEValueParsingError, propertyName);
       REPORT_UNEXPECTED(PEDeclDropped);
       OUTPUT_ERROR();
       mTempData.ClearProperty(propID);
       mTempData.AssertInitialState();
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -515,20 +515,25 @@ nsCSSProps::IsCustomPropertyName(const n
 nsCSSProps::IsCustomPropertyName(const nsAString& aProperty)
 {
   return aProperty.Length() >= CSS_CUSTOM_NAME_PREFIX_LENGTH &&
          StringBeginsWith(aProperty, NS_LITERAL_STRING("--"));
 }
 
 nsCSSProperty
 nsCSSProps::LookupProperty(const nsACString& aProperty,
-                           EnabledState aEnabled)
+                           EnabledState aEnabled,
+                           nsCSSProperty* aAliasPropID /* outparam */)
 {
   MOZ_ASSERT(gPropertyTable, "no lookup table, needs addref");
 
+  if (aAliasPropID) {
+    *aAliasPropID = eCSSProperty_UNKNOWN;
+  }
+
   if (nsLayoutUtils::CSSVariablesEnabled() &&
       IsCustomPropertyName(aProperty)) {
     return eCSSPropertyExtra_variable;
   }
 
   nsCSSProperty res = nsCSSProperty(gPropertyTable->Lookup(aProperty));
   if (MOZ_LIKELY(res < eCSSProperty_COUNT)) {
     if (res != eCSSProperty_UNKNOWN && !IsEnabled(res, aEnabled)) {
@@ -536,29 +541,41 @@ nsCSSProps::LookupProperty(const nsACStr
     }
     return res;
   }
   MOZ_ASSERT(eCSSAliasCount != 0,
              "'res' must be an alias at this point so we better have some!");
   // We intentionally don't support eEnabledInUASheets or eEnabledInChrome
   // for aliases yet because it's unlikely there will be a need for it.
   if (IsEnabled(res) || aEnabled == eIgnoreEnabledState) {
+    // Save the alias's propID. (Don't set outparam yet, though - not until
+    // we're sure we're succeeding.)
+    nsCSSProperty aliasPropID = res;
     res = gAliases[res - eCSSProperty_COUNT];
     MOZ_ASSERT(0 <= res && res < eCSSProperty_COUNT,
                "aliases must not point to other aliases");
     if (IsEnabled(res) || aEnabled == eIgnoreEnabledState) {
+      if (aAliasPropID) {
+        *aAliasPropID = aliasPropID;
+      }
       return res;
     }
   }
   return eCSSProperty_UNKNOWN;
 }
 
 nsCSSProperty
-nsCSSProps::LookupProperty(const nsAString& aProperty, EnabledState aEnabled)
+nsCSSProps::LookupProperty(const nsAString& aProperty,
+                           EnabledState aEnabled,
+                           nsCSSProperty* aAliasPropID /* outparam */)
 {
+  if (aAliasPropID) {
+    *aAliasPropID = eCSSProperty_UNKNOWN;
+  }
+
   if (nsLayoutUtils::CSSVariablesEnabled() &&
       IsCustomPropertyName(aProperty)) {
     return eCSSPropertyExtra_variable;
   }
 
   // This is faster than converting and calling
   // LookupProperty(nsACString&).  The table will do its own
   // converting and avoid a PromiseFlatCString() call.
@@ -570,20 +587,26 @@ nsCSSProps::LookupProperty(const nsAStri
     }
     return res;
   }
   MOZ_ASSERT(eCSSAliasCount != 0,
              "'res' must be an alias at this point so we better have some!");
   // We intentionally don't support eEnabledInUASheets or eEnabledInChrome
   // for aliases yet because it's unlikely there will be a need for it.
   if (IsEnabled(res) || aEnabled == eIgnoreEnabledState) {
+    // Save the alias's propID. (Don't set outparam yet, though - not until
+    // we're sure we're succeeding.)
+    nsCSSProperty aliasPropID = res;
     res = gAliases[res - eCSSProperty_COUNT];
     MOZ_ASSERT(0 <= res && res < eCSSProperty_COUNT,
                "aliases must not point to other aliases");
     if (IsEnabled(res) || aEnabled == eIgnoreEnabledState) {
+      if (aAliasPropID) {
+        *aAliasPropID = aliasPropID;
+      }
       return res;
     }
   }
   return eCSSProperty_UNKNOWN;
 }
 
 nsCSSProperty
 nsCSSProps::LookupPropertyByIDLName(const nsACString& aPropertyIDLName,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -354,22 +354,34 @@ public:
     // Special value to unconditionally enable a property. This implies all the
     // bits above, but is strictly more than just their OR-ed union.
     // This just skips any test so a property will be enabled even if it would
     // have been disabled with all the bits above set.
     eIgnoreEnabledState   = 0xff
   };
 
   // Looks up the property with name aProperty and returns its corresponding
-  // nsCSSProperty value.  If aProperty is the name of a custom property,
-  // then eCSSPropertyExtra_variable will be returned.
+  // nsCSSProperty value.
+  //  * If aProperty is the name of a custom property, then
+  //    eCSSPropertyExtra_variable will be returned.
+  //  * If aProperty is the name of a property alias (e.g. a vendor-prefixed
+  //    property name), then the target (unprefixed) property ID will be
+  //    returned.
+  //
+  // If the outparam 'aAliasPropID' is non-null, this function will set its
+  // value to indicate whether aProperty is the name of an alias. Specifically:
+  // if aProperty _is_ the name of an alias, then *aAliasPropID will be set to
+  // the nsCSSProperty ID for the alias. Otherwise, *aAliasPropID will be set
+  // to eCSSProperty_UNKNOWN.
   static nsCSSProperty LookupProperty(const nsAString& aProperty,
-                                      EnabledState aEnabled);
+                                      EnabledState aEnabled,
+                                      nsCSSProperty* aAliasPropID = nullptr);
   static nsCSSProperty LookupProperty(const nsACString& aProperty,
-                                      EnabledState aEnabled);
+                                      EnabledState aEnabled,
+                                      nsCSSProperty* aAliasPropID = nullptr);
   // As above, but looked up using a property's IDL name.
   // eCSSPropertyExtra_variable won't be returned from these methods.
   static nsCSSProperty LookupPropertyByIDLName(
       const nsAString& aPropertyIDLName,
       EnabledState aEnabled);
   static nsCSSProperty LookupPropertyByIDLName(
       const nsACString& aPropertyIDLName,
       EnabledState aEnabled);