From fd441b954da741e992ac79acfde55cf30ccf0994 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 17 Jan 2021 09:34:01 +0100 Subject: [PATCH] LibWeb: Add fast_is() for some DOM and layout node subclasses The generic is() 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. --- Userland/Libraries/LibWeb/DOM/Element.h | 8 +------- Userland/Libraries/LibWeb/DOM/Node.h | 3 +++ Userland/Libraries/LibWeb/Layout/BlockBox.h | 6 ++++++ Userland/Libraries/LibWeb/Layout/Box.h | 8 +------- Userland/Libraries/LibWeb/Layout/Node.cpp | 6 +++--- Userland/Libraries/LibWeb/Layout/Node.h | 6 ++++++ Userland/Libraries/LibWeb/Layout/TextNode.h | 4 ++++ 7 files changed, 24 insertions(+), 17 deletions(-) diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h index ddefb2ab93..2269ce4c2b 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.h +++ b/Userland/Libraries/LibWeb/DOM/Element.h @@ -115,13 +115,7 @@ private: Vector m_classes; }; -} - -namespace AK { template<> -inline bool is(const Web::DOM::Node& input) -{ - return input.is_element(); -} +inline bool Node::fast_is() const { return is_element(); } } diff --git a/Userland/Libraries/LibWeb/DOM/Node.h b/Userland/Libraries/LibWeb/DOM/Node.h index 624b41b951..d3eaab1b8b 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.h +++ b/Userland/Libraries/LibWeb/DOM/Node.h @@ -143,6 +143,9 @@ public: virtual EventTarget* get_parent(const Event&) override; + template + bool fast_is() const = delete; + protected: Node(Document&, NodeType); diff --git a/Userland/Libraries/LibWeb/Layout/BlockBox.h b/Userland/Libraries/LibWeb/Layout/BlockBox.h index 0062841454..48639ed557 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockBox.h +++ b/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() const { return is_block_box(); } + template void BlockBox::for_each_fragment(Callback callback) { diff --git a/Userland/Libraries/LibWeb/Layout/Box.h b/Userland/Libraries/LibWeb/Layout/Box.h index 7b05b381e3..fbc4850eae 100644 --- a/Userland/Libraries/LibWeb/Layout/Box.h +++ b/Userland/Libraries/LibWeb/Layout/Box.h @@ -134,13 +134,7 @@ private: OwnPtr m_stacking_context; }; -} - -namespace AK { template<> -inline bool is(const Web::Layout::Node& input) -{ - return input.is_box(); -} +inline bool Node::fast_is() const { return is_box(); } } diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index 7af494a0fb..ef4841bccc 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -67,7 +67,7 @@ const BlockBox* Node::containing_block() const auto* ancestor = parent(); while (ancestor && !is(*ancestor)) ancestor = ancestor->parent(); - return downcast(ancestor); + return static_cast(ancestor); }; if (is(*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(ancestor) || ancestor->is_anonymous())) + while (ancestor && (!is(*ancestor) || ancestor->is_anonymous())) ancestor = ancestor->containing_block(); - return downcast(ancestor); + return static_cast(ancestor); } if (position == CSS::Position::Fixed) diff --git a/Userland/Libraries/LibWeb/Layout/Node.h b/Userland/Libraries/LibWeb/Layout/Node.h index c1699924e3..41397762b1 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.h +++ b/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 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 + bool fast_is() const = delete; bool is_floating() const; bool is_positioned() const; diff --git a/Userland/Libraries/LibWeb/Layout/TextNode.h b/Userland/Libraries/LibWeb/Layout/TextNode.h index 03781a22b2..f7c6282957 100644 --- a/Userland/Libraries/LibWeb/Layout/TextNode.h +++ b/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() const { return is_text_node(); } + }