Commit 5c7d48b0 authored by Kevin Babbitt's avatar Kevin Babbitt Committed by Commit Bot

[CSSParser] Plumb streaming parser into at-rule handlers

This CL pushes stream-based parsing one level deeper in the stack for
at-rules. The most notable difference is that at-rule handler functions
are now responsible for tokenizing their own preludes and starting
block handling if needed.

Actual parsing for at-rule preludes is unchanged as of yet; the handler
functions generate token ranges on their own and parse them as before.
In future CLs we'll be able to convert each at-rule handler to make
full use of stream parsing.

Bug: 661854
Change-Id: Ia3345be73ab8cc9fce2537443e8a3ed9df017b96
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2208812Reviewed-by: default avatarAnders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Kevin Babbitt <kbabbitt@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#771906}
parent 714a98f9
......@@ -472,6 +472,43 @@ bool CSSParserImpl::ConsumeRuleList(CSSParserTokenStream& stream,
return first_rule_valid;
}
CSSParserTokenRange ConsumeAtRulePrelude(CSSParserTokenStream& stream) {
return stream.ConsumeUntilPeekedTypeIs<kLeftBraceToken, kSemicolonToken>();
}
bool ConsumeEndOfPreludeForAtRuleWithoutBlock(CSSParserTokenStream& stream) {
if (stream.AtEnd() || stream.UncheckedPeek().GetType() == kSemicolonToken) {
if (!stream.UncheckedAtEnd())
stream.UncheckedConsume(); // kSemicolonToken
return true;
}
// Consume the erroneous block.
CSSParserTokenStream::BlockGuard guard(stream);
return false; // Parse error, we expected no block.
}
bool ConsumeEndOfPreludeForAtRuleWithBlock(CSSParserTokenStream& stream) {
if (stream.AtEnd() || stream.UncheckedPeek().GetType() == kSemicolonToken) {
if (!stream.UncheckedAtEnd())
stream.UncheckedConsume(); // kSemicolonToken
return false; // Parse error, we expected a block.
}
return true;
}
void ConsumeErroneousAtRule(CSSParserTokenStream& stream) {
// Consume the prelude and block if present.
ConsumeAtRulePrelude(stream);
if (!stream.AtEnd()) {
if (stream.UncheckedPeek().GetType() == kLeftBraceToken)
CSSParserTokenStream::BlockGuard guard(stream);
else
stream.UncheckedConsume(); // kSemicolonToken
}
}
StyleRuleBase* CSSParserImpl::ConsumeAtRule(CSSParserTokenStream& stream,
AllowedRulesType allowed_rules) {
DCHECK_EQ(stream.Peek().GetType(), kAtKeywordToken);
......@@ -484,63 +521,49 @@ StyleRuleBase* CSSParserImpl::ConsumeAtRule(CSSParserTokenStream& stream,
if (allowed_rules <= kAllowImportRules && id == kCSSAtRuleImport)
import_prelude_uri = ConsumeStringOrURI(stream);
stream.EnsureLookAhead();
const wtf_size_t prelude_offset_start = stream.LookAheadOffset();
const CSSParserTokenRange prelude =
stream.ConsumeUntilPeekedTypeIs<kLeftBraceToken, kSemicolonToken>();
const RangeOffset prelude_offset(prelude_offset_start,
stream.LookAheadOffset());
if (id != kCSSAtRuleInvalid && context_->IsUseCounterRecordingEnabled())
CountAtRule(context_, id);
if (stream.AtEnd() || stream.UncheckedPeek().GetType() == kSemicolonToken) {
if (!stream.UncheckedAtEnd())
stream.UncheckedConsume(); // kSemicolonToken
if (allowed_rules == kAllowCharsetRules && id == kCSSAtRuleCharset)
return ConsumeCharsetRule(prelude);
if (allowed_rules <= kAllowImportRules && id == kCSSAtRuleImport) {
return ConsumeImportRule(std::move(import_prelude_uri), prelude,
prelude_offset);
}
if (allowed_rules <= kAllowNamespaceRules && id == kCSSAtRuleNamespace)
return ConsumeNamespaceRule(prelude);
return nullptr; // Parse error, unrecognised at-rule without block
if (allowed_rules == kKeyframeRules || allowed_rules == kFontFeatureRules ||
allowed_rules == kNoRules) {
// Parse error, no at-rules supported inside @keyframes,
// @font-feature-values, or blocks supported inside declaration lists.
ConsumeErroneousAtRule(stream);
return nullptr;
}
CSSParserTokenStream::BlockGuard guard(stream);
if (allowed_rules == kKeyframeRules)
return nullptr; // Parse error, no at-rules supported inside @keyframes
// Parse error, no at-rules currently supported inside @font-feature-values
if (allowed_rules == kFontFeatureRules)
return nullptr;
if (allowed_rules == kNoRules)
return nullptr; // Parse error, no at-rules with blocks supported inside
// declaration lists
DCHECK_LE(allowed_rules, kRegularRules);
switch (id) {
case kCSSAtRuleMedia:
return ConsumeMediaRule(prelude, prelude_offset, stream);
case kCSSAtRuleSupports:
return ConsumeSupportsRule(prelude, prelude_offset, stream);
case kCSSAtRuleViewport:
return ConsumeViewportRule(prelude, prelude_offset, stream);
case kCSSAtRuleFontFace:
return ConsumeFontFaceRule(prelude, prelude_offset, stream);
case kCSSAtRuleWebkitKeyframes:
return ConsumeKeyframesRule(true, prelude, prelude_offset, stream);
case kCSSAtRuleKeyframes:
return ConsumeKeyframesRule(false, prelude, prelude_offset, stream);
case kCSSAtRulePage:
return ConsumePageRule(prelude, prelude_offset, stream);
case kCSSAtRuleProperty:
return ConsumePropertyRule(prelude, prelude_offset, stream);
default:
return nullptr; // Parse error, unrecognised at-rule with block
stream.EnsureLookAhead();
if (allowed_rules == kAllowCharsetRules && id == kCSSAtRuleCharset) {
return ConsumeCharsetRule(stream);
} else if (allowed_rules <= kAllowImportRules && id == kCSSAtRuleImport) {
return ConsumeImportRule(std::move(import_prelude_uri), stream);
} else if (allowed_rules <= kAllowNamespaceRules &&
id == kCSSAtRuleNamespace) {
return ConsumeNamespaceRule(stream);
} else {
DCHECK_LE(allowed_rules, kRegularRules);
switch (id) {
case kCSSAtRuleMedia:
return ConsumeMediaRule(stream);
case kCSSAtRuleSupports:
return ConsumeSupportsRule(stream);
case kCSSAtRuleViewport:
return ConsumeViewportRule(stream);
case kCSSAtRuleFontFace:
return ConsumeFontFaceRule(stream);
case kCSSAtRuleWebkitKeyframes:
return ConsumeKeyframesRule(true, stream);
case kCSSAtRuleKeyframes:
return ConsumeKeyframesRule(false, stream);
case kCSSAtRulePage:
return ConsumePageRule(stream);
case kCSSAtRuleProperty:
return ConsumePropertyRule(stream);
default:
ConsumeErroneousAtRule(stream);
return nullptr; // Parse error, unrecognised or not-allowed at-rule
}
}
}
......@@ -616,7 +639,11 @@ static AtomicString ConsumeStringOrURI(CSSParserTokenRange& range) {
}
StyleRuleCharset* CSSParserImpl::ConsumeCharsetRule(
CSSParserTokenRange prelude) {
CSSParserTokenStream& stream) {
CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
if (!ConsumeEndOfPreludeForAtRuleWithoutBlock(stream))
return nullptr;
const CSSParserToken& string = prelude.ConsumeIncludingWhitespace();
if (string.GetType() != kStringToken || !prelude.AtEnd())
return nullptr; // Parse error, expected a single string
......@@ -625,16 +652,21 @@ StyleRuleCharset* CSSParserImpl::ConsumeCharsetRule(
StyleRuleImport* CSSParserImpl::ConsumeImportRule(
AtomicString uri,
CSSParserTokenRange prelude,
const RangeOffset& prelude_offset) {
CSSParserTokenStream& stream) {
wtf_size_t prelude_offset_start = stream.LookAheadOffset();
CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
wtf_size_t prelude_offset_end = stream.LookAheadOffset();
if (!ConsumeEndOfPreludeForAtRuleWithoutBlock(stream))
return nullptr;
if (uri.IsNull())
return nullptr; // Parse error, expected string or URI
if (observer_) {
observer_->StartRuleHeader(StyleRule::kImport, prelude_offset.start);
observer_->EndRuleHeader(prelude_offset.end);
observer_->StartRuleBody(prelude_offset.end);
observer_->EndRuleBody(prelude_offset.end);
observer_->StartRuleHeader(StyleRule::kImport, prelude_offset_start);
observer_->EndRuleHeader(prelude_offset_end);
observer_->StartRuleBody(prelude_offset_end);
observer_->EndRuleBody(prelude_offset_end);
}
return MakeGarbageCollected<StyleRuleImport>(
......@@ -645,7 +677,11 @@ StyleRuleImport* CSSParserImpl::ConsumeImportRule(
}
StyleRuleNamespace* CSSParserImpl::ConsumeNamespaceRule(
CSSParserTokenRange prelude) {
CSSParserTokenStream& stream) {
CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
if (!ConsumeEndOfPreludeForAtRuleWithoutBlock(stream))
return nullptr;
AtomicString namespace_prefix;
if (prelude.Peek().GetType() == kIdentToken)
namespace_prefix =
......@@ -658,16 +694,20 @@ StyleRuleNamespace* CSSParserImpl::ConsumeNamespaceRule(
return MakeGarbageCollected<StyleRuleNamespace>(namespace_prefix, uri);
}
StyleRuleMedia* CSSParserImpl::ConsumeMediaRule(
const CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block) {
StyleRuleMedia* CSSParserImpl::ConsumeMediaRule(CSSParserTokenStream& stream) {
wtf_size_t prelude_offset_start = stream.LookAheadOffset();
CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
wtf_size_t prelude_offset_end = stream.LookAheadOffset();
if (!ConsumeEndOfPreludeForAtRuleWithBlock(stream))
return nullptr;
CSSParserTokenStream::BlockGuard guard(stream);
HeapVector<Member<StyleRuleBase>> rules;
if (observer_) {
observer_->StartRuleHeader(StyleRule::kMedia, prelude_offset.start);
observer_->EndRuleHeader(prelude_offset.end);
observer_->StartRuleBody(block.Offset());
observer_->StartRuleHeader(StyleRule::kMedia, prelude_offset_start);
observer_->EndRuleHeader(prelude_offset_end);
observer_->StartRuleBody(stream.Offset());
}
if (style_sheet_)
......@@ -676,38 +716,43 @@ StyleRuleMedia* CSSParserImpl::ConsumeMediaRule(
const auto media = MediaQueryParser::ParseMediaQuerySet(
prelude, context_->GetExecutionContext());
ConsumeRuleList(block, kRegularRuleList,
ConsumeRuleList(stream, kRegularRuleList,
[&rules](StyleRuleBase* rule) { rules.push_back(rule); });
if (observer_)
observer_->EndRuleBody(block.Offset());
observer_->EndRuleBody(stream.Offset());
return MakeGarbageCollected<StyleRuleMedia>(media, rules);
}
StyleRuleSupports* CSSParserImpl::ConsumeSupportsRule(
const CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block) {
CSSParserTokenStream& stream) {
wtf_size_t prelude_offset_start = stream.LookAheadOffset();
CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
wtf_size_t prelude_offset_end = stream.LookAheadOffset();
if (!ConsumeEndOfPreludeForAtRuleWithBlock(stream))
return nullptr;
CSSParserTokenStream::BlockGuard guard(stream);
CSSSupportsParser::Result supported = CSSSupportsParser::SupportsCondition(
prelude, *this, CSSSupportsParser::Mode::kForAtRule);
if (supported == CSSSupportsParser::Result::kParseFailure)
return nullptr; // Parse error, invalid @supports condition
if (observer_) {
observer_->StartRuleHeader(StyleRule::kSupports, prelude_offset.start);
observer_->EndRuleHeader(prelude_offset.end);
observer_->StartRuleBody(block.Offset());
observer_->StartRuleHeader(StyleRule::kSupports, prelude_offset_start);
observer_->EndRuleHeader(prelude_offset_end);
observer_->StartRuleBody(stream.Offset());
}
const auto prelude_serialized = prelude.Serialize().StripWhiteSpace();
HeapVector<Member<StyleRuleBase>> rules;
ConsumeRuleList(block, kRegularRuleList,
ConsumeRuleList(stream, kRegularRuleList,
[&rules](StyleRuleBase* rule) { rules.push_back(rule); });
if (observer_)
observer_->EndRuleBody(block.Offset());
observer_->EndRuleBody(stream.Offset());
return MakeGarbageCollected<StyleRuleSupports>(
prelude_serialized, supported == CSSSupportsParser::Result::kSupported,
......@@ -715,9 +760,14 @@ StyleRuleSupports* CSSParserImpl::ConsumeSupportsRule(
}
StyleRuleViewport* CSSParserImpl::ConsumeViewportRule(
const CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block) {
CSSParserTokenStream& stream) {
wtf_size_t prelude_offset_start = stream.LookAheadOffset();
const CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
wtf_size_t prelude_offset_end = stream.LookAheadOffset();
if (!ConsumeEndOfPreludeForAtRuleWithBlock(stream))
return nullptr;
CSSParserTokenStream::BlockGuard guard(stream);
// Allow @viewport rules from UA stylesheets only.
if (!IsUASheetBehavior(context_->Mode()))
return nullptr;
......@@ -726,32 +776,37 @@ StyleRuleViewport* CSSParserImpl::ConsumeViewportRule(
return nullptr; // Parser error; @viewport prelude should be empty
if (observer_) {
observer_->StartRuleHeader(StyleRule::kViewport, prelude_offset.start);
observer_->EndRuleHeader(prelude_offset.end);
observer_->StartRuleBody(prelude_offset.end);
observer_->EndRuleBody(prelude_offset.end);
observer_->StartRuleHeader(StyleRule::kViewport, prelude_offset_start);
observer_->EndRuleHeader(prelude_offset_end);
observer_->StartRuleBody(prelude_offset_end);
observer_->EndRuleBody(prelude_offset_end);
}
if (style_sheet_)
style_sheet_->SetHasViewportRule();
ConsumeDeclarationList(block, StyleRule::kViewport);
ConsumeDeclarationList(stream, StyleRule::kViewport);
return MakeGarbageCollected<StyleRuleViewport>(
CreateCSSPropertyValueSet(parsed_properties_, kCSSViewportRuleMode));
}
StyleRuleFontFace* CSSParserImpl::ConsumeFontFaceRule(
const CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& stream) {
wtf_size_t prelude_offset_start = stream.LookAheadOffset();
CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
wtf_size_t prelude_offset_end = stream.LookAheadOffset();
if (!ConsumeEndOfPreludeForAtRuleWithBlock(stream))
return nullptr;
CSSParserTokenStream::BlockGuard guard(stream);
if (!prelude.AtEnd())
return nullptr; // Parse error; @font-face prelude should be empty
if (observer_) {
observer_->StartRuleHeader(StyleRule::kFontFace, prelude_offset.start);
observer_->EndRuleHeader(prelude_offset.end);
observer_->StartRuleBody(prelude_offset.end);
observer_->EndRuleBody(prelude_offset.end);
observer_->StartRuleHeader(StyleRule::kFontFace, prelude_offset_start);
observer_->EndRuleHeader(prelude_offset_end);
observer_->StartRuleBody(prelude_offset_end);
observer_->EndRuleBody(prelude_offset_end);
}
if (style_sheet_)
......@@ -764,9 +819,14 @@ StyleRuleFontFace* CSSParserImpl::ConsumeFontFaceRule(
StyleRuleKeyframes* CSSParserImpl::ConsumeKeyframesRule(
bool webkit_prefixed,
CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block) {
CSSParserTokenStream& stream) {
wtf_size_t prelude_offset_start = stream.LookAheadOffset();
CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
wtf_size_t prelude_offset_end = stream.LookAheadOffset();
if (!ConsumeEndOfPreludeForAtRuleWithBlock(stream))
return nullptr;
CSSParserTokenStream::BlockGuard guard(stream);
const CSSParserToken& name_token = prelude.ConsumeIncludingWhitespace();
if (!prelude.AtEnd())
return nullptr; // Parse error; expected single non-whitespace token in
......@@ -783,38 +843,43 @@ StyleRuleKeyframes* CSSParserImpl::ConsumeKeyframesRule(
}
if (observer_) {
observer_->StartRuleHeader(StyleRule::kKeyframes, prelude_offset.start);
observer_->EndRuleHeader(prelude_offset.end);
observer_->StartRuleBody(block.Offset());
observer_->StartRuleHeader(StyleRule::kKeyframes, prelude_offset_start);
observer_->EndRuleHeader(prelude_offset_end);
observer_->StartRuleBody(stream.Offset());
}
auto* keyframe_rule = MakeGarbageCollected<StyleRuleKeyframes>();
ConsumeRuleList(
block, kKeyframesRuleList, [keyframe_rule](StyleRuleBase* keyframe) {
stream, kKeyframesRuleList, [keyframe_rule](StyleRuleBase* keyframe) {
keyframe_rule->ParserAppendKeyframe(To<StyleRuleKeyframe>(keyframe));
});
keyframe_rule->SetName(name);
keyframe_rule->SetVendorPrefixed(webkit_prefixed);
if (observer_)
observer_->EndRuleBody(block.Offset());
observer_->EndRuleBody(stream.Offset());
return keyframe_rule;
}
StyleRulePage* CSSParserImpl::ConsumePageRule(const CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block) {
StyleRulePage* CSSParserImpl::ConsumePageRule(CSSParserTokenStream& stream) {
wtf_size_t prelude_offset_start = stream.LookAheadOffset();
CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
wtf_size_t prelude_offset_end = stream.LookAheadOffset();
if (!ConsumeEndOfPreludeForAtRuleWithBlock(stream))
return nullptr;
CSSParserTokenStream::BlockGuard guard(stream);
CSSSelectorList selector_list = ParsePageSelector(prelude, style_sheet_);
if (!selector_list.IsValid())
return nullptr; // Parse error, invalid @page selector
if (observer_) {
observer_->StartRuleHeader(StyleRule::kPage, prelude_offset.start);
observer_->EndRuleHeader(prelude_offset.end);
observer_->StartRuleHeader(StyleRule::kPage, prelude_offset_start);
observer_->EndRuleHeader(prelude_offset_end);
}
ConsumeDeclarationList(block, StyleRule::kStyle);
ConsumeDeclarationList(stream, StyleRule::kStyle);
return MakeGarbageCollected<StyleRulePage>(
std::move(selector_list),
......@@ -822,9 +887,14 @@ StyleRulePage* CSSParserImpl::ConsumePageRule(const CSSParserTokenRange prelude,
}
StyleRuleProperty* CSSParserImpl::ConsumePropertyRule(
CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block) {
CSSParserTokenStream& stream) {
wtf_size_t prelude_offset_start = stream.LookAheadOffset();
CSSParserTokenRange prelude = ConsumeAtRulePrelude(stream);
wtf_size_t prelude_offset_end = stream.LookAheadOffset();
if (!ConsumeEndOfPreludeForAtRuleWithBlock(stream))
return nullptr;
CSSParserTokenStream::BlockGuard guard(stream);
if (!RuntimeEnabledFeatures::CSSVariables2AtPropertyEnabled())
return nullptr;
......@@ -836,11 +906,11 @@ StyleRuleProperty* CSSParserImpl::ConsumePropertyRule(
String name = name_token.Value().ToString();
if (observer_) {
observer_->StartRuleHeader(StyleRule::kProperty, prelude_offset.start);
observer_->EndRuleHeader(prelude_offset.end);
observer_->StartRuleHeader(StyleRule::kProperty, prelude_offset_start);
observer_->EndRuleHeader(prelude_offset_end);
}
ConsumeDeclarationList(block, StyleRule::kProperty);
ConsumeDeclarationList(stream, StyleRule::kProperty);
return MakeGarbageCollected<StyleRuleProperty>(
name, CreateCSSPropertyValueSet(parsed_properties_, context_->Mode()));
}
......
......@@ -147,33 +147,18 @@ class CORE_EXPORT CSSParserImpl {
StyleRuleBase* ConsumeAtRule(CSSParserTokenStream&, AllowedRulesType);
StyleRuleBase* ConsumeQualifiedRule(CSSParserTokenStream&, AllowedRulesType);
static StyleRuleCharset* ConsumeCharsetRule(CSSParserTokenRange prelude);
static StyleRuleCharset* ConsumeCharsetRule(CSSParserTokenStream&);
StyleRuleImport* ConsumeImportRule(AtomicString prelude_uri,
CSSParserTokenRange prelude,
const RangeOffset& prelude_offset);
StyleRuleNamespace* ConsumeNamespaceRule(CSSParserTokenRange prelude);
StyleRuleMedia* ConsumeMediaRule(CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block);
StyleRuleSupports* ConsumeSupportsRule(CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block);
StyleRuleViewport* ConsumeViewportRule(CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block);
StyleRuleFontFace* ConsumeFontFaceRule(CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block);
CSSParserTokenStream&);
StyleRuleNamespace* ConsumeNamespaceRule(CSSParserTokenStream&);
StyleRuleMedia* ConsumeMediaRule(CSSParserTokenStream&);
StyleRuleSupports* ConsumeSupportsRule(CSSParserTokenStream&);
StyleRuleViewport* ConsumeViewportRule(CSSParserTokenStream&);
StyleRuleFontFace* ConsumeFontFaceRule(CSSParserTokenStream&);
StyleRuleKeyframes* ConsumeKeyframesRule(bool webkit_prefixed,
CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block);
StyleRulePage* ConsumePageRule(CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block);
StyleRuleProperty* ConsumePropertyRule(CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
CSSParserTokenStream& block);
CSSParserTokenStream&);
StyleRulePage* ConsumePageRule(CSSParserTokenStream&);
StyleRuleProperty* ConsumePropertyRule(CSSParserTokenStream&);
StyleRuleKeyframe* ConsumeKeyframeStyleRule(CSSParserTokenRange prelude,
const RangeOffset& prelude_offset,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment