Bug 1102650 - Make the :-moz-dir() and :-moz-locale-dir() selectors be valid selectors (matching nothing) with arguments other than rtl and ltr, rather than invalid. r=heycam
authorL. David Baron <dbaron@dbaron.org>
Wed, 26 Nov 2014 22:29:45 -0800
changeset 242145 0ae211c02f121e4ad16f3544ecacc38400a94f1a
parent 242144 3e2da595d50d4da8b43a9e65deac79603dd578f6
child 242146 f88af511f6836fd362c4564bab4f5e61e69509ef
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1102650
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1102650 - Make the :-moz-dir() and :-moz-locale-dir() selectors be valid selectors (matching nothing) with arguments other than rtl and ltr, rather than invalid. r=heycam
layout/style/nsCSSParser.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/test/test_selectors.html
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -5702,25 +5702,22 @@ CSSParserImpl::ParsePseudoClassWithIdent
   }
   // We expect an identifier with a language abbreviation
   if (eCSSToken_Ident != mToken.mType) {
     REPORT_UNEXPECTED_TOKEN(PEPseudoClassArgNotIdent);
     UngetToken();
     return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
   }
 
-  // -moz-locale-dir and -moz-dir can only have values of 'ltr' or 'rtl'.
+  // -moz-locale-dir and -moz-dir take an identifier argument.  While
+  // only 'ltr' and 'rtl' (case-insensitively) will match anything, any
+  // other identifier is still valid.
   if (aType == nsCSSPseudoClasses::ePseudoClass_mozLocaleDir ||
       aType == nsCSSPseudoClasses::ePseudoClass_dir) {
     nsContentUtils::ASCIIToLower(mToken.mIdent); // case insensitive
-    if (!mToken.mIdent.EqualsLiteral("ltr") &&
-        !mToken.mIdent.EqualsLiteral("rtl")) {
-      REPORT_UNEXPECTED_TOKEN(PEBadDirValue);
-      return eSelectorParsingStatus_Error; // our caller calls SkipUntil(')')
-    }
   }
 
   // Add the pseudo with the language parameter
   aSelector.AddPseudoClass(aType, mToken.mIdent.get());
 
   // close the parenthesis
   if (!ExpectSymbol(')', true)) {
     REPORT_UNEXPECTED_TOKEN(PEPseudoClassNoClose);
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -2137,21 +2137,27 @@ static bool SelectorMatches(Element* aEl
 
       case nsCSSPseudoClasses::ePseudoClass_mozLocaleDir:
         {
           bool docIsRTL =
             aTreeMatchContext.mDocument->GetDocumentState().
               HasState(NS_DOCUMENT_STATE_RTL_LOCALE);
 
           nsDependentString dirString(pseudoClass->u.mString);
-          NS_ASSERTION(dirString.EqualsLiteral("ltr") ||
-                       dirString.EqualsLiteral("rtl"),
-                       "invalid value for -moz-locale-dir");
-
-          if (dirString.EqualsLiteral("rtl") != docIsRTL) {
+
+          if (dirString.EqualsLiteral("rtl")) {
+            if (!docIsRTL) {
+              return false;
+            }
+          } else if (dirString.EqualsLiteral("ltr")) {
+            if (docIsRTL) {
+              return false;
+            }
+          } else {
+            // Selectors specifying other directions never match.
             return false;
           }
         }
         break;
 
       case nsCSSPseudoClasses::ePseudoClass_mozLWTheme:
         {
           if (aTreeMatchContext.mDocument->GetDocumentLWTheme() <=
@@ -2206,32 +2212,35 @@ static bool SelectorMatches(Element* aEl
             EventStates states
               = sPseudoClassStateDependences[pseudoClass->mType];
             if (aNodeMatchContext.mStateMask.HasAtLeastOneOfStates(states)) {
               *aDependence = true;
               return false;
             }
           }
 
-          // if we only had to consider HTML, directionality would be exclusively
-          // LTR or RTL, and this could be just
-          //
-          //  if (dirString.EqualsLiteral("rtl") !=
-          //    aElement->StyleState().HasState(NS_EVENT_STATE_RTL)
+          // If we only had to consider HTML, directionality would be
+          // exclusively LTR or RTL.
           //
           // However, in markup languages where there is no direction attribute
           // we have to consider the possibility that neither -moz-dir(rtl) nor
           // -moz-dir(ltr) matches.
           EventStates state = aElement->StyleState();
-          bool elementIsRTL = state.HasState(NS_EVENT_STATE_RTL);
-          bool elementIsLTR = state.HasState(NS_EVENT_STATE_LTR);
           nsDependentString dirString(pseudoClass->u.mString);
 
-          if ((dirString.EqualsLiteral("rtl") && !elementIsRTL) ||
-              (dirString.EqualsLiteral("ltr") && !elementIsLTR)) {
+          if (dirString.EqualsLiteral("rtl")) {
+            if (!state.HasState(NS_EVENT_STATE_RTL)) {
+              return false;
+            }
+          } else if (dirString.EqualsLiteral("ltr")) {
+            if (!state.HasState(NS_EVENT_STATE_LTR)) {
+              return false;
+            }
+          } else {
+            // Selectors specifying other directions never match.
             return false;
           }
         }
         break;
 
       case nsCSSPseudoClasses::ePseudoClass_scope:
         if (aTreeMatchContext.mForScopedStyle) {
           if (aTreeMatchContext.mCurrentStyleScope) {
--- a/layout/style/test/test_selectors.html
+++ b/layout/style/test/test_selectors.html
@@ -923,16 +923,17 @@ function run() {
     test_selector_in_html("html|a:not(*|a)", single_a, empty_set, set_single,
                           xul_default_ns + html_ns);
 
     // Test -moz-locale-dir
     test_parseable(":-moz-locale-dir(ltr)");
     test_parseable(":-moz-locale-dir(rtl)");
     test_parseable(":-moz-locale-dir(rTl)");
     test_parseable(":-moz-locale-dir(LTR)");
+    test_parseable(":-moz-locale-dir(other)");
     if (document.body.matches(":-moz-locale-dir(ltr)")) {
         test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-locale-dir(ltR)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-locale-dir(LTR)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-locale-dir(RTl)", single_a,
@@ -942,31 +943,34 @@ function run() {
                               set_single, empty_set);
         test_selector_in_html("a:-moz-locale-dir(rtL)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-locale-dir(RTL)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-locale-dir(LTr)", single_a,
                               empty_set, set_single);
     }
+    test_selector_in_html("a:-moz-locale-dir(other)", single_a,
+                          empty_set, set_single);
 
-    test_balanced_unparseable(":-moz-locale-dir(other)");
     test_balanced_unparseable(":-moz-locale-dir()");
     test_balanced_unparseable(":-moz-locale-dir(())");
     test_balanced_unparseable(":-moz-locale-dir(3())");
     test_balanced_unparseable(":-moz-locale-dir(f{})");
     test_balanced_unparseable(":-moz-locale-dir('ltr')");
     test_balanced_unparseable(":-moz-locale-dir(ltr, other)");
+    test_balanced_unparseable(":-moz-locale-dir(ltr other)");
     test_balanced_unparseable(":-moz-locale-dir");
 
     // Test :-moz-dir()
     test_parseable(":-moz-dir(ltr)");
     test_parseable(":-moz-dir(rtl)");
     test_parseable(":-moz-dir(rTl)");
     test_parseable(":-moz-dir(LTR)");
+    test_parseable(":-moz-dir(other)");
     if (document.body.matches(":-moz-dir(ltr)")) {
         test_selector_in_html("a:-moz-dir(LTr)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-dir(ltR)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-dir(LTR)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-dir(RTl)", single_a,
@@ -976,24 +980,26 @@ function run() {
                               set_single, empty_set);
         test_selector_in_html("a:-moz-dir(rtL)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-dir(RTL)", single_a,
                               set_single, empty_set);
         test_selector_in_html("a:-moz-dir(LTr)", single_a,
                               empty_set, set_single);
     }
+    test_selector_in_html("a:-moz-dir(other)", single_a,
+                          empty_set, set_single);
 
-    test_balanced_unparseable(":-moz-dir(other)");
     test_balanced_unparseable(":-moz-dir()");
     test_balanced_unparseable(":-moz-dir(())");
     test_balanced_unparseable(":-moz-dir(3())");
     test_balanced_unparseable(":-moz-dir(f{})");
     test_balanced_unparseable(":-moz-dir('ltr')");
     test_balanced_unparseable(":-moz-dir(ltr, other)");
+    test_balanced_unparseable(":-moz-dir(ltr other)");
     test_balanced_unparseable(":-moz-dir");
 
     // Test -moz-lwtheme and -moz-lwtheme-[darktext|brighttext]
     test_parseable(":-moz-lwtheme");
     test_parseable(":-moz-lwtheme-brighttext");
     test_parseable(":-moz-lwtheme-darktext");
 
     test_parseable(":-moz-tree-row(selected)");