mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-18 09:50:27 +00:00
No parsing yet, just CSSContainerRule and the supporting ContainerQuery class. CSSContainerRule is unusual in how it matches, because instead of it either matching or not matching globally, it instead is matched against a specific element. But also, some at-rules inside it always apply, as if they were written outside it. This doesn't fit well with how CSSConditionRule is implemented, and will likely require some rework later. For now, `condition_matches()` always returns false, and `for_each_effective_rule()` is overridden to always process those global at-rules and nothing else.
143 lines
4.4 KiB
C++
143 lines
4.4 KiB
C++
/*
|
|
* Copyright (c) 2021, the SerenityOS developers.
|
|
* Copyright (c) 2022-2025, Sam Atkins <sam@ladybird.org>
|
|
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibWeb/Bindings/CSSRulePrototype.h>
|
|
#include <LibWeb/CSS/CSSImportRule.h>
|
|
#include <LibWeb/CSS/CSSLayerBlockRule.h>
|
|
#include <LibWeb/CSS/CSSRule.h>
|
|
#include <LibWeb/CSS/CSSStyleSheet.h>
|
|
#include <LibWeb/Dump.h>
|
|
|
|
namespace Web::CSS {
|
|
|
|
CSSRule::CSSRule(JS::Realm& realm, Type type)
|
|
: PlatformObject(realm)
|
|
, m_type(type)
|
|
{
|
|
}
|
|
|
|
void CSSRule::visit_edges(Cell::Visitor& visitor)
|
|
{
|
|
Base::visit_edges(visitor);
|
|
visitor.visit(m_parent_style_sheet);
|
|
visitor.visit(m_parent_rule);
|
|
}
|
|
|
|
// https://www.w3.org/TR/cssom/#dom-cssrule-type
|
|
WebIDL::UnsignedShort CSSRule::type_for_bindings() const
|
|
{
|
|
// NOTE: Types that aren't defined in the spec must return 0.
|
|
// To do this, we arbitrarily make non-spec ones start at 100.
|
|
auto type = to_underlying(m_type);
|
|
if (type >= 100)
|
|
return 0;
|
|
return type;
|
|
}
|
|
|
|
// https://www.w3.org/TR/cssom/#dom-cssrule-csstext
|
|
String CSSRule::css_text() const
|
|
{
|
|
// The cssText attribute must return a serialization of the CSS rule.
|
|
return serialized();
|
|
}
|
|
|
|
// https://www.w3.org/TR/cssom/#dom-cssrule-csstext
|
|
void CSSRule::set_css_text(StringView)
|
|
{
|
|
// On setting the cssText attribute must do nothing.
|
|
}
|
|
|
|
void CSSRule::set_parent_rule(CSSRule* parent_rule)
|
|
{
|
|
clear_caches();
|
|
m_parent_rule = parent_rule;
|
|
|
|
if (parent_rule == nullptr)
|
|
set_parent_style_sheet(nullptr);
|
|
else
|
|
set_parent_style_sheet(parent_rule->parent_style_sheet());
|
|
clear_caches();
|
|
}
|
|
|
|
void CSSRule::set_parent_style_sheet(CSSStyleSheet* parent_style_sheet)
|
|
{
|
|
clear_caches();
|
|
m_parent_style_sheet = parent_style_sheet;
|
|
clear_caches();
|
|
}
|
|
|
|
void CSSRule::dump(StringBuilder& builder, int indent_levels) const
|
|
{
|
|
dump_indent(builder, indent_levels);
|
|
builder.appendff("{}:\n", class_name());
|
|
}
|
|
|
|
void CSSRule::clear_caches()
|
|
{
|
|
m_cached_layer_name.clear();
|
|
}
|
|
|
|
FlyString CSSRule::parent_layer_internal_qualified_name_slow_case() const
|
|
{
|
|
Vector<FlyString> layer_names;
|
|
for (auto* rule = parent_rule(); rule; rule = rule->parent_rule()) {
|
|
switch (rule->type()) {
|
|
case Type::Import:
|
|
// @import is only a parent to style sheets, not to rules directly. It's handled below this loop.
|
|
VERIFY_NOT_REACHED();
|
|
break;
|
|
|
|
case Type::LayerBlock: {
|
|
auto& layer_block = as<CSSLayerBlockRule>(*rule);
|
|
layer_names.append(layer_block.internal_name());
|
|
break;
|
|
}
|
|
|
|
// Ignore everything else
|
|
// Note that LayerStatement cannot have child rules so we still ignore it here.
|
|
case Type::Container:
|
|
case Type::CounterStyle:
|
|
case Type::LayerStatement:
|
|
case Type::Style:
|
|
case Type::Media:
|
|
case Type::FontFace:
|
|
case Type::FontFeatureValues:
|
|
case Type::Function:
|
|
case Type::FunctionDeclarations:
|
|
case Type::Keyframes:
|
|
case Type::Keyframe:
|
|
case Type::Namespace:
|
|
case Type::Supports:
|
|
case Type::NestedDeclarations:
|
|
case Type::Property:
|
|
case Type::Page:
|
|
case Type::Margin:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If this style sheet is owned by a rule, include its qualified layer name.
|
|
if (m_parent_style_sheet && m_parent_style_sheet->owner_rule()) {
|
|
if (auto* import = as_if<CSSImportRule>(*m_parent_style_sheet->owner_rule())) {
|
|
// https://drafts.csswg.org/css-cascade-5/#at-import
|
|
// The layer is added to the layer order even if the import fails to load the stylesheet, but is subject to
|
|
// any import conditions (just as if declared by an @layer rule wrapped in the appropriate conditional
|
|
// group rules).
|
|
if (auto layer_name = import->internal_layer_name(); layer_name.has_value() && import->matches()) {
|
|
layer_names.append(layer_name.release_value());
|
|
auto parent_qualified_layer_name = m_parent_style_sheet->owner_rule()->parent_layer_internal_qualified_name();
|
|
if (!parent_qualified_layer_name.is_empty())
|
|
layer_names.append(move(parent_qualified_layer_name));
|
|
}
|
|
}
|
|
}
|
|
|
|
return MUST(String::join('.', layer_names.in_reverse()));
|
|
}
|
|
|
|
}
|