|
17 | 17 | #include <LibWeb/CSS/PseudoElement.h> |
18 | 18 | #include <LibWeb/CSS/StyleComputer.h> |
19 | 19 | #include <LibWeb/CSS/StyleValues/DisplayStyleValue.h> |
20 | | -#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h> |
21 | 20 | #include <LibWeb/DOM/Document.h> |
22 | 21 | #include <LibWeb/DOM/Element.h> |
23 | 22 | #include <LibWeb/DOM/ParentNode.h> |
|
27 | 26 | #include <LibWeb/HTML/HTMLSlotElement.h> |
28 | 27 | #include <LibWeb/Layout/FieldSetBox.h> |
29 | 28 | #include <LibWeb/Layout/ImageBox.h> |
| 29 | +#include <LibWeb/Layout/InlineNode.h> |
30 | 30 | #include <LibWeb/Layout/ListItemBox.h> |
31 | 31 | #include <LibWeb/Layout/ListItemMarkerBox.h> |
32 | 32 | #include <LibWeb/Layout/Node.h> |
@@ -101,51 +101,53 @@ static Layout::Node& insertion_parent_for_inline_node(Layout::NodeWithStyle& lay |
101 | 101 | static Layout::Node& insertion_parent_for_block_node(Layout::NodeWithStyle& layout_parent, Layout::Node& layout_node) |
102 | 102 | { |
103 | 103 | // Inline is fine for in-flow block children; we'll maintain the (non-)inline invariant after insertion. |
104 | | - if (layout_parent.is_inline() && layout_parent.display().is_flow_inside() && !layout_node.is_out_of_flow()) |
| 104 | + if (!layout_node.is_anonymous() && layout_parent.is_inline() && layout_parent.display().is_flow_inside() && !layout_node.is_out_of_flow()) |
105 | 105 | return layout_parent; |
106 | 106 |
|
107 | | - if (!has_inline_or_in_flow_block_children(layout_parent)) { |
108 | | - // Parent block has no children, insert this block into parent. |
109 | | - return layout_parent; |
110 | | - } |
| 107 | + // Make sure we're not inserting into an inline node, since those do not support block nodes. |
| 108 | + auto* new_parent = &layout_parent; |
| 109 | + while (is<InlineNode>(new_parent)) |
| 110 | + new_parent = new_parent->parent(); |
111 | 111 |
|
112 | | - if (layout_node.is_out_of_flow() |
113 | | - && !layout_parent.display().is_flex_inside() |
114 | | - && !layout_parent.display().is_grid_inside() |
115 | | - && !layout_parent.last_child()->is_generated_for_pseudo_element() |
116 | | - && layout_parent.last_child()->is_anonymous() |
117 | | - && layout_parent.last_child()->children_are_inline()) { |
118 | | - // Block is out-of-flow & previous sibling was wrapped in an anonymous block. |
119 | | - // Join the previous sibling inside the anonymous block. |
120 | | - return *layout_parent.last_child(); |
121 | | - } |
122 | | - |
123 | | - if (!layout_parent.children_are_inline()) { |
124 | | - // Parent block has block-level children, insert this block into parent. |
125 | | - return layout_parent; |
126 | | - } |
| 112 | + // If the parent block has no children, insert this block into parent. |
| 113 | + if (!has_inline_or_in_flow_block_children(*new_parent)) |
| 114 | + return *new_parent; |
127 | 115 |
|
| 116 | + // If the block is out-of-flow, |
128 | 117 | if (layout_node.is_out_of_flow()) { |
129 | | - // Block is out-of-flow, it can have inline siblings if necessary. |
130 | | - return layout_parent; |
| 118 | + // And the parent's last child is an anonymous block, join that anonymous block. |
| 119 | + if (!new_parent->display().is_flex_inside() |
| 120 | + && !new_parent->display().is_grid_inside() |
| 121 | + && !new_parent->last_child()->is_generated_for_pseudo_element() |
| 122 | + && new_parent->last_child()->is_anonymous() |
| 123 | + && new_parent->last_child()->children_are_inline()) { |
| 124 | + return *new_parent->last_child(); |
| 125 | + } |
| 126 | + |
| 127 | + // Otherwise, insert this block into parent. |
| 128 | + return *new_parent; |
131 | 129 | } |
132 | 130 |
|
| 131 | + // If the parent block has block-level children, insert this block into parent. |
| 132 | + if (!new_parent->children_are_inline()) |
| 133 | + return *new_parent; |
| 134 | + |
133 | 135 | // Parent block has inline-level children (our siblings); wrap these siblings into an anonymous wrapper block. |
134 | | - auto wrapper = layout_parent.create_anonymous_wrapper(); |
| 136 | + auto wrapper = new_parent->create_anonymous_wrapper(); |
135 | 137 | wrapper->set_children_are_inline(true); |
136 | 138 |
|
137 | | - for (GC::Ptr<Node> child = layout_parent.first_child(); child;) { |
| 139 | + for (GC::Ptr<Node> child = new_parent->first_child(); child;) { |
138 | 140 | GC::Ptr<Node> next_child = child->next_sibling(); |
139 | | - layout_parent.remove_child(*child); |
| 141 | + new_parent->remove_child(*child); |
140 | 142 | wrapper->append_child(*child); |
141 | 143 | child = next_child; |
142 | 144 | } |
143 | 145 |
|
144 | | - layout_parent.set_children_are_inline(false); |
145 | | - layout_parent.append_child(wrapper); |
| 146 | + new_parent->set_children_are_inline(false); |
| 147 | + new_parent->append_child(wrapper); |
146 | 148 |
|
147 | 149 | // Then it's safe to insert this block into parent. |
148 | | - return layout_parent; |
| 150 | + return *new_parent; |
149 | 151 | } |
150 | 152 |
|
151 | 153 | void TreeBuilder::insert_node_into_inline_or_block_ancestor(Layout::Node& node, CSS::Display display, AppendOrPrepend mode) |
|
0 commit comments