소스 검색

LibWeb: Add fast_is<T>() for some DOM and layout node subclasses

The generic is<T>() uses dynamic_cast which is fine in the majority
of cases, but when one of them shows up in profiles, we can make it
faster by answering the is-a question manually.
Andreas Kling 4 년 전
부모
커밋
fd441b954d

+ 1 - 7
Userland/Libraries/LibWeb/DOM/Element.h

@@ -115,13 +115,7 @@ private:
     Vector<FlyString> m_classes;
 };
 
-}
-
-namespace AK {
 template<>
-inline bool is<Web::DOM::Element>(const Web::DOM::Node& input)
-{
-    return input.is_element();
-}
+inline bool Node::fast_is<Element>() const { return is_element(); }
 
 }

+ 3 - 0
Userland/Libraries/LibWeb/DOM/Node.h

@@ -143,6 +143,9 @@ public:
 
     virtual EventTarget* get_parent(const Event&) override;
 
+    template<typename T>
+    bool fast_is() const = delete;
+
 protected:
     Node(Document&, NodeType);
 

+ 6 - 0
Userland/Libraries/LibWeb/Layout/BlockBox.h

@@ -52,8 +52,14 @@ public:
     void for_each_fragment(Callback) const;
 
     virtual void split_into_lines(InlineFormattingContext&, LayoutMode) override;
+
+private:
+    virtual bool is_block_box() const final { return true; }
 };
 
+template<>
+inline bool Node::fast_is<BlockBox>() const { return is_block_box(); }
+
 template<typename Callback>
 void BlockBox::for_each_fragment(Callback callback)
 {

+ 1 - 7
Userland/Libraries/LibWeb/Layout/Box.h

@@ -134,13 +134,7 @@ private:
     OwnPtr<StackingContext> m_stacking_context;
 };
 
-}
-
-namespace AK {
 template<>
-inline bool is<Web::Layout::Box>(const Web::Layout::Node& input)
-{
-    return input.is_box();
-}
+inline bool Node::fast_is<Box>() const { return is_box(); }
 
 }

+ 3 - 3
Userland/Libraries/LibWeb/Layout/Node.cpp

@@ -67,7 +67,7 @@ const BlockBox* Node::containing_block() const
         auto* ancestor = parent();
         while (ancestor && !is<BlockBox>(*ancestor))
             ancestor = ancestor->parent();
-        return downcast<BlockBox>(ancestor);
+        return static_cast<const BlockBox*>(ancestor);
     };
 
     if (is<TextNode>(*this))
@@ -79,9 +79,9 @@ const BlockBox* Node::containing_block() const
         auto* ancestor = parent();
         while (ancestor && !ancestor->can_contain_boxes_with_position_absolute())
             ancestor = ancestor->parent();
-        while (ancestor && (!is<BlockBox>(ancestor) || ancestor->is_anonymous()))
+        while (ancestor && (!is<BlockBox>(*ancestor) || ancestor->is_anonymous()))
             ancestor = ancestor->containing_block();
-        return downcast<BlockBox>(ancestor);
+        return static_cast<const BlockBox*>(ancestor);
     }
 
     if (position == CSS::Position::Fixed)

+ 6 - 0
Userland/Libraries/LibWeb/Layout/Node.h

@@ -115,7 +115,13 @@ public:
     virtual void paint_fragment(PaintContext&, const LineBoxFragment&, PaintPhase) const { }
     virtual void after_children_paint(PaintContext&, PaintPhase) {};
 
+    // These are used to optimize hot is<T> variants for some classes where dynamic_cast is too slow.
     virtual bool is_box() const { return false; }
+    virtual bool is_block_box() const { return false; }
+    virtual bool is_text_node() const { return false; }
+
+    template<typename T>
+    bool fast_is() const = delete;
 
     bool is_floating() const;
     bool is_positioned() const;

+ 4 - 0
Userland/Libraries/LibWeb/Layout/TextNode.h

@@ -47,6 +47,7 @@ public:
     virtual void split_into_lines(InlineFormattingContext&, LayoutMode) override;
 
 private:
+    virtual bool is_text_node() const final { return true; }
     void split_into_lines_by_rules(InlineFormattingContext&, LayoutMode, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks);
     void paint_cursor_if_needed(PaintContext&, const LineBoxFragment&) const;
 
@@ -56,4 +57,7 @@ private:
     String m_text_for_rendering;
 };
 
+template<>
+inline bool Node::fast_is<TextNode>() const { return is_text_node(); }
+
 }