Bug 1107378 part 3: In cases where we're unprefixing, treat "display:-webkit-box" as "display: flex" (& same for "-moz-box" if we previously saw "-webkit-box"). r=dbaron
☠☠ backed out by 68df163b1792 ☠ ☠
authorDaniel Holbert <dholbert@cs.stanford.edu>
Thu, 26 Feb 2015 12:07:07 -0800
changeset 249280 5a8d5e8ff5241612e67fdbe3a952806a19153ba1
parent 249279 960037d0fc98f36d1ed9e8c47a03b677f4f5c778
child 249281 44144b89241487a8b89d3ceaf4a91856bc9060a5
push id7860
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:46:02 +0000
treeherdermozilla-aurora@8ac636cd51f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1107378
milestone39.0a1
Bug 1107378 part 3: In cases where we're unprefixing, treat "display:-webkit-box" as "display: flex" (& same for "-moz-box" if we previously saw "-webkit-box"). r=dbaron
layout/style/nsCSSParser.cpp
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -717,16 +717,23 @@ protected:
   css::Declaration* ParseDeclarationBlock(uint32_t aFlags,
                                           nsCSSContextType aContext = eCSSContext_General);
   bool ParseDeclaration(css::Declaration* aDeclaration,
                         uint32_t aFlags,
                         bool aMustCallValueAppended,
                         bool* aChanged,
                         nsCSSContextType aContext = eCSSContext_General);
 
+  // A "prefix-aware" wrapper for nsCSSKeywords::LookupKeyword().
+  // Use this instead of LookupKeyword() if you might be parsing an unprefixed
+  // property (like "display") for which we emulate a vendor-prefixed value
+  // (like "-webkit-box").
+  nsCSSKeyword LookupKeywordPrefixAware(nsAString& aKeywordStr,
+                                        const KTableValue aKeywordTable[]);
+
   bool ShouldUseUnprefixingService();
   bool ParsePropertyWithUnprefixingService(const nsAString& aPropertyName,
                                            css::Declaration* aDeclaration,
                                            uint32_t aFlags,
                                            bool aMustCallValueAppended,
                                            bool* aChanged,
                                            nsCSSContextType aContext);
 
@@ -1190,16 +1197,22 @@ protected:
   // false.
   bool mInFailingSupportsRule : 1;
 
   // True if we will suppress all parse errors (except unexpected EOFs).
   // This is used to prevent errors for declarations inside a failing
   // @supports rule.
   bool mSuppressErrors : 1;
 
+  // True if we've parsed "display: -webkit-box" as "display: flex" in an
+  // earlier declaration within the current block of declarations, as part of
+  // emulating support for certain -webkit-prefixed properties on certain
+  // sites.
+  bool mDidUnprefixWebkitBoxInEarlierDecl; // not :1 so we can use AutoRestore
+
   // Stack of rule groups; used for @media and such.
   InfallibleTArray<nsRefPtr<css::GroupRule> > mGroupStack;
 
   // During the parsing of a property (which may be a shorthand), the data
   // are stored in |mTempData|.  (It is needed to ensure that parser
   // errors cause the data to be ignored, and to ensure that a
   // non-'!important' declaration does not override an '!important'
   // one.)
@@ -1266,16 +1279,17 @@ CSSParserImpl::CSSParserImpl()
     mUnsafeRulesEnabled(false),
     mIsChromeOrCertifiedApp(false),
     mViewportUnitsEnabled(true),
     mHTMLMediaMode(false),
     mParsingCompoundProperty(false),
     mInSupportsCondition(false),
     mInFailingSupportsRule(false),
     mSuppressErrors(false),
+    mDidUnprefixWebkitBoxInEarlierDecl(false),
     mNextFree(nullptr)
 {
 }
 
 CSSParserImpl::~CSSParserImpl()
 {
   mData.AssertInitialState();
   mTempData.AssertInitialState();
@@ -1494,16 +1508,20 @@ CSSParserImpl::ParseDeclarations(const n
   *aChanged = false;
 
   NS_PRECONDITION(aSheetPrincipal, "Must have principal here!");
 
   nsCSSScanner scanner(aBuffer, 0);
   css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI);
   InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal);
 
+  MOZ_ASSERT(!mDidUnprefixWebkitBoxInEarlierDecl,
+             "Someone forgot to clear the 'did unprefix webkit-box' flag");
+  AutoRestore<bool> autoRestore(mDidUnprefixWebkitBoxInEarlierDecl);
+
   mSection = eCSSSection_General;
 
   mData.AssertInitialState();
   aDeclaration->ClearData();
   // We could check if it was already empty, but...
   *aChanged = true;
 
   for (;;) {
@@ -6138,16 +6156,20 @@ CSSParserImpl::ParseSelector(nsCSSSelect
   return true;
 }
 
 css::Declaration*
 CSSParserImpl::ParseDeclarationBlock(uint32_t aFlags, nsCSSContextType aContext)
 {
   bool checkForBraces = (aFlags & eParseDeclaration_InBraces) != 0;
 
+  MOZ_ASSERT(!mDidUnprefixWebkitBoxInEarlierDecl,
+             "Someone forgot to clear the 'did unprefix webkit-box' flag");
+  AutoRestore<bool> restorer(mDidUnprefixWebkitBoxInEarlierDecl);
+
   if (checkForBraces) {
     if (!ExpectSymbol('{', true)) {
       REPORT_UNEXPECTED_TOKEN(PEBadDeclBlockStart);
       OUTPUT_ERROR();
       return nullptr;
     }
   }
   css::Declaration* declaration = new css::Declaration();
@@ -6545,16 +6567,51 @@ CSSParserImpl::ParseTreePseudoElement(ns
     }
   }
   *aPseudoElementArgs = fakeSelector.mClassList;
   fakeSelector.mClassList = nullptr;
   return true;
 }
 #endif
 
+nsCSSKeyword
+CSSParserImpl::LookupKeywordPrefixAware(nsAString& aKeywordStr,
+                                        const KTableValue aKeywordTable[])
+{
+  nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(aKeywordStr);
+
+  if (aKeywordTable == nsCSSProps::kDisplayKTable) {
+    if (keyword == eCSSKeyword_UNKNOWN &&
+        ShouldUseUnprefixingService() &&
+        aKeywordStr.EqualsLiteral("-webkit-box")) {
+      // Treat "display: -webkit-box" as "display: flex". In simple scenarios,
+      // they largely behave the same, as long as we use the CSS Unprefixing
+      // Service to also translate the associated properties.
+      mDidUnprefixWebkitBoxInEarlierDecl = true;
+      return eCSSKeyword_flex;
+    }
+
+    // If we've seen "display: -webkit-box" in an earlier declaration and we
+    // tried to unprefix it to emulate support for it, then we have to watch
+    // out for later "display: -moz-box" declarations; they're likely just a
+    // halfhearted attempt at compatibility, and they actually end up stomping
+    // on our emulation of the earlier -webkit-box display-value, via the CSS
+    // cascade. To prevent this problem, we also treat "display: -moz-box" as
+    // "display: flex" (but only if we unprefixed an earlier "-webkit-box").
+    if (mDidUnprefixWebkitBoxInEarlierDecl && keyword == eCSSKeyword__moz_box) {
+      MOZ_ASSERT(ShouldUseUnprefixingService(),
+                 "mDidUnprefixWebkitBoxInEarlierDecl should only be set if "
+                 "we're using the unprefixing service on this site");
+      return eCSSKeyword_flex;
+    }
+  }
+
+  return keyword;
+}
+
 bool
 CSSParserImpl::ShouldUseUnprefixingService()
 {
   if (!sUnprefixingServiceEnabled) {
     return false;
   }
 
   // XXXdholbert Bug 1132743: Check if stylesheet URI is on fixlist here.
@@ -7084,17 +7141,19 @@ CSSParserImpl::ParseVariant(nsCSSValue& 
              "VARIANT_IDENTIFIER_NO_INHERIT");
 
   if (!GetToken(true)) {
     return false;
   }
   nsCSSToken* tk = &mToken;
   if (((aVariantMask & (VARIANT_AHK | VARIANT_NORMAL | VARIANT_NONE | VARIANT_ALL)) != 0) &&
       (eCSSToken_Ident == tk->mType)) {
-    nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(tk->mIdent);
+    nsCSSKeyword keyword = LookupKeywordPrefixAware(tk->mIdent,
+                                                    aKeywordTable);
+
     if (eCSSKeyword_UNKNOWN < keyword) { // known keyword
       if ((aVariantMask & VARIANT_AUTO) != 0) {
         if (eCSSKeyword_auto == keyword) {
           aValue.SetAutoValue();
           return true;
         }
       }
       if ((aVariantMask & VARIANT_INHERIT) != 0) {