Forráskód Böngészése

LibWeb: Use `IterationDecision` in single level Node iteration methods

`Node::for_each_child()` and `Node::for_each_child_of_type()` callbacks
now return an `IterationDecision`, which allows us to break early if
required.
Tim Ledbetter 1 éve
szülő
commit
c57d395a48
25 módosított fájl, 81 hozzáadás és 27 törlés
  1. 12 2
      Userland/Libraries/LibWeb/DOM/Node.cpp
  2. 8 4
      Userland/Libraries/LibWeb/DOM/Node.h
  3. 8 4
      Userland/Libraries/LibWeb/DOM/ParentNode.h
  4. 3 1
      Userland/Libraries/LibWeb/DOM/Slottable.cpp
  5. 2 0
      Userland/Libraries/LibWeb/Dump.cpp
  6. 1 0
      Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp
  7. 1 0
      Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp
  8. 2 0
      Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp
  9. 3 0
      Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp
  10. 2 0
      Userland/Libraries/LibWeb/HTML/HTMLTemplateElement.cpp
  11. 2 2
      Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp
  12. 1 0
      Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp
  13. 1 0
      Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp
  14. 1 0
      Userland/Libraries/LibWeb/Layout/FormattingContext.cpp
  15. 1 0
      Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp
  16. 2 0
      Userland/Libraries/LibWeb/Layout/LayoutState.cpp
  17. 1 0
      Userland/Libraries/LibWeb/Layout/Node.cpp
  18. 5 1
      Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp
  19. 1 0
      Userland/Libraries/LibWeb/Layout/TableGrid.h
  20. 3 0
      Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp
  21. 5 4
      Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp
  22. 6 4
      Userland/Libraries/LibWeb/Painting/StackingContext.cpp
  23. 1 1
      Userland/Libraries/LibWeb/Painting/TableBordersPainting.cpp
  24. 1 0
      Userland/Libraries/LibWeb/SVG/SVGGradientElement.h
  25. 8 4
      Userland/Libraries/LibWeb/TreeNode.h

+ 12 - 2
Userland/Libraries/LibWeb/DOM/Node.cpp

@@ -300,6 +300,7 @@ String Node::child_text_content() const
             if (maybe_content.has_value())
                 builder.append(maybe_content.value());
         }
+        return IterationDecision::Continue;
     });
     return MUST(builder.to_string());
 }
@@ -903,6 +904,7 @@ JS::NonnullGCPtr<Node> Node::clone_node(Document* document, bool clone_children)
     if (clone_children) {
         for_each_child([&](auto& child) {
             MUST(copy->append_child(child.clone_node(document, true)));
+            return IterationDecision::Continue;
         });
     }
 
@@ -1032,6 +1034,7 @@ Vector<JS::Handle<Node>> Node::children_as_vector() const
 
     for_each_child([&](auto& child) {
         nodes.append(JS::make_handle(child));
+        return IterationDecision::Continue;
     });
 
     return nodes;
@@ -1223,10 +1226,11 @@ void Node::serialize_tree_as_json(JsonObjectSerializer<StringBuilder>& object) c
         auto children = MUST(object.add_array("children"sv));
         auto add_child = [&children](DOM::Node const& child) {
             if (child.is_uninteresting_whitespace_node())
-                return;
+                return IterationDecision::Continue;
             JsonObjectSerializer<StringBuilder> child_object = MUST(children.add_object());
             child.serialize_tree_as_json(child_object);
             MUST(child_object.finish());
+            return IterationDecision::Continue;
         };
         for_each_child(add_child);
 
@@ -1741,6 +1745,7 @@ void Node::build_accessibility_tree(AccessibilityTreeNode& parent)
             if (document_element->has_child_nodes())
                 document_element->for_each_child([&parent](DOM::Node& child) {
                     child.build_accessibility_tree(parent);
+                    return IterationDecision::Continue;
                 });
         }
     } else if (is_element()) {
@@ -1755,11 +1760,13 @@ void Node::build_accessibility_tree(AccessibilityTreeNode& parent)
             if (has_child_nodes()) {
                 for_each_child([&current_node](DOM::Node& child) {
                     child.build_accessibility_tree(*current_node);
+                    return IterationDecision::Continue;
                 });
             }
         } else if (has_child_nodes()) {
             for_each_child([&parent](DOM::Node& child) {
                 child.build_accessibility_tree(parent);
+                return IterationDecision::Continue;
             });
         }
     } else if (is_text()) {
@@ -1767,6 +1774,7 @@ void Node::build_accessibility_tree(AccessibilityTreeNode& parent)
         if (has_child_nodes()) {
             for_each_child([&parent](DOM::Node& child) {
                 child.build_accessibility_tree(parent);
+                return IterationDecision::Continue;
             });
         }
     }
@@ -1865,7 +1873,7 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
             element->for_each_child([&total_accumulated_text, current_node, target, &document, &visited_nodes](
                                         DOM::Node const& child_node) mutable {
                 if (visited_nodes.contains(child_node.unique_id()))
-                    return;
+                    return IterationDecision::Continue;
 
                 // a. Set the current node to the child node.
                 current_node = &child_node;
@@ -1875,6 +1883,8 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
 
                 // c. Append the result to the accumulated text.
                 total_accumulated_text.append(result);
+
+                return IterationDecision::Continue;
             });
             // iv. Return the accumulated text.
             return total_accumulated_text.to_string();

+ 8 - 4
Userland/Libraries/LibWeb/DOM/Node.h

@@ -560,16 +560,20 @@ public:
     template<typename Callback>
     void for_each_child(Callback callback)
     {
-        for (auto* node = first_child(); node; node = node->next_sibling())
-            callback(*node);
+        for (auto* node = first_child(); node; node = node->next_sibling()) {
+            if (callback(*node) == IterationDecision::Break)
+                return;
+        }
     }
 
     template<typename U, typename Callback>
     void for_each_child_of_type(Callback callback)
     {
         for (auto* node = first_child(); node; node = node->next_sibling()) {
-            if (is<U>(node))
-                callback(verify_cast<U>(*node));
+            if (is<U>(node)) {
+                if (callback(verify_cast<U>(*node)) == IterationDecision::Break)
+                    return;
+            }
         }
     }
 

+ 8 - 4
Userland/Libraries/LibWeb/DOM/ParentNode.h

@@ -70,15 +70,19 @@ inline U* Node::shadow_including_first_ancestor_of_type()
 template<typename Callback>
 inline void ParentNode::for_each_child(Callback callback) const
 {
-    for (auto* node = first_child(); node; node = node->next_sibling())
-        callback(*node);
+    for (auto* node = first_child(); node; node = node->next_sibling()) {
+        if (callback(*node) == IterationDecision::Break)
+            return;
+    }
 }
 
 template<typename Callback>
 inline void ParentNode::for_each_child(Callback callback)
 {
-    for (auto* node = first_child(); node; node = node->next_sibling())
-        callback(*node);
+    for (auto* node = first_child(); node; node = node->next_sibling()) {
+        if (callback(*node) == IterationDecision::Break)
+            return;
+    }
 }
 
 }

+ 3 - 1
Userland/Libraries/LibWeb/DOM/Slottable.cpp

@@ -134,7 +134,7 @@ Vector<Slottable> find_slottables(JS::NonnullGCPtr<HTML::HTMLSlotElement> slot)
     else {
         host->for_each_child([&](auto& node) {
             if (!node.is_slottable())
-                return;
+                return IterationDecision::Continue;
 
             auto slottable = node.as_slottable();
 
@@ -144,6 +144,8 @@ Vector<Slottable> find_slottables(JS::NonnullGCPtr<HTML::HTMLSlotElement> slot)
             // 2. If foundSlot is slot, then append slottable to result.
             if (found_slot == slot)
                 result.append(move(slottable));
+
+            return IterationDecision::Continue;
         });
     }
 

+ 2 - 0
Userland/Libraries/LibWeb/Dump.cpp

@@ -118,6 +118,7 @@ void dump_tree(StringBuilder& builder, DOM::Node const& node)
         if (!is<HTML::HTMLTemplateElement>(node)) {
             static_cast<DOM::ParentNode const&>(node).for_each_child([&](auto& child) {
                 dump_tree(builder, child);
+                return IterationDecision::Continue;
             });
         } else {
             auto& template_element = verify_cast<HTML::HTMLTemplateElement>(node);
@@ -403,6 +404,7 @@ void dump_tree(StringBuilder& builder, Layout::Node const& layout_node, bool sho
     ++indent;
     layout_node.for_each_child([&](auto& child) {
         dump_tree(builder, child, show_box_model, show_specified_style, interactive);
+        return IterationDecision::Continue;
     });
     --indent;
 }

+ 1 - 0
Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp

@@ -864,6 +864,7 @@ static void update_the_source_set(DOM::Element& element)
         elements.clear();
         element.parent()->for_each_child_of_type<DOM::Element>([&](auto& child) {
             elements.append(&child);
+            return IterationDecision::Continue;
         });
     }
 

+ 1 - 0
Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp

@@ -135,6 +135,7 @@ void HTMLInputElement::set_checked(bool checked, ChangeSource change_source)
     if (parent()) {
         parent()->for_each_child([&](auto& child) {
             child.invalidate_style();
+            return IterationDecision::Continue;
         });
     }
 }

+ 2 - 0
Userland/Libraries/LibWeb/HTML/HTMLOptionElement.cpp

@@ -85,6 +85,7 @@ static void concatenate_descendants_text_content(DOM::Node const* node, StringBu
         builder.append(verify_cast<DOM::Text>(node)->data());
     node->for_each_child([&](auto const& node) {
         concatenate_descendants_text_content(&node, builder);
+        return IterationDecision::Continue;
     });
 }
 
@@ -98,6 +99,7 @@ String HTMLOptionElement::text() const
     // script or SVG script elements.
     for_each_child([&](auto const& node) {
         concatenate_descendants_text_content(&node, builder);
+        return IterationDecision::Continue;
     });
 
     // Return the result of stripping and collapsing ASCII whitespace from the above concatenation.

+ 3 - 0
Userland/Libraries/LibWeb/HTML/HTMLSelectElement.cpp

@@ -174,12 +174,15 @@ Vector<JS::Handle<HTMLOptionElement>> HTMLSelectElement::list_of_options() const
 
     for_each_child_of_type<HTMLOptionElement>([&](HTMLOptionElement& option_element) {
         list.append(JS::make_handle(option_element));
+        return IterationDecision::Continue;
     });
 
     for_each_child_of_type<HTMLOptGroupElement>([&](HTMLOptGroupElement const& optgroup_element) {
         optgroup_element.for_each_child_of_type<HTMLOptionElement>([&](HTMLOptionElement& option_element) {
             list.append(JS::make_handle(option_element));
+            return IterationDecision::Continue;
         });
+        return IterationDecision::Continue;
     });
 
     return list;

+ 2 - 0
Userland/Libraries/LibWeb/HTML/HTMLTemplateElement.cpp

@@ -58,6 +58,8 @@ void HTMLTemplateElement::cloned(Node& copy, bool clone_children)
 
         // FIXME: Should this use TreeNode::append_child instead?
         MUST(template_clone.content()->append_child(cloned_child));
+
+        return IterationDecision::Continue;
     });
 }
 

+ 2 - 2
Userland/Libraries/LibWeb/HTML/Parser/HTMLParser.cpp

@@ -4418,7 +4418,8 @@ String HTMLParser::serialize_html_fragment(DOM::Node const& node, DOM::FragmentS
         if (is<DOM::Element>(current_node)) {
             // -> If current node is an Element
             auto& element = verify_cast<DOM::Element>(current_node);
-            return serialize_element(element);
+            serialize_element(element);
+            return IterationDecision::Continue;
         }
 
         if (is<DOM::Text>(current_node)) {
@@ -4440,7 +4441,6 @@ String HTMLParser::serialize_html_fragment(DOM::Node const& node, DOM::FragmentS
 
             // 2. Otherwise, append the value of current node's data IDL attribute, escaped as described below.
             builder.append(escape_string(text_node.data(), AttributeMode::No));
-            return IterationDecision::Continue;
         }
 
         if (is<DOM::Comment>(current_node)) {

+ 1 - 0
Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp

@@ -1215,6 +1215,7 @@ CSSPixels BlockFormattingContext::greatest_child_width(Box const& box) const
         box.for_each_child_of_type<Box>([&](Box const& child) {
             if (!child.is_absolutely_positioned())
                 max_width = max(max_width, m_state.get(child).margin_box_width());
+            return IterationDecision::Continue;
         });
     }
     return max_width;

+ 1 - 0
Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp

@@ -199,6 +199,7 @@ void FlexFormattingContext::parent_context_did_dimension_child_root_box()
             auto available_height = AvailableSize::make_definite(cb_state.content_height() + cb_state.padding_top + cb_state.padding_bottom);
             layout_absolutely_positioned_element(box, AvailableSpace(available_width, available_height));
         }
+        return IterationDecision::Continue;
     });
 }
 

+ 1 - 0
Userland/Libraries/LibWeb/Layout/FormattingContext.cpp

@@ -243,6 +243,7 @@ CSSPixels FormattingContext::greatest_child_width(Box const& box) const
         box.for_each_child_of_type<Box>([&](Box const& child) {
             if (!child.is_absolutely_positioned())
                 max_width = max(max_width, m_state.get(child).margin_box_width());
+            return IterationDecision::Continue;
         });
     }
     return max_width;

+ 1 - 0
Userland/Libraries/LibWeb/Layout/GridFormattingContext.cpp

@@ -1940,6 +1940,7 @@ void GridFormattingContext::parent_context_did_dimension_child_root_box()
             auto available_height = AvailableSize::make_definite(cb_state.content_height() + cb_state.padding_top + cb_state.padding_bottom);
             layout_absolutely_positioned_element(box, AvailableSpace(available_width, available_height));
         }
+        return IterationDecision::Continue;
     });
 }
 

+ 2 - 0
Userland/Libraries/LibWeb/Layout/LayoutState.cpp

@@ -127,6 +127,8 @@ static CSSPixelRect measure_scrollable_overflow(Box const& box)
                 for (auto const& fragment : static_cast<Painting::InlinePaintable const&>(*child.paintable()).fragments())
                     scrollable_overflow_rect = scrollable_overflow_rect.united(fragment.absolute_rect());
             }
+
+            return IterationDecision::Continue;
         });
     }
 

+ 1 - 0
Userland/Libraries/LibWeb/Layout/Node.cpp

@@ -882,6 +882,7 @@ void NodeWithStyle::propagate_style_to_anonymous_wrappers()
             auto& child_computed_values = static_cast<CSS::MutableComputedValues&>(static_cast<CSS::ComputedValues&>(const_cast<CSS::ImmutableComputedValues&>(child.computed_values())));
             child_computed_values.inherit_from(computed_values());
         }
+        return IterationDecision::Continue;
     });
 }
 

+ 5 - 1
Userland/Libraries/LibWeb/Layout/SVGFormattingContext.cpp

@@ -250,6 +250,7 @@ void SVGFormattingContext::run(Box const& box, LayoutMode, AvailableSpace const&
 
     box.for_each_child_of_type<Box>([&](Box const& child) {
         layout_svg_element(child);
+        return IterationDecision::Continue;
     });
 }
 
@@ -264,6 +265,7 @@ void SVGFormattingContext::layout_svg_element(Box const& child)
         child_state.set_content_offset(child_state.offset.translated(m_svg_offset));
         child.for_each_child_of_type<SVGMaskBox>([&](SVGMaskBox const& child) {
             layout_svg_element(child);
+            return IterationDecision::Continue;
         });
     } else if (is<SVGGraphicsBox>(child)) {
         layout_graphics_element(static_cast<SVGGraphicsBox const&>(child));
@@ -369,6 +371,7 @@ void SVGFormattingContext::layout_path_like_element(SVGGraphicsBox const& graphi
         text_box.for_each_child_of_type<SVGGraphicsBox>([&](auto& child) {
             if (is<SVGTextBox>(child) || is<SVGTextPathBox>(child))
                 layout_graphics_element(child);
+            return IterationDecision::Continue;
         });
     } else if (is<SVGTextPathBox>(graphics_box)) {
         // FIXME: Support <tspan> in <textPath>.
@@ -446,11 +449,12 @@ void SVGFormattingContext::layout_container_element(SVGBox const& container)
     container.for_each_child_of_type<Box>([&](Box const& child) {
         // Masks/clips do not change the bounding box of their parents.
         if (is<SVGMaskBox>(child) || is<SVGClipBox>(child))
-            return;
+            return IterationDecision::Continue;
         layout_svg_element(child);
         auto& child_state = m_state.get(child);
         bounding_box.add_point(child_state.offset);
         bounding_box.add_point(child_state.offset.translated(child_state.content_width(), child_state.content_height()));
+        return IterationDecision::Continue;
     });
     box_state.set_content_x(bounding_box.x());
     box_state.set_content_y(bounding_box.y());

+ 1 - 0
Userland/Libraries/LibWeb/Layout/TableGrid.h

@@ -76,6 +76,7 @@ public:
         parent.for_each_child_of_type<Box>([&](Box const& child_box) {
             if (matcher(child_box))
                 callback(child_box);
+            return IterationDecision::Continue;
         });
     }
 

+ 3 - 0
Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp

@@ -553,6 +553,7 @@ void TreeBuilder::remove_irrelevant_boxes(NodeWithStyle& root)
     for_each_in_tree_with_internal_display<CSS::DisplayInternal::TableColumn>(root, [&](Box& table_column) {
         table_column.for_each_child([&](auto& child) {
             to_remove.append(child);
+            return IterationDecision::Continue;
         });
     });
 
@@ -561,6 +562,7 @@ void TreeBuilder::remove_irrelevant_boxes(NodeWithStyle& root)
         table_column_group.for_each_child([&](auto& child) {
             if (!child.display().is_table_column())
                 to_remove.append(child);
+            return IterationDecision::Continue;
         });
     });
 
@@ -770,6 +772,7 @@ static void for_each_child_box_matching(Box& parent, Matcher matcher, Callback c
     parent.for_each_child_of_type<Box>([&](Box& child_box) {
         if (matcher(child_box))
             callback(child_box);
+        return IterationDecision::Continue;
     });
 }
 

+ 5 - 4
Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp

@@ -211,12 +211,13 @@ TraversalDecision InlinePaintable::hit_test(CSSPixelPoint position, HitTestType
 
     bool should_exit = false;
     for_each_child([&](Paintable const& child) {
-        if (should_exit)
-            return;
         if (child.stacking_context())
-            return;
-        if (child.hit_test(position, type, callback) == TraversalDecision::Break)
+            return IterationDecision::Continue;
+        if (child.hit_test(position, type, callback) == TraversalDecision::Break) {
             should_exit = true;
+            return IterationDecision::Break;
+        }
+        return IterationDecision::Continue;
     });
 
     if (should_exit)

+ 6 - 4
Userland/Libraries/LibWeb/Painting/StackingContext.cpp

@@ -112,13 +112,13 @@ void StackingContext::paint_descendants(PaintContext& context, Paintable const&
             // FIXME: This may not be fully correct with respect to the paint phases.
             if (phase == StackingContextPaintPhase::Foreground)
                 paint_node_as_stacking_context(child, context);
-            return;
+            return IterationDecision::Continue;
         }
 
         if (stacking_context && z_index.value_or(0) != 0)
-            return;
+            return IterationDecision::Continue;
         if (child.is_positioned() && z_index.value_or(0) == 0)
-            return;
+            return IterationDecision::Continue;
 
         if (stacking_context) {
             // FIXME: This may not be fully correct with respect to the paint phases.
@@ -126,7 +126,7 @@ void StackingContext::paint_descendants(PaintContext& context, Paintable const&
                 paint_child(context, *stacking_context);
             }
             // Note: Don't further recurse into descendants as paint_child() will do that.
-            return;
+            return IterationDecision::Continue;
         }
 
         bool child_is_inline_or_replaced = child.is_inline() || is<Layout::ReplacedBox>(child.layout_node());
@@ -171,6 +171,8 @@ void StackingContext::paint_descendants(PaintContext& context, Paintable const&
             paint_descendants(context, child, phase);
             break;
         }
+
+        return IterationDecision::Continue;
     });
 
     paintable.after_children_paint(context, to_paint_phase(phase));

+ 1 - 1
Userland/Libraries/LibWeb/Painting/TableBordersPainting.cpp

@@ -38,7 +38,7 @@ static void collect_cell_boxes(Vector<PaintableBox const&>& cell_boxes, Paintabl
         } else {
             collect_cell_boxes(cell_boxes, child);
         }
-        return TraversalDecision::Continue;
+        return IterationDecision::Continue;
     });
 }
 

+ 1 - 0
Userland/Libraries/LibWeb/SVG/SVGGradientElement.h

@@ -76,6 +76,7 @@ private:
         for_each_child_of_type<SVG::SVGStopElement>([&](auto& stop) {
             color_stops_found = true;
             callback(stop);
+            return IterationDecision::Continue;
         });
         if (!color_stops_found) {
             if (auto gradient = linked_gradient(seen_gradients))

+ 8 - 4
Userland/Libraries/LibWeb/TreeNode.h

@@ -224,16 +224,20 @@ public:
     template<typename Callback>
     void for_each_child(Callback callback)
     {
-        for (auto* node = first_child(); node; node = node->next_sibling())
-            callback(*node);
+        for (auto* node = first_child(); node; node = node->next_sibling()) {
+            if (callback(*node) == IterationDecision::Break)
+                return;
+        }
     }
 
     template<typename U, typename Callback>
     void for_each_child_of_type(Callback callback)
     {
         for (auto* node = first_child(); node; node = node->next_sibling()) {
-            if (is<U>(node))
-                callback(verify_cast<U>(*node));
+            if (is<U>(node)) {
+                if (callback(verify_cast<U>(*node)) == IterationDecision::Break)
+                    return;
+            }
         }
     }