blob: bff21cd4208646e9148cacaa80d47268d88c6e55 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/css/css_scope_rule.h"
#include "third_party/blink/renderer/core/css/css_markup.h"
#include "third_party/blink/renderer/core/css/css_style_rule.h"
#include "third_party/blink/renderer/core/css/css_style_sheet.h"
#include "third_party/blink/renderer/core/css/style_rule.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
CSSScopeRule::CSSScopeRule(StyleRuleScope* scope_rule, CSSStyleSheet* parent)
: CSSGroupingRule(scope_rule, parent) {}
CSSScopeRule::~CSSScopeRule() = default;
String CSSScopeRule::PreludeText() const {
StringBuilder result;
const StyleScope& scope =
To<StyleRuleScope>(*group_rule_.Get()).GetStyleScope();
if (!scope.IsImplicit()) {
result.Append('(');
result.Append(CSSSelectorList::SelectorsText(scope.From()));
result.Append(')');
}
if (scope.To()) {
if (!result.empty()) {
result.Append(" ");
}
result.Append("to (");
result.Append(CSSSelectorList::SelectorsText(scope.To()));
result.Append(')');
}
return result.ReleaseString();
}
String CSSScopeRule::cssText() const {
StringBuilder result;
result.Append("@scope");
String prelude = PreludeText();
if (!prelude.empty()) {
result.Append(" ");
result.Append(prelude);
}
AppendCSSTextForItems(result);
return result.ReleaseString();
}
String CSSScopeRule::start() const {
const StyleScope& scope =
To<StyleRuleScope>(*group_rule_.Get()).GetStyleScope();
return scope.From() ? CSSSelectorList::SelectorsText(scope.From())
: g_null_atom;
}
String CSSScopeRule::end() const {
const StyleScope& scope =
To<StyleRuleScope>(*group_rule_.Get()).GetStyleScope();
return scope.To() ? CSSSelectorList::SelectorsText(scope.To()) : g_null_atom;
}
void CSSScopeRule::SetPreludeText(const ExecutionContext* execution_context,
String value) {
CSSStyleSheet::RuleMutationScope mutation_scope(this);
// Find enclosing style rule or @scope rule, whichever comes first:
CSSNestingType nesting_type = CSSNestingType::kNone;
StyleRule* parent_rule_for_nesting = nullptr;
bool is_within_scope = false;
for (CSSRule* parent = parentRule(); parent; parent = parent->parentRule()) {
if (const auto* style_rule = DynamicTo<CSSStyleRule>(parent)) {
if (nesting_type == CSSNestingType::kNone) {
nesting_type = CSSNestingType::kNesting;
parent_rule_for_nesting = style_rule->GetStyleRule();
}
}
if (const auto* scope_rule = DynamicTo<CSSScopeRule>(parent)) {
if (nesting_type == CSSNestingType::kNone) {
nesting_type = CSSNestingType::kScope;
parent_rule_for_nesting =
scope_rule->GetStyleRuleScope().GetStyleScope().RuleForNesting();
}
is_within_scope = true;
}
}
CSSStyleSheet* style_sheet = parentStyleSheet();
StyleSheetContents* contents =
style_sheet ? style_sheet->Contents() : nullptr;
GetStyleRuleScope().SetPreludeText(execution_context, value, nesting_type,
parent_rule_for_nesting, is_within_scope,
contents);
}
StyleRuleScope& CSSScopeRule::GetStyleRuleScope() {
return *To<StyleRuleScope>(group_rule_.Get());
}
const StyleRuleScope& CSSScopeRule::GetStyleRuleScope() const {
return *To<StyleRuleScope>(group_rule_.Get());
}
} // namespace blink