at (14,13) content-size 194x21.84375 flex-item [BFC] children: inline
TextNode <#text>
@@ -13,4 +16,6 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer) [9,9 782x29.84375]
PaintableWithLines (BlockContainer
) [10,10 202x27.84375]
PaintableBox (Box
) [11,11 200x25.84375]
+ PaintableWithLines (BlockContainer(anonymous)) [13,23.921875 0x0]
+ InlinePaintable (InlineNode
)
PaintableWithLines (BlockContainer
) [13,12 196x23.84375]
diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp
index 792922821e..9596f9dedb 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp
+++ b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.cpp
@@ -59,6 +59,11 @@ String PropertyOwningCSSStyleDeclaration::item(size_t index) const
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::create(DOM::Element& element, Vector properties, HashMap custom_properties)
{
auto& realm = element.realm();
diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h
index b485a6169d..864ccfda36 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h
+++ b/Userland/Libraries/LibWeb/CSS/CSSStyleDeclaration.h
@@ -24,6 +24,7 @@ public:
virtual size_t length() const = 0;
virtual String item(size_t index) const = 0;
+ virtual CSS::PropertyID property_id_by_index(size_t index) const = 0;
virtual Optional property(PropertyID) const = 0;
@@ -63,6 +64,7 @@ public:
virtual size_t length() const override;
virtual String item(size_t index) const override;
+ virtual CSS::PropertyID property_id_by_index(size_t index) const override;
virtual Optional property(PropertyID) const override;
diff --git a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp
index 0b2f71d216..a8246800f8 100644
--- a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp
+++ b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.cpp
@@ -82,6 +82,11 @@ String ResolvedCSSStyleDeclaration::item(size_t index) const
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(index + to_underlying(first_longhand_property_id));
+}
+
static NonnullRefPtr style_value_for_background_property(Layout::NodeWithStyle const& layout_node, Function(BackgroundLayerData const&)> callback, Function()> default_value)
{
auto const& background_layers = layout_node.background_layers();
diff --git a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.h b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.h
index a1a02febf5..8682e0ff48 100644
--- a/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.h
+++ b/Userland/Libraries/LibWeb/CSS/ResolvedCSSStyleDeclaration.h
@@ -21,6 +21,8 @@ public:
virtual size_t length() const override;
virtual String item(size_t index) const override;
+ virtual CSS::PropertyID property_id_by_index(size_t index) const override;
+
virtual Optional property(PropertyID) const override;
virtual WebIDL::ExceptionOr set_property(PropertyID, StringView css_text, StringView priority) override;
virtual WebIDL::ExceptionOr remove_property(PropertyID) override;
diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h
index c3c52f6e34..9a53db04c9 100644
--- a/Userland/Libraries/LibWeb/DOM/Element.h
+++ b/Userland/Libraries/LibWeb/DOM/Element.h
@@ -173,7 +173,8 @@ public:
RequiredInvalidationAfterStyleChange recompute_style();
- virtual Optional pseudo_element() const { return {}; }
+ Optional use_pseudo_element() const { return m_use_pseudo_element; }
+ void set_use_pseudo_element(Optional use_pseudo_element) { m_use_pseudo_element = use_pseudo_element; }
Layout::NodeWithStyle* layout_node();
Layout::NodeWithStyle const* layout_node() const;
@@ -413,6 +414,8 @@ private:
mutable OwnPtr m_pseudo_element_custom_properties;
PseudoElementCustomProperties& pseudo_element_custom_properties() const;
+ Optional m_use_pseudo_element {};
+
Vector m_classes;
Optional m_dir;
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
index e1004bc18a..5d648ec339 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
@@ -524,20 +524,6 @@ Optional HTMLInputElement::placeholder_value() const
return placeholder;
}
-class PlaceholderElement final : public HTMLDivElement {
- JS_CELL(PlaceholderElement, HTMLDivElement);
- JS_DECLARE_ALLOCATOR(PlaceholderElement);
-
-public:
- PlaceholderElement(DOM::Document& document)
- : HTMLDivElement(document, DOM::QualifiedName { HTML::TagNames::div, ""_fly_string, Namespace::HTML })
- {
- }
- virtual Optional pseudo_element() const override { return CSS::Selector::PseudoElement::Placeholder; }
-};
-
-JS_DEFINE_ALLOCATOR(PlaceholderElement);
-
void HTMLInputElement::create_shadow_tree_if_needed()
{
if (shadow_root_internal())
@@ -579,7 +565,8 @@ void HTMLInputElement::create_text_input_shadow_tree()
)~~~"_string));
MUST(shadow_root->append_child(element));
- m_placeholder_element = heap().allocate(realm(), document());
+ m_placeholder_element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML));
+ m_placeholder_element->set_use_pseudo_element(CSS::Selector::PseudoElement::Placeholder);
MUST(m_placeholder_element->set_attribute(HTML::AttributeNames::style, R"~~~(
flex: 1;
height: 1lh;
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMeterElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLMeterElement.cpp
index efae3276df..5aa8c39bac 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLMeterElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLMeterElement.cpp
@@ -6,9 +6,11 @@
*/
#include
+#include
#include
#include
#include
+#include
namespace Web::HTML {
@@ -188,10 +190,11 @@ void HTMLMeterElement::create_shadow_tree_if_needed()
auto shadow_root = heap().allocate(realm(), document(), *this, Bindings::ShadowRootMode::Closed);
set_shadow_root(shadow_root);
- auto meter_bar_element = heap().allocate(realm(), document());
+ auto meter_bar_element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML));
+ meter_bar_element->set_use_pseudo_element(CSS::Selector::PseudoElement::MeterBar);
MUST(shadow_root->append_child(*meter_bar_element));
- m_meter_value_element = heap().allocate(realm(), document());
+ m_meter_value_element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML));
MUST(meter_bar_element->append_child(*m_meter_value_element));
update_meter_value_element();
}
@@ -212,26 +215,26 @@ void HTMLMeterElement::update_meter_value_element()
// If the optimum point is equal to the low boundary or the high boundary, or anywhere in between them, then the region between the low and high boundaries of the gauge must be treated as the optimum region, and the low and high parts, if any, must be treated as suboptimal.
if (optimum >= low && optimum <= high) {
if (value >= low && value <= high)
- m_meter_value_element->set_pseudo_element(CSS::Selector::PseudoElement::MeterOptimumValue);
+ m_meter_value_element->set_use_pseudo_element(CSS::Selector::PseudoElement::MeterOptimumValue);
else
- m_meter_value_element->set_pseudo_element(CSS::Selector::PseudoElement::MeterSuboptimumValue);
+ m_meter_value_element->set_use_pseudo_element(CSS::Selector::PseudoElement::MeterSuboptimumValue);
}
// Otherwise, if the optimum point is less than the low boundary, then the region between the minimum value and the low boundary must be treated as the optimum region, the region from the low boundary up to the high boundary must be treated as a suboptimal region, and the remaining region must be treated as an even less good region.
else if (optimum < low) {
if (value >= low && value <= high)
- m_meter_value_element->set_pseudo_element(CSS::Selector::PseudoElement::MeterSuboptimumValue);
+ m_meter_value_element->set_use_pseudo_element(CSS::Selector::PseudoElement::MeterSuboptimumValue);
else
- m_meter_value_element->set_pseudo_element(CSS::Selector::PseudoElement::MeterEvenLessGoodValue);
+ m_meter_value_element->set_use_pseudo_element(CSS::Selector::PseudoElement::MeterEvenLessGoodValue);
}
// Finally, if the optimum point is higher than the high boundary, then the situation is reversed; the region between the high boundary and the maximum value must be treated as the optimum region, the region from the high boundary down to the low boundary must be treated as a suboptimal region, and the remaining region must be treated as an even less good region.
else {
if (value >= low && value <= high)
- m_meter_value_element->set_pseudo_element(CSS::Selector::PseudoElement::MeterSuboptimumValue);
+ m_meter_value_element->set_use_pseudo_element(CSS::Selector::PseudoElement::MeterSuboptimumValue);
else
- m_meter_value_element->set_pseudo_element(CSS::Selector::PseudoElement::MeterEvenLessGoodValue);
+ m_meter_value_element->set_use_pseudo_element(CSS::Selector::PseudoElement::MeterEvenLessGoodValue);
}
double position = (value - min) / (max - min) * 100;
- MUST(m_meter_value_element->set_attribute(HTML::AttributeNames::style, MUST(String::formatted("width: {}%;", position))));
+ MUST(m_meter_value_element->style_for_bindings()->set_property(CSS::PropertyID::Width, MUST(String::formatted("{}%", position))));
}
}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMeterElement.h b/Userland/Libraries/LibWeb/HTML/HTMLMeterElement.h
index 391da7867e..1ac3d39d04 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLMeterElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLMeterElement.h
@@ -9,39 +9,10 @@
#pragma once
#include
-#include
#include
-#include
namespace Web::HTML {
-class MeterBarElement final : public HTMLDivElement {
- JS_CELL(MeterBarElement, HTMLDivElement);
-
-public:
- MeterBarElement(DOM::Document& document)
- : HTMLDivElement(document, DOM::QualifiedName { HTML::TagNames::div, ""_fly_string, Namespace::HTML })
- {
- }
- virtual Optional pseudo_element() const override { return CSS::Selector::PseudoElement::MeterBar; }
-};
-
-class MeterValueElement final : public HTMLDivElement {
- JS_CELL(MeterValueElement, HTMLDivElement);
-
-public:
- MeterValueElement(DOM::Document& document)
- : HTMLDivElement(document, DOM::QualifiedName { HTML::TagNames::div, ""_fly_string, Namespace::HTML })
- {
- }
- virtual Optional pseudo_element() const override { return m_pseudo_element; }
-
- void set_pseudo_element(CSS::Selector::PseudoElement pseudo_element) { m_pseudo_element = pseudo_element; }
-
-private:
- CSS::Selector::PseudoElement m_pseudo_element;
-};
-
class HTMLMeterElement final : public HTMLElement {
WEB_PLATFORM_OBJECT(HTMLMeterElement, HTMLElement);
JS_DECLARE_ALLOCATOR(HTMLMeterElement);
@@ -82,7 +53,7 @@ private:
void update_meter_value_element();
- JS::GCPtr m_meter_value_element;
+ JS::GCPtr m_meter_value_element;
};
}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.cpp
index 3368460dbd..e7d9da40a7 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.cpp
@@ -7,9 +7,11 @@
*/
#include
+#include
#include
#include
#include
+#include
namespace Web::HTML {
@@ -102,17 +104,19 @@ void HTMLProgressElement::create_shadow_tree_if_needed()
auto shadow_root = heap().allocate(realm(), document(), *this, Bindings::ShadowRootMode::Closed);
set_shadow_root(shadow_root);
- auto progress_bar_element = heap().allocate(realm(), document());
+ auto progress_bar_element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML));
+ progress_bar_element->set_use_pseudo_element(CSS::Selector::PseudoElement::ProgressBar);
MUST(shadow_root->append_child(*progress_bar_element));
- m_progress_value_element = heap().allocate(realm(), document());
+ m_progress_value_element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML));
+ m_progress_value_element->set_use_pseudo_element(CSS::Selector::PseudoElement::ProgressValue);
MUST(progress_bar_element->append_child(*m_progress_value_element));
update_progress_value_element();
}
void HTMLProgressElement::update_progress_value_element()
{
- MUST(m_progress_value_element->set_attribute(HTML::AttributeNames::style, MUST(String::formatted("width: {}%;", position() * 100))));
+ MUST(m_progress_value_element->style_for_bindings()->set_property(CSS::PropertyID::Width, MUST(String::formatted("{}%", position() * 100))));
}
}
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.h b/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.h
index 089c37217b..de8f266f83 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.h
@@ -8,34 +8,10 @@
#pragma once
#include
-#include
#include
-#include
namespace Web::HTML {
-class ProgressBarElement final : public HTMLDivElement {
- JS_CELL(ProgressBarElement, HTMLDivElement);
-
-public:
- ProgressBarElement(DOM::Document& document)
- : HTMLDivElement(document, DOM::QualifiedName { HTML::TagNames::div, ""_fly_string, Namespace::HTML })
- {
- }
- virtual Optional pseudo_element() const override { return CSS::Selector::PseudoElement::ProgressBar; }
-};
-
-class ProgressValueElement final : public HTMLDivElement {
- JS_CELL(ProgressValueElement, HTMLDivElement);
-
-public:
- ProgressValueElement(DOM::Document& document)
- : HTMLDivElement(document, DOM::QualifiedName { HTML::TagNames::div, ""_fly_string, Namespace::HTML })
- {
- }
- virtual Optional pseudo_element() const override { return CSS::Selector::PseudoElement::ProgressValue; }
-};
-
class HTMLProgressElement final : public HTMLElement {
WEB_PLATFORM_OBJECT(HTMLProgressElement, HTMLElement);
JS_DECLARE_ALLOCATOR(HTMLProgressElement);
@@ -76,7 +52,7 @@ private:
bool is_determinate() const { return has_attribute(HTML::AttributeNames::value); }
- JS::GCPtr m_progress_value_element;
+ JS::GCPtr m_progress_value_element;
};
}
diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp
index 9176153126..c7ba7165b1 100644
--- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp
+++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp
@@ -307,21 +307,23 @@ ErrorOr TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::
if (is(dom_node)) {
auto& element = static_cast(dom_node);
- // Special path for elements that use pseudo selectors.
- // FIXME: This is very hackish. Find a better way to architect this.
- if (element.pseudo_element() == CSS::Selector::PseudoElement::Placeholder || element.pseudo_element() == CSS::Selector::PseudoElement::MeterBar || element.pseudo_element() == CSS::Selector::PseudoElement::MeterOptimumValue || element.pseudo_element() == CSS::Selector::PseudoElement::MeterSuboptimumValue || element.pseudo_element() == CSS::Selector::PseudoElement::MeterEvenLessGoodValue || element.pseudo_element() == CSS::Selector::PseudoElement::ProgressBar || element.pseudo_element() == CSS::Selector::PseudoElement::ProgressValue) {
+ // Special path for elements that use pseudo element as style selector.
+ if (element.use_pseudo_element().has_value()) {
+ // Get base psuedo element selector style properties
auto& parent_element = verify_cast(*element.root().parent_or_shadow_host());
- style = TRY(style_computer.compute_style(parent_element, element.pseudo_element()));
+ 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();
- if (element.pseudo_element() == CSS::Selector::PseudoElement::Placeholder) {
- auto& input_element = verify_cast(parent_element);
- if (!input_element.placeholder_value().has_value())
- display = CSS::Display::from_short(CSS::Display::Short::None);
- }
- if (element.pseudo_element() == CSS::Selector::PseudoElement::MeterOptimumValue || element.pseudo_element() == CSS::Selector::PseudoElement::MeterSuboptimumValue || element.pseudo_element() == CSS::Selector::PseudoElement::MeterEvenLessGoodValue || element.pseudo_element() == CSS::Selector::PseudoElement::ProgressValue) {
- auto computed_style = element.computed_css_values();
- style->set_property(CSS::PropertyID::Width, computed_style->property(CSS::PropertyID::Width));
- }
}
// Common path: this is a regular DOM element. Style should be present already, thanks to Document::update_style().
else {