Commit 905006a8 authored by Emilio Cobos Álvarez's avatar Emilio Cobos Álvarez Committed by Chromium LUCI CQ

[css-shadow-parts] Don't match disallowed selectors for ::part() pseudo-elements.

Couldn't help myself when I noticed this bug with
::file-selector-button.

Fixed: 978105
Change-Id: I42da51ffa7117e0d4ecd55e2e12fbb7548571378
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2587042
Commit-Queue: Emilio Cobos Álvarez <emilio@chromium.org>
Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Auto-Submit: Emilio Cobos Álvarez <emilio@chromium.org>
Cr-Commit-Position: refs/heads/master@{#836724}
parent a021ce94
...@@ -134,7 +134,7 @@ void ElementRuleCollector::CollectMatchingRulesForList( ...@@ -134,7 +134,7 @@ void ElementRuleCollector::CollectMatchingRulesForList(
const RuleDataListType* rules, const RuleDataListType* rules,
ShadowV0CascadeOrder cascade_order, ShadowV0CascadeOrder cascade_order,
const MatchRequest& match_request, const MatchRequest& match_request,
PartNames* part_names) { PartRequest* part_request) {
if (!rules) if (!rules)
return; return;
...@@ -144,7 +144,7 @@ void ElementRuleCollector::CollectMatchingRulesForList( ...@@ -144,7 +144,7 @@ void ElementRuleCollector::CollectMatchingRulesForList(
init.element_style = style_.get(); init.element_style = style_.get();
init.scrollbar = pseudo_style_request_.scrollbar; init.scrollbar = pseudo_style_request_.scrollbar;
init.scrollbar_part = pseudo_style_request_.scrollbar_part; init.scrollbar_part = pseudo_style_request_.scrollbar_part;
init.part_names = part_names; init.part_names = part_request ? &part_request->part_names : nullptr;
SelectorChecker checker(init); SelectorChecker checker(init);
SelectorChecker::SelectorCheckingContext context(&context_.GetElement()); SelectorChecker::SelectorCheckingContext context(&context_.GetElement());
context.scope = match_request.scope; context.scope = match_request.scope;
...@@ -175,12 +175,22 @@ void ElementRuleCollector::CollectMatchingRulesForList( ...@@ -175,12 +175,22 @@ void ElementRuleCollector::CollectMatchingRulesForList(
if (!rule->ShouldConsiderForMatchingRules(include_empty_rules_)) if (!rule->ShouldConsiderForMatchingRules(include_empty_rules_))
continue; continue;
const auto& selector = rule_data->Selector();
if (UNLIKELY(part_request && part_request->for_shadow_pseudo)) {
if (!selector.IsAllowedAfterPart()) {
DCHECK_EQ(selector.GetPseudoType(), CSSSelector::kPseudoPart);
rejected++;
continue;
}
DCHECK_EQ(selector.Relation(), CSSSelector::kShadowPseudo);
}
SelectorChecker::MatchResult result; SelectorChecker::MatchResult result;
context.selector = &rule_data->Selector(); context.selector = &selector;
context.is_inside_visited_link = context.is_inside_visited_link =
rule_data->LinkMatchType() == CSSSelector::kMatchVisited; rule_data->LinkMatchType() == CSSSelector::kMatchVisited;
DCHECK(!context.is_inside_visited_link || DCHECK(!context.is_inside_visited_link ||
(inside_link_ == EInsideLink::kInsideVisitedLink)); inside_link_ == EInsideLink::kInsideVisitedLink);
if (!checker.Match(context, result)) { if (!checker.Match(context, result)) {
rejected++; rejected++;
continue; continue;
...@@ -283,9 +293,10 @@ void ElementRuleCollector::CollectMatchingShadowHostRules( ...@@ -283,9 +293,10 @@ void ElementRuleCollector::CollectMatchingShadowHostRules(
void ElementRuleCollector::CollectMatchingPartPseudoRules( void ElementRuleCollector::CollectMatchingPartPseudoRules(
const MatchRequest& match_request, const MatchRequest& match_request,
PartNames& part_names, PartNames& part_names,
ShadowV0CascadeOrder cascade_order) { bool for_shadow_pseudo) {
PartRequest request{part_names, for_shadow_pseudo};
CollectMatchingRulesForList(match_request.rule_set->PartPseudoRules(), CollectMatchingRulesForList(match_request.rule_set->PartPseudoRules(),
cascade_order, match_request, &part_names); kIgnoreCascadeOrder, match_request, &request);
} }
template <class CSSRuleCollection> template <class CSSRuleCollection>
......
...@@ -136,10 +136,9 @@ class CORE_EXPORT ElementRuleCollector { ...@@ -136,10 +136,9 @@ class CORE_EXPORT ElementRuleCollector {
void CollectMatchingShadowHostRules( void CollectMatchingShadowHostRules(
const MatchRequest&, const MatchRequest&,
ShadowV0CascadeOrder = kIgnoreCascadeOrder); ShadowV0CascadeOrder = kIgnoreCascadeOrder);
void CollectMatchingPartPseudoRules( void CollectMatchingPartPseudoRules(const MatchRequest&,
const MatchRequest&, PartNames&,
PartNames&, bool for_shadow_pseudo);
ShadowV0CascadeOrder = kIgnoreCascadeOrder);
void SortAndTransferMatchedRules(); void SortAndTransferMatchedRules();
void ClearMatchedRules(); void ClearMatchedRules();
void AddElementStyleProperties(const CSSPropertyValueSet*, void AddElementStyleProperties(const CSSPropertyValueSet*,
...@@ -160,11 +159,18 @@ class CORE_EXPORT ElementRuleCollector { ...@@ -160,11 +159,18 @@ class CORE_EXPORT ElementRuleCollector {
void AddMatchedRulesToTracker(StyleRuleUsageTracker*) const; void AddMatchedRulesToTracker(StyleRuleUsageTracker*) const;
private: private:
struct PartRequest {
PartNames& part_names;
// If this is true, we're matching for a pseudo-element of the part, such as
// ::placeholder.
bool for_shadow_pseudo = false;
};
template <typename RuleDataListType> template <typename RuleDataListType>
void CollectMatchingRulesForList(const RuleDataListType*, void CollectMatchingRulesForList(const RuleDataListType*,
ShadowV0CascadeOrder, ShadowV0CascadeOrder,
const MatchRequest&, const MatchRequest&,
PartNames* = nullptr); PartRequest* = nullptr);
bool Match(SelectorChecker&, bool Match(SelectorChecker&,
const SelectorChecker::SelectorCheckingContext&, const SelectorChecker::SelectorCheckingContext&,
......
...@@ -317,14 +317,14 @@ void ScopedStyleResolver::CollectMatchingTreeBoundaryCrossingRules( ...@@ -317,14 +317,14 @@ void ScopedStyleResolver::CollectMatchingTreeBoundaryCrossingRules(
void ScopedStyleResolver::CollectMatchingPartPseudoRules( void ScopedStyleResolver::CollectMatchingPartPseudoRules(
ElementRuleCollector& collector, ElementRuleCollector& collector,
PartNames& part_names, PartNames& part_names,
ShadowV0CascadeOrder cascade_order) { bool for_shadow_pseudo) {
wtf_size_t sheet_index = 0; wtf_size_t sheet_index = 0;
for (auto sheet : style_sheets_) { for (auto sheet : style_sheets_) {
DCHECK(sheet->ownerNode() || sheet->IsConstructed()); DCHECK(sheet->ownerNode() || sheet->IsConstructed());
MatchRequest match_request(&sheet->Contents()->GetRuleSet(), MatchRequest match_request(&sheet->Contents()->GetRuleSet(),
&scope_->RootNode(), sheet, sheet_index++); &scope_->RootNode(), sheet, sheet_index++);
collector.CollectMatchingPartPseudoRules(match_request, part_names, collector.CollectMatchingPartPseudoRules(match_request, part_names,
cascade_order); for_shadow_pseudo);
} }
} }
......
...@@ -78,10 +78,9 @@ class CORE_EXPORT ScopedStyleResolver final ...@@ -78,10 +78,9 @@ class CORE_EXPORT ScopedStyleResolver final
void CollectMatchingTreeBoundaryCrossingRules( void CollectMatchingTreeBoundaryCrossingRules(
ElementRuleCollector&, ElementRuleCollector&,
ShadowV0CascadeOrder = kIgnoreCascadeOrder); ShadowV0CascadeOrder = kIgnoreCascadeOrder);
void CollectMatchingPartPseudoRules( void CollectMatchingPartPseudoRules(ElementRuleCollector&,
ElementRuleCollector&, PartNames& part_names,
PartNames& part_names, bool for_shadow_pseudo);
ShadowV0CascadeOrder = kIgnoreCascadeOrder);
void MatchPageRules(PageRuleCollector&); void MatchPageRules(PageRuleCollector&);
void CollectFeaturesTo(RuleFeatureSet&, void CollectFeaturesTo(RuleFeatureSet&,
HeapHashSet<Member<const StyleSheetContents>>& HeapHashSet<Member<const StyleSheetContents>>&
......
...@@ -400,7 +400,7 @@ const static TextTrack* GetTextTrackFromElement(const Element& element) { ...@@ -400,7 +400,7 @@ const static TextTrack* GetTextTrackFromElement(const Element& element) {
} }
static void MatchVTTRules(const Element& element, static void MatchVTTRules(const Element& element,
ElementRuleCollector& collector) { ElementRuleCollector& collector) {
const TextTrack* text_track = GetTextTrackFromElement(element); const TextTrack* text_track = GetTextTrackFromElement(element);
if (!text_track) if (!text_track)
return; return;
...@@ -458,12 +458,15 @@ void StyleResolver::MatchPseudoPartRulesForUAHost( ...@@ -458,12 +458,15 @@ void StyleResolver::MatchPseudoPartRulesForUAHost(
// We allow ::placeholder pseudo element after ::part(). See // We allow ::placeholder pseudo element after ::part(). See
// MatchSlottedRulesForUAHost for a more detailed explanation. // MatchSlottedRulesForUAHost for a more detailed explanation.
DCHECK(element.OwnerShadowHost()); DCHECK(element.OwnerShadowHost());
MatchPseudoPartRules(*element.OwnerShadowHost(), collector); MatchPseudoPartRules(*element.OwnerShadowHost(), collector,
/* for_shadow_pseudo */ true);
} }
void StyleResolver::MatchPseudoPartRules(const Element& element, void StyleResolver::MatchPseudoPartRules(const Element& element,
ElementRuleCollector& collector) { ElementRuleCollector& collector,
MatchPseudoPartRulesForUAHost(element, collector); bool for_shadow_pseudo) {
if (!for_shadow_pseudo)
MatchPseudoPartRulesForUAHost(element, collector);
DOMTokenList* part = element.GetPart(); DOMTokenList* part = element.GetPart();
if (!part) if (!part)
return; return;
...@@ -480,7 +483,8 @@ void StyleResolver::MatchPseudoPartRules(const Element& element, ...@@ -480,7 +483,8 @@ void StyleResolver::MatchPseudoPartRules(const Element& element,
TreeScope& tree_scope = host->GetTreeScope(); TreeScope& tree_scope = host->GetTreeScope();
if (ScopedStyleResolver* resolver = tree_scope.GetScopedStyleResolver()) { if (ScopedStyleResolver* resolver = tree_scope.GetScopedStyleResolver()) {
collector.ClearMatchedRules(); collector.ClearMatchedRules();
resolver->CollectMatchingPartPseudoRules(collector, current_names); resolver->CollectMatchingPartPseudoRules(collector, current_names,
for_shadow_pseudo);
collector.SortAndTransferMatchedRules(); collector.SortAndTransferMatchedRules();
collector.FinishAddingAuthorRulesForTreeScope(resolver->GetTreeScope()); collector.FinishAddingAuthorRulesForTreeScope(resolver->GetTreeScope());
} }
......
...@@ -187,7 +187,9 @@ class CORE_EXPORT StyleResolver final : public GarbageCollected<StyleResolver> { ...@@ -187,7 +187,9 @@ class CORE_EXPORT StyleResolver final : public GarbageCollected<StyleResolver> {
void MatchUserRules(ElementRuleCollector&); void MatchUserRules(ElementRuleCollector&);
// This matches `::part` selectors. It looks in ancestor scopes as far as // This matches `::part` selectors. It looks in ancestor scopes as far as
// part mapping requires. // part mapping requires.
void MatchPseudoPartRules(const Element&, ElementRuleCollector&); void MatchPseudoPartRules(const Element&,
ElementRuleCollector&,
bool for_shadow_pseudo = false);
void MatchPseudoPartRulesForUAHost(const Element&, ElementRuleCollector&); void MatchPseudoPartRulesForUAHost(const Element&, ElementRuleCollector&);
void MatchScopedRulesV0(const Element&, void MatchScopedRulesV0(const Element&,
ElementRuleCollector&, ElementRuleCollector&,
......
<!doctype html>
<title>CSS Test Reference</title>
<style>
input {
border: 1px solid green;
}
</style>
<input type=file part=input>
<input type=text part=input placeholder=Foobar>
<!doctype html>
<title>::part() doesn't incorrectly match pseudo-elements of the part</title>
<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=978105">
<link rel="help" href="https://drafts.csswg.org/css-shadow-parts/">
<link rel="match" href="part-nested-pseudo-ref.html">
<style>
#host::part(input) {
border: 1px solid green;
}
</style>
<div id="host"></div>
<script>
document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = `
<input type=file part=input>
<input type=text part=input placeholder=Foobar>
`;
</script>
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