Commit 612b2729 authored by evliu's avatar evliu Committed by Commit Bot

Add WebVTT support for inline styling - style resolution components

Bug: 724598
Change-Id: If27937335d5761a227e62218fe47cdf30bf20c3a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1863357
Commit-Queue: Evan Liu <evliu@google.com>
Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706990}
parent 50bdbe40
...@@ -133,6 +133,7 @@ void ElementRuleCollector::CollectMatchingRulesForList( ...@@ -133,6 +133,7 @@ void ElementRuleCollector::CollectMatchingRulesForList(
&context_.GetElement(), SelectorChecker::kVisitedMatchEnabled); &context_.GetElement(), SelectorChecker::kVisitedMatchEnabled);
context.scope = match_request.scope; context.scope = match_request.scope;
context.pseudo_id = pseudo_style_request_.pseudo_id; context.pseudo_id = pseudo_style_request_.pseudo_id;
context.is_from_vtt = match_request.is_from_vtt;
unsigned rejected = 0; unsigned rejected = 0;
unsigned fast_rejected = 0; unsigned fast_rejected = 0;
......
...@@ -73,7 +73,8 @@ CSSValueList* ConsumeFontFaceUnicodeRange(CSSParserTokenRange& range) { ...@@ -73,7 +73,8 @@ CSSValueList* ConsumeFontFaceUnicodeRange(CSSParserTokenRange& range) {
CSSValue* ConsumeFontFaceSrcURI(CSSParserTokenRange& range, CSSValue* ConsumeFontFaceSrcURI(CSSParserTokenRange& range,
const CSSParserContext& context) { const CSSParserContext& context) {
String url = String url =
css_property_parser_helpers::ConsumeUrlAsStringView(range).ToString(); css_property_parser_helpers::ConsumeUrlAsStringView(range, &context)
.ToString();
if (url.IsNull()) if (url.IsNull())
return nullptr; return nullptr;
CSSFontFaceSrcValue* uri_value(CSSFontFaceSrcValue::Create( CSSFontFaceSrcValue* uri_value(CSSFontFaceSrcValue::Create(
......
...@@ -668,13 +668,14 @@ CSSStringValue* ConsumeString(CSSParserTokenRange& range) { ...@@ -668,13 +668,14 @@ CSSStringValue* ConsumeString(CSSParserTokenRange& range) {
range.ConsumeIncludingWhitespace().Value().ToString()); range.ConsumeIncludingWhitespace().Value().ToString());
} }
StringView ConsumeUrlAsStringView(CSSParserTokenRange& range) { StringView ConsumeUrlAsStringView(CSSParserTokenRange& range,
const CSSParserContext* context) {
StringView url;
const CSSParserToken& token = range.Peek(); const CSSParserToken& token = range.Peek();
if (token.GetType() == kUrlToken) { if (token.GetType() == kUrlToken) {
range.ConsumeIncludingWhitespace(); range.ConsumeIncludingWhitespace();
return token.Value(); url = token.Value();
} } else if (token.FunctionId() == CSSValueID::kUrl) {
if (token.FunctionId() == CSSValueID::kUrl) {
CSSParserTokenRange url_range = range; CSSParserTokenRange url_range = range;
CSSParserTokenRange url_args = url_range.ConsumeBlock(); CSSParserTokenRange url_args = url_range.ConsumeBlock();
const CSSParserToken& next = url_args.ConsumeIncludingWhitespace(); const CSSParserToken& next = url_args.ConsumeIncludingWhitespace();
...@@ -683,15 +684,27 @@ StringView ConsumeUrlAsStringView(CSSParserTokenRange& range) { ...@@ -683,15 +684,27 @@ StringView ConsumeUrlAsStringView(CSSParserTokenRange& range) {
DCHECK_EQ(next.GetType(), kStringToken); DCHECK_EQ(next.GetType(), kStringToken);
range = url_range; range = url_range;
range.ConsumeWhitespace(); range.ConsumeWhitespace();
return next.Value(); url = next.Value();
}
// Invalidate the URL if only data URLs are allowed and the protocol is not
// data.
if (!url.IsNull() &&
context->ResourceFetchRestriction() ==
ResourceFetchRestriction::kOnlyDataUrls &&
!ProtocolIs(url.ToString(), "data")) {
// The StringView must be instantiated with an empty string otherwise the
// URL will incorrectly be identified as null. The resource should behave as
// if it failed to load.
url = StringView("");
} }
return StringView(); return url;
} }
CSSURIValue* ConsumeUrl(CSSParserTokenRange& range, CSSURIValue* ConsumeUrl(CSSParserTokenRange& range,
const CSSParserContext* context) { const CSSParserContext* context) {
StringView url = ConsumeUrlAsStringView(range); StringView url = ConsumeUrlAsStringView(range, context);
if (url.IsNull()) if (url.IsNull())
return nullptr; return nullptr;
String url_string = url.ToString(); String url_string = url.ToString();
...@@ -1758,7 +1771,8 @@ static CSSValue* ConsumeImageSet(CSSParserTokenRange& range, ...@@ -1758,7 +1771,8 @@ static CSSValue* ConsumeImageSet(CSSParserTokenRange& range,
CSSParserTokenRange args = ConsumeFunction(range_copy); CSSParserTokenRange args = ConsumeFunction(range_copy);
auto* image_set = MakeGarbageCollected<CSSImageSetValue>(context->Mode()); auto* image_set = MakeGarbageCollected<CSSImageSetValue>(context->Mode());
do { do {
AtomicString url_value = ConsumeUrlAsStringView(args).ToAtomicString(); AtomicString url_value =
ConsumeUrlAsStringView(args, context).ToAtomicString();
if (url_value.IsNull()) if (url_value.IsNull())
return nullptr; return nullptr;
...@@ -1801,7 +1815,7 @@ static bool IsGeneratedImage(CSSValueID id) { ...@@ -1801,7 +1815,7 @@ static bool IsGeneratedImage(CSSValueID id) {
CSSValue* ConsumeImage(CSSParserTokenRange& range, CSSValue* ConsumeImage(CSSParserTokenRange& range,
const CSSParserContext* context, const CSSParserContext* context,
ConsumeGeneratedImagePolicy generated_image) { ConsumeGeneratedImagePolicy generated_image) {
AtomicString uri = ConsumeUrlAsStringView(range).ToAtomicString(); AtomicString uri = ConsumeUrlAsStringView(range, context).ToAtomicString();
if (!uri.IsNull()) if (!uri.IsNull())
return CreateCSSImageValueWithReferrer(uri, context); return CreateCSSImageValueWithReferrer(uri, context);
if (range.Peek().GetType() == kFunctionToken) { if (range.Peek().GetType() == kFunctionToken) {
......
...@@ -94,7 +94,8 @@ CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange&); ...@@ -94,7 +94,8 @@ CSSIdentifierValue* ConsumeIdent(CSSParserTokenRange&);
CSSCustomIdentValue* ConsumeCustomIdent(CSSParserTokenRange&, CSSCustomIdentValue* ConsumeCustomIdent(CSSParserTokenRange&,
const CSSParserContext&); const CSSParserContext&);
CSSStringValue* ConsumeString(CSSParserTokenRange&); CSSStringValue* ConsumeString(CSSParserTokenRange&);
StringView ConsumeUrlAsStringView(CSSParserTokenRange&); StringView ConsumeUrlAsStringView(CSSParserTokenRange&,
const CSSParserContext*);
cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange&, cssvalue::CSSURIValue* ConsumeUrl(CSSParserTokenRange&,
const CSSParserContext*); const CSSParserContext*);
......
...@@ -41,11 +41,13 @@ class MatchRequest { ...@@ -41,11 +41,13 @@ class MatchRequest {
MatchRequest(RuleSet* rule_set, MatchRequest(RuleSet* rule_set,
const ContainerNode* scope = nullptr, const ContainerNode* scope = nullptr,
const CSSStyleSheet* css_sheet = nullptr, const CSSStyleSheet* css_sheet = nullptr,
unsigned style_sheet_index = 0) unsigned style_sheet_index = 0,
bool is_from_vtt = false)
: rule_set(rule_set), : rule_set(rule_set),
scope(scope), scope(scope),
style_sheet(css_sheet), style_sheet(css_sheet),
style_sheet_index(style_sheet_index) { style_sheet_index(style_sheet_index),
is_from_vtt(is_from_vtt) {
// Now that we're about to read from the RuleSet, we're done adding more // Now that we're about to read from the RuleSet, we're done adding more
// rules to the set and we should make sure it's compacted. // rules to the set and we should make sure it's compacted.
rule_set->CompactRulesIfNeeded(); rule_set->CompactRulesIfNeeded();
...@@ -55,6 +57,7 @@ class MatchRequest { ...@@ -55,6 +57,7 @@ class MatchRequest {
Member<const ContainerNode> scope; Member<const ContainerNode> scope;
Member<const CSSStyleSheet> style_sheet; Member<const CSSStyleSheet> style_sheet;
const unsigned style_sheet_index; const unsigned style_sheet_index;
bool is_from_vtt;
}; };
} // namespace blink } // namespace blink
......
...@@ -58,7 +58,6 @@ ...@@ -58,7 +58,6 @@
#include "third_party/blink/renderer/core/css/css_value_list.h" #include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/element_rule_collector.h" #include "third_party/blink/renderer/core/css/element_rule_collector.h"
#include "third_party/blink/renderer/core/css/font_face.h" #include "third_party/blink/renderer/core/css/font_face.h"
#include "third_party/blink/renderer/core/css/media_query_evaluator.h"
#include "third_party/blink/renderer/core/css/page_rule_collector.h" #include "third_party/blink/renderer/core/css/page_rule_collector.h"
#include "third_party/blink/renderer/core/css/part_names.h" #include "third_party/blink/renderer/core/css/part_names.h"
#include "third_party/blink/renderer/core/css/properties/css_property.h" #include "third_party/blink/renderer/core/css/properties/css_property.h"
...@@ -66,7 +65,6 @@ ...@@ -66,7 +65,6 @@
#include "third_party/blink/renderer/core/css/resolver/css_variable_animator.h" #include "third_party/blink/renderer/core/css/resolver/css_variable_animator.h"
#include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h" #include "third_party/blink/renderer/core/css/resolver/css_variable_resolver.h"
#include "third_party/blink/renderer/core/css/resolver/match_result.h" #include "third_party/blink/renderer/core/css/resolver/match_result.h"
#include "third_party/blink/renderer/core/css/resolver/media_query_result.h"
#include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h" #include "third_party/blink/renderer/core/css/resolver/scoped_style_resolver.h"
#include "third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.h" #include "third_party/blink/renderer/core/css/resolver/selector_filter_parent_scope.h"
#include "third_party/blink/renderer/core/css/resolver/style_adjuster.h" #include "third_party/blink/renderer/core/css/resolver/style_adjuster.h"
...@@ -90,6 +88,9 @@ ...@@ -90,6 +88,9 @@
#include "third_party/blink/renderer/core/html/custom/custom_element_definition.h" #include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h" #include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/html/html_slot_element.h" #include "third_party/blink/renderer/core/html/html_slot_element.h"
#include "third_party/blink/renderer/core/html/track/text_track.h"
#include "third_party/blink/renderer/core/html/track/vtt/vtt_cue.h"
#include "third_party/blink/renderer/core/html/track/vtt/vtt_element.h"
#include "third_party/blink/renderer/core/html_names.h" #include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/media_type_names.h" #include "third_party/blink/renderer/core/media_type_names.h"
#include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/core/probe/core_probes.h"
...@@ -312,6 +313,38 @@ static void MatchSlottedRules(const Element& element, ...@@ -312,6 +313,38 @@ static void MatchSlottedRules(const Element& element,
} }
} }
const static TextTrack* GetTextTrackFromElement(const Element& element) {
if (auto* vtt_element = DynamicTo<VTTElement>(element))
return vtt_element->GetTrack();
if (auto* vtt_cue_background_box = DynamicTo<VTTCueBackgroundBox>(element))
return vtt_cue_background_box->GetTrack();
return nullptr;
}
static void MatchVTTRules(const Element& element,
ElementRuleCollector& collector) {
const TextTrack* text_track = GetTextTrackFromElement(element);
if (!text_track)
return;
const HeapVector<Member<CSSStyleSheet>>& styles =
text_track->GetCSSStyleSheets();
if (!styles.IsEmpty()) {
int style_sheet_index = 0;
collector.ClearMatchedRules();
for (CSSStyleSheet* style : styles) {
RuleSet* rule_set =
element.GetDocument().GetStyleEngine().RuleSetForSheet(*style);
if (rule_set) {
collector.CollectMatchingRules(
MatchRequest(rule_set, nullptr /* scope */, style,
style_sheet_index, true /* is_from_webvtt */));
style_sheet_index++;
}
}
collector.SortAndTransferMatchedRules();
}
}
// Matches rules from the element's scope. The selectors may cross shadow // Matches rules from the element's scope. The selectors may cross shadow
// boundaries during matching, like for :host-context. // boundaries during matching, like for :host-context.
static void MatchElementScopeRules(const Element& element, static void MatchElementScopeRules(const Element& element,
...@@ -324,6 +357,7 @@ static void MatchElementScopeRules(const Element& element, ...@@ -324,6 +357,7 @@ static void MatchElementScopeRules(const Element& element,
collector.SortAndTransferMatchedRules(); collector.SortAndTransferMatchedRules();
} }
MatchVTTRules(element, collector);
if (element.IsStyledElement() && element.InlineStyle() && if (element.IsStyledElement() && element.InlineStyle() &&
!collector.IsCollectingForPseudoElement()) { !collector.IsCollectingForPseudoElement()) {
// Inline style is immutable as long as there is no CSSOM wrapper. // Inline style is immutable as long as there is no CSSOM wrapper.
......
...@@ -88,8 +88,10 @@ static bool MatchesListBoxPseudoClass(const Element& element) { ...@@ -88,8 +88,10 @@ static bool MatchesListBoxPseudoClass(const Element& element) {
return html_select_element && !html_select_element->UsesMenuList(); return html_select_element && !html_select_element->UsesMenuList();
} }
static bool MatchesTagName(const Element& element, static bool MatchesTagName(
const QualifiedName& tag_q_name) { const Element& element,
const QualifiedName& tag_q_name,
const SelectorChecker::SelectorCheckingContext& context) {
if (tag_q_name == AnyQName()) if (tag_q_name == AnyQName())
return true; return true;
const AtomicString& local_name = tag_q_name.LocalName(); const AtomicString& local_name = tag_q_name.LocalName();
...@@ -105,8 +107,12 @@ static bool MatchesTagName(const Element& element, ...@@ -105,8 +107,12 @@ static bool MatchesTagName(const Element& element,
return false; return false;
} }
const AtomicString& namespace_uri = tag_q_name.NamespaceURI(); const AtomicString& namespace_uri = tag_q_name.NamespaceURI();
return namespace_uri == g_star_atom || if (namespace_uri == g_star_atom)
namespace_uri == element.namespaceURI(); return true;
// VTT style sheets should apply to a hypothetical document with no namespace
if (context.is_from_vtt)
return namespace_uri.IsEmpty();
return namespace_uri == element.namespaceURI();
} }
static Element* ParentElement( static Element* ParentElement(
...@@ -204,6 +210,26 @@ static bool IsLastOfType(Element& element, const QualifiedName& type) { ...@@ -204,6 +210,26 @@ static bool IsLastOfType(Element& element, const QualifiedName& type) {
return !ElementTraversal::NextSibling(element, HasTagName(type)); return !ElementTraversal::NextSibling(element, HasTagName(type));
} }
bool SelectorChecker::Match(const SelectorCheckingContext& context,
MatchResult& result) const {
DCHECK(context.selector);
if (context.is_from_vtt)
return MatchVTTBlockSelector(context, result);
return MatchSelector(context, result) == kSelectorMatches;
}
bool SelectorChecker::MatchVTTBlockSelector(
const SelectorCheckingContext& context,
MatchResult& result) const {
DCHECK(context.selector);
if (context.selector->IsLastInTagHistory() ||
context.selector->TagHistory()->Specificity() != 0) {
return false;
}
return MatchSelector(context, result) == kSelectorMatches;
}
// Recursive check of selectors and combinators // Recursive check of selectors and combinators
// It can return 4 different values: // It can return 4 different values:
// * SelectorMatches - the selector matches the element e // * SelectorMatches - the selector matches the element e
...@@ -330,6 +356,14 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation( ...@@ -330,6 +356,14 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
next_context.previous_element = context.element; next_context.previous_element = context.element;
next_context.pseudo_id = kPseudoIdNone; next_context.pseudo_id = kPseudoIdNone;
// Rules that come from a WebVTT STYLE block apply to a hypothetical
// document with a single empty element with no explicit name, no namespace,
// no attribute, no classes, no IDs, and unknown primary language that acts
// as the originating element for the cue pseudo-elements. This element
// must not be generally selectable.
if (context.is_from_vtt && relation != CSSSelector::kShadowPseudo)
return kSelectorFailsCompletely;
switch (relation) { switch (relation) {
case CSSSelector::kShadowDeepAsDescendant: case CSSSelector::kShadowDeepAsDescendant:
Deprecation::CountDeprecation(context.element->GetDocument(), Deprecation::CountDeprecation(context.element->GetDocument(),
...@@ -690,7 +724,7 @@ bool SelectorChecker::CheckOne(const SelectorCheckingContext& context, ...@@ -690,7 +724,7 @@ bool SelectorChecker::CheckOne(const SelectorCheckingContext& context,
switch (selector.Match()) { switch (selector.Match()) {
case CSSSelector::kTag: case CSSSelector::kTag:
return MatchesTagName(element, selector.TagQName()); return MatchesTagName(element, selector.TagQName(), context);
case CSSSelector::kClass: case CSSSelector::kClass:
return element.HasClass() && return element.HasClass() &&
element.ClassNames().Contains(selector.Value()); element.ClassNames().Contains(selector.Value());
...@@ -896,7 +930,8 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context, ...@@ -896,7 +930,8 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context,
for (sub_context.selector = selector.SelectorList()->First(); for (sub_context.selector = selector.SelectorList()->First();
sub_context.selector; sub_context.selector = CSSSelectorList::Next( sub_context.selector; sub_context.selector = CSSSelectorList::Next(
*sub_context.selector)) { *sub_context.selector)) {
if (Match(sub_context)) MatchResult sub_result;
if (MatchSelector(sub_context, sub_result) == kSelectorMatches)
return true; return true;
} }
} break; } break;
...@@ -1150,7 +1185,8 @@ bool SelectorChecker::CheckPseudoElement(const SelectorCheckingContext& context, ...@@ -1150,7 +1185,8 @@ bool SelectorChecker::CheckPseudoElement(const SelectorCheckingContext& context,
for (sub_context.selector = selector.SelectorList()->First(); for (sub_context.selector = selector.SelectorList()->First();
sub_context.selector; sub_context.selector = CSSSelectorList::Next( sub_context.selector; sub_context.selector = CSSSelectorList::Next(
*sub_context.selector)) { *sub_context.selector)) {
if (Match(sub_context)) MatchResult sub_result;
if (MatchSelector(sub_context, sub_result) == kSelectorMatches)
return true; return true;
} }
return false; return false;
......
...@@ -115,7 +115,8 @@ class SelectorChecker { ...@@ -115,7 +115,8 @@ class SelectorChecker {
in_rightmost_compound(true), in_rightmost_compound(true),
has_scrollbar_pseudo(false), has_scrollbar_pseudo(false),
has_selection_pseudo(false), has_selection_pseudo(false),
treat_shadow_host_as_normal_scope(false) {} treat_shadow_host_as_normal_scope(false),
is_from_vtt(false) {}
const CSSSelector* selector; const CSSSelector* selector;
Member<Element> element; Member<Element> element;
...@@ -128,6 +129,7 @@ class SelectorChecker { ...@@ -128,6 +129,7 @@ class SelectorChecker {
bool has_scrollbar_pseudo; bool has_scrollbar_pseudo;
bool has_selection_pseudo; bool has_selection_pseudo;
bool treat_shadow_host_as_normal_scope; bool treat_shadow_host_as_normal_scope;
bool is_from_vtt;
}; };
struct MatchResult { struct MatchResult {
...@@ -140,11 +142,7 @@ class SelectorChecker { ...@@ -140,11 +142,7 @@ class SelectorChecker {
unsigned specificity; unsigned specificity;
}; };
bool Match(const SelectorCheckingContext& context, bool Match(const SelectorCheckingContext& context, MatchResult& result) const;
MatchResult& result) const {
DCHECK(context.selector);
return MatchSelector(context, result) == kSelectorMatches;
}
bool Match(const SelectorCheckingContext& context) const { bool Match(const SelectorCheckingContext& context) const {
MatchResult ignore_result; MatchResult ignore_result;
...@@ -196,6 +194,8 @@ class SelectorChecker { ...@@ -196,6 +194,8 @@ class SelectorChecker {
MatchStatus MatchForPseudoShadow(const SelectorCheckingContext&, MatchStatus MatchForPseudoShadow(const SelectorCheckingContext&,
const ContainerNode*, const ContainerNode*,
MatchResult&) const; MatchResult&) const;
bool MatchVTTBlockSelector(const SelectorCheckingContext& context,
MatchResult& result) const;
bool CheckPseudoClass(const SelectorCheckingContext&, MatchResult&) const; bool CheckPseudoClass(const SelectorCheckingContext&, MatchResult&) const;
bool CheckPseudoElement(const SelectorCheckingContext&, MatchResult&) const; bool CheckPseudoElement(const SelectorCheckingContext&, MatchResult&) const;
bool CheckScrollbarPseudoClass(const SelectorCheckingContext&, bool CheckScrollbarPseudoClass(const SelectorCheckingContext&,
......
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