Browse Source

LibHTML: LayoutText should always use parent's style properties

This patch makes StyleProperties heap-allocated and ref-counted so that
a LayoutNode can be without one. The ref-counting also allows anonymous
blocks to share style with their parent block.

LayoutText never needs a StyleProperties, since text always inherits
style from its parent element. This is handled by style_properties().
Andreas Kling 5 năm trước cách đây
mục cha
commit
4e35bbffdd

+ 3 - 1
Libraries/LibHTML/CSS/StyleProperties.h

@@ -6,8 +6,10 @@
 
 class Color;
 
-class StyleProperties {
+class StyleProperties : public RefCounted<StyleProperties> {
 public:
+    static NonnullRefPtr<StyleProperties> create() { return adopt(*new StyleProperties); }
+
     template<typename Callback>
     inline void for_each_property(Callback callback) const
     {

+ 5 - 5
Libraries/LibHTML/CSS/StyleResolver.cpp

@@ -57,22 +57,22 @@ NonnullRefPtrVector<StyleRule> StyleResolver::collect_matching_rules(const Eleme
     return matching_rules;
 }
 
-StyleProperties StyleResolver::resolve_style(const Element& element, const StyleProperties* parent_properties) const
+NonnullRefPtr<StyleProperties> StyleResolver::resolve_style(const Element& element, const StyleProperties* parent_properties) const
 {
-    StyleProperties style_properties;
+    auto style_properties = StyleProperties::create();
 
     if (parent_properties) {
         parent_properties->for_each_property([&](const StringView& name, auto& value) {
             // TODO: proper inheritance
             if (name.starts_with("font") || name == "white-space" || name == "color" || name == "text-decoration")
-                style_properties.set_property(name, value);
+                style_properties->set_property(name, value);
         });
     }
 
     auto matching_rules = collect_matching_rules(element);
     for (auto& rule : matching_rules) {
         for (auto& property : rule.declaration().properties()) {
-            style_properties.set_property(property.name, property.value);
+            style_properties->set_property(property.name, property.value);
         }
     }
 
@@ -80,7 +80,7 @@ StyleProperties StyleResolver::resolve_style(const Element& element, const Style
     if (!style_attribute.is_null()) {
         if (auto declaration = parse_css_declaration(style_attribute)) {
             for (auto& property : declaration->properties()) {
-                style_properties.set_property(property.name, property.value);
+                style_properties->set_property(property.name, property.value);
             }
         }
     }

+ 1 - 1
Libraries/LibHTML/CSS/StyleResolver.h

@@ -18,7 +18,7 @@ public:
     Document& document() { return m_document; }
     const Document& document() const { return m_document; }
 
-    StyleProperties resolve_style(const Element&, const StyleProperties* parent_properties) const;
+    NonnullRefPtr<StyleProperties> resolve_style(const Element&, const StyleProperties* parent_properties) const;
 
     NonnullRefPtrVector<StyleRule> collect_matching_rules(const Element&) const;
 

+ 7 - 10
Libraries/LibHTML/DOM/Node.cpp

@@ -22,19 +22,16 @@ Node::~Node()
 RefPtr<LayoutNode> Node::create_layout_node(const StyleResolver& resolver, const StyleProperties* parent_properties) const
 {
     if (is_document())
-        return adopt(*new LayoutDocument(static_cast<const Document&>(*this), {}));
+        return adopt(*new LayoutDocument(static_cast<const Document&>(*this), StyleProperties::create()));
 
-    StyleProperties style_properties;
-    if (is_element())
-        style_properties = resolver.resolve_style(static_cast<const Element&>(*this), parent_properties);
-    else
-        style_properties = *parent_properties;
+    if (is_text())
+        return adopt(*new LayoutText(static_cast<const Text&>(*this)));
+
+    auto style_properties = resolver.resolve_style(static_cast<const Element&>(*this), parent_properties);
 
-    auto display_property = style_properties.property("display");
+    auto display_property = style_properties->property("display");
     String display = display_property.has_value() ? display_property.release_value()->to_string() : "inline";
 
-    if (is_text())
-        return adopt(*new LayoutText(static_cast<const Text&>(*this), move(style_properties)));
     if (display == "none")
         return nullptr;
     if (display == "block" || display == "list-item")
@@ -71,7 +68,7 @@ RefPtr<LayoutNode> Node::create_layout_tree(const StyleResolver& resolver, const
 
     for (auto layout_child : layout_children)
         if (have_block_children && have_inline_children && !layout_child->is_block()) {
-            if (layout_child->is_text() && static_cast<const LayoutText&>(*layout_child).text() == " ")
+            if (layout_child->is_text() && static_cast<const LayoutText&>(*layout_child).text_for_style(*parent_properties) == " ")
                 continue;
             layout_node->inline_wrapper().append_child(*layout_child);
         } else {

+ 2 - 2
Libraries/LibHTML/Layout/LayoutBlock.cpp

@@ -3,7 +3,7 @@
 #include <LibHTML/Layout/LayoutBlock.h>
 #include <LibHTML/Layout/LayoutInline.h>
 
-LayoutBlock::LayoutBlock(const Node* node, StyleProperties&& style_properties)
+LayoutBlock::LayoutBlock(const Node* node, NonnullRefPtr<StyleProperties> style_properties)
     : LayoutNode(node, move(style_properties))
 {
 }
@@ -15,7 +15,7 @@ LayoutBlock::~LayoutBlock()
 LayoutNode& LayoutBlock::inline_wrapper()
 {
     if (!last_child() || !last_child()->is_block() || last_child()->node() != nullptr) {
-        append_child(adopt(*new LayoutBlock(nullptr, {})));
+        append_child(adopt(*new LayoutBlock(nullptr, style_properties())));
     }
     return *last_child();
 }

+ 1 - 1
Libraries/LibHTML/Layout/LayoutBlock.h

@@ -7,7 +7,7 @@ class Element;
 
 class LayoutBlock : public LayoutNode {
 public:
-    LayoutBlock(const Node*, StyleProperties&&);
+    LayoutBlock(const Node*, NonnullRefPtr<StyleProperties>);
     virtual ~LayoutBlock() override;
 
     virtual const char* class_name() const override { return "LayoutBlock"; }

+ 1 - 1
Libraries/LibHTML/Layout/LayoutDocument.cpp

@@ -1,6 +1,6 @@
 #include <LibHTML/Layout/LayoutDocument.h>
 
-LayoutDocument::LayoutDocument(const Document& document, StyleProperties&& style_properties)
+LayoutDocument::LayoutDocument(const Document& document, NonnullRefPtr<StyleProperties> style_properties)
     : LayoutBlock(&document, move(style_properties))
 {
 }

+ 1 - 1
Libraries/LibHTML/Layout/LayoutDocument.h

@@ -5,7 +5,7 @@
 
 class LayoutDocument final : public LayoutBlock {
 public:
-    LayoutDocument(const Document&, StyleProperties&&);
+    explicit LayoutDocument(const Document&, NonnullRefPtr<StyleProperties>);
     virtual ~LayoutDocument() override;
 
     const Document& node() const { return static_cast<const Document&>(*LayoutNode::node()); }

+ 1 - 1
Libraries/LibHTML/Layout/LayoutInline.cpp

@@ -1,7 +1,7 @@
 #include <LibHTML/Layout/LayoutBlock.h>
 #include <LibHTML/Layout/LayoutInline.h>
 
-LayoutInline::LayoutInline(const Node& node, StyleProperties&& style_properties)
+LayoutInline::LayoutInline(const Node& node, RefPtr<StyleProperties> style_properties)
     : LayoutNode(&node, move(style_properties))
 {
 }

+ 1 - 1
Libraries/LibHTML/Layout/LayoutInline.h

@@ -6,7 +6,7 @@ class LayoutBlock;
 
 class LayoutInline : public LayoutNode {
 public:
-    LayoutInline(const Node&, StyleProperties&&);
+    LayoutInline(const Node&, RefPtr<StyleProperties>);
     virtual ~LayoutInline() override;
 
     virtual const char* class_name() const override { return "LayoutInline"; }

+ 2 - 2
Libraries/LibHTML/Layout/LayoutNode.cpp

@@ -7,9 +7,9 @@
 //#define DRAW_BOXES_AROUND_LAYOUT_NODES
 //#define DRAW_BOXES_AROUND_HOVERED_NODES
 
-LayoutNode::LayoutNode(const Node* node, StyleProperties&& style_properties)
+LayoutNode::LayoutNode(const Node* node, RefPtr<StyleProperties> style_properties)
     : m_node(node)
-    , m_style_properties(style_properties)
+    , m_style_properties(move(style_properties))
 {
 }
 

+ 8 - 3
Libraries/LibHTML/Layout/LayoutNode.h

@@ -62,18 +62,23 @@ public:
 
     virtual LayoutNode& inline_wrapper() { return *this; }
 
-    const StyleProperties& style_properties() const { return m_style_properties; }
+    const StyleProperties& style_properties() const
+    {
+        if (m_style_properties)
+            return *m_style_properties;
+        return parent()->style_properties();
+    }
 
     void inserted_into(LayoutNode&) {}
     void removed_from(LayoutNode&) {}
 
 protected:
-    explicit LayoutNode(const Node*, StyleProperties&&);
+    explicit LayoutNode(const Node*, RefPtr<StyleProperties>);
 
 private:
     const Node* m_node { nullptr };
 
-    StyleProperties m_style_properties;
+    RefPtr<StyleProperties> m_style_properties;
     ComputedStyle m_style;
     Rect m_rect;
 };

+ 6 - 5
Libraries/LibHTML/Layout/LayoutText.cpp

@@ -7,8 +7,8 @@
 #include <LibHTML/Layout/LayoutText.h>
 #include <ctype.h>
 
-LayoutText::LayoutText(const Text& text, StyleProperties&& style_properties)
-    : LayoutInline(text, move(style_properties))
+LayoutText::LayoutText(const Text& text)
+    : LayoutInline(text, {})
 {
 }
 
@@ -78,12 +78,13 @@ static bool is_all_whitespace(const String& string)
     return true;
 }
 
-const String& LayoutText::text() const
+const String& LayoutText::text_for_style(const StyleProperties& style_properties) const
 {
     static String one_space = " ";
-    if (is_all_whitespace(node().data()))
-        if (style_properties().string_or_fallback("white-space", "normal") == "normal")
+    if (is_all_whitespace(node().data())) {
+        if (style_properties.string_or_fallback("white-space", "normal") == "normal")
             return one_space;
+    }
     return node().data();
 }
 

+ 4 - 3
Libraries/LibHTML/Layout/LayoutText.h

@@ -8,12 +8,12 @@ class LineBoxFragment;
 
 class LayoutText : public LayoutInline {
 public:
-    LayoutText(const Text&, StyleProperties&&);
+    explicit LayoutText(const Text&);
     virtual ~LayoutText() override;
 
     const Text& node() const { return static_cast<const Text&>(*LayoutNode::node()); }
 
-    const String& text() const;
+    const String& text_for_style(const StyleProperties&) const;
 
     virtual const char* class_name() const override { return "LayoutText"; }
     virtual bool is_text() const final { return true; }
@@ -22,6 +22,8 @@ public:
 
     virtual void split_into_lines(LayoutBlock& container) override;
 
+    const StyleProperties& style_properties() const { return parent()->style_properties(); }
+
 private:
     template<typename Callback>
     void for_each_word(Callback) const;
@@ -29,7 +31,6 @@ private:
     void for_each_source_line(Callback) const;
 
     void load_font();
-    void compute_runs();
 
     RefPtr<Font> m_font;
 };