mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-09 17:49:40 +00:00
LibWeb/CSS: Add basic registered properties with initial values
Add global registry for registered properties and partial support for `@property` rule. Enables registering properties with initial values. Also adds basic retrieval via `var()`. Note: This is not a complete `@property` implementation.
This commit is contained in:
parent
e7f0126c2e
commit
7ad01d28a8
Notes:
github-actions[bot]
2025-07-18 10:13:56 +00:00
Author: https://github.com/Norbiros 🔰
Commit: 7ad01d28a8
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5456
Reviewed-by: https://github.com/AtkinsSJ ✅
9 changed files with 73 additions and 20 deletions
|
@ -29,6 +29,7 @@ public:
|
||||||
FlyString const& syntax() const { return m_syntax; }
|
FlyString const& syntax() const { return m_syntax; }
|
||||||
bool inherits() const { return m_inherits; }
|
bool inherits() const { return m_inherits; }
|
||||||
Optional<String> initial_value() const;
|
Optional<String> initial_value() const;
|
||||||
|
RefPtr<CSSStyleValue const> initial_style_value() const { return m_initial_value; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSSPropertyRule(JS::Realm&, FlyString name, FlyString syntax, bool inherits, RefPtr<CSSStyleValue const> initial_value);
|
CSSPropertyRule(JS::Realm&, FlyString name, FlyString syntax, bool inherits, RefPtr<CSSStyleValue const> initial_value);
|
||||||
|
|
|
@ -145,6 +145,13 @@ GC::RootVector<GC::Ref<CSSRule>> Parser::convert_rules(Vector<Rule> const& raw_r
|
||||||
|
|
||||||
m_declared_namespaces.set(as<CSSNamespaceRule>(*rule).prefix());
|
m_declared_namespaces.set(as<CSSNamespaceRule>(*rule).prefix());
|
||||||
break;
|
break;
|
||||||
|
case CSSRule::Type::Property: {
|
||||||
|
auto& property_rule = as<CSSPropertyRule>(*rule);
|
||||||
|
if (m_document) {
|
||||||
|
const_cast<DOM::Document*>(m_document.ptr())->registered_custom_properties().set(property_rule.name(), property_rule);
|
||||||
|
}
|
||||||
|
[[fallthrough]];
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
import_rules_valid = false;
|
import_rules_valid = false;
|
||||||
namespace_rules_valid = false;
|
namespace_rules_valid = false;
|
||||||
|
|
|
@ -3106,33 +3106,25 @@ void StyleComputer::unload_fonts_from_sheet(CSSStyleSheet& sheet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static NonnullRefPtr<CSSStyleValue const> custom_property_initial_value(FlyString const& name)
|
|
||||||
{
|
|
||||||
// FIXME: Look-up initial value for registered properties. (@property)
|
|
||||||
(void)name;
|
|
||||||
|
|
||||||
// For non-registered properties, the initial value is the guaranteed-invalid value.
|
|
||||||
return GuaranteedInvalidStyleValue::create();
|
|
||||||
}
|
|
||||||
|
|
||||||
NonnullRefPtr<CSSStyleValue const> StyleComputer::compute_value_of_custom_property(DOM::AbstractElement abstract_element, FlyString const& name, Optional<Parser::GuardedSubstitutionContexts&> guarded_contexts)
|
NonnullRefPtr<CSSStyleValue const> StyleComputer::compute_value_of_custom_property(DOM::AbstractElement abstract_element, FlyString const& name, Optional<Parser::GuardedSubstitutionContexts&> guarded_contexts)
|
||||||
{
|
{
|
||||||
// https://drafts.csswg.org/css-variables/#propdef-
|
// https://drafts.csswg.org/css-variables/#propdef-
|
||||||
// The computed value of a custom property is its specified value with any arbitrary-substitution functions replaced.
|
// The computed value of a custom property is its specified value with any arbitrary-substitution functions replaced.
|
||||||
// FIXME: These should probably be part of ComputedProperties.
|
// FIXME: These should probably be part of ComputedProperties.
|
||||||
|
auto& document = abstract_element.document();
|
||||||
|
|
||||||
auto value = abstract_element.get_custom_property(name);
|
auto value = abstract_element.get_custom_property(name);
|
||||||
if (!value || value->is_initial())
|
if (!value || value->is_initial())
|
||||||
return custom_property_initial_value(name);
|
return document.custom_property_initial_value(name);
|
||||||
|
|
||||||
// Unset is the same as inherit for inherited properties, and by default all custom properties are inherited.
|
// Unset is the same as inherit for inherited properties, and by default all custom properties are inherited.
|
||||||
// FIXME: Support non-inherited registered custom properties.
|
// FIXME: Support non-inherited registered custom properties.
|
||||||
if (value->is_inherit() || value->is_unset()) {
|
if (value->is_inherit() || value->is_unset()) {
|
||||||
if (!abstract_element.parent_element())
|
if (!abstract_element.parent_element())
|
||||||
return custom_property_initial_value(name);
|
return document.custom_property_initial_value(name);
|
||||||
auto inherited_value = DOM::AbstractElement { const_cast<DOM::Element&>(*abstract_element.parent_element()) }.get_custom_property(name);
|
auto inherited_value = DOM::AbstractElement { const_cast<DOM::Element&>(*abstract_element.parent_element()) }.get_custom_property(name);
|
||||||
if (!inherited_value)
|
if (!inherited_value)
|
||||||
return custom_property_initial_value(name);
|
return document.custom_property_initial_value(name);
|
||||||
return inherited_value.release_nonnull();
|
return inherited_value.release_nonnull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include <LibWeb/CSS/StyleComputer.h>
|
#include <LibWeb/CSS/StyleComputer.h>
|
||||||
#include <LibWeb/CSS/StyleSheetIdentifier.h>
|
#include <LibWeb/CSS/StyleSheetIdentifier.h>
|
||||||
#include <LibWeb/CSS/StyleValues/ColorSchemeStyleValue.h>
|
#include <LibWeb/CSS/StyleValues/ColorSchemeStyleValue.h>
|
||||||
|
#include <LibWeb/CSS/StyleValues/GuaranteedInvalidStyleValue.h>
|
||||||
#include <LibWeb/CSS/SystemColor.h>
|
#include <LibWeb/CSS/SystemColor.h>
|
||||||
#include <LibWeb/CSS/TransitionEvent.h>
|
#include <LibWeb/CSS/TransitionEvent.h>
|
||||||
#include <LibWeb/CSS/VisualViewport.h>
|
#include <LibWeb/CSS/VisualViewport.h>
|
||||||
|
@ -620,6 +621,7 @@ void Document::visit_edges(Cell::Visitor& visitor)
|
||||||
visitor.visit(m_render_blocking_elements);
|
visitor.visit(m_render_blocking_elements);
|
||||||
visitor.visit(m_policy_container);
|
visitor.visit(m_policy_container);
|
||||||
visitor.visit(m_style_invalidator);
|
visitor.visit(m_style_invalidator);
|
||||||
|
visitor.visit(m_registered_custom_properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://w3c.github.io/selection-api/#dom-document-getselection
|
// https://w3c.github.io/selection-api/#dom-document-getselection
|
||||||
|
@ -6576,6 +6578,26 @@ String Document::dump_display_list()
|
||||||
return display_list->dump();
|
return display_list->dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashMap<FlyString, GC::Ref<Web::CSS::CSSPropertyRule>>& Document::registered_custom_properties()
|
||||||
|
{
|
||||||
|
return m_registered_custom_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<CSS::CSSStyleValue const> Document::custom_property_initial_value(FlyString const& name) const
|
||||||
|
{
|
||||||
|
auto maybe_custom_property = m_registered_custom_properties.get(name);
|
||||||
|
if (maybe_custom_property.has_value()) {
|
||||||
|
auto parsed_value = maybe_custom_property.value()->initial_style_value();
|
||||||
|
if (!parsed_value)
|
||||||
|
return CSS::GuaranteedInvalidStyleValue::create();
|
||||||
|
return parsed_value.release_nonnull();
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-registered properties, the initial value is the guaranteed-invalid value.
|
||||||
|
// See: https://drafts.csswg.org/css-variables/#propdef-
|
||||||
|
return CSS::GuaranteedInvalidStyleValue::create();
|
||||||
|
}
|
||||||
|
|
||||||
GC::Ptr<Element> ElementByIdMap::get(FlyString const& element_id) const
|
GC::Ptr<Element> ElementByIdMap::get(FlyString const& element_id) const
|
||||||
{
|
{
|
||||||
if (auto elements = m_map.get(element_id); elements.has_value() && !elements->is_empty()) {
|
if (auto elements = m_map.get(element_id); elements.has_value() && !elements->is_empty()) {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <LibURL/Origin.h>
|
#include <LibURL/Origin.h>
|
||||||
#include <LibURL/URL.h>
|
#include <LibURL/URL.h>
|
||||||
#include <LibUnicode/Forward.h>
|
#include <LibUnicode/Forward.h>
|
||||||
|
#include <LibWeb/CSS/CSSPropertyRule.h>
|
||||||
#include <LibWeb/CSS/CSSStyleSheet.h>
|
#include <LibWeb/CSS/CSSStyleSheet.h>
|
||||||
#include <LibWeb/CSS/StyleSheetList.h>
|
#include <LibWeb/CSS/StyleSheetList.h>
|
||||||
#include <LibWeb/Cookie/Cookie.h>
|
#include <LibWeb/Cookie/Cookie.h>
|
||||||
|
@ -905,6 +906,11 @@ public:
|
||||||
|
|
||||||
StyleInvalidator& style_invalidator() { return m_style_invalidator; }
|
StyleInvalidator& style_invalidator() { return m_style_invalidator; }
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/css-properties-values-api-1/#dom-window-registeredpropertyset-slot
|
||||||
|
HashMap<FlyString, GC::Ref<Web::CSS::CSSPropertyRule>>& registered_custom_properties();
|
||||||
|
|
||||||
|
NonnullRefPtr<CSS::CSSStyleValue const> custom_property_initial_value(FlyString const& name) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
virtual void visit_edges(Cell::Visitor&) override;
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
@ -1265,6 +1271,9 @@ private:
|
||||||
HashTable<WeakPtr<Node>> m_pending_nodes_for_style_invalidation_due_to_presence_of_has;
|
HashTable<WeakPtr<Node>> m_pending_nodes_for_style_invalidation_due_to_presence_of_has;
|
||||||
|
|
||||||
GC::Ref<StyleInvalidator> m_style_invalidator;
|
GC::Ref<StyleInvalidator> m_style_invalidator;
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/css-properties-values-api-1/#dom-window-registeredpropertyset-slot
|
||||||
|
HashMap<FlyString, GC::Ref<Web::CSS::CSSPropertyRule>> m_registered_custom_properties;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Computed background-color: rgb(255, 0, 0)
|
|
@ -2,8 +2,8 @@ Harness status: OK
|
||||||
|
|
||||||
Found 139 tests
|
Found 139 tests
|
||||||
|
|
||||||
128 Pass
|
130 Pass
|
||||||
11 Fail
|
9 Fail
|
||||||
Pass CSS Values and Units Test: attr
|
Pass CSS Values and Units Test: attr
|
||||||
Fail CSS Values and Units Test: attr 1
|
Fail CSS Values and Units Test: attr 1
|
||||||
Pass CSS Values and Units Test: attr 2
|
Pass CSS Values and Units Test: attr 2
|
||||||
|
@ -54,12 +54,12 @@ Pass CSS Values and Units Test: attr 46
|
||||||
Pass CSS Values and Units Test: attr 47
|
Pass CSS Values and Units Test: attr 47
|
||||||
Pass CSS Values and Units Test: attr 48
|
Pass CSS Values and Units Test: attr 48
|
||||||
Pass CSS Values and Units Test: attr 49
|
Pass CSS Values and Units Test: attr 49
|
||||||
Fail CSS Values and Units Test: attr 50
|
Pass CSS Values and Units Test: attr 50
|
||||||
Fail CSS Values and Units Test: attr 51
|
Fail CSS Values and Units Test: attr 51
|
||||||
Pass CSS Values and Units Test: attr 52
|
Pass CSS Values and Units Test: attr 52
|
||||||
Pass CSS Values and Units Test: attr 53
|
Pass CSS Values and Units Test: attr 53
|
||||||
Pass CSS Values and Units Test: attr 54
|
Pass CSS Values and Units Test: attr 54
|
||||||
Fail CSS Values and Units Test: attr 55
|
Pass CSS Values and Units Test: attr 55
|
||||||
Pass CSS Values and Units Test: attr 56
|
Pass CSS Values and Units Test: attr 56
|
||||||
Pass CSS Values and Units Test: attr 57
|
Pass CSS Values and Units Test: attr 57
|
||||||
Pass CSS Values and Units Test: attr 58
|
Pass CSS Values and Units Test: attr 58
|
||||||
|
|
|
@ -2,15 +2,15 @@ Harness status: OK
|
||||||
|
|
||||||
Found 30 tests
|
Found 30 tests
|
||||||
|
|
||||||
9 Pass
|
11 Pass
|
||||||
21 Fail
|
19 Fail
|
||||||
Pass `initial` as a value for an unregistered custom property
|
Pass `initial` as a value for an unregistered custom property
|
||||||
Pass `inherit` as a value for an unregistered custom property
|
Pass `inherit` as a value for an unregistered custom property
|
||||||
Pass `unset` as a value for an unregistered custom property
|
Pass `unset` as a value for an unregistered custom property
|
||||||
Fail `revert` as a value for an unregistered custom property
|
Fail `revert` as a value for an unregistered custom property
|
||||||
Pass `revert-layer` as a value for an unregistered custom property
|
Pass `revert-layer` as a value for an unregistered custom property
|
||||||
Fail `initial` as a value for a non-inheriting registered custom property
|
Pass `initial` as a value for a non-inheriting registered custom property
|
||||||
Fail `initial` as a value for an inheriting registered custom property
|
Pass `initial` as a value for an inheriting registered custom property
|
||||||
Pass `inherit` as a value for a non-inheriting registered custom property
|
Pass `inherit` as a value for a non-inheriting registered custom property
|
||||||
Pass `inherit` as a value for an inheriting registered custom property
|
Pass `inherit` as a value for an inheriting registered custom property
|
||||||
Fail `unset` as a value for a non-inheriting registered custom property
|
Fail `unset` as a value for a non-inheriting registered custom property
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
.background {
|
||||||
|
background-color: var(--bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@property --bg-color {
|
||||||
|
syntax: '*';
|
||||||
|
inherits: false;
|
||||||
|
initial-value: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="background">It should have red bg</div>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
const el = document.querySelector(".background");
|
||||||
|
const style = getComputedStyle(el);
|
||||||
|
println(`Computed background-color: ${style.backgroundColor}`);
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue