LibWeb/CSS: Add basic implementation of CSSMarginRule

This is a bit under-specced, specifically there's no definition of
CSSMarginDescriptors so I've gone with CSSStyleProperties for now. Gets
us 17 WPT subtests.
This commit is contained in:
Sam Atkins 2025-05-15 11:48:56 +01:00
commit 870f24f181
Notes: github-actions[bot] 2025-05-16 10:02:36 +00:00
21 changed files with 233 additions and 32 deletions

View file

@ -80,6 +80,7 @@ set(SOURCES
CSS/CSSKeyframesRule.cpp CSS/CSSKeyframesRule.cpp
CSS/CSSLayerBlockRule.cpp CSS/CSSLayerBlockRule.cpp
CSS/CSSLayerStatementRule.cpp CSS/CSSLayerStatementRule.cpp
CSS/CSSMarginRule.cpp
CSS/CSSMediaRule.cpp CSS/CSSMediaRule.cpp
CSS/CSSNamespaceRule.cpp CSS/CSSNamespaceRule.cpp
CSS/CSSNestedDeclarations.cpp CSS/CSSNestedDeclarations.cpp

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/Bindings/CSSMarginRulePrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/CSS/CSSMarginRule.h>
#include <LibWeb/CSS/CSSStyleProperties.h>
#include <LibWeb/WebIDL/ExceptionOr.h>
namespace Web::CSS {
GC_DEFINE_ALLOCATOR(CSSMarginRule);
GC::Ref<CSSMarginRule> CSSMarginRule::create(JS::Realm& realm, FlyString name, GC::Ref<CSSStyleProperties> style)
{
return realm.create<CSSMarginRule>(realm, move(name), style);
}
CSSMarginRule::CSSMarginRule(JS::Realm& realm, FlyString name, GC::Ref<CSSStyleProperties> style)
: CSSRule(realm, Type::Margin)
, m_name(name.to_ascii_lowercase())
, m_style(style)
{
m_style->set_parent_rule(*this);
}
void CSSMarginRule::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSMarginRule);
Base::initialize(realm);
}
String CSSMarginRule::serialized() const
{
// AD-HOC: There is currently no spec for serializing CSSMarginRule.
StringBuilder builder;
builder.appendff("@{} {{ ", m_name);
if (m_style->length() > 0) {
builder.append(m_style->serialized());
builder.append(' ');
}
builder.append('}');
return builder.to_string_without_validation();
}
void CSSMarginRule::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_style);
}
// https://drafts.csswg.org/css-page-3/#syntax-page-selector
bool is_margin_rule_name(StringView name)
{
return name.equals_ignoring_ascii_case("top-left-corner"sv)
|| name.equals_ignoring_ascii_case("top-left"sv)
|| name.equals_ignoring_ascii_case("top-center"sv)
|| name.equals_ignoring_ascii_case("top-right"sv)
|| name.equals_ignoring_ascii_case("top-right-corner"sv)
|| name.equals_ignoring_ascii_case("bottom-left-corner"sv)
|| name.equals_ignoring_ascii_case("bottom-left"sv)
|| name.equals_ignoring_ascii_case("bottom-center"sv)
|| name.equals_ignoring_ascii_case("bottom-right"sv)
|| name.equals_ignoring_ascii_case("bottom-right-corner"sv)
|| name.equals_ignoring_ascii_case("left-top"sv)
|| name.equals_ignoring_ascii_case("left-middle"sv)
|| name.equals_ignoring_ascii_case("left-bottom"sv)
|| name.equals_ignoring_ascii_case("right-top"sv)
|| name.equals_ignoring_ascii_case("right-middle"sv)
|| name.equals_ignoring_ascii_case("right-bottom"sv);
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/CSS/CSSRule.h>
namespace Web::CSS {
// https://drafts.csswg.org/cssom/#cssmarginrule
class CSSMarginRule final : public CSSRule {
WEB_PLATFORM_OBJECT(CSSMarginRule, CSSRule);
GC_DECLARE_ALLOCATOR(CSSMarginRule);
public:
[[nodiscard]] static GC::Ref<CSSMarginRule> create(JS::Realm&, FlyString name, GC::Ref<CSSStyleProperties>);
virtual ~CSSMarginRule() override = default;
String name() const { return m_name.to_string(); }
GC::Ref<CSSStyleProperties> style() { return m_style; }
GC::Ref<CSSStyleProperties const> style() const { return m_style; }
private:
CSSMarginRule(JS::Realm&, FlyString name, GC::Ref<CSSStyleProperties>);
virtual void initialize(JS::Realm&) override;
virtual String serialized() const override;
virtual void visit_edges(Visitor&) override;
FlyString m_name;
GC::Ref<CSSStyleProperties> m_style;
};
bool is_margin_rule_name(StringView);
}

View file

@ -0,0 +1,10 @@
#import <CSS/CSSRule.idl>
#import <CSS/CSSStyleProperties.idl>
// https://drafts.csswg.org/cssom/#cssmarginrule
[Exposed=Window]
interface CSSMarginRule : CSSRule {
readonly attribute CSSOMString name;
// FIXME: This should be CSSMarginDescriptors, but that has no spec. https://github.com/w3c/csswg-drafts/issues/10106
[SameObject, PutForwards=cssText] readonly attribute CSSStyleProperties style;
};

View file

@ -104,7 +104,7 @@ String CSSPageRule::serialized() const
StringBuilder builder; StringBuilder builder;
// AD-HOC: There's no spec for this yet. // AD-HOC: There's no spec for this yet, but Chrome puts declarations before margin rules.
builder.append("@page "sv); builder.append("@page "sv);
if (auto selector = selector_text(); !selector.is_empty()) if (auto selector = selector_text(); !selector.is_empty())
builder.appendff("{} ", selector); builder.appendff("{} ", selector);
@ -113,6 +113,15 @@ String CSSPageRule::serialized() const
builder.append(descriptors.serialized()); builder.append(descriptors.serialized());
builder.append(' '); builder.append(' ');
} }
for (size_t i = 0; i < css_rules().length(); i++) {
auto rule = css_rules().item(i);
auto result = rule->css_text();
if (result.is_empty())
continue;
builder.appendff("{} ", result);
}
builder.append("}"sv); builder.append("}"sv);
return builder.to_string_without_validation(); return builder.to_string_without_validation();

View file

@ -95,6 +95,7 @@ FlyString const& CSSRule::parent_layer_internal_qualified_name_slow_case() const
case Type::NestedDeclarations: case Type::NestedDeclarations:
case Type::Property: case Type::Property:
case Type::Page: case Type::Page:
case Type::Margin:
break; break;
} }
} }

View file

@ -31,6 +31,7 @@ public:
Page = 6, Page = 6,
Keyframes = 7, Keyframes = 7,
Keyframe = 8, Keyframe = 8,
Margin = 9,
Namespace = 10, Namespace = 10,
Supports = 12, Supports = 12,
// AD-HOC: These are not included in the spec, but we need them internally. So, their numbers are arbitrary. // AD-HOC: These are not included in the spec, but we need them internally. So, their numbers are arbitrary.

View file

@ -152,6 +152,7 @@ void CSSRuleList::for_each_effective_rule(TraversalOrder order, Function<void(We
case CSSRule::Type::LayerBlock: case CSSRule::Type::LayerBlock:
case CSSRule::Type::Media: case CSSRule::Type::Media:
case CSSRule::Type::Page:
case CSSRule::Type::Style: case CSSRule::Type::Style:
case CSSRule::Type::Supports: case CSSRule::Type::Supports:
static_cast<CSSGroupingRule const&>(*rule).for_each_effective_rule(order, callback); static_cast<CSSGroupingRule const&>(*rule).for_each_effective_rule(order, callback);
@ -161,10 +162,10 @@ void CSSRuleList::for_each_effective_rule(TraversalOrder order, Function<void(We
case CSSRule::Type::Keyframe: case CSSRule::Type::Keyframe:
case CSSRule::Type::Keyframes: case CSSRule::Type::Keyframes:
case CSSRule::Type::LayerStatement: case CSSRule::Type::LayerStatement:
case CSSRule::Type::Margin:
case CSSRule::Type::Namespace: case CSSRule::Type::Namespace:
case CSSRule::Type::NestedDeclarations: case CSSRule::Type::NestedDeclarations:
case CSSRule::Type::Property: case CSSRule::Type::Property:
case CSSRule::Type::Page:
break; break;
} }
@ -217,6 +218,7 @@ bool CSSRuleList::evaluate_media_queries(HTML::Window const& window)
case CSSRule::Type::Keyframe: case CSSRule::Type::Keyframe:
case CSSRule::Type::Keyframes: case CSSRule::Type::Keyframes:
case CSSRule::Type::LayerStatement: case CSSRule::Type::LayerStatement:
case CSSRule::Type::Margin:
case CSSRule::Type::Namespace: case CSSRule::Type::Namespace:
case CSSRule::Type::NestedDeclarations: case CSSRule::Type::NestedDeclarations:
case CSSRule::Type::Property: case CSSRule::Type::Property:

View file

@ -14,6 +14,7 @@
#include <AK/Debug.h> #include <AK/Debug.h>
#include <LibURL/Parser.h> #include <LibURL/Parser.h>
#include <LibWeb/CSS/CSSMarginRule.h>
#include <LibWeb/CSS/CSSStyleDeclaration.h> #include <LibWeb/CSS/CSSStyleDeclaration.h>
#include <LibWeb/CSS/CSSStyleProperties.h> #include <LibWeb/CSS/CSSStyleProperties.h>
#include <LibWeb/CSS/CSSStyleSheet.h> #include <LibWeb/CSS/CSSStyleSheet.h>
@ -1438,7 +1439,8 @@ bool Parser::is_valid_in_the_current_context(Declaration const&) const
case RuleContext::AtFontFace: case RuleContext::AtFontFace:
case RuleContext::AtPage: case RuleContext::AtPage:
case RuleContext::AtProperty: case RuleContext::AtProperty:
// @font-face, @page, and @property have descriptor declarations case RuleContext::Margin:
// These have descriptor declarations
return true; return true;
case RuleContext::AtKeyframes: case RuleContext::AtKeyframes:
@ -1455,9 +1457,9 @@ bool Parser::is_valid_in_the_current_context(Declaration const&) const
bool Parser::is_valid_in_the_current_context(AtRule const& at_rule) const bool Parser::is_valid_in_the_current_context(AtRule const& at_rule) const
{ {
// All at-rules can appear at the top level // All at-rules can appear at the top level, except margin rules
if (m_rule_context.is_empty()) if (m_rule_context.is_empty())
return true; return !is_margin_rule_name(at_rule.name);
// Only grouping rules can be nested within style rules // Only grouping rules can be nested within style rules
if (m_rule_context.contains_slow(RuleContext::Style)) if (m_rule_context.contains_slow(RuleContext::Style))
@ -1482,13 +1484,16 @@ bool Parser::is_valid_in_the_current_context(AtRule const& at_rule) const
// @supports cannot check for at-rules // @supports cannot check for at-rules
return false; return false;
case RuleContext::AtPage:
// @page rules can contain margin rules
return is_margin_rule_name(at_rule.name);
case RuleContext::AtFontFace: case RuleContext::AtFontFace:
case RuleContext::AtKeyframes: case RuleContext::AtKeyframes:
case RuleContext::Keyframe: case RuleContext::Keyframe:
case RuleContext::AtPage:
case RuleContext::AtProperty: case RuleContext::AtProperty:
case RuleContext::Margin:
// These can't contain any at-rules // These can't contain any at-rules
// FIXME: Eventually @page can contain margin-box at-rules: https://drafts.csswg.org/css-page-3/#margin-at-rules
return false; return false;
} }
@ -1530,6 +1535,7 @@ bool Parser::is_valid_in_the_current_context(QualifiedRule const&) const
case RuleContext::AtPage: case RuleContext::AtPage:
case RuleContext::AtProperty: case RuleContext::AtProperty:
case RuleContext::Keyframe: case RuleContext::Keyframe:
case RuleContext::Margin:
// These can't contain qualified rules // These can't contain qualified rules
return false; return false;
} }

View file

@ -243,6 +243,7 @@ private:
GC::Ptr<CSSKeyframesRule> convert_to_keyframes_rule(AtRule const&); GC::Ptr<CSSKeyframesRule> convert_to_keyframes_rule(AtRule const&);
GC::Ptr<CSSImportRule> convert_to_import_rule(AtRule const&); GC::Ptr<CSSImportRule> convert_to_import_rule(AtRule const&);
GC::Ptr<CSSRule> convert_to_layer_rule(AtRule const&, Nested); GC::Ptr<CSSRule> convert_to_layer_rule(AtRule const&, Nested);
GC::Ptr<CSSMarginRule> convert_to_margin_rule(AtRule const&);
GC::Ptr<CSSMediaRule> convert_to_media_rule(AtRule const&, Nested); GC::Ptr<CSSMediaRule> convert_to_media_rule(AtRule const&, Nested);
GC::Ptr<CSSNamespaceRule> convert_to_namespace_rule(AtRule const&); GC::Ptr<CSSNamespaceRule> convert_to_namespace_rule(AtRule const&);
GC::Ptr<CSSPageRule> convert_to_page_rule(AtRule const& rule); GC::Ptr<CSSPageRule> convert_to_page_rule(AtRule const& rule);

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibWeb/CSS/CSSMarginRule.h>
#include <LibWeb/CSS/Parser/RuleContext.h> #include <LibWeb/CSS/Parser/RuleContext.h>
namespace Web::CSS::Parser { namespace Web::CSS::Parser {
@ -25,6 +26,8 @@ RuleContext rule_context_type_for_rule(CSSRule::Type rule_type)
return RuleContext::AtSupports; return RuleContext::AtSupports;
case CSSRule::Type::LayerBlock: case CSSRule::Type::LayerBlock:
return RuleContext::AtLayer; return RuleContext::AtLayer;
case CSSRule::Type::Margin:
return RuleContext::Margin;
case CSSRule::Type::NestedDeclarations: case CSSRule::Type::NestedDeclarations:
return RuleContext::Style; return RuleContext::Style;
case CSSRule::Type::Page: case CSSRule::Type::Page:
@ -56,6 +59,8 @@ RuleContext rule_context_type_for_at_rule(FlyString const& name)
return RuleContext::AtProperty; return RuleContext::AtProperty;
if (name.equals_ignoring_ascii_case("page"sv)) if (name.equals_ignoring_ascii_case("page"sv))
return RuleContext::AtPage; return RuleContext::AtPage;
if (is_margin_rule_name(name))
return RuleContext::Margin;
return RuleContext::Unknown; return RuleContext::Unknown;
} }

View file

@ -23,6 +23,7 @@ enum class RuleContext : u8 {
AtLayer, AtLayer,
AtProperty, AtProperty,
AtPage, AtPage,
Margin,
}; };
RuleContext rule_context_type_for_rule(CSSRule::Type); RuleContext rule_context_type_for_rule(CSSRule::Type);
RuleContext rule_context_type_for_at_rule(FlyString const&); RuleContext rule_context_type_for_at_rule(FlyString const&);

View file

@ -18,6 +18,7 @@
#include <LibWeb/CSS/CSSKeyframesRule.h> #include <LibWeb/CSS/CSSKeyframesRule.h>
#include <LibWeb/CSS/CSSLayerBlockRule.h> #include <LibWeb/CSS/CSSLayerBlockRule.h>
#include <LibWeb/CSS/CSSLayerStatementRule.h> #include <LibWeb/CSS/CSSLayerStatementRule.h>
#include <LibWeb/CSS/CSSMarginRule.h>
#include <LibWeb/CSS/CSSMediaRule.h> #include <LibWeb/CSS/CSSMediaRule.h>
#include <LibWeb/CSS/CSSNamespaceRule.h> #include <LibWeb/CSS/CSSNamespaceRule.h>
#include <LibWeb/CSS/CSSNestedDeclarations.h> #include <LibWeb/CSS/CSSNestedDeclarations.h>
@ -102,6 +103,9 @@ GC::Ptr<CSSRule> Parser::convert_to_rule(Rule const& rule, Nested nested)
if (at_rule.name.equals_ignoring_ascii_case("layer"sv)) if (at_rule.name.equals_ignoring_ascii_case("layer"sv))
return convert_to_layer_rule(at_rule, nested); return convert_to_layer_rule(at_rule, nested);
if (is_margin_rule_name(at_rule.name))
return convert_to_margin_rule(at_rule);
if (at_rule.name.equals_ignoring_ascii_case("media"sv)) if (at_rule.name.equals_ignoring_ascii_case("media"sv))
return convert_to_media_rule(at_rule, nested); return convert_to_media_rule(at_rule, nested);
@ -697,20 +701,25 @@ static Optional<PageSelectorList> parse_page_selector_list(Vector<ComponentValue
return selector_list; return selector_list;
} }
GC::Ptr<CSSPageRule> Parser::convert_to_page_rule(AtRule const& rule) GC::Ptr<CSSPageRule> Parser::convert_to_page_rule(AtRule const& page_rule)
{ {
// https://drafts.csswg.org/css-page-3/#syntax-page-selector // https://drafts.csswg.org/css-page-3/#syntax-page-selector
// @page = @page <page-selector-list>? { <declaration-rule-list> } // @page = @page <page-selector-list>? { <declaration-rule-list> }
auto page_selectors = parse_page_selector_list(rule.prelude); auto page_selectors = parse_page_selector_list(page_rule.prelude);
if (!page_selectors.has_value()) if (!page_selectors.has_value())
return nullptr; return nullptr;
GC::RootVector<GC::Ref<CSSRule>> child_rules { realm().heap() }; GC::RootVector<GC::Ref<CSSRule>> child_rules { realm().heap() };
DescriptorList descriptors { AtRuleID::Page }; DescriptorList descriptors { AtRuleID::Page };
rule.for_each_as_declaration_rule_list( page_rule.for_each_as_declaration_rule_list(
[&](auto& at_rule) { [&](auto& at_rule) {
// FIXME: Parse margin rules here. if (auto converted_rule = convert_to_rule(at_rule, Nested::No)) {
(void)at_rule; if (is<CSSMarginRule>(*converted_rule)) {
child_rules.append(*converted_rule);
} else {
dbgln_if(CSS_PARSER_DEBUG, "CSSParser: nested {} is not allowed inside @page rule; discarding.", converted_rule->class_name());
}
}
}, },
[&](auto& declaration) { [&](auto& declaration) {
if (auto descriptor = convert_to_descriptor(AtRuleID::Page, declaration); descriptor.has_value()) { if (auto descriptor = convert_to_descriptor(AtRuleID::Page, declaration); descriptor.has_value()) {
@ -722,4 +731,21 @@ GC::Ptr<CSSPageRule> Parser::convert_to_page_rule(AtRule const& rule)
return CSSPageRule::create(realm(), page_selectors.release_value(), CSSPageDescriptors::create(realm(), descriptors.release_descriptors()), rule_list); return CSSPageRule::create(realm(), page_selectors.release_value(), CSSPageDescriptors::create(realm(), descriptors.release_descriptors()), rule_list);
} }
GC::Ptr<CSSMarginRule> Parser::convert_to_margin_rule(AtRule const& rule)
{
// https://drafts.csswg.org/css-page-3/#syntax-page-selector
// There are lots of these, but they're all in the format:
// @foo = @foo { <declaration-list> };
// FIXME: The declaration list should be a CSSMarginDescriptors, but that has no spec definition:
// https://github.com/w3c/csswg-drafts/issues/10106
// So, we just parse a CSSStyleProperties instead for now.
PropertiesAndCustomProperties properties;
rule.for_each_as_declaration_list([&](auto const& declaration) {
extract_property(declaration, properties);
});
auto style = CSSStyleProperties::create(realm(), move(properties.properties), move(properties.custom_properties));
return CSSMarginRule::create(realm(), rule.name, style);
}
} }

View file

@ -3025,6 +3025,7 @@ void StyleComputer::build_qualified_layer_names_cache()
case CSSRule::Type::FontFace: case CSSRule::Type::FontFace:
case CSSRule::Type::Keyframes: case CSSRule::Type::Keyframes:
case CSSRule::Type::Keyframe: case CSSRule::Type::Keyframe:
case CSSRule::Type::Margin:
case CSSRule::Type::Namespace: case CSSRule::Type::Namespace:
case CSSRule::Type::NestedDeclarations: case CSSRule::Type::NestedDeclarations:
case CSSRule::Type::Page: case CSSRule::Type::Page:

View file

@ -16,6 +16,7 @@
#include <LibWeb/CSS/CSSKeyframesRule.h> #include <LibWeb/CSS/CSSKeyframesRule.h>
#include <LibWeb/CSS/CSSLayerBlockRule.h> #include <LibWeb/CSS/CSSLayerBlockRule.h>
#include <LibWeb/CSS/CSSLayerStatementRule.h> #include <LibWeb/CSS/CSSLayerStatementRule.h>
#include <LibWeb/CSS/CSSMarginRule.h>
#include <LibWeb/CSS/CSSMediaRule.h> #include <LibWeb/CSS/CSSMediaRule.h>
#include <LibWeb/CSS/CSSNamespaceRule.h> #include <LibWeb/CSS/CSSNamespaceRule.h>
#include <LibWeb/CSS/CSSNestedDeclarations.h> #include <LibWeb/CSS/CSSNestedDeclarations.h>
@ -687,6 +688,9 @@ void dump_rule(StringBuilder& builder, CSS::CSSRule const& rule, int indent_leve
case CSS::CSSRule::Type::LayerStatement: case CSS::CSSRule::Type::LayerStatement:
dump_layer_statement_rule(builder, as<CSS::CSSLayerStatementRule const>(rule), indent_levels); dump_layer_statement_rule(builder, as<CSS::CSSLayerStatementRule const>(rule), indent_levels);
break; break;
case CSS::CSSRule::Type::Margin:
dump_margin_rule(builder, as<CSS::CSSMarginRule const>(rule), indent_levels);
break;
case CSS::CSSRule::Type::Media: case CSS::CSSRule::Type::Media:
dump_media_rule(builder, as<CSS::CSSMediaRule const>(rule), indent_levels); dump_media_rule(builder, as<CSS::CSSMediaRule const>(rule), indent_levels);
break; break;
@ -774,6 +778,18 @@ void dump_page_rule(StringBuilder& builder, CSS::CSSPageRule const& page, int in
indent(builder, indent_levels + 1); indent(builder, indent_levels + 1);
builder.appendff("selector: {}\n", page.selector_text()); builder.appendff("selector: {}\n", page.selector_text());
dump_descriptors(builder, page.descriptors(), indent_levels + 1); dump_descriptors(builder, page.descriptors(), indent_levels + 1);
indent(builder, indent_levels + 1);
builder.appendff(" Rules ({}):\n", page.css_rules().length());
for (auto& rule : page.css_rules())
dump_rule(builder, rule, indent_levels + 2);
}
void dump_margin_rule(StringBuilder& builder, CSS::CSSMarginRule const& margin, int indent_levels)
{
indent(builder, indent_levels + 1);
builder.appendff("name: {}\n", margin.name());
dump_style_properties(builder, margin.style(), indent_levels + 1);
} }
void dump_supports_rule(StringBuilder& builder, CSS::CSSSupportsRule const& supports, int indent_levels) void dump_supports_rule(StringBuilder& builder, CSS::CSSSupportsRule const& supports, int indent_levels)

View file

@ -31,6 +31,7 @@ void dump_keyframe_rule(StringBuilder&, CSS::CSSKeyframeRule const&, int indent_
void dump_keyframes_rule(StringBuilder&, CSS::CSSKeyframesRule const&, int indent_levels = 0); void dump_keyframes_rule(StringBuilder&, CSS::CSSKeyframesRule const&, int indent_levels = 0);
void dump_media_rule(StringBuilder&, CSS::CSSMediaRule const&, int indent_levels = 0); void dump_media_rule(StringBuilder&, CSS::CSSMediaRule const&, int indent_levels = 0);
void dump_page_rule(StringBuilder&, CSS::CSSPageRule const&, int indent_levels = 0); void dump_page_rule(StringBuilder&, CSS::CSSPageRule const&, int indent_levels = 0);
void dump_margin_rule(StringBuilder&, CSS::CSSMarginRule const&, int indent_levels = 0);
void dump_style_rule(StringBuilder&, CSS::CSSStyleRule const&, int indent_levels = 0); void dump_style_rule(StringBuilder&, CSS::CSSStyleRule const&, int indent_levels = 0);
void dump_supports_rule(StringBuilder&, CSS::CSSSupportsRule const&, int indent_levels = 0); void dump_supports_rule(StringBuilder&, CSS::CSSSupportsRule const&, int indent_levels = 0);
void dump_property_rule(StringBuilder&, CSS::CSSPropertyRule const&, int indent_levels = 0); void dump_property_rule(StringBuilder&, CSS::CSSPropertyRule const&, int indent_levels = 0);

View file

@ -200,6 +200,7 @@ class CSSKeyframesRule;
class CSSKeywordValue; class CSSKeywordValue;
class CSSLayerBlockRule; class CSSLayerBlockRule;
class CSSLayerStatementRule; class CSSLayerStatementRule;
class CSSMarginRule;
class CSSMediaRule; class CSSMediaRule;
class CSSNamespaceRule; class CSSNamespaceRule;
class CSSNestedDeclarations; class CSSNestedDeclarations;

View file

@ -31,6 +31,7 @@ libweb_js_bindings(CSS/CSSKeyframeRule)
libweb_js_bindings(CSS/CSSKeyframesRule) libweb_js_bindings(CSS/CSSKeyframesRule)
libweb_js_bindings(CSS/CSSLayerBlockRule) libweb_js_bindings(CSS/CSSLayerBlockRule)
libweb_js_bindings(CSS/CSSLayerStatementRule) libweb_js_bindings(CSS/CSSLayerStatementRule)
libweb_js_bindings(CSS/CSSMarginRule)
libweb_js_bindings(CSS/CSSMediaRule) libweb_js_bindings(CSS/CSSMediaRule)
libweb_js_bindings(CSS/CSS NAMESPACE) libweb_js_bindings(CSS/CSS NAMESPACE)
libweb_js_bindings(CSS/CSSNamespaceRule) libweb_js_bindings(CSS/CSSNamespaceRule)

View file

@ -46,6 +46,7 @@ CSSKeyframeRule
CSSKeyframesRule CSSKeyframesRule
CSSLayerBlockRule CSSLayerBlockRule
CSSLayerStatementRule CSSLayerStatementRule
CSSMarginRule
CSSMediaRule CSSMediaRule
CSSNamespaceRule CSSNamespaceRule
CSSNestedDeclarations CSSNestedDeclarations

View file

@ -2,8 +2,7 @@ Harness status: OK
Found 33 tests Found 33 tests
17 Pass 33 Pass
16 Fail
Pass margin-rules-001 Pass margin-rules-001
Pass @top-left-corner{ } should be an invalid rule Pass @top-left-corner{ } should be an invalid rule
Pass @top-left{ } should be an invalid rule Pass @top-left{ } should be an invalid rule
@ -21,19 +20,19 @@ Pass @left-bottom{ } should be an invalid rule
Pass @right-top{ } should be an invalid rule Pass @right-top{ } should be an invalid rule
Pass @right-middle{ } should be an invalid rule Pass @right-middle{ } should be an invalid rule
Pass @right-bottom{ } should be an invalid rule Pass @right-bottom{ } should be an invalid rule
Fail @page { @top-left-corner { } } should be a valid rule Pass @page { @top-left-corner { } } should be a valid rule
Fail @page { @top-left { } } should be a valid rule Pass @page { @top-left { } } should be a valid rule
Fail @page { @top-center { } } should be a valid rule Pass @page { @top-center { } } should be a valid rule
Fail @page { @top-right { } } should be a valid rule Pass @page { @top-right { } } should be a valid rule
Fail @page { @top-right-corner { } } should be a valid rule Pass @page { @top-right-corner { } } should be a valid rule
Fail @page { @bottom-left-corner { } } should be a valid rule Pass @page { @bottom-left-corner { } } should be a valid rule
Fail @page { @bottom-left { } } should be a valid rule Pass @page { @bottom-left { } } should be a valid rule
Fail @page { @bottom-center { } } should be a valid rule Pass @page { @bottom-center { } } should be a valid rule
Fail @page { @bottom-right { } } should be a valid rule Pass @page { @bottom-right { } } should be a valid rule
Fail @page { @bottom-right-corner { } } should be a valid rule Pass @page { @bottom-right-corner { } } should be a valid rule
Fail @page { @left-top { } } should be a valid rule Pass @page { @left-top { } } should be a valid rule
Fail @page { @left-middle { } } should be a valid rule Pass @page { @left-middle { } } should be a valid rule
Fail @page { @left-bottom { } } should be a valid rule Pass @page { @left-bottom { } } should be a valid rule
Fail @page { @right-top { } } should be a valid rule Pass @page { @right-top { } } should be a valid rule
Fail @page { @right-middle { } } should be a valid rule Pass @page { @right-middle { } } should be a valid rule
Fail @page { @right-bottom { } } should be a valid rule Pass @page { @right-bottom { } } should be a valid rule

View file

@ -2,8 +2,9 @@ Harness status: OK
Found 4 tests Found 4 tests
4 Fail 1 Pass
Fail margin rule without any preceding @page properties 3 Fail
Pass margin rule without any preceding @page properties
Fail margin rule followed by @page properties Fail margin rule followed by @page properties
Fail margin rule preceded by @page properties Fail margin rule preceded by @page properties
Fail margin rules with @page properties between Fail margin rules with @page properties between