void CSSVariableResolver::resolveApplyAtRule(CSSParserTokenRange& range, Vector<CSSParserToken>& result) { ASSERT(range.peek().type() == AtKeywordToken && range.peek().valueEqualsIgnoringASCIICase("apply")); range.consumeIncludingWhitespace(); const CSSParserToken& variableName = range.consumeIncludingWhitespace(); // TODO(timloh): Should we actually be consuming this? if (range.peek().type() == SemicolonToken) range.consume(); CSSVariableData* variableData = valueForCustomProperty(variableName.value()); if (!variableData) return; // Invalid custom property CSSParserTokenRange rule = variableData->tokenRange(); rule.consumeWhitespace(); if (rule.peek().type() != LeftBraceToken) return; CSSParserTokenRange ruleContents = rule.consumeBlock(); rule.consumeWhitespace(); if (!rule.atEnd()) return; result.appendRange(ruleContents.begin(), ruleContents.end()); }
CSSParserTokenRange consumeFunction(CSSParserTokenRange& range) { ASSERT(range.peek().type() == FunctionToken); CSSParserTokenRange contents = range.consumeBlock(); range.consumeWhitespace(); contents.consumeWhitespace(); return contents; }
PassRefPtrWillBeRawPtr<StyleRulePage> CSSParserImpl::consumePageRule(CSSParserTokenRange prelude, CSSParserTokenRange block) { // We only support a small subset of the css-page spec. prelude.consumeWhitespace(); AtomicString typeSelector; if (prelude.peek().type() == IdentToken) typeSelector = prelude.consume().value(); AtomicString pseudo; if (prelude.peek().type() == ColonToken) { prelude.consume(); if (prelude.peek().type() != IdentToken) return nullptr; // Parse error; expected ident token following colon in @page header pseudo = prelude.consume().value(); } prelude.consumeWhitespace(); if (!prelude.atEnd()) return nullptr; // Parse error; extra tokens in @page header OwnPtr<CSSParserSelector> selector; if (!typeSelector.isNull() && pseudo.isNull()) { selector = CSSParserSelector::create(QualifiedName(nullAtom, typeSelector, m_defaultNamespace)); } else { selector = CSSParserSelector::create(); if (!pseudo.isNull()) { selector->setMatch(CSSSelector::PagePseudoClass); selector->setValue(pseudo.lower()); if (selector->pseudoType() == CSSSelector::PseudoUnknown) return nullptr; // Parse error; unknown page pseudo-class } if (!typeSelector.isNull()) selector->prependTagSelector(QualifiedName(nullAtom, typeSelector, m_defaultNamespace)); } if (m_observerWrapper) { unsigned endOffset = m_observerWrapper->endOffset(prelude); m_observerWrapper->observer().startRuleHeader(StyleRule::Page, m_observerWrapper->startOffset(prelude)); m_observerWrapper->observer().endRuleHeader(endOffset); } selector->setForPage(); RefPtrWillBeRawPtr<StyleRulePage> pageRule = StyleRulePage::create(); Vector<OwnPtr<CSSParserSelector>> selectorVector; selectorVector.append(selector.release()); pageRule->parserAdoptSelectorVector(selectorVector); consumeDeclarationList(block, StyleRule::Style); pageRule->setProperties(createStylePropertySet(m_parsedProperties, m_context.mode())); m_parsedProperties.clear(); return pageRule.release(); }
bool parseValueTerm(CSSParserTokenRange& tokens, int depth, Value* result) { if (checkDepthAndIndex(&depth, tokens) != OK) return false; if (tokens.peek().type() == LeftParenthesisToken) { CSSParserTokenRange innerRange = tokens.consumeBlock(); tokens.consumeWhitespace(); innerRange.consumeWhitespace(); return parseValueExpression(innerRange, depth, result); } return parseValue(tokens, result); }
PassRefPtrWillBeRawPtr<StyleRuleNamespace> CSSParserImpl::consumeNamespaceRule(CSSParserTokenRange prelude) { prelude.consumeWhitespace(); AtomicString namespacePrefix; if (prelude.peek().type() == IdentToken) namespacePrefix = prelude.consumeIncludingWhitespace().value(); AtomicString uri(consumeStringOrURI(prelude)); prelude.consumeWhitespace(); if (uri.isNull() || !prelude.atEnd()) return nullptr; // Parse error, expected string or URI return StyleRuleNamespace::create(namespacePrefix, uri); }
bool CSSVariableData::checkVariablesForCyclesWithRange(CSSParserTokenRange range, CustomPropertyValueMap& customProperties, HashSet<AtomicString>& seenProperties, HashSet<AtomicString>& invalidProperties) const { while (!range.atEnd()) { if (range.peek().functionId() == CSSValueVar) { CSSParserTokenRange block = range.consumeBlock(); block.consumeWhitespace(); ASSERT(block.peek().type() == IdentToken); AtomicString variableName = block.consumeIncludingWhitespace().value().toAtomicString(); ASSERT(block.atEnd() || block.peek().type() == CommaToken); if (seenProperties.contains(variableName)) return false; RefPtr<CSSCustomPropertyValue> value = customProperties.get(variableName); if (value && value->containsVariables() && !value->checkVariablesForCycles(variableName, customProperties, seenProperties, invalidProperties)) return false; if (range.peek().type() == CommaToken) { // Fallback. range.consume(); return checkVariablesForCyclesWithRange(block, customProperties, seenProperties, invalidProperties); } } else range.consume(); } return true; }
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; }
PassRefPtrWillBeRawPtr<StyleRuleKeyframes> CSSParserImpl::consumeKeyframesRule(bool webkitPrefixed, CSSParserTokenRange prelude, CSSParserTokenRange block) { prelude.consumeWhitespace(); const CSSParserToken& nameToken = prelude.consumeIncludingWhitespace(); if (!prelude.atEnd()) return nullptr; // Parse error; expected single non-whitespace token in @keyframes header String name; if (nameToken.type() == IdentToken) { name = nameToken.value(); } else if (nameToken.type() == StringToken && webkitPrefixed) { if (m_context.useCounter()) m_context.useCounter()->count(UseCounter::QuotedKeyframesRule); name = nameToken.value(); } else { return nullptr; // Parse error; expected ident token in @keyframes header } if (m_observerWrapper) { unsigned endOffset = m_observerWrapper->endOffset(prelude); m_observerWrapper->observer().startRuleHeader(StyleRule::Keyframes, m_observerWrapper->startOffset(prelude)); m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(prelude)); m_observerWrapper->observer().startRuleBody(endOffset); m_observerWrapper->observer().endRuleBody(endOffset); } RefPtrWillBeRawPtr<StyleRuleKeyframes> keyframeRule = StyleRuleKeyframes::create(); consumeRuleList(block, KeyframesRuleList, [keyframeRule](PassRefPtrWillBeRawPtr<StyleRuleBase> keyframe) { keyframeRule->parserAppendKeyframe(toStyleRuleKeyframe(keyframe.get())); }); keyframeRule->setName(name); keyframeRule->setVendorPrefixed(webkitPrefixed); return keyframeRule.release(); }
PassRefPtrWillBeRawPtr<StyleRuleCharset> CSSParserImpl::consumeCharsetRule(CSSParserTokenRange prelude) { prelude.consumeWhitespace(); const CSSParserToken& string = prelude.consumeIncludingWhitespace(); if (string.type() != StringToken || !prelude.atEnd()) return nullptr; // Parse error, expected a single string return StyleRuleCharset::create(); }
CSSSupportsParser::SupportsResult CSSSupportsParser::supportsCondition( CSSParserTokenRange range, CSSParserImpl& parser) { // TODO(timloh): The spec allows leading whitespace in @supports but not // CSS.supports, but major browser vendors allow it in CSS.supports also. range.consumeWhitespace(); return CSSSupportsParser(parser).consumeCondition(range); }
std::unique_ptr<CSSParserSelector> CSSSelectorParser::consumeAttribute( CSSParserTokenRange& range) { ASSERT(range.peek().type() == LeftBracketToken); CSSParserTokenRange block = range.consumeBlock(); block.consumeWhitespace(); AtomicString namespacePrefix; AtomicString attributeName; if (!consumeName(block, attributeName, namespacePrefix)) return nullptr; block.consumeWhitespace(); if (m_context.isHTMLDocument()) attributeName = attributeName.lower(); AtomicString namespaceURI = determineNamespace(namespacePrefix); if (namespaceURI.isNull()) return nullptr; QualifiedName qualifiedName = namespacePrefix.isNull() ? QualifiedName(nullAtom, attributeName, nullAtom) : QualifiedName(namespacePrefix, attributeName, namespaceURI); std::unique_ptr<CSSParserSelector> selector = CSSParserSelector::create(); if (block.atEnd()) { selector->setAttribute(qualifiedName, CSSSelector::CaseSensitive); selector->setMatch(CSSSelector::AttributeSet); return selector; } selector->setMatch(consumeAttributeMatch(block)); const CSSParserToken& attributeValue = block.consumeIncludingWhitespace(); if (attributeValue.type() != IdentToken && attributeValue.type() != StringToken) return nullptr; selector->setValue(attributeValue.value().toAtomicString()); selector->setAttribute(qualifiedName, consumeAttributeFlags(block)); if (!block.atEnd()) return nullptr; return selector; }
PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange tokens) { Value result; tokens.consumeWhitespace(); bool ok = parseValueExpression(tokens, 0, &result); if (!ok || !tokens.atEnd()) return nullptr; return result.value; }
PassRefPtrWillBeRawPtr<StyleRuleBase> CSSParserImpl::parseRule(const String& string, const CSSParserContext& context, StyleSheetContents* styleSheet, AllowedRulesType allowedRules) { CSSParserImpl parser(context, styleSheet); CSSTokenizer::Scope scope(string); CSSParserTokenRange range = scope.tokenRange(); range.consumeWhitespace(); if (range.atEnd()) return nullptr; // Parse error, empty rule RefPtrWillBeRawPtr<StyleRuleBase> rule; if (range.peek().type() == AtKeywordToken) rule = parser.consumeAtRule(range, allowedRules); else rule = parser.consumeQualifiedRule(range, allowedRules); if (!rule) return nullptr; // Parse error, failed to consume rule range.consumeWhitespace(); if (!rule || !range.atEnd()) return nullptr; // Parse error, trailing garbage return rule; }
void CSSSelectorParser::parseSelector(CSSParserTokenRange range, const CSSParserContext& context, const AtomicString& defaultNamespace, StyleSheetContents* styleSheet, CSSSelectorList& output) { CSSSelectorParser parser(context, defaultNamespace, styleSheet); range.consumeWhitespace(); CSSSelectorList result; parser.consumeComplexSelectorList(range, result); if (range.atEnd()) { output.adopt(result); recordSelectorStats(context, output); } ASSERT(!(output.isValid() && parser.m_failedParsing)); }
CSSSupportsParser::SupportsResult CSSSupportsParser::consumeNegation( CSSParserTokenRange range) { ASSERT(range.peek().type() == IdentToken); if (!equalIgnoringASCIICase(range.consume().value(), "not")) return Invalid; if (range.consumeIncludingWhitespace().type() != WhitespaceToken) return Invalid; SupportsResult result = consumeConditionInParenthesis(range); range.consumeWhitespace(); if (!range.atEnd() || result == Invalid) return Invalid; return result ? Unsupported : Supported; }
CSSSelectorList CSSSelectorParser::consumeCompoundSelectorList( CSSParserTokenRange& range) { Vector<std::unique_ptr<CSSParserSelector>> selectorList; std::unique_ptr<CSSParserSelector> selector = consumeCompoundSelector(range); range.consumeWhitespace(); if (!selector) return CSSSelectorList(); selectorList.append(std::move(selector)); while (!range.atEnd() && range.peek().type() == CommaToken) { range.consumeIncludingWhitespace(); selector = consumeCompoundSelector(range); range.consumeWhitespace(); if (!selector) return CSSSelectorList(); selectorList.append(std::move(selector)); } if (m_failedParsing) return CSSSelectorList(); return CSSSelectorList::adoptSelectorVector(selectorList); }
CSSSelectorList CSSSelectorParser::parseSelector( CSSParserTokenRange range, const CSSParserContext& context, StyleSheetContents* styleSheet) { CSSSelectorParser parser(context, styleSheet); range.consumeWhitespace(); CSSSelectorList result = parser.consumeComplexSelectorList(range); if (!range.atEnd()) return CSSSelectorList(); recordSelectorStats(context, result); return result; }
bool CSSParserImpl::consumeRuleList(CSSParserTokenRange range, RuleListType ruleListType, const T callback) { AllowedRulesType allowedRules = RegularRules; switch (ruleListType) { case TopLevelRuleList: allowedRules = AllowCharsetRules; break; case RegularRuleList: allowedRules = RegularRules; break; case KeyframesRuleList: allowedRules = KeyframeRules; break; default: ASSERT_NOT_REACHED(); } bool seenRule = false; bool firstRuleValid = false; while (!range.atEnd()) { RefPtrWillBeRawPtr<StyleRuleBase> rule; switch (range.peek().type()) { case WhitespaceToken: range.consumeWhitespace(); continue; case AtKeywordToken: rule = consumeAtRule(range, allowedRules); break; case CDOToken: case CDCToken: if (ruleListType == TopLevelRuleList) { range.consume(); continue; } // fallthrough default: rule = consumeQualifiedRule(range, allowedRules); break; } if (!seenRule) { seenRule = true; firstRuleValid = rule; } if (rule) { allowedRules = computeNewAllowedRules(allowedRules, rule.get()); callback(rule.release()); } } return firstRuleValid; }
void CSSSelectorParser::consumeCompoundSelectorList(CSSParserTokenRange& range, CSSSelectorList& output) { Vector<OwnPtr<CSSParserSelector>> selectorList; OwnPtr<CSSParserSelector> selector = consumeCompoundSelector(range); range.consumeWhitespace(); if (!selector) return; selectorList.append(selector.release()); while (!range.atEnd() && range.peek().type() == CommaToken) { // FIXME: This differs from the spec grammar: // Spec: compound_selector S* [ COMMA S* compound_selector ]* S* // Impl: compound_selector S* [ COMMA S* compound_selector S* ]* range.consumeIncludingWhitespace(); selector = consumeCompoundSelector(range); range.consumeWhitespace(); if (!selector) return; selectorList.append(selector.release()); } if (!m_failedParsing) output.adoptSelectorVector(selectorList); }
static CSSValueID classifyVariableRange(CSSParserTokenRange range, bool& hasReferences) { hasReferences = false; range.consumeWhitespace(); if (range.peek().type() == IdentToken) { CSSValueID id = range.consumeIncludingWhitespace().id(); if (range.atEnd() && (id == CSSValueInherit || id == CSSValueInitial || id == CSSValueUnset)) return id; } if (classifyBlock(range, hasReferences)) return CSSValueInternalVariableValue; return CSSValueInvalid; }
bool CSSVariableResolver::resolveVariableReference(CSSParserTokenRange range, Vector<CSSParserToken>& result) { range.consumeWhitespace(); ASSERT(range.peek().type() == IdentToken); AtomicString variableName = range.consumeIncludingWhitespace().value(); ASSERT(range.atEnd() || (range.peek().type() == CommaToken)); CSSVariableData* variableData = valueForCustomProperty(variableName); if (!variableData) return resolveFallback(range, result); result.appendVector(variableData->tokens()); Vector<CSSParserToken> trash; resolveFallback(range, trash); return true; }
bool isValidVariableReference(CSSParserTokenRange range) { range.consumeWhitespace(); if (!CSSVariableParser::isValidVariableName(range.consumeIncludingWhitespace())) return false; if (range.atEnd()) return true; if (range.consume().type() != CommaToken) return false; if (range.atEnd()) return false; bool hasReferences = false; return classifyBlock(range, hasReferences); }
PassRefPtrWillBeRawPtr<StyleRuleImport> CSSParserImpl::consumeImportRule(CSSParserTokenRange prelude) { prelude.consumeWhitespace(); AtomicString uri(consumeStringOrURI(prelude)); if (uri.isNull()) return nullptr; // Parse error, expected string or URI if (m_observerWrapper) { unsigned endOffset = m_observerWrapper->endOffset(prelude); m_observerWrapper->observer().startRuleHeader(StyleRule::Import, m_observerWrapper->startOffset(prelude)); m_observerWrapper->observer().endRuleHeader(endOffset); m_observerWrapper->observer().startRuleBody(endOffset); m_observerWrapper->observer().endRuleBody(endOffset); } return StyleRuleImport::create(uri, MediaQueryParser::parseMediaQuerySet(prelude)); }
CSSSupportsParser::SupportsResult CSSSupportsParser::consumeConditionInParenthesis(CSSParserTokenRange& range) { if (range.peek().type() == FunctionToken) { range.consumeComponentValue(); return Unsupported; } if (range.peek().type() != LeftParenthesisToken) return Invalid; CSSParserTokenRange innerRange = range.consumeBlock(); innerRange.consumeWhitespace(); SupportsResult result = consumeCondition(innerRange); if (result != Invalid) return result; return innerRange.peek().type() == IdentToken && m_parser.supportsDeclaration(innerRange) ? Supported : Unsupported; }
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)); }
PassOwnPtr<Vector<double>> CSSParserImpl::consumeKeyframeKeyList(CSSParserTokenRange range) { OwnPtr<Vector<double>> result = adoptPtr(new Vector<double>); while (true) { range.consumeWhitespace(); const CSSParserToken& token = range.consumeIncludingWhitespace(); if (token.type() == PercentageToken && token.numericValue() >= 0 && token.numericValue() <= 100) result->append(token.numericValue() / 100); else if (token.type() == IdentToken && token.valueEqualsIgnoringCase("from")) result->append(0); else if (token.type() == IdentToken && token.valueEqualsIgnoringCase("to")) result->append(1); else return nullptr; // Parser error, invalid value in keyframe selector if (range.atEnd()) return result.release(); if (range.consume().type() != CommaToken) return nullptr; // Parser error } }
PassRefPtrWillBeRawPtr<StyleRuleFontFace> CSSParserImpl::consumeFontFaceRule(CSSParserTokenRange prelude, CSSParserTokenRange block) { prelude.consumeWhitespace(); if (!prelude.atEnd()) return nullptr; // Parse error; @font-face prelude should be empty if (m_observerWrapper) { unsigned endOffset = m_observerWrapper->endOffset(prelude); m_observerWrapper->observer().startRuleHeader(StyleRule::FontFace, m_observerWrapper->startOffset(prelude)); m_observerWrapper->observer().endRuleHeader(endOffset); m_observerWrapper->observer().startRuleBody(endOffset); m_observerWrapper->observer().endRuleBody(endOffset); } if (m_styleSheet) m_styleSheet->setHasFontFaceRule(true); consumeDeclarationList(block, StyleRule::FontFace); return StyleRuleFontFace::create(createStylePropertySet(m_parsedProperties, m_context.mode())); }
String consumeUrl(CSSParserTokenRange& range) { const CSSParserToken& token = range.peek(); if (token.type() == UrlToken) { range.consumeIncludingWhitespace(); return token.value(); } if (token.functionId() == CSSValueUrl) { CSSParserTokenRange urlRange = range; CSSParserTokenRange urlArgs = urlRange.consumeBlock(); const CSSParserToken& next = urlArgs.consumeIncludingWhitespace(); if (next.type() == BadStringToken || !urlArgs.atEnd()) return String(); ASSERT(next.type() == StringToken); range = urlRange; range.consumeWhitespace(); return next.value(); } return String(); }
PassRefPtrWillBeRawPtr<StyleRuleViewport> CSSParserImpl::consumeViewportRule(CSSParserTokenRange prelude, CSSParserTokenRange block) { // Allow @viewport rules from UA stylesheets even if the feature is disabled. if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode())) return nullptr; prelude.consumeWhitespace(); if (!prelude.atEnd()) return nullptr; // Parser error; @viewport prelude should be empty if (m_observerWrapper) { unsigned endOffset = m_observerWrapper->endOffset(prelude); m_observerWrapper->observer().startRuleHeader(StyleRule::Viewport, m_observerWrapper->startOffset(prelude)); m_observerWrapper->observer().endRuleHeader(endOffset); m_observerWrapper->observer().startRuleBody(endOffset); m_observerWrapper->observer().endRuleBody(endOffset); } consumeDeclarationList(block, StyleRule::Viewport); return StyleRuleViewport::create(createStylePropertySet(m_parsedProperties, CSSViewportRuleMode)); }
PassRefPtrWillBeRawPtr<StyleRuleMedia> CSSParserImpl::consumeMediaRule(CSSParserTokenRange prelude, CSSParserTokenRange block) { WillBeHeapVector<RefPtrWillBeMember<StyleRuleBase>> rules; if (m_observerWrapper) { CSSParserTokenRange preludeWithoutWhitespace = prelude; preludeWithoutWhitespace.consumeWhitespace(); m_observerWrapper->observer().startRuleHeader(StyleRule::Media, m_observerWrapper->startOffset(preludeWithoutWhitespace)); m_observerWrapper->observer().endRuleHeader(m_observerWrapper->endOffset(preludeWithoutWhitespace)); m_observerWrapper->observer().startRuleBody(m_observerWrapper->previousTokenStartOffset(block)); } consumeRuleList(block, RegularRuleList, [&rules](PassRefPtrWillBeRawPtr<StyleRuleBase> rule) { rules.append(rule); }); if (m_observerWrapper) m_observerWrapper->observer().endRuleBody(m_observerWrapper->endOffset(block)); return StyleRuleMedia::create(MediaQueryParser::parseMediaQuerySet(prelude), rules); }