mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
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:
parent
aa9fa88428
commit
870f24f181
Notes:
github-actions[bot]
2025-05-16 10:02:36 +00:00
Author: https://github.com/AtkinsSJ
Commit: 870f24f181
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4746
21 changed files with 233 additions and 32 deletions
|
@ -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
|
||||||
|
|
77
Libraries/LibWeb/CSS/CSSMarginRule.cpp
Normal file
77
Libraries/LibWeb/CSS/CSSMarginRule.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
40
Libraries/LibWeb/CSS/CSSMarginRule.h
Normal file
40
Libraries/LibWeb/CSS/CSSMarginRule.h
Normal 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);
|
||||||
|
|
||||||
|
}
|
10
Libraries/LibWeb/CSS/CSSMarginRule.idl
Normal file
10
Libraries/LibWeb/CSS/CSSMarginRule.idl
Normal 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;
|
||||||
|
};
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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&);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -46,6 +46,7 @@ CSSKeyframeRule
|
||||||
CSSKeyframesRule
|
CSSKeyframesRule
|
||||||
CSSLayerBlockRule
|
CSSLayerBlockRule
|
||||||
CSSLayerStatementRule
|
CSSLayerStatementRule
|
||||||
|
CSSMarginRule
|
||||||
CSSMediaRule
|
CSSMediaRule
|
||||||
CSSNamespaceRule
|
CSSNamespaceRule
|
||||||
CSSNestedDeclarations
|
CSSNestedDeclarations
|
||||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue