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 CSSLazyParsingState::shouldLazilyParseProperties( const CSSSelectorList& selectors, const CSSParserTokenRange& block) const { // Simple heuristic for an empty block. Note that |block| here does not // include {} brackets. We avoid lazy parsing empty blocks so we can avoid // considering them when possible for matching. Lazy blocks must always be // considered. Three tokens is a reasonable minimum for a block: // ident ':' <value>. if (block.end() - block.begin() <= 2) return false; // Disallow lazy parsing for blocks which have before/after in their selector // list. This ensures we don't cause a collectFeatures() when we trigger // parsing for attr() functions which would trigger expensive invalidation // propagation. for (const auto* s = selectors.first(); s; s = CSSSelectorList::next(*s)) { for (const CSSSelector* current = s; current; current = current->tagHistory()) { const CSSSelector::PseudoType type(current->getPseudoType()); if (type == CSSSelector::PseudoBefore || type == CSSSelector::PseudoAfter) return false; if (current->relation() != CSSSelector::SubSelector) break; } } return true; }
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()); }
DeferredStyleGroupRuleList::DeferredStyleGroupRuleList(const CSSParserTokenRange& range, CSSDeferredParser& parser) : m_parser(parser) { size_t length = range.end() - range.begin(); m_tokens.reserveCapacity(length); m_tokens.append(range.begin(), length); }
CSSLazyPropertyParserImpl::CSSLazyPropertyParserImpl(CSSParserTokenRange block, CSSLazyParsingState* state) : CSSLazyPropertyParser(), m_lazyState(state) { // Reserve capacity to minimize heap bloat. size_t length = block.end() - block.begin(); m_tokens.reserveCapacity(length); m_tokens.append(block.begin(), length); }
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); }
unsigned CSSParserObserverWrapper::endOffset(const CSSParserTokenRange& range) { return m_tokenOffsets[range.end() - m_firstParserToken]; }