mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:48:11 +00:00
LibWeb: Move use pseudo element styles from TreeBuilder to StyleComputer
The styling of elements using the `use_pseudo_element()` was only applied on layout. When an element style was recomputed later that styling was not overruled with the pseudo element selector styles. This moves the styling override from `TreeBuilder.cpp` to `StyleComputer.cpp`. Now the styles are always correctly applied. I also removed the method `property_id_by_index()` because it was not needed anymore. Als some calls to `invalidate_layout()` in the Meter, Progress and Select elements where not needed anymore because the style values are update on the changing of the style attribute. This fixes issue #22278.
This commit is contained in:
parent
7578620f25
commit
a05fd28b7b
11 changed files with 44 additions and 49 deletions
17
Tests/LibWeb/Layout/expected/element-use-pseudo-element.txt
Normal file
17
Tests/LibWeb/Layout/expected/element-use-pseudo-element.txt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
||||||
|
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
|
||||||
|
BlockContainer <body> at (8,8) content-size 784x21.84375 children: inline
|
||||||
|
line 0 width: 300, height: 21.84375, bottom: 21.84375, baseline: 16.921875
|
||||||
|
frag 0 from BlockContainer start: 0, length: 0, rect: [8,12 300x12]
|
||||||
|
BlockContainer <progress#a> at (8,12) content-size 300x12 inline-block [BFC] children: not-inline
|
||||||
|
BlockContainer <div> at (9,13) content-size 298x12 children: not-inline
|
||||||
|
BlockContainer <div> at (9,13) content-size 298x12 children: not-inline
|
||||||
|
TextNode <#text>
|
||||||
|
TextNode <#text>
|
||||||
|
|
||||||
|
ViewportPaintable (Viewport<#document>) [0,0 800x600]
|
||||||
|
PaintableWithLines (BlockContainer<HTML>) [0,0 800x600]
|
||||||
|
PaintableWithLines (BlockContainer<BODY>) [8,8 784x21.84375]
|
||||||
|
PaintableWithLines (BlockContainer<PROGRESS>#a) [8,12 300x12] overflow: [8,12 300x14]
|
||||||
|
PaintableWithLines (BlockContainer<DIV>) [8,12 300x14]
|
||||||
|
PaintableWithLines (BlockContainer<DIV>) [9,13 298x12]
|
|
@ -0,0 +1,9 @@
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
font: 20px 'SerenitySans';
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<progress id="a"></progress>
|
||||||
|
<script>
|
||||||
|
a.style.backgroundColor = 'red'; // Trigger style invalidation
|
||||||
|
</script>
|
|
@ -59,11 +59,6 @@ String PropertyOwningCSSStyleDeclaration::item(size_t index) const
|
||||||
return MUST(String::from_utf8(CSS::string_from_property_id(m_properties[index].property_id)));
|
return MUST(String::from_utf8(CSS::string_from_property_id(m_properties[index].property_id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSS::PropertyID PropertyOwningCSSStyleDeclaration::property_id_by_index(size_t index) const
|
|
||||||
{
|
|
||||||
return m_properties[index].property_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS::NonnullGCPtr<ElementInlineCSSStyleDeclaration> ElementInlineCSSStyleDeclaration::create(DOM::Element& element, Vector<StyleProperty> properties, HashMap<FlyString, StyleProperty> custom_properties)
|
JS::NonnullGCPtr<ElementInlineCSSStyleDeclaration> ElementInlineCSSStyleDeclaration::create(DOM::Element& element, Vector<StyleProperty> properties, HashMap<FlyString, StyleProperty> custom_properties)
|
||||||
{
|
{
|
||||||
auto& realm = element.realm();
|
auto& realm = element.realm();
|
||||||
|
|
|
@ -24,7 +24,6 @@ public:
|
||||||
|
|
||||||
virtual size_t length() const = 0;
|
virtual size_t length() const = 0;
|
||||||
virtual String item(size_t index) const = 0;
|
virtual String item(size_t index) const = 0;
|
||||||
virtual CSS::PropertyID property_id_by_index(size_t index) const = 0;
|
|
||||||
|
|
||||||
virtual Optional<StyleProperty> property(PropertyID) const = 0;
|
virtual Optional<StyleProperty> property(PropertyID) const = 0;
|
||||||
|
|
||||||
|
@ -64,7 +63,6 @@ public:
|
||||||
|
|
||||||
virtual size_t length() const override;
|
virtual size_t length() const override;
|
||||||
virtual String item(size_t index) const override;
|
virtual String item(size_t index) const override;
|
||||||
virtual CSS::PropertyID property_id_by_index(size_t index) const override;
|
|
||||||
|
|
||||||
virtual Optional<StyleProperty> property(PropertyID) const override;
|
virtual Optional<StyleProperty> property(PropertyID) const override;
|
||||||
|
|
||||||
|
|
|
@ -82,11 +82,6 @@ String ResolvedCSSStyleDeclaration::item(size_t index) const
|
||||||
return MUST(String::from_utf8(string_from_property_id(property_id)));
|
return MUST(String::from_utf8(string_from_property_id(property_id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSS::PropertyID ResolvedCSSStyleDeclaration::property_id_by_index(size_t index) const
|
|
||||||
{
|
|
||||||
return static_cast<PropertyID>(index + to_underlying(first_longhand_property_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
static NonnullRefPtr<StyleValue const> style_value_for_background_property(Layout::NodeWithStyle const& layout_node, Function<NonnullRefPtr<StyleValue const>(BackgroundLayerData const&)> callback, Function<NonnullRefPtr<StyleValue const>()> default_value)
|
static NonnullRefPtr<StyleValue const> style_value_for_background_property(Layout::NodeWithStyle const& layout_node, Function<NonnullRefPtr<StyleValue const>(BackgroundLayerData const&)> callback, Function<NonnullRefPtr<StyleValue const>()> default_value)
|
||||||
{
|
{
|
||||||
auto const& background_layers = layout_node.background_layers();
|
auto const& background_layers = layout_node.background_layers();
|
||||||
|
|
|
@ -21,7 +21,6 @@ public:
|
||||||
|
|
||||||
virtual size_t length() const override;
|
virtual size_t length() const override;
|
||||||
virtual String item(size_t index) const override;
|
virtual String item(size_t index) const override;
|
||||||
virtual CSS::PropertyID property_id_by_index(size_t index) const override;
|
|
||||||
|
|
||||||
virtual Optional<StyleProperty> property(PropertyID) const override;
|
virtual Optional<StyleProperty> property(PropertyID) const override;
|
||||||
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority) override;
|
virtual WebIDL::ExceptionOr<void> set_property(PropertyID, StringView css_text, StringView priority) override;
|
||||||
|
|
|
@ -2136,6 +2136,20 @@ ErrorOr<RefPtr<StyleProperties>> StyleComputer::compute_style_impl(DOM::Element&
|
||||||
{
|
{
|
||||||
build_rule_cache_if_needed();
|
build_rule_cache_if_needed();
|
||||||
|
|
||||||
|
// Special path for elements that use pseudo element as style selector
|
||||||
|
if (element.use_pseudo_element().has_value()) {
|
||||||
|
auto& parent_element = verify_cast<HTML::HTMLElement>(*element.root().parent_or_shadow_host());
|
||||||
|
auto style = TRY(compute_style(parent_element, *element.use_pseudo_element()));
|
||||||
|
|
||||||
|
// Merge back inline styles
|
||||||
|
if (element.has_attribute(HTML::AttributeNames::style)) {
|
||||||
|
auto* inline_style = parse_css_style_attribute(CSS::Parser::ParsingContext(document()), *element.get_attribute(HTML::AttributeNames::style), element);
|
||||||
|
for (auto const& property : inline_style->properties())
|
||||||
|
style->set_property(property.property_id, property.value);
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
auto style = StyleProperties::create();
|
auto style = StyleProperties::create();
|
||||||
// 1. Perform the cascade. This produces the "specified style"
|
// 1. Perform the cascade. This produces the "specified style"
|
||||||
bool did_match_any_pseudo_element_rules = false;
|
bool did_match_any_pseudo_element_rules = false;
|
||||||
|
|
|
@ -55,7 +55,6 @@ WebIDL::ExceptionOr<void> HTMLMeterElement::set_value(double value)
|
||||||
{
|
{
|
||||||
TRY(set_attribute(HTML::AttributeNames::value, MUST(String::number(value))));
|
TRY(set_attribute(HTML::AttributeNames::value, MUST(String::number(value))));
|
||||||
update_meter_value_element();
|
update_meter_value_element();
|
||||||
document().invalidate_layout();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +73,6 @@ WebIDL::ExceptionOr<void> HTMLMeterElement::set_min(double value)
|
||||||
{
|
{
|
||||||
TRY(set_attribute(HTML::AttributeNames::min, MUST(String::number(value))));
|
TRY(set_attribute(HTML::AttributeNames::min, MUST(String::number(value))));
|
||||||
update_meter_value_element();
|
update_meter_value_element();
|
||||||
document().invalidate_layout();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +94,6 @@ WebIDL::ExceptionOr<void> HTMLMeterElement::set_max(double value)
|
||||||
{
|
{
|
||||||
TRY(set_attribute(HTML::AttributeNames::max, MUST(String::number(value))));
|
TRY(set_attribute(HTML::AttributeNames::max, MUST(String::number(value))));
|
||||||
update_meter_value_element();
|
update_meter_value_element();
|
||||||
document().invalidate_layout();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +117,6 @@ WebIDL::ExceptionOr<void> HTMLMeterElement::set_low(double value)
|
||||||
{
|
{
|
||||||
TRY(set_attribute(HTML::AttributeNames::low, MUST(String::number(value))));
|
TRY(set_attribute(HTML::AttributeNames::low, MUST(String::number(value))));
|
||||||
update_meter_value_element();
|
update_meter_value_element();
|
||||||
document().invalidate_layout();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +140,6 @@ WebIDL::ExceptionOr<void> HTMLMeterElement::set_high(double value)
|
||||||
{
|
{
|
||||||
TRY(set_attribute(HTML::AttributeNames::high, MUST(String::number(value))));
|
TRY(set_attribute(HTML::AttributeNames::high, MUST(String::number(value))));
|
||||||
update_meter_value_element();
|
update_meter_value_element();
|
||||||
document().invalidate_layout();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +163,6 @@ WebIDL::ExceptionOr<void> HTMLMeterElement::set_optimum(double value)
|
||||||
{
|
{
|
||||||
TRY(set_attribute(HTML::AttributeNames::optimum, MUST(String::number(value))));
|
TRY(set_attribute(HTML::AttributeNames::optimum, MUST(String::number(value))));
|
||||||
update_meter_value_element();
|
update_meter_value_element();
|
||||||
document().invalidate_layout();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,6 @@ WebIDL::ExceptionOr<void> HTMLProgressElement::set_value(double value)
|
||||||
|
|
||||||
TRY(set_attribute(HTML::AttributeNames::value, MUST(String::number(value))));
|
TRY(set_attribute(HTML::AttributeNames::value, MUST(String::number(value))));
|
||||||
update_progress_value_element();
|
update_progress_value_element();
|
||||||
document().invalidate_layout();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +73,6 @@ WebIDL::ExceptionOr<void> HTMLProgressElement::set_max(double value)
|
||||||
|
|
||||||
TRY(set_attribute(HTML::AttributeNames::max, MUST(String::number(value))));
|
TRY(set_attribute(HTML::AttributeNames::max, MUST(String::number(value))));
|
||||||
update_progress_value_element();
|
update_progress_value_element();
|
||||||
document().invalidate_layout();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,7 +213,6 @@ WebIDL::ExceptionOr<void> HTMLSelectElement::set_value(String const& value)
|
||||||
for (auto const& option_element : list_of_options())
|
for (auto const& option_element : list_of_options())
|
||||||
option_element->set_selected(option_element->value() == value);
|
option_element->set_selected(option_element->value() == value);
|
||||||
update_inner_text_element();
|
update_inner_text_element();
|
||||||
document().invalidate_layout();
|
|
||||||
|
|
||||||
// When the user agent is to send select update notifications, queue an element task on the user interaction task source given the select element to run these steps:
|
// When the user agent is to send select update notifications, queue an element task on the user interaction task source given the select element to run these steps:
|
||||||
queue_an_element_task(HTML::Task::Source::UserInteraction, [this] {
|
queue_an_element_task(HTML::Task::Source::UserInteraction, [this] {
|
||||||
|
@ -323,7 +322,6 @@ void HTMLSelectElement::form_associated_element_was_inserted()
|
||||||
if (options.size() > 0) {
|
if (options.size() > 0) {
|
||||||
options.at(0)->set_selected(true);
|
options.at(0)->set_selected(true);
|
||||||
update_inner_text_element();
|
update_inner_text_element();
|
||||||
document().invalidate_layout();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -313,32 +313,10 @@ ErrorOr<void> TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::
|
||||||
|
|
||||||
if (is<DOM::Element>(dom_node)) {
|
if (is<DOM::Element>(dom_node)) {
|
||||||
auto& element = static_cast<DOM::Element&>(dom_node);
|
auto& element = static_cast<DOM::Element&>(dom_node);
|
||||||
|
element.clear_pseudo_element_nodes({});
|
||||||
// Special path for elements that use pseudo element as style selector.
|
VERIFY(!element.needs_style_update());
|
||||||
if (element.use_pseudo_element().has_value()) {
|
style = element.computed_css_values();
|
||||||
// Get base psuedo element selector style properties
|
display = style->display();
|
||||||
auto& parent_element = verify_cast<HTML::HTMLElement>(*element.root().parent_or_shadow_host());
|
|
||||||
style = TRY(style_computer.compute_style(parent_element, *element.use_pseudo_element()));
|
|
||||||
|
|
||||||
// Merge back inline styles
|
|
||||||
auto const* inline_style = element.inline_style();
|
|
||||||
if (inline_style) {
|
|
||||||
auto const& computed_style = element.computed_css_values();
|
|
||||||
for (size_t i = 0; i < inline_style->length(); i++) {
|
|
||||||
auto property_id = inline_style->property_id_by_index(i);
|
|
||||||
if (auto property = computed_style->maybe_null_property(property_id); property)
|
|
||||||
style->set_property(property_id, *property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
display = style->display();
|
|
||||||
}
|
|
||||||
// Common path: this is a regular DOM element. Style should be present already, thanks to Document::update_style().
|
|
||||||
else {
|
|
||||||
element.clear_pseudo_element_nodes({});
|
|
||||||
VERIFY(!element.needs_style_update());
|
|
||||||
style = element.computed_css_values();
|
|
||||||
display = style->display();
|
|
||||||
}
|
|
||||||
if (display.is_none())
|
if (display.is_none())
|
||||||
return {};
|
return {};
|
||||||
layout_node = element.create_layout_node(*style);
|
layout_node = element.create_layout_node(*style);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue