void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, StyleRule::Type ruleType) { CSSParserTokenRange rangeCopy = range; // For inspector callbacks ASSERT(range.peek().type() == IdentToken); const CSSParserToken& token = range.consumeIncludingWhitespace(); CSSPropertyID unresolvedProperty = token.parseAsUnresolvedCSSPropertyID(); if (range.consume().type() != ColonToken) return; // Parse error bool important = false; const CSSParserToken* declarationValueEnd = range.end(); const CSSParserToken* last = range.end() - 1; while (last->type() == WhitespaceToken) --last; if (last->type() == IdentToken && last->valueEqualsIgnoringCase("important")) { --last; while (last->type() == WhitespaceToken) --last; if (last->type() == DelimiterToken && last->delimiter() == '!') { important = true; declarationValueEnd = last; } } if (RuntimeEnabledFeatures::cssVariablesEnabled() && unresolvedProperty == CSSPropertyInvalid && CSSVariableParser::isValidVariableName(token)) { AtomicString variableName = token.value(); consumeVariableDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), variableName, important); return; } if (important && (ruleType == StyleRule::FontFace || ruleType == StyleRule::Keyframes)) return; if (m_observerWrapper && ruleType == StyleRule::Style) { size_t propertiesCount = m_parsedProperties.size(); if (unresolvedProperty != CSSPropertyInvalid) consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), unresolvedProperty, important, ruleType); m_observerWrapper->observer().observeProperty( m_observerWrapper->startOffset(rangeCopy), m_observerWrapper->endOffset(rangeCopy), important, m_parsedProperties.size() != propertiesCount); return; } if (unresolvedProperty == CSSPropertyInvalid) return; consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), unresolvedProperty, important, ruleType); }
bool SizesAttributeParser::parse(CSSParserTokenRange range) { // Split on a comma token and parse the result tokens as (media-condition, length) pairs while (!range.atEnd()) { const CSSParserToken* mediaConditionStart = &range.peek(); // The length is the last component value before the comma which isn't whitespace or a comment const CSSParserToken* lengthTokenStart = &range.peek(); const CSSParserToken* lengthTokenEnd = &range.peek(); while (!range.atEnd() && range.peek().type() != CommaToken) { lengthTokenStart = &range.peek(); range.consumeComponentValue(); lengthTokenEnd = &range.peek(); range.consumeWhitespace(); } range.consume(); float length; if (!calculateLengthInPixels(range.makeSubRange(lengthTokenStart, lengthTokenEnd), length)) continue; RefPtrWillBeRawPtr<MediaQuerySet> mediaCondition = MediaQueryParser::parseMediaCondition(range.makeSubRange(mediaConditionStart, lengthTokenStart)); if (!mediaCondition || !mediaConditionMatches(mediaCondition)) continue; m_length = length; m_lengthWasSet = true; return true; } return false; }
void CSSParserImpl::consumeDeclaration(CSSParserTokenRange range, StyleRule::Type ruleType) { CSSParserTokenRange rangeCopy = range; // For inspector callbacks ASSERT(range.peek().type() == IdentToken); CSSPropertyID unresolvedProperty = range.consumeIncludingWhitespace().parseAsUnresolvedCSSPropertyID(); if (range.consume().type() != ColonToken) return; // Parse error // FIXME: We shouldn't allow !important in @keyframes or @font-face bool important = false; const CSSParserToken* declarationValueEnd = range.end(); const CSSParserToken* last = range.end() - 1; while (last->type() == WhitespaceToken) --last; if (last->type() == IdentToken && last->valueEqualsIgnoringCase("important")) { --last; while (last->type() == WhitespaceToken) --last; if (last->type() == DelimiterToken && last->delimiter() == '!') { important = true; declarationValueEnd = last; } } if (m_observerWrapper && ruleType == StyleRule::Style) { size_t propertiesCount = m_parsedProperties.size(); if (unresolvedProperty != CSSPropertyInvalid) consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), unresolvedProperty, important, ruleType); m_observerWrapper->observer().startProperty(m_observerWrapper->startOffset(rangeCopy)); m_observerWrapper->observer().endProperty(important, m_parsedProperties.size() != propertiesCount, m_observerWrapper->endOffset(rangeCopy), NoCSSError); return; } if (unresolvedProperty == CSSPropertyInvalid) return; consumeDeclarationValue(range.makeSubRange(&range.peek(), declarationValueEnd), unresolvedProperty, important, ruleType); }
PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::consumeAtRule(CSSParserTokenRange& range, AllowedRulesType allowedRules) { ASSERT(range.peek().type() == AtKeywordToken); const CSSParserString& name = range.consume().value(); const CSSParserToken* preludeStart = &range.peek(); while (!range.atEnd() && range.peek().type() != LeftBraceToken && range.peek().type() != SemicolonToken) range.consumeComponentValue(); CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek()); CSSAtRuleID id = cssAtRuleID(name); if (id != CSSAtRuleInvalid && m_context.useCounter()) countAtRule(m_context.useCounter(), id); if (range.atEnd() || range.peek().type() == SemicolonToken) { range.consume(); if (allowedRules == AllowCharsetRules && id == CSSAtRuleCharset) return consumeCharsetRule(prelude); if (allowedRules <= AllowImportRules && id == CSSAtRuleImport) return consumeImportRule(prelude); if (allowedRules <= AllowNamespaceRules && id == CSSAtRuleNamespace) return consumeNamespaceRule(prelude); return nullptr; // Parse error, unrecognised at-rule without block } CSSParserTokenRange block = range.consumeBlock(); if (allowedRules == KeyframeRules) return nullptr; // Parse error, no at-rules supported inside @keyframes if (allowedRules == NoRules) return nullptr; // Parse error, no at-rules supported inside declaration lists ASSERT(allowedRules <= RegularRules); switch (id) { case CSSAtRuleMedia: return consumeMediaRule(prelude, block); case CSSAtRuleSupports: return consumeSupportsRule(prelude, block); case CSSAtRuleViewport: return consumeViewportRule(prelude, block); case CSSAtRuleFontFace: return consumeFontFaceRule(prelude, block); case CSSAtRuleWebkitKeyframes: return consumeKeyframesRule(true, prelude, block); case CSSAtRuleKeyframes: return consumeKeyframesRule(false, prelude, block); case CSSAtRulePage: return consumePageRule(prelude, block); default: return nullptr; // Parse error, unrecognised at-rule with block } }
void CSSParserImpl::consumeDeclarationList(CSSParserTokenRange range, StyleRule::Type ruleType) { ASSERT(m_parsedProperties.isEmpty()); bool useObserver = m_observerWrapper && ruleType == StyleRule::Style; if (useObserver) { m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(range)); m_observerWrapper->skipCommentsBefore(range, true); } while (!range.atEnd()) { switch (range.peek().type()) { case WhitespaceToken: case SemicolonToken: range.consume(); break; case IdentToken: { const CSSParserToken* declarationStart = &range.peek(); if (useObserver) m_observerWrapper->yieldCommentsBefore(range); while (!range.atEnd() && range.peek().type() != SemicolonToken) range.consumeComponentValue(); consumeDeclaration(range.makeSubRange(declarationStart, &range.peek()), ruleType); if (useObserver) m_observerWrapper->skipCommentsBefore(range, false); break; } case AtKeywordToken: { RefPtrWillBeRawPtr<StyleRuleBase> rule = consumeAtRule(range, NoRules); ASSERT_UNUSED(rule, !rule); break; } default: // Parse error, unexpected token in declaration list while (!range.atEnd() && range.peek().type() != SemicolonToken) range.consumeComponentValue(); break; } } // Yield remaining comments if (useObserver) { m_observerWrapper->yieldCommentsBefore(range); m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(range)); } }
PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::consumeAtRule(CSSParserTokenRange& range, AllowedRulesType allowedRules) { ASSERT(range.peek().type() == AtKeywordToken); const CSSParserString& name = range.consume().value(); const CSSParserToken* preludeStart = &range.peek(); while (!range.atEnd() && range.peek().type() != LeftBraceToken && range.peek().type() != SemicolonToken) range.consumeComponentValue(); CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek()); if (range.atEnd() || range.peek().type() == SemicolonToken) { range.consume(); if (allowedRules == AllowCharsetRules && name.equalIgnoringCase("charset")) return consumeCharsetRule(prelude); if (allowedRules <= AllowImportRules && name.equalIgnoringCase("import")) return consumeImportRule(prelude); if (allowedRules <= AllowNamespaceRules && name.equalIgnoringCase("namespace")) return consumeNamespaceRule(prelude); return nullptr; // Parse error, unrecognised at-rule without block } CSSParserTokenRange block = range.consumeBlock(); if (allowedRules == KeyframeRules) return nullptr; // Parse error, no at-rules supported inside @keyframes if (allowedRules == NoRules) return nullptr; // Parse error, no at-rules supported inside declaration lists ASSERT(allowedRules <= RegularRules); if (name.equalIgnoringCase("media")) return consumeMediaRule(prelude, block); if (name.equalIgnoringCase("supports")) return consumeSupportsRule(prelude, block); if (name.equalIgnoringCase("viewport")) return consumeViewportRule(prelude, block); if (name.equalIgnoringCase("font-face")) return consumeFontFaceRule(prelude, block); if (name.equalIgnoringCase("-webkit-keyframes")) return consumeKeyframesRule(true, prelude, block); if (name.equalIgnoringCase("keyframes")) return consumeKeyframesRule(false, prelude, block); if (name.equalIgnoringCase("page")) return consumePageRule(prelude, block); return nullptr; // Parse error, unrecognised at-rule with block }
static void observeSelectors(CSSParserObserverWrapper& wrapper, CSSParserTokenRange selectors) { // This is easier than hooking into the CSSSelectorParser selectors.consumeWhitespace(); CSSParserTokenRange originalRange = selectors; wrapper.observer().startRuleHeader(StyleRule::Style, wrapper.startOffset(originalRange)); while (!selectors.atEnd()) { const CSSParserToken* selectorStart = &selectors.peek(); while (!selectors.atEnd() && selectors.peek().type() != CommaToken) selectors.consumeComponentValue(); CSSParserTokenRange selector = selectors.makeSubRange(selectorStart, &selectors.peek()); selectors.consumeIncludingWhitespace(); wrapper.observer().observeSelector(wrapper.startOffset(selector), wrapper.endOffset(selector)); } wrapper.observer().endRuleHeader(wrapper.endOffset(originalRange)); }
PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::consumeQualifiedRule(CSSParserTokenRange& range, AllowedRulesType allowedRules) { const CSSParserToken* preludeStart = &range.peek(); while (!range.atEnd() && range.peek().type() != LeftBraceToken) range.consumeComponentValue(); if (range.atEnd()) return nullptr; // Parse error, EOF instead of qualified rule block CSSParserTokenRange prelude = range.makeSubRange(preludeStart, &range.peek()); CSSParserTokenRange block = range.consumeBlock(); if (allowedRules <= RegularRules) return consumeStyleRule(prelude, block); if (allowedRules == KeyframeRules) return consumeKeyframeStyleRule(prelude, block); ASSERT_NOT_REACHED(); return nullptr; }