Example #1
0
 internal CssSelector AddSelector(char aOperator)
 {
     var newSel = new CssSelector();
     if (mSelectors != null)
         mSelectors.SetOperator(aOperator);
     newSel.mNext = mSelectors;
     mSelectors = newSel;
     return newSel;
 }
Example #2
0
        internal CssSelector AddSelector(char aOperator)
        {
            var newSel = new CssSelector();

            if (mSelectors != null)
            {
                mSelectors.SetOperator(aOperator);
            }
            newSel.mNext = mSelectors;
            mSelectors   = newSel;
            return(newSel);
        }
Example #3
0
 internal static IEnumerable<CssSelector> TraverseList(CssSelector @this)
 {
     return @this.TraverseList(i => i.mNext);
 }
Example #4
0
        //
        // Parse attribute selectors [attr], [attr=value], [attr|=value],
        // [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
        //
        internal nsSelectorParsingStatus ParseAttributeSelector(ref int32_t       aDataMask,
                                              nsCSSSelector aSelector)
        {
            if (! GetToken(true)) { // premature EOF
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameEOF"); };
            return nsSelectorParsingStatus.Error;
              }

              int32_t nameSpaceID = nsNameSpace.None;
              string  attr;
              if (mToken.IsSymbol('*')) { // wildcard namespace
            nameSpaceID = nsNameSpace.Unknown;
            if (ExpectSymbol('|', false)) {
              if (! GetToken(false)) { // premature EOF
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameEOF"); };
                return nsSelectorParsingStatus.Error;
              }
              if (nsCSSTokenType.Ident == mToken.mType) { // attr name
                attr = mToken.mIdentStr;
              }
              else {
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameExpected", mToken); };
                UngetToken();
                return nsSelectorParsingStatus.Error;
               }
            }
            else {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelNoBar", mToken); };
              return nsSelectorParsingStatus.Error;
            }
              }
              else if (mToken.IsSymbol('|')) { // NO namespace
            if (! GetToken(false)) { // premature EOF
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameEOF"); };
              return nsSelectorParsingStatus.Error;
            }
            if (nsCSSTokenType.Ident == mToken.mType) { // attr name
              attr = mToken.mIdentStr;
            }
            else {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameExpected", mToken); };
              UngetToken();
              return nsSelectorParsingStatus.Error;
            }
              }
              else if (nsCSSTokenType.Ident == mToken.mType) { // attr name or namespace
            attr = mToken.mIdentStr; // hang on to it
            if (ExpectSymbol('|', false)) {  // was a namespace
              nameSpaceID = GetNamespaceIdForPrefix(attr);
              if (nameSpaceID == nsNameSpace.Unknown) {
                return nsSelectorParsingStatus.Error;
              }
              if (! GetToken(false)) { // premature EOF
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameEOF"); };
                return nsSelectorParsingStatus.Error;
              }
              if (nsCSSTokenType.Ident == mToken.mType) { // attr name
                attr = mToken.mIdentStr;
              }
              else {
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameExpected", mToken); };
                UngetToken();
                return nsSelectorParsingStatus.Error;
              }
            }
              }
              else {  // malformed
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttributeNameOrNamespaceExpected", mToken); };
            UngetToken();
            return nsSelectorParsingStatus.Error;
              }

              if (! GetToken(true)) { // premature EOF
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelInnerEOF"); };
            return nsSelectorParsingStatus.Error;
              }
              if ((nsCSSTokenType.Symbol == mToken.mType) ||
              (nsCSSTokenType.Includes == mToken.mType) ||
              (nsCSSTokenType.Dashmatch == mToken.mType) ||
              (nsCSSTokenType.Beginsmatch == mToken.mType) ||
              (nsCSSTokenType.Endsmatch == mToken.mType) ||
              (nsCSSTokenType.Containsmatch == mToken.mType)) {
            nsAttrFunc func;
            if (nsCSSTokenType.Includes == mToken.mType) {
              func = nsAttrFunc.Includes;
            }
            else if (nsCSSTokenType.Dashmatch == mToken.mType) {
              func = nsAttrFunc.DashMatch;
            }
            else if (nsCSSTokenType.Beginsmatch == mToken.mType) {
              func = nsAttrFunc.BeginsMatch;
            }
            else if (nsCSSTokenType.Endsmatch == mToken.mType) {
              func = nsAttrFunc.EndsMatch;
            }
            else if (nsCSSTokenType.Containsmatch == mToken.mType) {
              func = nsAttrFunc.ContainsMatch;
            }
            else if (']' == mToken.mSymbol) {
              aDataMask |= SEL_MASK_ATTRIB;
              aSelector.AddAttribute(nameSpaceID, attr);
              func = nsAttrFunc.Set;
            }
            else if ('=' == mToken.mSymbol) {
              func = nsAttrFunc.Equals;
            }
            else {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelUnexpected", mToken); };
              UngetToken(); // bad function
              return nsSelectorParsingStatus.Error;
            }
            if (nsAttrFunc.Set != func) { // get value
              if (! GetToken(true)) { // premature EOF
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelValueEOF"); };
                return nsSelectorParsingStatus.Error;
              }
              if ((nsCSSTokenType.Ident == mToken.mType) || (nsCSSTokenType.String == mToken.mType)) {
                string value = mToken.mIdentStr;
                if (! GetToken(true)) { // premature EOF
                  { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelCloseEOF"); };
                  return nsSelectorParsingStatus.Error;
                }
                if (mToken.IsSymbol(']')) {
                  bool isCaseSensitive = true;

                  // For cases when this style sheet is applied to an HTML
                  // element in an HTML document, and the attribute selector is
                  // for a non-namespaced attribute, then check to see if it's
                  // one of the known attributes whose VALUE is
                  // case-insensitive.
                  if (nameSpaceID == nsNameSpace.None) {
                    /*TODO: static*/ string[] caseInsensitiveHTMLAttribute = {
                      // list based on http://www.w3.org/TR/html4/
                      "lang",
                      "dir",
                      "http-equiv",
                      "text",
                      "link",
                      "vlink",
                      "alink",
                      "compact",
                      "align",
                      "frame",
                      "rules",
                      "valign",
                      "scope",
                      "axis",
                      "nowrap",
                      "hreflang",
                      "rel",
                      "rev",
                      "charset",
                      "codetype",
                      "declare",
                      "valuetype",
                      "shape",
                      "nohref",
                      "media",
                      "bgcolor",
                      "clear",
                      "color",
                      "face",
                      "noshade",
                      "noresize",
                      "scrolling",
                      "target",
                      "method",
                      "enctype",
                      "accept-charset",
                      "accept",
                      "checked",
                      "multiple",
                      "selected",
                      "disabled",
                      "readonly",
                      "language",
                      "defer",
                      "type",
                      // additional attributes not in HTML4
                      "direction", // marquee
                      null
                    };
                    short i = 0;
                    string htmlAttr;
                    while ((htmlAttr = caseInsensitiveHTMLAttribute[i++]) != null) {
                      if (attr.LowerCaseEqualsASCII(htmlAttr)) {
                        isCaseSensitive = false;
                        break;
                      }
                    }
                  }
                  aDataMask |= SEL_MASK_ATTRIB;
                  aSelector.AddAttribute(nameSpaceID, attr, func, value, isCaseSensitive);
                }
                else {
                  { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelNoClose", mToken); };
                  UngetToken();
                  return nsSelectorParsingStatus.Error;
                }
              }
              else {
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelBadValue", mToken); };
                UngetToken();
                return nsSelectorParsingStatus.Error;
              }
            }
              }
              else {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEAttSelUnexpected", mToken); };
            UngetToken(); // bad dog, no biscut!
            return nsSelectorParsingStatus.Error;
               }
               return nsSelectorParsingStatus.Continue;
        }
Example #5
0
 static bool IsUniversalSelector(nsCSSSelector aSelector)
 {
     return ((bool)((aSelector.mNameSpace == nsNameSpace.Unknown) &&
                 (aSelector.mLowercaseTag == null) &&
                 (aSelector.mIDList == null) &&
                 (aSelector.mClassList == null) &&
                 (aSelector.mAttrList == null) &&
                 (aSelector.mNegations == null) &&
                 (aSelector.mPseudoClassList == null)));
 }
Example #6
0
 internal void SetDefaultNamespaceOnSelector(nsCSSSelector aSelector)
 {
     if (mNameSpaceMap != null) {
     aSelector.SetNameSpace(mNameSpaceMap.FindNameSpaceID(null));
       } else {
     aSelector.SetNameSpace(nsNameSpace.Unknown); // wildcard
       }
 }
Example #7
0
        //
        // Parse a type element selector or a universal selector
        // namespace|type or namespace|* or *|* or *
        //
        internal nsSelectorParsingStatus ParseTypeOrUniversalSelector(ref int32_t       aDataMask,
                                                    nsCSSSelector aSelector,
                                                    bool           aIsNegated)
        {
            string buffer;
              if (mToken.IsSymbol('*')) {  // universal element selector, or universal namespace
            if (ExpectSymbol('|', false)) {  // was namespace
              aDataMask |= SEL_MASK_NSPACE;
              aSelector.SetNameSpace(nsNameSpace.Unknown); // namespace wildcard

              if (! GetToken(false)) {
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelEOF"); };
                return nsSelectorParsingStatus.Error;
              }
              if (nsCSSTokenType.Ident == mToken.mType) {  // element name
                aDataMask |= SEL_MASK_ELEM;

                aSelector.SetTag(mToken.mIdentStr);
              }
              else if (mToken.IsSymbol('*')) {  // universal selector
                aDataMask |= SEL_MASK_ELEM;
                // don't set tag
              }
              else {
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelNotType", mToken); };
                UngetToken();
                return nsSelectorParsingStatus.Error;
              }
            }
            else {  // was universal element selector
              SetDefaultNamespaceOnSelector(aSelector);
              aDataMask |= SEL_MASK_ELEM;
              // don't set any tag in the selector
            }
            if (! GetToken(false)) {   // premature eof is ok (here!)
              return nsSelectorParsingStatus.Done;
            }
              }
              else if (nsCSSTokenType.Ident == mToken.mType) {    // element name or namespace name
            buffer = mToken.mIdentStr; // hang on to ident

            if (ExpectSymbol('|', false)) {  // was namespace
              aDataMask |= SEL_MASK_NSPACE;
              int32_t nameSpaceID = GetNamespaceIdForPrefix(buffer);
              if (nameSpaceID == nsNameSpace.Unknown) {
                return nsSelectorParsingStatus.Error;
              }
              aSelector.SetNameSpace(nameSpaceID);

              if (! GetToken(false)) {
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelEOF"); };
                return nsSelectorParsingStatus.Error;
              }
              if (nsCSSTokenType.Ident == mToken.mType) {  // element name
                aDataMask |= SEL_MASK_ELEM;
                aSelector.SetTag(mToken.mIdentStr);
              }
              else if (mToken.IsSymbol('*')) {  // universal selector
                aDataMask |= SEL_MASK_ELEM;
                // don't set tag
              }
              else {
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelNotType", mToken); };
                UngetToken();
                return nsSelectorParsingStatus.Error;
              }
            }
            else {  // was element name
              SetDefaultNamespaceOnSelector(aSelector);
              aSelector.SetTag(buffer);

              aDataMask |= SEL_MASK_ELEM;
            }
            if (! GetToken(false)) {   // premature eof is ok (here!)
              return nsSelectorParsingStatus.Done;
            }
              }
              else if (mToken.IsSymbol('|')) {  // No namespace
            aDataMask |= SEL_MASK_NSPACE;
            aSelector.SetNameSpace(nsNameSpace.None);  // explicit NO namespace

            // get mandatory tag
            if (! GetToken(false)) {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelEOF"); };
              return nsSelectorParsingStatus.Error;
            }
            if (nsCSSTokenType.Ident == mToken.mType) {  // element name
              aDataMask |= SEL_MASK_ELEM;
              aSelector.SetTag(mToken.mIdentStr);
            }
            else if (mToken.IsSymbol('*')) {  // universal selector
              aDataMask |= SEL_MASK_ELEM;
              // don't set tag
            }
            else {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PETypeSelNotType", mToken); };
              UngetToken();
              return nsSelectorParsingStatus.Error;
            }
            if (! GetToken(false)) {   // premature eof is ok (here!)
              return nsSelectorParsingStatus.Done;
            }
              }
              else {
            SetDefaultNamespaceOnSelector(aSelector);
              }

              if (aIsNegated) {
            // restore last token read in case of a negated type selector
            UngetToken();
              }
              return nsSelectorParsingStatus.Continue;
        }
Example #8
0
        //
        // Parse pseudo-classes and pseudo-elements
        //
        internal nsSelectorParsingStatus ParsePseudoSelector(ref int32_t       aDataMask,
                                           nsCSSSelector aSelector,
                                           bool           aIsNegated,
                                           ref string      aPseudoElement,
                                           object   aPseudoElementArgs,
                                           ref nsCSSPseudoElement aPseudoElementType)
        {
            Debug.Assert(!aIsNegated || (aPseudoElement == null && aPseudoElementArgs == null),
                       "negated selectors shouldn't have a place to store pseudo elements");
              if (! GetToken(false)) { // premature eof
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelEOF"); };
            return nsSelectorParsingStatus.Error;
              }

              // First, find out whether we are parsing a CSS3 pseudo-element
              bool parsingPseudoElement = false;
              if (mToken.IsSymbol(':')) {
            parsingPseudoElement = true;
            if (! GetToken(false)) { // premature eof
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelEOF"); };
              return nsSelectorParsingStatus.Error;
            }
              }

              // Do some sanity-checking on the token
              if (nsCSSTokenType.Ident != mToken.mType && nsCSSTokenType.Function != mToken.mType) {
            // malformed selector
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelBadName", mToken); };
            UngetToken();
            return nsSelectorParsingStatus.Error;
              }

              // OK, now we know we have an mIdent.  Atomize it.  All the atoms, for
              // pseudo-classes as well as pseudo-elements, start with a single ':'
              string pseudo = String.Intern(":" + mToken.mIdentStr);

              // stash away some info about this pseudo so we only have to get it once.
              bool isTreePseudo = false;
              nsCSSPseudoElement pseudoElementType =
            nsCSSPseudoElements.GetPseudoType(pseudo);
              nsCSSPseudoClass pseudoClassType =
            nsCSSPseudoClasses.GetPseudoType(pseudo);

              // We currently allow :-moz-placeholder and .-moz-placeholder. We have to
              // be a bit stricter regarding the pseudo-element parsing rules.
              if (pseudoElementType == nsCSSPseudoElement.MozPlaceholder &&
              pseudoClassType == nsCSSPseudoClass.MozPlaceholder) {
            if (parsingPseudoElement) {
              pseudoClassType = nsCSSPseudoClass.NotPseudoClass;
            } else {
              pseudoElementType = nsCSSPseudoElement.NotPseudoElement;
            }
              }

            #if MOZ_XUL
              isTreePseudo = (pseudoElementType == nsCSSPseudoElement.Xultree);
              // If a tree pseudo-element is using the function syntax, it will
              // get isTree set here and will pass the check below that only
              // allows functions if they are in our list of things allowed to be
              // functions.  If it is _not_ using the function syntax, isTree will
              // be false, and it will still pass that check.  So the tree
              // pseudo-elements are allowed to be either functions or not, as
              // desired.
              bool isTree = (nsCSSTokenType.Function == mToken.mType) && isTreePseudo;
            #endif
              bool isPseudoElement =
            (pseudoElementType < nsCSSPseudoElement.PseudoElementCount);
              // anonymous boxes are only allowed if they're the tree boxes or we have
              // enabled unsafe rules
              bool isAnonBox = isTreePseudo ||
            (pseudoElementType == nsCSSPseudoElement.AnonBox &&
             mUnsafeRulesEnabled);
              bool isPseudoClass =
            (pseudoClassType != nsCSSPseudoClass.NotPseudoClass);

              Debug.Assert(!isPseudoClass ||
                       pseudoElementType == nsCSSPseudoElement.NotPseudoElement,
                       "Why is this atom both a pseudo-class and a pseudo-element?");
              Debug.Assert((isPseudoClass?1:0) + (isPseudoElement?1:0) + (isAnonBox?1:0) <= 1,
                       "Shouldn't be more than one of these");

              if (!isPseudoClass && !isPseudoElement && !isAnonBox) {
            // Not a pseudo-class, not a pseudo-element.... forget it
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelUnknown", mToken); };
            UngetToken();
            return nsSelectorParsingStatus.Error;
              }

              // If it's a function token, it better be on our "ok" list, and if the name
              // is that of a function pseudo it better be a function token
              if ((nsCSSTokenType.Function == mToken.mType) !=
              (
            #if MOZ_XUL
               isTree ||
            #endif
               nsCSSPseudoClass.NotPseudo == pseudoClassType ||
               nsCSSPseudoClasses.HasStringArg(pseudoClassType) ||
               nsCSSPseudoClasses.HasNthPairArg(pseudoClassType) ||
               nsCSSPseudoClasses.HasSelectorListArg(pseudoClassType))) {
            // There are no other function pseudos
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelNonFunc", mToken); };
            UngetToken();
            return nsSelectorParsingStatus.Error;
              }

              // If it starts with ".", it better be a pseudo-element
              if (parsingPseudoElement &&
              !isPseudoElement &&
              !isAnonBox) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelNotPE", mToken); };
            UngetToken();
            return nsSelectorParsingStatus.Error;
              }

              if (!parsingPseudoElement &&
              nsCSSPseudoClass.NotPseudo == pseudoClassType) {
            if (aIsNegated) { // :not() can't be itself negated
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelDoubleNot", mToken); };
              UngetToken();
              return nsSelectorParsingStatus.Error;
            }
            // CSS 3 Negation pseudo-class takes one simple selector as argument
            nsSelectorParsingStatus parsingStatus =
              ParseNegatedSimpleSelector(ref aDataMask, aSelector);
            if (nsSelectorParsingStatus.Continue != parsingStatus) {
              return parsingStatus;
            }
              }
              else if (!parsingPseudoElement && isPseudoClass) {
            aDataMask |= SEL_MASK_PCLASS;
            if (nsCSSTokenType.Function == mToken.mType) {
              nsSelectorParsingStatus parsingStatus;
              if (nsCSSPseudoClasses.HasStringArg(pseudoClassType)) {
                parsingStatus =
                  ParsePseudoClassWithIdentArg(aSelector, pseudoClassType);
              }
              else if (nsCSSPseudoClasses.HasNthPairArg(pseudoClassType)) {
                parsingStatus =
                  ParsePseudoClassWithNthPairArg(aSelector, pseudoClassType);
              }
              else {
                Debug.Assert(nsCSSPseudoClasses.HasSelectorListArg(pseudoClassType),
                                  "unexpected pseudo with function token");
                parsingStatus = ParsePseudoClassWithSelectorListArg(aSelector,
                                                                    pseudoClassType);
              }
              if (nsSelectorParsingStatus.Continue != parsingStatus) {
                if (nsSelectorParsingStatus.Error == parsingStatus) {
                  SkipUntil(')');
                }
                return parsingStatus;
              }
            }
            else {
              aSelector.AddPseudoClass(pseudoClassType);
            }
              }
              else if (isPseudoElement || isAnonBox) {
            // Pseudo-element.  Make some more sanity checks.

            if (aIsNegated) { // pseudo-elements can't be negated
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelPEInNot", mToken); };
              UngetToken();
              return nsSelectorParsingStatus.Error;
            }
            // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
            // to have a single ':' on them.  Others (CSS3+ pseudo-elements and
            // various -moz-* pseudo-elements) must have |parsingPseudoElement|
            // set.
            if (!parsingPseudoElement &&
                !nsCSSPseudoElements.IsCSS2PseudoElement(pseudo)
            #if MOZ_XUL
                && !isTreePseudo
            #endif
                ) {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelNewStyleOnly", mToken); };
              UngetToken();
              return nsSelectorParsingStatus.Error;
            }

            if (0 == (aDataMask & SEL_MASK_PELEM)) {
              aDataMask |= SEL_MASK_PELEM;
              aPseudoElement = pseudo;
              aPseudoElementType = pseudoElementType;

            #if MOZ_XUL
              if (isTree) {
                // We have encountered a pseudoelement of the form
                // -moz-tree-xxxx(a,b,c).  We parse (a,b,c) and add each
                // item in the list to the pseudoclass list.  They will be pulled
                // from the list later along with the pseudo-element.
                if (!ParseTreePseudoElement(aPseudoElementArgs)) {
                  return nsSelectorParsingStatus.Error;
                }
              }
            #endif

              // the next *non*whitespace token must be '{' or ',' or EOF
              if (!GetToken(true)) { // premature eof is ok (here!)
                return nsSelectorParsingStatus.Done;
              }
              if ((mToken.IsSymbol('{') || mToken.IsSymbol(','))) {
                UngetToken();
                return nsSelectorParsingStatus.Done;
              }
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelTrailing", mToken); };
              UngetToken();
              return nsSelectorParsingStatus.Error;
            }
            else {  // multiple pseudo elements, not legal
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoSelMultiplePE", mToken); };
              UngetToken();
              return nsSelectorParsingStatus.Error;
            }
              }
            #if DEBUG
              else {
            // We should never end up here.  Indeed, if we ended up here, we know (from
            // the current if/else cascade) that !isPseudoElement and !isAnonBox.  But
            // then due to our earlier check we know that isPseudoClass.  Since we
            // didn't fall into the isPseudoClass case in this cascade, we must have
            // parsingPseudoElement.  But we've already checked the
            // parsingPseudoElement && !isPseudoClass && !isAnonBox case and bailed if
            // it's happened.
            Debug.Fail("How did this happen?");
              }
            #endif
              return nsSelectorParsingStatus.Continue;
        }
Example #9
0
        //
        // Parse the argument of a pseudo-class that has a selector list argument.
        // Such selector lists cannot contain combinators, but can contain
        // anything that goes between a pair of combinators.
        //
        internal nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector aSelector,
                                                           nsCSSPseudoClass aType)
        {
            var slist = new nsCSSSelectorList();
              if (! ParseSelectorList(ref slist, ')')) {
            return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
              }

              // Check that none of the selectors in the list have combinators or
              // pseudo-elements.
              for (nsCSSSelectorList l = slist; l != null; l = l.mNext) {
            nsCSSSelector s = l.mSelectors;
            if (s.mNext != null || s.IsPseudoElement()) {
              return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
            }
              }

              // Add the pseudo with the selector list parameter
              aSelector.AddPseudoClass(aType, slist);

              // close the parenthesis
              if (!ExpectSymbol(')', true)) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassNoClose", mToken); };
            return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
              }

              return nsSelectorParsingStatus.Continue;
        }
Example #10
0
        internal nsSelectorParsingStatus ParsePseudoClassWithNthPairArg(nsCSSSelector aSelector,
                                                      nsCSSPseudoClass aType)
        {
            int32_t[] numbers = { 0, 0 };
              bool lookForB = true;

              // Follow the whitespace rules as proposed in
              // http://lists.w3.org/Archives/Public/www-style/2008Mar/0121.html

              if (! GetToken(true)) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); };
            return nsSelectorParsingStatus.Error;
              }

              if (nsCSSTokenType.Ident == mToken.mType || nsCSSTokenType.Dimension == mToken.mType) {
            // The CSS tokenization doesn't handle :nth-child() containing - well:
            //   2n-1 is a dimension
            //   n-1 is an identifier
            // The easiest way to deal with that is to push everything from the
            // minus on back onto the scanner's pushback buffer.
            uint32_t truncAt = 0;
            if (StringBeginsWith(mToken.mIdentStr, "n-")) {
              truncAt = 1;
            } else if (StringBeginsWith(mToken.mIdentStr, "-n-")) {
              truncAt = 2;
            }
            if (truncAt != 0) {
              mScanner.Backup(mToken.mIdentStr.Length() - truncAt);
              mToken.mIdentStr = mToken.mIdentStr.Substring(0, truncAt);
            }
              }

              if (nsCSSTokenType.Ident == mToken.mType) {
            if (mToken.mIdentStr.LowerCaseEqualsLiteral("odd")) {
              numbers[0] = 2;
              numbers[1] = 1;
              lookForB = false;
            }
            else if (mToken.mIdentStr.LowerCaseEqualsLiteral("even")) {
              numbers[0] = 2;
              numbers[1] = 0;
              lookForB = false;
            }
            else if (mToken.mIdentStr.LowerCaseEqualsLiteral("n")) {
              numbers[0] = 1;
            }
            else if (mToken.mIdentStr.LowerCaseEqualsLiteral("-n")) {
              numbers[0] = -1;
            }
            else {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); };
              return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
            }
              }
              else if (nsCSSTokenType.Number == mToken.mType) {
            if (!mToken.mIntegerValid) {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); };
              return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
            }
            numbers[1] = mToken.mInteger;
            lookForB = false;
              }
              else if (nsCSSTokenType.Dimension == mToken.mType) {
            if (!mToken.mIntegerValid || !mToken.mIdentStr.LowerCaseEqualsLiteral("n")) {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); };
              return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
            }
            numbers[0] = mToken.mInteger;
              }
              // XXX If it's a ')', is that valid?  (as 0n+0)
              else {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); };
            UngetToken();
            return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
              }

              if (! GetToken(true)) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); };
            return nsSelectorParsingStatus.Error;
              }
              if (lookForB && !mToken.IsSymbol(')')) {
            // The '+' or '-' sign can optionally be separated by whitespace.
            // If it is separated by whitespace from what follows it, it appears
            // as a separate token rather than part of the number token.
            bool haveSign = false;
            int32_t sign = 1;
            if (mToken.IsSymbol('+') || mToken.IsSymbol('-')) {
              haveSign = true;
              if (mToken.IsSymbol('-')) {
                sign = -1;
              }
              if (! GetToken(true)) {
                { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); };
                return nsSelectorParsingStatus.Error;
              }
            }
            if (nsCSSTokenType.Number != mToken.mType ||
                !mToken.mIntegerValid || mToken.mHasSign == haveSign) {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotNth", mToken); };
              return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
            }
            numbers[1] = mToken.mInteger * sign;
            if (! GetToken(true)) {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); };
              return nsSelectorParsingStatus.Error;
            }
              }
              if (!mToken.IsSymbol(')')) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassNoClose", mToken); };
            return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
              }
              aSelector.AddPseudoClass(aType, numbers);
              return nsSelectorParsingStatus.Continue;
        }
Example #11
0
        //
        // Parse the argument of a pseudo-class that has an ident arg
        //
        internal nsSelectorParsingStatus ParsePseudoClassWithIdentArg(nsCSSSelector aSelector,
                                                    nsCSSPseudoClass aType)
        {
            if (! GetToken(true)) { // premature eof
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgEOF"); };
            return nsSelectorParsingStatus.Error;
              }
              // We expect an identifier with a language abbreviation
              if (nsCSSTokenType.Ident != mToken.mType) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassArgNotIdent", mToken); };
            UngetToken();
            return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
              }

              // -moz-locale-dir and -moz-dir can only have values of 'ltr' or 'rtl'.
              if (aType == nsCSSPseudoClass.MozLocaleDir ||
              aType == nsCSSPseudoClass.Dir) {
            mToken.mIdentStr = mToken.mIdentStr.ToLower(); // case insensitive
            if (!mToken.mIdentStr.EqualsLiteral("ltr") &&
                !mToken.mIdentStr.EqualsLiteral("rtl")) {
              { if (!mSuppressErrors) mReporter.ReportUnexpected("PEBadDirValue", mToken); };
              return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
            }
              }

              // Add the pseudo with the language parameter
              aSelector.AddPseudoClass(aType, mToken.mIdentStr);

              // close the parenthesis
              if (!ExpectSymbol(')', true)) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEPseudoClassNoClose", mToken); };
            return nsSelectorParsingStatus.Error; // our caller calls SkipUntil(')')
              }

              return nsSelectorParsingStatus.Continue;
        }
Example #12
0
        //
        // Parse the argument of a negation pseudo-class :not()
        //
        internal nsSelectorParsingStatus ParseNegatedSimpleSelector(ref int32_t       aDataMask,
                                                  nsCSSSelector aSelector)
        {
            if (! GetToken(true)) { // premature eof
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PENegationEOF"); };
            return nsSelectorParsingStatus.Error;
              }

              if (mToken.IsSymbol(')')) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PENegationBadArg", mToken); };
            return nsSelectorParsingStatus.Error;
              }

              // Create a new nsCSSSelector and add it to the end of
              // aSelector.mNegations.
              // Given the current parsing rules, every selector in mNegations
              // contains only one simple selector (css3 definition) within it.
              // This could easily change in future versions of CSS, and the only
              // thing we need to change to support that is this parsing code and the
              // serialization code for nsCSSSelector.
              nsCSSSelector newSel = new nsCSSSelector();
              nsCSSSelector negations = aSelector;
              while (negations.mNegations != null) {
            negations = negations.mNegations;
              }
              negations.mNegations = newSel;

              nsSelectorParsingStatus parsingStatus;
              if (nsCSSTokenType.ID == mToken.mType) { // #id
            parsingStatus = ParseIDSelector(ref aDataMask, newSel);
              }
              else if (mToken.IsSymbol('.')) {    // .class
            parsingStatus = ParseClassSelector(ref aDataMask, newSel);
              }
              else if (mToken.IsSymbol(':')) {    // :pseudo
            { string _1 = null; nsCSSPseudoElement _2 = 0; parsingStatus = ParsePseudoSelector(ref aDataMask, newSel, true, ref _1, null, ref _2); }
              }
              else if (mToken.IsSymbol('[')) {    // [attribute
            parsingStatus = ParseAttributeSelector(ref aDataMask, newSel);
            if (nsSelectorParsingStatus.Error == parsingStatus) {
              // Skip forward to the matching ']'
              SkipUntil(']');
            }
              }
              else {
            // then it should be a type element or universal selector
            parsingStatus = ParseTypeOrUniversalSelector(ref aDataMask, newSel, true);
              }
              if (nsSelectorParsingStatus.Error == parsingStatus) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PENegationBadInner", mToken); };
            SkipUntil(')');
            return parsingStatus;
              }
              // close the parenthesis
              if (!ExpectSymbol(')', true)) {
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PENegationNoClose", mToken); };
            SkipUntil(')');
            return nsSelectorParsingStatus.Error;
              }

              Debug.Assert(newSel.mNameSpace == nsNameSpace.Unknown ||
                       (newSel.mIDList == null && newSel.mClassList == null &&
                        newSel.mPseudoClassList == null && newSel.mAttrList == null),
                       "Need to fix the serialization code to deal with this");

              return nsSelectorParsingStatus.Continue;
        }
Example #13
0
 //
 // Parses an ID selector #name
 //
 internal nsSelectorParsingStatus ParseIDSelector(ref int32_t       aDataMask,
                                nsCSSSelector aSelector)
 {
     Debug.Assert(!mToken.mIdentStr.IsEmpty(),
                "Empty mIdent in nsCSSTokenType.ID token?");
       aDataMask |= SEL_MASK_ID;
       aSelector.AddID(mToken.mIdentStr);
       return nsSelectorParsingStatus.Continue;
 }
Example #14
0
        //
        // Parses a class selector .name
        //
        internal nsSelectorParsingStatus ParseClassSelector(ref int32_t       aDataMask,
                                          nsCSSSelector aSelector)
        {
            if (! GetToken(false)) { // get ident
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEClassSelEOF"); };
            return nsSelectorParsingStatus.Error;
              }
              if (nsCSSTokenType.Ident != mToken.mType) {  // malformed selector
            { if (!mSuppressErrors) mReporter.ReportUnexpected("PEClassSelNotIdent", mToken); };
            UngetToken();
            return nsSelectorParsingStatus.Error;
              }
              aDataMask |= SEL_MASK_CLASS;

              aSelector.AddClass(mToken.mIdentStr);

              return nsSelectorParsingStatus.Continue;
        }
Example #15
0
 internal static IEnumerable <CssSelector> TraverseList(CssSelector @this)
 {
     return(@this.TraverseList(i => i.mNext));
 }