Commit fe0a5fdc authored by Anders Hartvoll Ruud's avatar Anders Hartvoll Ruud Committed by Commit Bot

Remove ForVTT codepath in SelectorMatcher

Having a separate copy-pasted codepath for selector matching is not
acceptable for maintainability reasons. Instead we can lazily create
an actual Element to represent the almost-featureless element
described by the spec [1], and use this as the originating element
during selector matching. The element has no ID, no classes, no
attributes, no tag name, no namespace, no parent, no siblings; so it
should be pretty hard to match against it.

Longer term it would be nice to make the originating element actually
featureless [2].

Bug: 1137349
TEST=external/wpt/webvtt/rendering/cues-with-video/processing-model/support/embedded_style_selectors.html

[1] https://w3c.github.io/webvtt/#obtaining-css-boxes
[2] https://github.com/w3c/webvtt/issues/477

Change-Id: I06d618546893be3942ea5406507a01bc508340d3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2462274
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Cr-Commit-Position: refs/heads/master@{#816299}
parent bd17fcf4
...@@ -150,7 +150,7 @@ void ElementRuleCollector::CollectMatchingRulesForList( ...@@ -150,7 +150,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; context.vtt_originating_element = match_request.vtt_originating_element;
unsigned rejected = 0; unsigned rejected = 0;
unsigned fast_rejected = 0; unsigned fast_rejected = 0;
......
...@@ -42,12 +42,12 @@ class MatchRequest { ...@@ -42,12 +42,12 @@ class MatchRequest {
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) Element* vtt_originating_element = nullptr)
: 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) { vtt_originating_element(vtt_originating_element) {
// 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();
...@@ -57,7 +57,10 @@ class MatchRequest { ...@@ -57,7 +57,10 @@ class MatchRequest {
const ContainerNode* scope; const ContainerNode* scope;
const CSSStyleSheet* style_sheet; const CSSStyleSheet* style_sheet;
const unsigned style_sheet_index; const unsigned style_sheet_index;
bool is_from_vtt; // For WebVTT STYLE blocks, this is set to the featureless-like Element
// described by the spec:
// https://w3c.github.io/webvtt/#obtaining-css-boxes
Element* vtt_originating_element;
}; };
} // namespace blink } // namespace blink
......
...@@ -409,12 +409,12 @@ static void MatchVTTRules(const Element& element, ...@@ -409,12 +409,12 @@ static void MatchVTTRules(const Element& element,
int style_sheet_index = 0; int style_sheet_index = 0;
collector.ClearMatchedRules(); collector.ClearMatchedRules();
for (CSSStyleSheet* style : styles) { for (CSSStyleSheet* style : styles) {
RuleSet* rule_set = StyleEngine& style_engine = element.GetDocument().GetStyleEngine();
element.GetDocument().GetStyleEngine().RuleSetForSheet(*style); RuleSet* rule_set = style_engine.RuleSetForSheet(*style);
if (rule_set) { if (rule_set) {
collector.CollectMatchingRules( collector.CollectMatchingRules(MatchRequest(
MatchRequest(rule_set, nullptr /* scope */, style, rule_set, nullptr /* scope */, style, style_sheet_index,
style_sheet_index, true /* is_from_webvtt */)); style_engine.EnsureVTTOriginatingElement()));
style_sheet_index++; style_sheet_index++;
} }
} }
......
...@@ -123,38 +123,6 @@ static bool MatchesTagName(const Element& element, ...@@ -123,38 +123,6 @@ static bool MatchesTagName(const Element& element,
namespace_uri == element.namespaceURI(); namespace_uri == element.namespaceURI();
} }
static bool MatchesTagNameForVTT(
const Element& element,
const QualifiedName& tag_q_name,
const SelectorChecker::SelectorCheckingContext& context) {
if (tag_q_name == AnyQName())
return true;
const AtomicString& local_name = tag_q_name.LocalName();
// The originating element for the cues has no explicit name.
if (!context.in_rightmost_compound && !local_name.IsEmpty() &&
local_name != CSSSelector::UniversalSelectorAtom()) {
return false;
}
if (local_name != CSSSelector::UniversalSelectorAtom() &&
local_name != element.localName()) {
if (element.IsHTMLElement() || !IsA<HTMLDocument>(element.GetDocument()))
return false;
// Non-html elements in html documents are normalized to their camel-cased
// version during parsing if applicable. Yet, type selectors are lower-cased
// for selectors in html documents. Compare the upper case converted names
// instead to allow matching SVG elements like foreignObject.
if (element.TagQName().LocalNameUpper() != tag_q_name.LocalNameUpper())
return false;
}
const AtomicString& namespace_uri = tag_q_name.NamespaceURI();
return namespace_uri == g_star_atom || namespace_uri.IsEmpty();
}
static Element* ParentElement( static Element* ParentElement(
const SelectorChecker::SelectorCheckingContext& context) { const SelectorChecker::SelectorCheckingContext& context) {
// - If context.scope is a shadow root, we should walk up to its shadow host. // - If context.scope is a shadow root, we should walk up to its shadow host.
...@@ -260,19 +228,12 @@ static bool IsLastOfType(Element& element, const QualifiedName& type) { ...@@ -260,19 +228,12 @@ static bool IsLastOfType(Element& element, const QualifiedName& type) {
bool SelectorChecker::Match(const SelectorCheckingContext& context, bool SelectorChecker::Match(const SelectorCheckingContext& context,
MatchResult& result) const { MatchResult& result) const {
DCHECK(context.selector); DCHECK(context.selector);
if (context.is_from_vtt) if (UNLIKELY(context.vtt_originating_element)) {
return MatchVTTBlockSelector(context, result); // A kShadowPseudo combinator is required for VTT matching.
return MatchSelector(context, result) == kSelectorMatches;
}
bool SelectorChecker::MatchVTTBlockSelector(
const SelectorCheckingContext& context,
MatchResult& result) const {
DCHECK(context.selector);
if (context.selector->IsLastInTagHistory()) if (context.selector->IsLastInTagHistory())
return false; return false;
}
return MatchSelectorForVTT(context, result) == kSelectorMatches; return MatchSelector(context, result) == kSelectorMatches;
} }
// Recursive check of selectors and combinators // Recursive check of selectors and combinators
...@@ -320,44 +281,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchSelector( ...@@ -320,44 +281,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchSelector(
return match; return match;
} }
SelectorChecker::MatchStatus SelectorChecker::MatchSelectorForVTT(
const SelectorCheckingContext& context,
MatchResult& result) const {
MatchResult sub_result;
if (!CheckOneForVTT(context, sub_result))
return kSelectorFailsLocally;
if (sub_result.dynamic_pseudo != kPseudoIdNone)
result.dynamic_pseudo = sub_result.dynamic_pseudo;
if (context.selector->IsLastInTagHistory()) {
if (ScopeContainsLastMatchedElement(context)) {
result.specificity += sub_result.specificity;
return kSelectorMatches;
}
return kSelectorFailsLocally;
}
MatchStatus match;
if (context.selector->Relation() != CSSSelector::kSubSelector) {
if (NextSelectorExceedsScope(context))
return kSelectorFailsCompletely;
if (context.pseudo_id != kPseudoIdNone &&
context.pseudo_id != result.dynamic_pseudo)
return kSelectorFailsCompletely;
base::AutoReset<PseudoId> dynamic_pseudo_scope(&result.dynamic_pseudo,
kPseudoIdNone);
match = MatchForRelationForVTT(context, result);
} else {
match = MatchForSubSelectorForVTT(context, result);
}
if (match == kSelectorMatches)
result.specificity += sub_result.specificity;
return match;
}
static inline SelectorChecker::SelectorCheckingContext static inline SelectorChecker::SelectorCheckingContext
PrepareNextContextForRelation( PrepareNextContextForRelation(
const SelectorChecker::SelectorCheckingContext& context) { const SelectorChecker::SelectorCheckingContext& context) {
...@@ -393,14 +316,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForSubSelector( ...@@ -393,14 +316,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForSubSelector(
return MatchSelector(next_context, result); return MatchSelector(next_context, result);
} }
SelectorChecker::MatchStatus SelectorChecker::MatchForSubSelectorForVTT(
const SelectorCheckingContext& context,
MatchResult& result) const {
SelectorCheckingContext next_context = PrepareNextContextForRelation(context);
next_context.is_sub_selector = true;
return MatchSelectorForVTT(next_context, result);
}
static inline bool IsV0ShadowRoot(const Node* node) { static inline bool IsV0ShadowRoot(const Node* node) {
auto* shadow_root = DynamicTo<ShadowRoot>(node); auto* shadow_root = DynamicTo<ShadowRoot>(node);
return shadow_root && shadow_root->GetType() == ShadowRootType::V0; return shadow_root && shadow_root->GetType() == ShadowRootType::V0;
...@@ -562,6 +477,10 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation( ...@@ -562,6 +477,10 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
Element* shadow_host = context.element->OwnerShadowHost(); Element* shadow_host = context.element->OwnerShadowHost();
if (!shadow_host) if (!shadow_host)
return kSelectorFailsCompletely; return kSelectorFailsCompletely;
// Match against featureless-like Element described by spec:
// https://w3c.github.io/webvtt/#obtaining-css-boxes
if (context.vtt_originating_element)
shadow_host = context.vtt_originating_element;
next_context.element = shadow_host; next_context.element = shadow_host;
return MatchSelector(next_context, result); return MatchSelector(next_context, result);
} }
...@@ -641,49 +560,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation( ...@@ -641,49 +560,6 @@ SelectorChecker::MatchStatus SelectorChecker::MatchForRelation(
return kSelectorFailsCompletely; return kSelectorFailsCompletely;
} }
SelectorChecker::MatchStatus SelectorChecker::MatchForRelationForVTT(
const SelectorCheckingContext& context,
MatchResult& result) const {
SelectorCheckingContext next_context = PrepareNextContextForRelation(context);
CSSSelector::RelationType relation = context.selector->Relation();
// 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 (relation != CSSSelector::kShadowPseudo)
return kSelectorFailsCompletely;
if (!context.is_sub_selector)
next_context.visited_match_type = kVisitedMatchDisabled;
next_context.in_rightmost_compound = false;
next_context.is_sub_selector = false;
next_context.previous_element = context.element;
next_context.pseudo_id = kPseudoIdNone;
DCHECK(mode_ == kQueryingRules ||
context.selector->GetPseudoType() != CSSSelector::kPseudoShadow);
if (context.selector->GetPseudoType() == CSSSelector::kPseudoShadow) {
UseCounter::Count(context.element->GetDocument(),
WebFeature::kPseudoShadowInStaticProfile);
}
// If we're in the same tree-scope as the scoping element, then following
// a shadow descendant combinator would escape that and thus the scope.
if (context.scope && context.scope->OwnerShadowHost() &&
context.scope->OwnerShadowHost()->GetTreeScope() ==
context.element->GetTreeScope())
return kSelectorFailsCompletely;
Element* shadow_host = context.element->OwnerShadowHost();
if (!shadow_host)
return kSelectorFailsCompletely;
next_context.element = shadow_host;
return MatchSelectorForVTT(next_context, result);
}
SelectorChecker::MatchStatus SelectorChecker::MatchForPseudoContent( SelectorChecker::MatchStatus SelectorChecker::MatchForPseudoContent(
const SelectorCheckingContext& context, const SelectorCheckingContext& context,
const Element& element, const Element& element,
...@@ -879,35 +755,6 @@ bool SelectorChecker::CheckOne(const SelectorCheckingContext& context, ...@@ -879,35 +755,6 @@ bool SelectorChecker::CheckOne(const SelectorCheckingContext& context,
} }
} }
bool SelectorChecker::CheckOneForVTT(const SelectorCheckingContext& context,
MatchResult& result) const {
DCHECK(context.element);
Element& element = *context.element;
DCHECK(context.selector);
const CSSSelector& selector = *context.selector;
switch (selector.Match()) {
case CSSSelector::kTag:
return MatchesTagNameForVTT(element, selector.TagQName(), context);
// Attribute selectors
case CSSSelector::kAttributeExact:
case CSSSelector::kAttributeSet:
case CSSSelector::kAttributeHyphen:
case CSSSelector::kAttributeList:
case CSSSelector::kAttributeContain:
case CSSSelector::kAttributeBegin:
case CSSSelector::kAttributeEnd:
return AnyAttributeMatches(element, selector.Match(), selector);
case CSSSelector::kPseudoClass:
return CheckPseudoClassForVTT(context, result);
case CSSSelector::kPseudoElement:
return CheckPseudoElementForVTT(context, result);
default:
return false;
}
}
bool SelectorChecker::CheckPseudoNot(const SelectorCheckingContext& context, bool SelectorChecker::CheckPseudoNot(const SelectorCheckingContext& context,
MatchResult& result) const { MatchResult& result) const {
const CSSSelector& selector = *context.selector; const CSSSelector& selector = *context.selector;
...@@ -934,32 +781,6 @@ bool SelectorChecker::CheckPseudoNot(const SelectorCheckingContext& context, ...@@ -934,32 +781,6 @@ bool SelectorChecker::CheckPseudoNot(const SelectorCheckingContext& context,
return false; return false;
} }
bool SelectorChecker::CheckPseudoNotForVTT(
const SelectorCheckingContext& context,
MatchResult& result) const {
const CSSSelector& selector = *context.selector;
SelectorCheckingContext sub_context(context);
sub_context.is_sub_selector = true;
DCHECK(selector.SelectorList());
for (sub_context.selector = selector.SelectorList()->First();
sub_context.selector;
sub_context.selector = sub_context.selector->TagHistory()) {
// :not cannot nest. I don't really know why this is a
// restriction in CSS3, but it is, so let's honor it.
// the parser enforces that this never occurs
DCHECK_NE(sub_context.selector->GetPseudoType(), CSSSelector::kPseudoNot);
// We select between :visited and :link when applying. We don't know which
// one applied (or not) yet.
if (sub_context.selector->GetPseudoType() == CSSSelector::kPseudoVisited ||
(sub_context.selector->GetPseudoType() == CSSSelector::kPseudoLink &&
sub_context.visited_match_type == kVisitedMatchEnabled))
return true;
if (!CheckOneForVTT(sub_context, result))
return true;
}
return false;
}
bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context, bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context,
MatchResult& result) const { MatchResult& result) const {
Element& element = *context.element; Element& element = *context.element;
...@@ -1361,36 +1182,6 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context, ...@@ -1361,36 +1182,6 @@ bool SelectorChecker::CheckPseudoClass(const SelectorCheckingContext& context,
return false; return false;
} }
bool SelectorChecker::CheckPseudoClassForVTT(
const SelectorCheckingContext& context,
MatchResult& result) const {
const CSSSelector& selector = *context.selector;
switch (selector.GetPseudoType()) {
case CSSSelector::kPseudoNot:
return CheckPseudoNotForVTT(context, result);
case CSSSelector::kPseudoAny: {
SelectorCheckingContext sub_context(context);
sub_context.is_sub_selector = true;
DCHECK(selector.SelectorList());
for (sub_context.selector = selector.SelectorList()->First();
sub_context.selector; sub_context.selector = CSSSelectorList::Next(
*sub_context.selector)) {
MatchResult sub_result;
if (MatchSelectorForVTT(sub_context, sub_result) == kSelectorMatches)
return true;
}
} break;
case CSSSelector::kPseudoHostContext:
FALLTHROUGH;
case CSSSelector::kPseudoHost:
return false;
default:
return CheckPseudoClass(context, result);
}
return false;
}
bool SelectorChecker::CheckPseudoElement(const SelectorCheckingContext& context, bool SelectorChecker::CheckPseudoElement(const SelectorCheckingContext& context,
MatchResult& result) const { MatchResult& result) const {
const CSSSelector& selector = *context.selector; const CSSSelector& selector = *context.selector;
...@@ -1479,38 +1270,6 @@ bool SelectorChecker::CheckPseudoElement(const SelectorCheckingContext& context, ...@@ -1479,38 +1270,6 @@ bool SelectorChecker::CheckPseudoElement(const SelectorCheckingContext& context,
} }
} }
bool SelectorChecker::CheckPseudoElementForVTT(
const SelectorCheckingContext& context,
MatchResult& result) const {
const CSSSelector& selector = *context.selector;
Element& element = *context.element;
switch (selector.GetPseudoType()) {
case CSSSelector::kPseudoCue: {
SelectorCheckingContext sub_context(context);
sub_context.is_sub_selector = true;
sub_context.scope = nullptr;
sub_context.treat_shadow_host_as_normal_scope = false;
for (sub_context.selector = selector.SelectorList()->First();
sub_context.selector; sub_context.selector = CSSSelectorList::Next(
*sub_context.selector)) {
MatchResult sub_result;
if (MatchSelectorForVTT(sub_context, sub_result) == kSelectorMatches)
return true;
}
return false;
}
case CSSSelector::kPseudoWebKitCustomElement: {
if (ShadowRoot* root = element.ContainingShadowRoot())
return root->IsUserAgent() &&
element.ShadowPseudoId() == selector.Value();
return false;
}
default:
return false;
}
}
bool SelectorChecker::CheckPseudoHost(const SelectorCheckingContext& context, bool SelectorChecker::CheckPseudoHost(const SelectorCheckingContext& context,
MatchResult& result) const { MatchResult& result) const {
const CSSSelector& selector = *context.selector; const CSSSelector& selector = *context.selector;
......
...@@ -125,7 +125,7 @@ class SelectorChecker { ...@@ -125,7 +125,7 @@ class SelectorChecker {
bool has_scrollbar_pseudo = false; bool has_scrollbar_pseudo = false;
bool has_selection_pseudo = false; bool has_selection_pseudo = false;
bool treat_shadow_host_as_normal_scope = false; bool treat_shadow_host_as_normal_scope = false;
bool is_from_vtt = false; Element* vtt_originating_element = nullptr;
bool in_nested_complex_selector = false; bool in_nested_complex_selector = false;
}; };
...@@ -155,7 +155,6 @@ class SelectorChecker { ...@@ -155,7 +155,6 @@ class SelectorChecker {
// to by the context are a match. Delegates most of the work to the Check* // to by the context are a match. Delegates most of the work to the Check*
// methods below. // methods below.
bool CheckOne(const SelectorCheckingContext&, MatchResult&) const; bool CheckOne(const SelectorCheckingContext&, MatchResult&) const;
bool CheckOneForVTT(const SelectorCheckingContext&, MatchResult&) const;
enum MatchStatus { enum MatchStatus {
kSelectorMatches, kSelectorMatches,
...@@ -182,35 +181,22 @@ class SelectorChecker { ...@@ -182,35 +181,22 @@ class SelectorChecker {
// to try (e.g. same element, parent, sibling) depends on the combinators in // to try (e.g. same element, parent, sibling) depends on the combinators in
// the selectors. // the selectors.
MatchStatus MatchSelector(const SelectorCheckingContext&, MatchResult&) const; MatchStatus MatchSelector(const SelectorCheckingContext&, MatchResult&) const;
MatchStatus MatchSelectorForVTT(const SelectorCheckingContext&,
MatchResult&) const;
MatchStatus MatchForSubSelector(const SelectorCheckingContext&, MatchStatus MatchForSubSelector(const SelectorCheckingContext&,
MatchResult&) const; MatchResult&) const;
MatchStatus MatchForSubSelectorForVTT(const SelectorCheckingContext&,
MatchResult&) const;
MatchStatus MatchForRelation(const SelectorCheckingContext&, MatchStatus MatchForRelation(const SelectorCheckingContext&,
MatchResult&) const; MatchResult&) const;
MatchStatus MatchForRelationForVTT(const SelectorCheckingContext&,
MatchResult&) const;
MatchStatus MatchForPseudoContent(const SelectorCheckingContext&, MatchStatus MatchForPseudoContent(const SelectorCheckingContext&,
const Element&, const Element&,
MatchResult&) const; MatchResult&) const;
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 CheckPseudoClassForVTT(const SelectorCheckingContext&,
MatchResult&) const;
bool CheckPseudoElement(const SelectorCheckingContext&, MatchResult&) const; bool CheckPseudoElement(const SelectorCheckingContext&, MatchResult&) const;
bool CheckPseudoElementForVTT(const SelectorCheckingContext&,
MatchResult&) const;
bool CheckScrollbarPseudoClass(const SelectorCheckingContext&, bool CheckScrollbarPseudoClass(const SelectorCheckingContext&,
MatchResult&) const; MatchResult&) const;
bool CheckPseudoHost(const SelectorCheckingContext&, MatchResult&) const; bool CheckPseudoHost(const SelectorCheckingContext&, MatchResult&) const;
bool CheckPseudoNot(const SelectorCheckingContext&, MatchResult&) const; bool CheckPseudoNot(const SelectorCheckingContext&, MatchResult&) const;
bool CheckPseudoNotForVTT(const SelectorCheckingContext&, MatchResult&) const;
ComputedStyle* element_style_; ComputedStyle* element_style_;
CustomScrollbar* scrollbar_; CustomScrollbar* scrollbar_;
......
...@@ -470,6 +470,14 @@ void StyleEngine::RemoveTextTrack(TextTrack* text_track) { ...@@ -470,6 +470,14 @@ void StyleEngine::RemoveTextTrack(TextTrack* text_track) {
text_tracks_.erase(text_track); text_tracks_.erase(text_track);
} }
Element* StyleEngine::EnsureVTTOriginatingElement() {
if (!vtt_originating_element_) {
vtt_originating_element_ = MakeGarbageCollected<Element>(
QualifiedName(g_null_atom, g_empty_atom, g_empty_atom), document_);
}
return vtt_originating_element_;
}
void StyleEngine::MediaQueryAffectingValueChanged( void StyleEngine::MediaQueryAffectingValueChanged(
HeapHashSet<Member<TextTrack>>& text_tracks, HeapHashSet<Member<TextTrack>>& text_tracks,
MediaValueChange change) { MediaValueChange change) {
...@@ -2344,6 +2352,7 @@ void StyleEngine::Trace(Visitor* visitor) const { ...@@ -2344,6 +2352,7 @@ void StyleEngine::Trace(Visitor* visitor) const {
visitor->Trace(tracker_); visitor->Trace(tracker_);
visitor->Trace(meta_color_scheme_); visitor->Trace(meta_color_scheme_);
visitor->Trace(text_tracks_); visitor->Trace(text_tracks_);
visitor->Trace(vtt_originating_element_);
FontSelectorClient::Trace(visitor); FontSelectorClient::Trace(visitor);
} }
......
...@@ -133,6 +133,14 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>, ...@@ -133,6 +133,14 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
void AddTextTrack(TextTrack*); void AddTextTrack(TextTrack*);
void RemoveTextTrack(TextTrack*); void RemoveTextTrack(TextTrack*);
// An Element with no tag name, IDs, classes (etc), as described by the
// WebVTT spec:
// https://w3c.github.io/webvtt/#obtaining-css-boxes
//
// TODO(https://github.com/w3c/webvtt/issues/477): Make originating element
// actually featureless.
Element* EnsureVTTOriginatingElement();
const ActiveStyleSheetVector ActiveStyleSheetsForInspector(); const ActiveStyleSheetVector ActiveStyleSheetsForInspector();
bool NeedsActiveStyleUpdate() const; bool NeedsActiveStyleUpdate() const;
...@@ -661,6 +669,7 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>, ...@@ -661,6 +669,7 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected<StyleEngine>,
friend class WhitespaceAttacherTest; friend class WhitespaceAttacherTest;
HeapHashSet<Member<TextTrack>> text_tracks_; HeapHashSet<Member<TextTrack>> text_tracks_;
Member<Element> vtt_originating_element_;
}; };
} // namespace blink } // namespace blink
......
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