mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
LibWeb: Add basic implementation of @page
This doesn't support selectors, and the only descriptors for now are for margins.
This commit is contained in:
parent
1002464322
commit
aaf07ae30d
Notes:
github-actions[bot]
2025-05-15 08:54:53 +00:00
Author: https://github.com/AtkinsSJ
Commit: aaf07ae30d
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4735
27 changed files with 471 additions and 20 deletions
|
@ -84,6 +84,8 @@ set(SOURCES
|
|||
CSS/CSSNamespaceRule.cpp
|
||||
CSS/CSSNestedDeclarations.cpp
|
||||
CSS/CSSNumericType.cpp
|
||||
CSS/CSSPageRule.cpp
|
||||
CSS/CSSPageDescriptors.cpp
|
||||
CSS/CSSPropertyRule.cpp
|
||||
CSS/CSSRule.cpp
|
||||
CSS/CSSRuleList.cpp
|
||||
|
|
122
Libraries/LibWeb/CSS/CSSPageDescriptors.cpp
Normal file
122
Libraries/LibWeb/CSS/CSSPageDescriptors.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/Bindings/CSSPageDescriptorsPrototype.h>
|
||||
#include <LibWeb/CSS/CSSPageDescriptors.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(CSSPageDescriptors);
|
||||
|
||||
GC::Ref<CSSPageDescriptors> CSSPageDescriptors::create(JS::Realm& realm, Vector<Descriptor> descriptors)
|
||||
{
|
||||
return realm.create<CSSPageDescriptors>(realm, move(descriptors));
|
||||
}
|
||||
|
||||
CSSPageDescriptors::CSSPageDescriptors(JS::Realm& realm, Vector<Descriptor> descriptors)
|
||||
: CSSDescriptors(realm, AtRuleID::Page, move(descriptors))
|
||||
{
|
||||
}
|
||||
|
||||
CSSPageDescriptors::~CSSPageDescriptors() = default;
|
||||
|
||||
void CSSPageDescriptors::initialize(JS::Realm& realm)
|
||||
{
|
||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSPageDescriptors);
|
||||
Base::initialize(realm);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> CSSPageDescriptors::set_margin(StringView value)
|
||||
{
|
||||
return set_property("margin"sv, value, ""sv);
|
||||
}
|
||||
|
||||
String CSSPageDescriptors::margin() const
|
||||
{
|
||||
return get_property_value("margin"sv);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> CSSPageDescriptors::set_margin_top(StringView value)
|
||||
{
|
||||
return set_property("margin-top"sv, value, ""sv);
|
||||
}
|
||||
|
||||
String CSSPageDescriptors::margin_top() const
|
||||
{
|
||||
return get_property_value("margin-top"sv);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> CSSPageDescriptors::set_margin_right(StringView value)
|
||||
{
|
||||
return set_property("margin-right"sv, value, ""sv);
|
||||
}
|
||||
|
||||
String CSSPageDescriptors::margin_right() const
|
||||
{
|
||||
return get_property_value("margin-right"sv);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> CSSPageDescriptors::set_margin_bottom(StringView value)
|
||||
{
|
||||
return set_property("margin-bottom"sv, value, ""sv);
|
||||
}
|
||||
|
||||
String CSSPageDescriptors::margin_bottom() const
|
||||
{
|
||||
return get_property_value("margin-bottom"sv);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> CSSPageDescriptors::set_margin_left(StringView value)
|
||||
{
|
||||
return set_property("margin-left"sv, value, ""sv);
|
||||
}
|
||||
|
||||
String CSSPageDescriptors::margin_left() const
|
||||
{
|
||||
return get_property_value("margin-left"sv);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> CSSPageDescriptors::set_size(StringView value)
|
||||
{
|
||||
return set_property("size"sv, value, ""sv);
|
||||
}
|
||||
|
||||
String CSSPageDescriptors::size() const
|
||||
{
|
||||
return get_property_value("size"sv);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> CSSPageDescriptors::set_page_orientation(StringView value)
|
||||
{
|
||||
return set_property("page-orientation"sv, value, ""sv);
|
||||
}
|
||||
|
||||
String CSSPageDescriptors::page_orientation() const
|
||||
{
|
||||
return get_property_value("page-orientation"sv);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> CSSPageDescriptors::set_marks(StringView value)
|
||||
{
|
||||
return set_property("marks"sv, value, ""sv);
|
||||
}
|
||||
|
||||
String CSSPageDescriptors::marks() const
|
||||
{
|
||||
return get_property_value("marks"sv);
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> CSSPageDescriptors::set_bleed(StringView value)
|
||||
{
|
||||
return set_property("bleed"sv, value, ""sv);
|
||||
}
|
||||
|
||||
String CSSPageDescriptors::bleed() const
|
||||
{
|
||||
return get_property_value("bleed"sv);
|
||||
}
|
||||
|
||||
}
|
56
Libraries/LibWeb/CSS/CSSPageDescriptors.h
Normal file
56
Libraries/LibWeb/CSS/CSSPageDescriptors.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/CSS/CSSDescriptors.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
// https://drafts.csswg.org/cssom/#csspagedescriptors
|
||||
class CSSPageDescriptors final : public CSSDescriptors {
|
||||
WEB_PLATFORM_OBJECT(CSSPageDescriptors, CSSDescriptors);
|
||||
GC_DECLARE_ALLOCATOR(CSSPageDescriptors);
|
||||
|
||||
public:
|
||||
[[nodiscard]] static GC::Ref<CSSPageDescriptors> create(JS::Realm&, Vector<Descriptor>);
|
||||
|
||||
virtual ~CSSPageDescriptors() override;
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_margin(StringView value);
|
||||
String margin() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_margin_top(StringView value);
|
||||
String margin_top() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_margin_right(StringView value);
|
||||
String margin_right() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_margin_bottom(StringView value);
|
||||
String margin_bottom() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_margin_left(StringView value);
|
||||
String margin_left() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_size(StringView value);
|
||||
String size() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_page_orientation(StringView value);
|
||||
String page_orientation() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_marks(StringView value);
|
||||
String marks() const;
|
||||
|
||||
WebIDL::ExceptionOr<void> set_bleed(StringView value);
|
||||
String bleed() const;
|
||||
|
||||
private:
|
||||
CSSPageDescriptors(JS::Realm&, Vector<Descriptor>);
|
||||
};
|
||||
|
||||
}
|
20
Libraries/LibWeb/CSS/CSSPageDescriptors.idl
Normal file
20
Libraries/LibWeb/CSS/CSSPageDescriptors.idl
Normal file
|
@ -0,0 +1,20 @@
|
|||
#import <CSS/CSSStyleDeclaration.idl>
|
||||
|
||||
// https://drafts.csswg.org/cssom/#csspagedescriptors
|
||||
[Exposed=Window]
|
||||
interface CSSPageDescriptors : CSSStyleDeclaration {
|
||||
[LegacyNullToEmptyString] attribute CSSOMString margin;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=margin_top_regular, ImplementedAs=margin_top] attribute CSSOMString marginTop;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=margin_right_regular, ImplementedAs=margin_right] attribute CSSOMString marginRight;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=margin_bottom_regular, ImplementedAs=margin_bottom] attribute CSSOMString marginBottom;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=margin_left_regular, ImplementedAs=margin_left] attribute CSSOMString marginLeft;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=margin_top_dashed, ImplementedAs=margin_top] attribute CSSOMString margin-top;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=margin_right_dashed, ImplementedAs=margin_right] attribute CSSOMString margin-right;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=margin_bottom_dashed, ImplementedAs=margin_bottom] attribute CSSOMString margin-bottom;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=margin_left_dashed, ImplementedAs=margin_left] attribute CSSOMString margin-left;
|
||||
[LegacyNullToEmptyString] attribute CSSOMString size;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=page_orientation_regular, ImplementedAs=page_orientation] attribute CSSOMString pageOrientation;
|
||||
[LegacyNullToEmptyString, AttributeCallbackName=page_orientation_dashed, ImplementedAs=page_orientation] attribute CSSOMString page-orientation;
|
||||
[LegacyNullToEmptyString] attribute CSSOMString marks;
|
||||
[LegacyNullToEmptyString] attribute CSSOMString bleed;
|
||||
};
|
80
Libraries/LibWeb/CSS/CSSPageRule.cpp
Normal file
80
Libraries/LibWeb/CSS/CSSPageRule.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/Bindings/CSSPageRulePrototype.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/CSS/CSSPageRule.h>
|
||||
#include <LibWeb/CSS/DescriptorID.h>
|
||||
#include <LibWeb/CSS/Serialize.h>
|
||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
GC_DEFINE_ALLOCATOR(CSSPageRule);
|
||||
|
||||
GC::Ref<CSSPageRule> CSSPageRule::create(JS::Realm& realm, SelectorList&& selectors, GC::Ref<CSSPageDescriptors> style, CSSRuleList& rules)
|
||||
{
|
||||
return realm.create<CSSPageRule>(realm, move(selectors), style, rules);
|
||||
}
|
||||
|
||||
CSSPageRule::CSSPageRule(JS::Realm& realm, SelectorList&& selectors, GC::Ref<CSSPageDescriptors> style, CSSRuleList& rules)
|
||||
: CSSGroupingRule(realm, rules, Type::Page)
|
||||
, m_selectors(move(selectors))
|
||||
, m_style(style)
|
||||
{
|
||||
m_style->set_parent_rule(*this);
|
||||
}
|
||||
|
||||
void CSSPageRule::initialize(JS::Realm& realm)
|
||||
{
|
||||
WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSPageRule);
|
||||
Base::initialize(realm);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom/#dom-csspagerule-selectortext
|
||||
String CSSPageRule::selector_text() const
|
||||
{
|
||||
// The selectorText attribute, on getting, must return the result of serializing the associated selector list.
|
||||
return serialize_a_group_of_selectors(m_selectors);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom/#dom-csspagerule-selectortext
|
||||
void CSSPageRule::set_selector_text(StringView)
|
||||
{
|
||||
// FIXME: On setting the selectorText attribute these steps must be run:
|
||||
// 1. Run the parse a list of CSS page selectors algorithm on the given value.
|
||||
// 2. If the algorithm returns a non-null value replace the associated selector list with the returned value.
|
||||
// 3. Otherwise, if the algorithm returns a null value, do nothing.
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom/#ref-for-csspagerule
|
||||
String CSSPageRule::serialized() const
|
||||
{
|
||||
auto& descriptors = *m_style;
|
||||
|
||||
StringBuilder builder;
|
||||
|
||||
// AD-HOC: There's no spec for this yet.
|
||||
builder.append("@page "sv);
|
||||
if (auto selector = selector_text(); !selector.is_empty())
|
||||
builder.appendff("{} ", selector);
|
||||
builder.append("{ "sv);
|
||||
if (descriptors.length() > 0) {
|
||||
builder.append(descriptors.serialized());
|
||||
builder.append(' ');
|
||||
}
|
||||
builder.append("}"sv);
|
||||
|
||||
return builder.to_string_without_validation();
|
||||
}
|
||||
|
||||
void CSSPageRule::visit_edges(Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_style);
|
||||
}
|
||||
|
||||
}
|
42
Libraries/LibWeb/CSS/CSSPageRule.h
Normal file
42
Libraries/LibWeb/CSS/CSSPageRule.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/CSS/CSSGroupingRule.h>
|
||||
#include <LibWeb/CSS/CSSPageDescriptors.h>
|
||||
#include <LibWeb/CSS/Selector.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
// https://drafts.csswg.org/css-page-3/#at-ruledef-page
|
||||
class CSSPageRule final : public CSSGroupingRule {
|
||||
WEB_PLATFORM_OBJECT(CSSPageRule, CSSGroupingRule);
|
||||
GC_DECLARE_ALLOCATOR(CSSPageRule);
|
||||
|
||||
public:
|
||||
[[nodiscard]] static GC::Ref<CSSPageRule> create(JS::Realm&, SelectorList&&, GC::Ref<CSSPageDescriptors>, CSSRuleList&);
|
||||
|
||||
virtual ~CSSPageRule() override = default;
|
||||
|
||||
String selector_text() const;
|
||||
void set_selector_text(StringView);
|
||||
|
||||
GC::Ref<CSSPageDescriptors> style() { return m_style; }
|
||||
GC::Ref<CSSPageDescriptors const> descriptors() const { return m_style; }
|
||||
|
||||
private:
|
||||
CSSPageRule(JS::Realm&, SelectorList&&, GC::Ref<CSSPageDescriptors>, CSSRuleList&);
|
||||
|
||||
virtual void initialize(JS::Realm&) override;
|
||||
virtual String serialized() const override;
|
||||
virtual void visit_edges(Visitor&) override;
|
||||
|
||||
SelectorList m_selectors;
|
||||
GC::Ref<CSSPageDescriptors> m_style;
|
||||
};
|
||||
|
||||
}
|
9
Libraries/LibWeb/CSS/CSSPageRule.idl
Normal file
9
Libraries/LibWeb/CSS/CSSPageRule.idl
Normal file
|
@ -0,0 +1,9 @@
|
|||
#import <CSS/CSSGroupingRule.idl>
|
||||
#import <CSS/CSSPageDescriptors.idl>
|
||||
|
||||
// https://drafts.csswg.org/cssom/#csspagerule
|
||||
[Exposed=Window]
|
||||
interface CSSPageRule : CSSGroupingRule {
|
||||
attribute CSSOMString selectorText;
|
||||
[SameObject, PutForwards=cssText] readonly attribute CSSPageDescriptors style;
|
||||
};
|
|
@ -94,6 +94,7 @@ FlyString const& CSSRule::parent_layer_internal_qualified_name_slow_case() const
|
|||
case Type::Supports:
|
||||
case Type::NestedDeclarations:
|
||||
case Type::Property:
|
||||
case Type::Page:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
Import = 3,
|
||||
Media = 4,
|
||||
FontFace = 5,
|
||||
Page = 6,
|
||||
Keyframes = 7,
|
||||
Keyframe = 8,
|
||||
Namespace = 10,
|
||||
|
|
|
@ -164,6 +164,7 @@ void CSSRuleList::for_each_effective_rule(TraversalOrder order, Function<void(We
|
|||
case CSSRule::Type::Namespace:
|
||||
case CSSRule::Type::NestedDeclarations:
|
||||
case CSSRule::Type::Property:
|
||||
case CSSRule::Type::Page:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -219,6 +220,7 @@ bool CSSRuleList::evaluate_media_queries(HTML::Window const& window)
|
|||
case CSSRule::Type::Namespace:
|
||||
case CSSRule::Type::NestedDeclarations:
|
||||
case CSSRule::Type::Property:
|
||||
case CSSRule::Type::Page:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,6 +104,42 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"page": {
|
||||
"spec": "https://drafts.csswg.org/css-page-3/#at-page-rule",
|
||||
"FIXME": "There are a lot more properties that are valid, see https://drafts.csswg.org/css-page-3/#properties-list",
|
||||
"descriptors": {
|
||||
"margin": {
|
||||
"initial": "0",
|
||||
"syntax": [
|
||||
"<'margin'>"
|
||||
]
|
||||
},
|
||||
"margin-bottom": {
|
||||
"initial": "0",
|
||||
"syntax": [
|
||||
"<'margin-bottom'>"
|
||||
]
|
||||
},
|
||||
"margin-left": {
|
||||
"initial": "0",
|
||||
"syntax": [
|
||||
"<'margin-left'>"
|
||||
]
|
||||
},
|
||||
"margin-right": {
|
||||
"initial": "0",
|
||||
"syntax": [
|
||||
"<'margin-right'>"
|
||||
]
|
||||
},
|
||||
"margin-top": {
|
||||
"initial": "0",
|
||||
"syntax": [
|
||||
"<'margin-top'>"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"property": {
|
||||
"spec": "https://drafts.css-houdini.org/css-properties-values-api/#at-property-rule",
|
||||
"descriptors": {
|
||||
|
|
|
@ -1375,6 +1375,8 @@ Vector<Descriptor> Parser::parse_as_descriptor_declaration_block(AtRuleID at_rul
|
|||
switch (at_rule_id) {
|
||||
case AtRuleID::FontFace:
|
||||
return RuleContext::AtFontFace;
|
||||
case AtRuleID::Page:
|
||||
return RuleContext::AtPage;
|
||||
case AtRuleID::Property:
|
||||
return RuleContext::AtProperty;
|
||||
}
|
||||
|
@ -1434,8 +1436,9 @@ bool Parser::is_valid_in_the_current_context(Declaration const&) const
|
|||
return m_rule_context.contains_slow(RuleContext::Style);
|
||||
|
||||
case RuleContext::AtFontFace:
|
||||
case RuleContext::AtPage:
|
||||
case RuleContext::AtProperty:
|
||||
// @font-face and @property have descriptor declarations
|
||||
// @font-face, @page, and @property have descriptor declarations
|
||||
return true;
|
||||
|
||||
case RuleContext::AtKeyframes:
|
||||
|
@ -1482,8 +1485,10 @@ bool Parser::is_valid_in_the_current_context(AtRule const& at_rule) const
|
|||
case RuleContext::AtFontFace:
|
||||
case RuleContext::AtKeyframes:
|
||||
case RuleContext::Keyframe:
|
||||
case RuleContext::AtPage:
|
||||
case RuleContext::AtProperty:
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -1522,6 +1527,7 @@ bool Parser::is_valid_in_the_current_context(QualifiedRule const&) const
|
|||
return false;
|
||||
|
||||
case RuleContext::AtFontFace:
|
||||
case RuleContext::AtPage:
|
||||
case RuleContext::AtProperty:
|
||||
case RuleContext::Keyframe:
|
||||
// These can't contain qualified rules
|
||||
|
|
|
@ -245,8 +245,9 @@ private:
|
|||
GC::Ptr<CSSRule> convert_to_layer_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<CSSSupportsRule> convert_to_supports_rule(AtRule const&, Nested);
|
||||
GC::Ptr<CSSPageRule> convert_to_page_rule(AtRule const& rule);
|
||||
GC::Ptr<CSSPropertyRule> convert_to_property_rule(AtRule const& rule);
|
||||
GC::Ptr<CSSSupportsRule> convert_to_supports_rule(AtRule const&, Nested);
|
||||
|
||||
GC::Ref<CSSStyleProperties> convert_to_style_declaration(Vector<Declaration> const&);
|
||||
Optional<StyleProperty> convert_to_style_property(Declaration const&);
|
||||
|
|
|
@ -27,6 +27,8 @@ RuleContext rule_context_type_for_rule(CSSRule::Type rule_type)
|
|||
return RuleContext::AtLayer;
|
||||
case CSSRule::Type::NestedDeclarations:
|
||||
return RuleContext::Style;
|
||||
case CSSRule::Type::Page:
|
||||
return RuleContext::AtPage;
|
||||
case CSSRule::Type::Property:
|
||||
return RuleContext::AtProperty;
|
||||
// Other types shouldn't be trying to create a context.
|
||||
|
@ -52,6 +54,8 @@ RuleContext rule_context_type_for_at_rule(FlyString const& name)
|
|||
return RuleContext::AtLayer;
|
||||
if (name == "property")
|
||||
return RuleContext::AtProperty;
|
||||
if (name == "page")
|
||||
return RuleContext::AtPage;
|
||||
return RuleContext::Unknown;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ enum class RuleContext : u8 {
|
|||
SupportsCondition,
|
||||
AtLayer,
|
||||
AtProperty,
|
||||
AtPage,
|
||||
};
|
||||
RuleContext rule_context_type_for_rule(CSSRule::Type);
|
||||
RuleContext rule_context_type_for_at_rule(FlyString const&);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <LibWeb/CSS/CSSMediaRule.h>
|
||||
#include <LibWeb/CSS/CSSNamespaceRule.h>
|
||||
#include <LibWeb/CSS/CSSNestedDeclarations.h>
|
||||
#include <LibWeb/CSS/CSSPageRule.h>
|
||||
#include <LibWeb/CSS/CSSPropertyRule.h>
|
||||
#include <LibWeb/CSS/CSSStyleProperties.h>
|
||||
#include <LibWeb/CSS/CSSStyleRule.h>
|
||||
|
@ -64,12 +65,15 @@ GC::Ptr<CSSRule> Parser::convert_to_rule(Rule const& rule, Nested nested)
|
|||
if (at_rule.name.equals_ignoring_ascii_case("namespace"sv))
|
||||
return convert_to_namespace_rule(at_rule);
|
||||
|
||||
if (at_rule.name.equals_ignoring_ascii_case("supports"sv))
|
||||
return convert_to_supports_rule(at_rule, nested);
|
||||
if (at_rule.name.equals_ignoring_ascii_case("page"sv))
|
||||
return convert_to_page_rule(at_rule);
|
||||
|
||||
if (at_rule.name.equals_ignoring_ascii_case("property"sv))
|
||||
return convert_to_property_rule(at_rule);
|
||||
|
||||
if (at_rule.name.equals_ignoring_ascii_case("supports"sv))
|
||||
return convert_to_supports_rule(at_rule, nested);
|
||||
|
||||
// FIXME: More at rules!
|
||||
dbgln_if(CSS_PARSER_DEBUG, "Unrecognized CSS at-rule: @{}", at_rule.name);
|
||||
return {};
|
||||
|
@ -596,4 +600,43 @@ GC::Ptr<CSSFontFaceRule> Parser::convert_to_font_face_rule(AtRule const& rule)
|
|||
return CSSFontFaceRule::create(realm(), CSSFontFaceDescriptors::create(realm(), move(descriptors)));
|
||||
}
|
||||
|
||||
GC::Ptr<CSSPageRule> Parser::convert_to_page_rule(AtRule const& rule)
|
||||
{
|
||||
// https://drafts.csswg.org/css-page-3/#syntax-page-selector
|
||||
// @page = @page <page-selector-list>? { <declaration-rule-list> }
|
||||
// <page-selector-list> = <page-selector>#
|
||||
// <page-selector> = [ <ident-token>? <pseudo-page>* ]!
|
||||
// <pseudo-page> = : [ left | right | first | blank ]
|
||||
SelectorList page_selectors;
|
||||
// FIXME: Parse page selectors
|
||||
if (rule.prelude.find_first_index_if([](ComponentValue const& it) { return !it.is(Token::Type::Whitespace); }).has_value()) {
|
||||
dbgln("@page prelude wasn't empty!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GC::RootVector<GC::Ref<CSSRule>> child_rules { realm().heap() };
|
||||
Vector<Descriptor> descriptors;
|
||||
HashTable<DescriptorID> seen_descriptor_ids;
|
||||
rule.for_each_as_declaration_rule_list(
|
||||
[&](auto& at_rule) {
|
||||
// FIXME: Parse margin rules here.
|
||||
(void)at_rule;
|
||||
},
|
||||
[&](auto& declaration) {
|
||||
if (auto descriptor = convert_to_descriptor(AtRuleID::Page, declaration); descriptor.has_value()) {
|
||||
if (seen_descriptor_ids.contains(descriptor->descriptor_id)) {
|
||||
descriptors.remove_first_matching([&descriptor](Descriptor const& existing) {
|
||||
return existing.descriptor_id == descriptor->descriptor_id;
|
||||
});
|
||||
} else {
|
||||
seen_descriptor_ids.set(descriptor->descriptor_id);
|
||||
}
|
||||
descriptors.append(descriptor.release_value());
|
||||
}
|
||||
});
|
||||
|
||||
auto rule_list = CSSRuleList::create(realm(), child_rules);
|
||||
return CSSPageRule::create(realm(), move(page_selectors), CSSPageDescriptors::create(realm(), move(descriptors)), rule_list);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3027,8 +3027,9 @@ void StyleComputer::build_qualified_layer_names_cache()
|
|||
case CSSRule::Type::Keyframe:
|
||||
case CSSRule::Type::Namespace:
|
||||
case CSSRule::Type::NestedDeclarations:
|
||||
case CSSRule::Type::Supports:
|
||||
case CSSRule::Type::Page:
|
||||
case CSSRule::Type::Property:
|
||||
case CSSRule::Type::Supports:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <LibWeb/CSS/CSSMediaRule.h>
|
||||
#include <LibWeb/CSS/CSSNamespaceRule.h>
|
||||
#include <LibWeb/CSS/CSSNestedDeclarations.h>
|
||||
#include <LibWeb/CSS/CSSPageRule.h>
|
||||
#include <LibWeb/CSS/CSSPropertyRule.h>
|
||||
#include <LibWeb/CSS/CSSRule.h>
|
||||
#include <LibWeb/CSS/CSSStyleProperties.h>
|
||||
|
@ -695,15 +696,18 @@ void dump_rule(StringBuilder& builder, CSS::CSSRule const& rule, int indent_leve
|
|||
case CSS::CSSRule::Type::NestedDeclarations:
|
||||
dump_nested_declarations(builder, as<CSS::CSSNestedDeclarations const>(rule), indent_levels);
|
||||
break;
|
||||
case CSS::CSSRule::Type::Page:
|
||||
dump_page_rule(builder, as<CSS::CSSPageRule const>(rule), indent_levels);
|
||||
break;
|
||||
case CSS::CSSRule::Type::Property:
|
||||
dump_property_rule(builder, as<CSS::CSSPropertyRule const>(rule), indent_levels);
|
||||
break;
|
||||
case CSS::CSSRule::Type::Style:
|
||||
dump_style_rule(builder, as<CSS::CSSStyleRule const>(rule), indent_levels);
|
||||
break;
|
||||
case CSS::CSSRule::Type::Supports:
|
||||
dump_supports_rule(builder, as<CSS::CSSSupportsRule const>(rule), indent_levels);
|
||||
break;
|
||||
case CSS::CSSRule::Type::Property:
|
||||
dump_property_rule(builder, as<CSS::CSSPropertyRule const>(rule), indent_levels);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -765,6 +769,13 @@ void dump_media_rule(StringBuilder& builder, CSS::CSSMediaRule const& media, int
|
|||
dump_rule(builder, rule, indent_levels + 2);
|
||||
}
|
||||
|
||||
void dump_page_rule(StringBuilder& builder, CSS::CSSPageRule const& page, int indent_levels)
|
||||
{
|
||||
indent(builder, indent_levels + 1);
|
||||
builder.appendff("selector: {}\n", page.selector_text());
|
||||
dump_descriptors(builder, page.descriptors(), indent_levels + 1);
|
||||
}
|
||||
|
||||
void dump_supports_rule(StringBuilder& builder, CSS::CSSSupportsRule const& supports, int indent_levels)
|
||||
{
|
||||
indent(builder, indent_levels);
|
||||
|
|
|
@ -30,6 +30,7 @@ void dump_import_rule(StringBuilder&, CSS::CSSImportRule const&, int indent_leve
|
|||
void dump_keyframe_rule(StringBuilder&, CSS::CSSKeyframeRule 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_page_rule(StringBuilder&, CSS::CSSPageRule 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_property_rule(StringBuilder&, CSS::CSSPropertyRule const&, int indent_levels = 0);
|
||||
|
|
|
@ -205,6 +205,8 @@ class CSSNamespaceRule;
|
|||
class CSSNestedDeclarations;
|
||||
class CSSOKLab;
|
||||
class CSSOKLCH;
|
||||
class CSSPageRule;
|
||||
class CSSPageDescriptors;
|
||||
class CSSPropertyRule;
|
||||
class CSSRGB;
|
||||
class CSSRule;
|
||||
|
|
|
@ -35,6 +35,8 @@ libweb_js_bindings(CSS/CSSMediaRule)
|
|||
libweb_js_bindings(CSS/CSS NAMESPACE)
|
||||
libweb_js_bindings(CSS/CSSNamespaceRule)
|
||||
libweb_js_bindings(CSS/CSSNestedDeclarations)
|
||||
libweb_js_bindings(CSS/CSSPageRule)
|
||||
libweb_js_bindings(CSS/CSSPageDescriptors)
|
||||
libweb_js_bindings(CSS/CSSPropertyRule)
|
||||
libweb_js_bindings(CSS/CSSRule)
|
||||
libweb_js_bindings(CSS/CSSRuleList)
|
||||
|
|
|
@ -49,6 +49,8 @@ CSSLayerStatementRule
|
|||
CSSMediaRule
|
||||
CSSNamespaceRule
|
||||
CSSNestedDeclarations
|
||||
CSSPageDescriptors
|
||||
CSSPageRule
|
||||
CSSPropertyRule
|
||||
CSSRule
|
||||
CSSRuleList
|
||||
|
|
|
@ -2,8 +2,9 @@ Harness status: OK
|
|||
|
||||
Found 4 tests
|
||||
|
||||
4 Fail
|
||||
1 Pass
|
||||
3 Fail
|
||||
Fail There should be 3 @page rules.
|
||||
Fail Rule #0
|
||||
Pass Rule #0
|
||||
Fail Rule #1
|
||||
Fail Rule #2
|
|
@ -1,3 +1,7 @@
|
|||
Harness status: Error
|
||||
Harness status: OK
|
||||
|
||||
Found 0 tests
|
||||
Found 2 tests
|
||||
|
||||
2 Fail
|
||||
Fail Add declarations
|
||||
Fail Remove declarations
|
|
@ -2,11 +2,11 @@ Harness status: OK
|
|||
|
||||
Found 8 tests
|
||||
|
||||
4 Pass
|
||||
4 Fail
|
||||
5 Pass
|
||||
3 Fail
|
||||
Pass page-rules-001
|
||||
Pass @page , { } should be an invalid rule
|
||||
Fail @page { } should be a valid rule
|
||||
Pass @page { } should be a valid rule
|
||||
Fail @page a { } should be a valid rule
|
||||
Fail @page page1 { } should be a valid rule
|
||||
Fail @page name1, name2 { } should be a valid rule
|
||||
|
|
|
@ -2,8 +2,9 @@ Harness status: OK
|
|||
|
||||
Found 15 tests
|
||||
|
||||
15 Fail
|
||||
Fail Test setup
|
||||
1 Pass
|
||||
14 Fail
|
||||
Pass Test setup
|
||||
Fail size: 640px 480px
|
||||
Fail size: 8.5in 11in
|
||||
Fail size: 3in 10in
|
||||
|
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
|||
|
||||
Found 11 tests
|
||||
|
||||
8 Pass
|
||||
3 Fail
|
||||
9 Pass
|
||||
2 Fail
|
||||
Pass CSSRule and CSSImportRule types
|
||||
Pass Type of CSSRule#type and constant values
|
||||
Pass Existence and writability of CSSRule attributes
|
||||
|
@ -11,7 +11,7 @@ Pass Values of CSSRule attributes
|
|||
Pass Existence and writability of CSSImportRule attributes
|
||||
Fail Values of CSSImportRule attributes
|
||||
Fail CSSImportRule : MediaList mediaText attribute should be updated due to [PutForwards]
|
||||
Fail CSSStyleDeclaration cssText attribute should be updated due to [PutForwards]
|
||||
Pass CSSStyleDeclaration cssText attribute should be updated due to [PutForwards]
|
||||
Pass StyleSheet : MediaList mediaText attribute should be updated due to [PutForwards]
|
||||
Pass Existence and writability of CSSImportRule supportsText attribute
|
||||
Pass Value of CSSImportRule supportsText attribute
|
Loading…
Add table
Add a link
Reference in a new issue