Sfoglia il codice sorgente

LibWeb: Make pseudo-elements inspectable

This makes it possible to set a pseudo-element as the inspected node
using Document::set_inspected_node(), Document then provides
inspected_layout_node() for the painting related functions.
Simon Wanner 2 anni fa
parent
commit
ee7282cbe4

+ 17 - 6
Userland/Libraries/LibWeb/DOM/Document.cpp

@@ -985,18 +985,29 @@ Layout::Viewport* Document::layout_node()
     return static_cast<Layout::Viewport*>(Node::layout_node());
     return static_cast<Layout::Viewport*>(Node::layout_node());
 }
 }
 
 
-void Document::set_inspected_node(Node* node)
+void Document::set_inspected_node(Node* node, Optional<CSS::Selector::PseudoElement> pseudo_element)
 {
 {
-    if (m_inspected_node.ptr() == node)
+    if (m_inspected_node.ptr() == node && m_inspected_pseudo_element == pseudo_element)
         return;
         return;
 
 
-    if (m_inspected_node && m_inspected_node->layout_node())
-        m_inspected_node->layout_node()->set_needs_display();
+    if (auto layout_node = inspected_layout_node())
+        layout_node->set_needs_display();
 
 
     m_inspected_node = node;
     m_inspected_node = node;
+    m_inspected_pseudo_element = pseudo_element;
 
 
-    if (m_inspected_node && m_inspected_node->layout_node())
-        m_inspected_node->layout_node()->set_needs_display();
+    if (auto layout_node = inspected_layout_node())
+        layout_node->set_needs_display();
+}
+
+Layout::Node* Document::inspected_layout_node()
+{
+    if (!m_inspected_node)
+        return nullptr;
+    if (!m_inspected_pseudo_element.has_value() || !m_inspected_node->is_element())
+        return m_inspected_node->layout_node();
+    auto& element = static_cast<Element&>(*m_inspected_node);
+    return element.get_pseudo_element_node(m_inspected_pseudo_element.value());
 }
 }
 
 
 static Node* find_common_ancestor(Node* a, Node* b)
 static Node* find_common_ancestor(Node* a, Node* b)

+ 4 - 1
Userland/Libraries/LibWeb/DOM/Document.h

@@ -136,9 +136,11 @@ public:
     Node* hovered_node() { return m_hovered_node.ptr(); }
     Node* hovered_node() { return m_hovered_node.ptr(); }
     Node const* hovered_node() const { return m_hovered_node.ptr(); }
     Node const* hovered_node() const { return m_hovered_node.ptr(); }
 
 
-    void set_inspected_node(Node*);
+    void set_inspected_node(Node*, Optional<CSS::Selector::PseudoElement>);
     Node* inspected_node() { return m_inspected_node.ptr(); }
     Node* inspected_node() { return m_inspected_node.ptr(); }
     Node const* inspected_node() const { return m_inspected_node.ptr(); }
     Node const* inspected_node() const { return m_inspected_node.ptr(); }
+    Layout::Node* inspected_layout_node();
+    Layout::Node const* inspected_layout_node() const { return const_cast<Document*>(this)->inspected_layout_node(); }
 
 
     Element* document_element();
     Element* document_element();
     Element const* document_element() const;
     Element const* document_element() const;
@@ -494,6 +496,7 @@ private:
     JS::GCPtr<CSS::StyleSheetList> m_style_sheets;
     JS::GCPtr<CSS::StyleSheetList> m_style_sheets;
     JS::GCPtr<Node> m_hovered_node;
     JS::GCPtr<Node> m_hovered_node;
     JS::GCPtr<Node> m_inspected_node;
     JS::GCPtr<Node> m_inspected_node;
+    Optional<CSS::Selector::PseudoElement> m_inspected_pseudo_element;
     JS::GCPtr<Node> m_active_favicon;
     JS::GCPtr<Node> m_active_favicon;
     WeakPtr<HTML::BrowsingContext> m_browsing_context;
     WeakPtr<HTML::BrowsingContext> m_browsing_context;
     AK::URL m_url;
     AK::URL m_url;

+ 1 - 3
Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp

@@ -114,9 +114,7 @@ void InlinePaintable::paint(PaintContext& context, PaintPhase phase) const
         });
         });
     }
     }
 
 
-    // FIXME: We check for a non-null dom_node(), since pseudo-elements have a null one and were getting
-    //        highlighted incorrectly. A better solution will be needed if we want to inspect them too.
-    if (phase == PaintPhase::Overlay && layout_node().dom_node() && layout_node().document().inspected_node() == layout_node().dom_node()) {
+    if (phase == PaintPhase::Overlay && layout_node().document().inspected_layout_node() == &layout_node()) {
         // FIXME: This paints a double-thick border between adjacent fragments, where ideally there
         // FIXME: This paints a double-thick border between adjacent fragments, where ideally there
         //        would be none. Once we implement non-rectangular outlines for the `outline` CSS
         //        would be none. Once we implement non-rectangular outlines for the `outline` CSS
         //        property, we can use that here instead.
         //        property, we can use that here instead.

+ 2 - 0
Userland/Libraries/LibWeb/Painting/MarkerPaintable.cpp

@@ -30,6 +30,8 @@ constexpr float sin_60_deg = 0.866025403f;
 
 
 void MarkerPaintable::paint(PaintContext& context, PaintPhase phase) const
 void MarkerPaintable::paint(PaintContext& context, PaintPhase phase) const
 {
 {
+    if (phase == PaintPhase::Overlay)
+        PaintableBox::paint(context, phase);
     if (phase != PaintPhase::Foreground)
     if (phase != PaintPhase::Foreground)
         return;
         return;
 
 

+ 2 - 2
Userland/Libraries/LibWeb/Painting/PaintableBox.cpp

@@ -169,7 +169,7 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
     if (phase == PaintPhase::Overlay && should_clip_rect)
     if (phase == PaintPhase::Overlay && should_clip_rect)
         context.painter().restore();
         context.painter().restore();
 
 
-    if (phase == PaintPhase::Overlay && layout_box().dom_node() && layout_box().document().inspected_node() == layout_box().dom_node()) {
+    if (phase == PaintPhase::Overlay && layout_box().document().inspected_layout_node() == &layout_box()) {
         auto content_rect = absolute_rect();
         auto content_rect = absolute_rect();
 
 
         auto margin_box = box_model().margin_box();
         auto margin_box = box_model().margin_box();
@@ -511,7 +511,7 @@ static void paint_text_fragment(PaintContext& context, Layout::TextNode const& t
         auto fragment_absolute_rect = fragment.absolute_rect();
         auto fragment_absolute_rect = fragment.absolute_rect();
         auto fragment_absolute_device_rect = context.enclosing_device_rect(fragment_absolute_rect);
         auto fragment_absolute_device_rect = context.enclosing_device_rect(fragment_absolute_rect);
 
 
-        if (text_node.document().inspected_node() == &text_node.dom_node())
+        if (text_node.document().inspected_layout_node() == &text_node)
             context.painter().draw_rect(fragment_absolute_device_rect.to_type<int>(), Color::Magenta);
             context.painter().draw_rect(fragment_absolute_device_rect.to_type<int>(), Color::Magenta);
 
 
         auto text = text_node.text_for_rendering();
         auto text = text_node.text_for_rendering();

+ 2 - 3
Userland/Services/WebContent/ConnectionFromClient.cpp

@@ -444,7 +444,7 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect
 
 
     top_context.for_each_in_inclusive_subtree([&](auto& ctx) {
     top_context.for_each_in_inclusive_subtree([&](auto& ctx) {
         if (ctx.active_document() != nullptr) {
         if (ctx.active_document() != nullptr) {
-            ctx.active_document()->set_inspected_node(nullptr);
+            ctx.active_document()->set_inspected_node(nullptr, {});
         }
         }
         return IterationDecision::Continue;
         return IterationDecision::Continue;
     });
     });
@@ -455,8 +455,7 @@ Messages::WebContentServer::InspectDomNodeResponse ConnectionFromClient::inspect
         return { false, "", "", "", "" };
         return { false, "", "", "", "" };
     }
     }
 
 
-    // FIXME: Pass the pseudo-element here.
-    node->document().set_inspected_node(node);
+    node->document().set_inspected_node(node, pseudo_element);
 
 
     if (node->is_element()) {
     if (node->is_element()) {
         auto& element = verify_cast<Web::DOM::Element>(*node);
         auto& element = verify_cast<Web::DOM::Element>(*node);