Bladeren bron

LibWeb: Move `m_needs_repaint` and `record_display_list()` in Document

Let's make document responsible for display list invalidation,
considering it already takes care of style and layout.
Aliaksandr Kalenik 11 maanden geleden
bovenliggende
commit
69c6e07139

+ 1 - 1
Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp

@@ -48,7 +48,7 @@ void ImageStyleValue::load_any_resources(DOM::Document& document)
                 m_document->set_needs_to_resolve_paint_only_properties();
 
                 // FIXME: Do less than a full repaint if possible?
-                navigable->set_needs_display();
+                m_document->set_needs_display();
             }
 
             auto image_data = m_resource_request->image_data();

+ 73 - 1
Userland/Libraries/LibWeb/DOM/Document.cpp

@@ -1153,7 +1153,7 @@ void Document::update_layout()
     // Broadcast the current viewport rect to any new paintables, so they know whether they're visible or not.
     inform_all_viewport_clients_about_the_current_viewport_rect();
 
-    navigable->set_needs_display();
+    m_document->set_needs_display();
     set_needs_to_resolve_paint_only_properties();
 
     paintable()->assign_scroll_frames();
@@ -5367,4 +5367,76 @@ void Document::set_cached_navigable(JS::GCPtr<HTML::Navigable> navigable)
     m_cached_navigable = navigable.ptr();
 }
 
+void Document::set_needs_display()
+{
+    set_needs_display(viewport_rect());
+}
+
+void Document::set_needs_display(CSSPixelRect const&)
+{
+    // FIXME: Ignore updates outside the visible viewport rect.
+    //        This requires accounting for fixed-position elements in the input rect, which we don't do yet.
+
+    m_needs_repaint = true;
+
+    auto navigable = this->navigable();
+    if (!navigable)
+        return;
+
+    if (navigable->is_traversable()) {
+        Web::HTML::main_thread_event_loop().schedule();
+        return;
+    }
+
+    if (navigable->container()) {
+        navigable->container()->document().set_needs_display();
+    }
+}
+
+RefPtr<Painting::DisplayList> Document::record_display_list(PaintConfig config)
+{
+    auto display_list = Painting::DisplayList::create();
+    Painting::DisplayListRecorder display_list_recorder(display_list);
+
+    if (config.canvas_fill_rect.has_value()) {
+        display_list_recorder.fill_rect(config.canvas_fill_rect.value(), CSS::SystemColor::canvas());
+    }
+
+    auto viewport_rect = page().css_to_device_rect(this->viewport_rect());
+    Gfx::IntRect bitmap_rect { {}, viewport_rect.size().to_type<int>() };
+
+    display_list_recorder.fill_rect(bitmap_rect, background_color());
+    if (!paintable()) {
+        VERIFY_NOT_REACHED();
+    }
+
+    Web::PaintContext context(display_list_recorder, page().palette(), page().client().device_pixels_per_css_pixel());
+    context.set_device_viewport_rect(viewport_rect);
+    context.set_should_show_line_box_borders(config.should_show_line_box_borders);
+    context.set_should_paint_overlay(config.paint_overlay);
+    context.set_has_focus(config.has_focus);
+
+    update_paint_and_hit_testing_properties_if_needed();
+
+    auto& viewport_paintable = *paintable();
+
+    viewport_paintable.refresh_scroll_state();
+
+    viewport_paintable.paint_all_phases(context);
+
+    display_list->set_device_pixels_per_css_pixel(page().client().device_pixels_per_css_pixel());
+
+    Vector<RefPtr<Painting::ScrollFrame>> scroll_state;
+    scroll_state.resize(viewport_paintable.scroll_state.size());
+    for (auto& [_, scrollable_frame] : viewport_paintable.scroll_state) {
+        scroll_state[scrollable_frame->id] = scrollable_frame;
+    }
+
+    display_list->set_scroll_state(move(scroll_state));
+
+    m_needs_repaint = false;
+
+    return display_list;
+}
+
 }

+ 14 - 0
Userland/Libraries/LibWeb/DOM/Document.h

@@ -699,6 +699,18 @@ public:
     JS::GCPtr<HTML::Navigable> cached_navigable();
     void set_cached_navigable(JS::GCPtr<HTML::Navigable>);
 
+    [[nodiscard]] bool needs_repaint() const { return m_needs_repaint; }
+    void set_needs_display();
+    void set_needs_display(CSSPixelRect const&);
+
+    struct PaintConfig {
+        bool paint_overlay { false };
+        bool should_show_line_box_borders { false };
+        bool has_focus { false };
+        Optional<Gfx::IntRect> canvas_fill_rect {};
+    };
+    RefPtr<Painting::DisplayList> record_display_list(PaintConfig);
+
 protected:
     virtual void initialize(JS::Realm&) override;
     virtual void visit_edges(Cell::Visitor&) override;
@@ -972,6 +984,8 @@ private:
 
     // NOTE: This is WeakPtr, not GCPtr, on purpose. We don't want the document to keep some old detached navigable alive.
     WeakPtr<HTML::Navigable> m_cached_navigable;
+
+    bool m_needs_repaint { false };
 };
 
 template<>

+ 1 - 1
Userland/Libraries/LibWeb/HTML/AudioTrack.cpp

@@ -31,7 +31,7 @@ AudioTrack::AudioTrack(JS::Realm& realm, JS::NonnullGCPtr<HTMLMediaElement> medi
     , m_audio_plugin(Platform::AudioCodecPlugin::create(move(loader)).release_value_but_fixme_should_propagate_errors())
 {
     m_audio_plugin->on_playback_position_updated = [this](auto position) {
-        if (auto const* paintable = m_media_element->paintable())
+        if (auto* paintable = m_media_element->paintable())
             paintable->set_needs_display();
 
         auto playback_position = static_cast<double>(position.to_milliseconds()) / 1000.0;

+ 3 - 3
Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp

@@ -209,7 +209,7 @@ void EventLoop::process()
     //         loop processing.
     for_each_fully_active_document_in_docs([&](DOM::Document& document) {
         auto navigable = document.navigable();
-        if (navigable && !navigable->has_a_rendering_opportunity() && navigable->needs_repaint())
+        if (navigable && !navigable->has_a_rendering_opportunity() && document.needs_repaint())
             schedule();
         if (navigable && navigable->has_a_rendering_opportunity())
             return;
@@ -328,7 +328,7 @@ void EventLoop::process()
     // 16. For each fully active Document in docs, update the rendering or user interface of that Document and its browsing context to reflect the current state.
     for_each_fully_active_document_in_docs([&](DOM::Document& document) {
         auto navigable = document.navigable();
-        if (navigable && navigable->needs_repaint()) {
+        if (navigable && document.needs_repaint()) {
             auto* browsing_context = document.browsing_context();
             auto& page = browsing_context->page();
             if (navigable->is_traversable()) {
@@ -341,7 +341,7 @@ void EventLoop::process()
     // FIXME: Not in the spec: If there is a screenshot request queued, process it now.
     //        This prevents tests deadlocking on screenshot requests on macOS.
     for (auto& document : docs) {
-        if (document->page().top_level_traversable()->needs_repaint())
+        if (document->needs_repaint())
             document->page().client().process_screenshot_requests();
     }
 

+ 5 - 72
Userland/Libraries/LibWeb/HTML/Navigable.cpp

@@ -2000,9 +2000,10 @@ void Navigable::set_viewport_size(CSSPixelSize size)
         document->invalidate_style();
         document->set_needs_layout();
     }
-    set_needs_display();
 
     if (auto document = active_document()) {
+        document->set_needs_display();
+
         document->inform_all_viewport_clients_about_the_current_viewport_rect();
 
         // Schedule the HTML event loop to ensure that a `resize` event gets fired.
@@ -2015,9 +2016,9 @@ void Navigable::perform_scroll_of_viewport(CSSPixelPoint new_position)
     if (m_viewport_scroll_offset != new_position) {
         m_viewport_scroll_offset = new_position;
         scroll_offset_did_change();
-        set_needs_display();
 
         if (auto document = active_document()) {
+            document->set_needs_display();
             document->set_needs_to_refresh_scroll_state(true);
             document->inform_all_viewport_clients_about_the_current_viewport_rect();
         }
@@ -2029,24 +2030,9 @@ void Navigable::perform_scroll_of_viewport(CSSPixelPoint new_position)
 
 void Navigable::set_needs_display()
 {
-    set_needs_display(viewport_rect());
-}
-
-void Navigable::set_needs_display(CSSPixelRect const&)
-{
-    // FIXME: Ignore updates outside the visible viewport rect.
-    //        This requires accounting for fixed-position elements in the input rect, which we don't do yet.
-
-    m_needs_repaint = true;
-
-    if (is<TraversableNavigable>(*this)) {
-        // Schedule the main thread event loop, which will, in turn, schedule a repaint.
-        Web::HTML::main_thread_event_loop().schedule();
-        return;
+    if (auto document = active_document(); document) {
+        document->set_needs_display();
     }
-
-    if (container() && container()->paintable())
-        container()->paintable()->set_needs_display();
 }
 
 // https://html.spec.whatwg.org/#rendering-opportunity
@@ -2090,59 +2076,6 @@ void Navigable::inform_the_navigation_api_about_aborting_navigation()
     }));
 }
 
-RefPtr<Painting::DisplayList> Navigable::record_display_list(PaintConfig config)
-{
-    auto document = active_document();
-    if (!document)
-        return {};
-
-    auto display_list = Painting::DisplayList::create();
-    Painting::DisplayListRecorder display_list_recorder(display_list);
-
-    if (config.canvas_fill_rect.has_value()) {
-        display_list_recorder.fill_rect(config.canvas_fill_rect.value(), CSS::SystemColor::canvas());
-    }
-
-    auto const& page = traversable_navigable()->page();
-    auto viewport_rect = page.css_to_device_rect(this->viewport_rect());
-    Gfx::IntRect bitmap_rect { {}, viewport_rect.size().to_type<int>() };
-
-    auto background_color = document->background_color();
-
-    display_list_recorder.fill_rect(bitmap_rect, background_color);
-    if (!document->paintable()) {
-        VERIFY_NOT_REACHED();
-    }
-
-    Web::PaintContext context(display_list_recorder, page.palette(), page.client().device_pixels_per_css_pixel());
-    context.set_device_viewport_rect(viewport_rect);
-    context.set_should_show_line_box_borders(config.should_show_line_box_borders);
-    context.set_should_paint_overlay(config.paint_overlay);
-    context.set_has_focus(config.has_focus);
-
-    document->update_paint_and_hit_testing_properties_if_needed();
-
-    auto& viewport_paintable = *document->paintable();
-
-    viewport_paintable.refresh_scroll_state();
-
-    viewport_paintable.paint_all_phases(context);
-
-    display_list->set_device_pixels_per_css_pixel(page.client().device_pixels_per_css_pixel());
-
-    Vector<RefPtr<Painting::ScrollFrame>> scroll_state;
-    scroll_state.resize(viewport_paintable.scroll_state.size());
-    for (auto& [_, scrollable_frame] : viewport_paintable.scroll_state) {
-        scroll_state[scrollable_frame->id] = scrollable_frame;
-    }
-
-    display_list->set_scroll_state(move(scroll_state));
-
-    m_needs_repaint = false;
-
-    return display_list;
-}
-
 // https://html.spec.whatwg.org/multipage/browsing-the-web.html#event-uni
 UserNavigationInvolvement user_navigation_involvement(DOM::Event const& event)
 {

+ 0 - 13
Userland/Libraries/LibWeb/HTML/Navigable.h

@@ -170,7 +170,6 @@ public:
     void perform_scroll_of_viewport(CSSPixelPoint position);
 
     void set_needs_display();
-    void set_needs_display(CSSPixelRect const&);
 
     void set_is_popup(TokenizedFeature::Popup is_popup) { m_is_popup = is_popup; }
 
@@ -179,16 +178,6 @@ public:
 
     [[nodiscard]] TargetSnapshotParams snapshot_target_snapshot_params();
 
-    [[nodiscard]] bool needs_repaint() const { return m_needs_repaint; }
-
-    struct PaintConfig {
-        bool paint_overlay { false };
-        bool should_show_line_box_borders { false };
-        bool has_focus { false };
-        Optional<Gfx::IntRect> canvas_fill_rect {};
-    };
-    RefPtr<Painting::DisplayList> record_display_list(PaintConfig);
-
     Page& page() { return m_page; }
     Page const& page() const { return m_page; }
 
@@ -245,8 +234,6 @@ private:
     CSSPixelSize m_size;
     CSSPixelPoint m_viewport_scroll_offset;
 
-    bool m_needs_repaint { false };
-
     Web::EventHandler m_event_handler;
 };
 

+ 6 - 2
Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp

@@ -1189,12 +1189,16 @@ JS::GCPtr<DOM::Node> TraversableNavigable::currently_focused_area()
 
 void TraversableNavigable::paint(DevicePixelRect const& content_rect, Painting::BackingStore& target, PaintOptions paint_options)
 {
-    HTML::Navigable::PaintConfig paint_config;
+    auto document = active_document();
+    if (!document)
+        return;
+
+    DOM::Document::PaintConfig paint_config;
     paint_config.paint_overlay = paint_options.paint_overlay == PaintOptions::PaintOverlay::Yes;
     paint_config.should_show_line_box_borders = paint_options.should_show_line_box_borders;
     paint_config.has_focus = paint_options.has_focus;
     paint_config.canvas_fill_rect = Gfx::IntRect { {}, content_rect.size() };
-    auto display_list = record_display_list(paint_config);
+    auto display_list = document->record_display_list(paint_config);
     if (!display_list) {
         return;
     }

+ 1 - 1
Userland/Libraries/LibWeb/Page/EventHandler.cpp

@@ -582,7 +582,7 @@ bool EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSPixelPoi
                 if (should_set_cursor_position)
                     document.set_cursor_position(DOM::Position::create(realm, *hit->dom_node(), *start_index));
 
-                document.navigable()->set_needs_display();
+                document.set_needs_display();
             }
         }
     }

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

@@ -54,11 +54,11 @@ void NestedBrowsingContextPaintable::paint(PaintContext& context, PaintPhase pha
 
         context.display_list_recorder().add_clip_rect(clip_rect.to_type<int>());
 
-        HTML::Navigable::PaintConfig paint_config;
+        DOM::Document::PaintConfig paint_config;
         paint_config.paint_overlay = context.should_paint_overlay();
         paint_config.should_show_line_box_borders = context.should_show_line_box_borders();
         paint_config.has_focus = context.has_focus();
-        auto display_list = const_cast<DOM::Document*>(hosted_document)->navigable()->record_display_list(paint_config);
+        auto display_list = const_cast<DOM::Document*>(hosted_document)->record_display_list(paint_config);
         context.display_list_recorder().paint_nested_display_list(display_list, context.enclosing_device_rect(absolute_rect).to_type<int>());
 
         context.display_list_recorder().restore();

+ 5 - 6
Userland/Libraries/LibWeb/Painting/Paintable.cpp

@@ -127,25 +127,24 @@ void Paintable::invalidate_stacking_context()
     m_stacking_context = nullptr;
 }
 
-void Paintable::set_needs_display() const
+void Paintable::set_needs_display()
 {
     auto* containing_block = this->containing_block();
     if (!containing_block)
         return;
-    auto navigable = this->navigable();
-    if (!navigable)
-        return;
+
+    auto& document = const_cast<DOM::Document&>(this->document());
 
     if (is<Painting::InlinePaintable>(*this)) {
         auto const& fragments = static_cast<Painting::InlinePaintable const*>(this)->fragments();
         for (auto const& fragment : fragments)
-            navigable->set_needs_display(fragment.absolute_rect());
+            document.set_needs_display(fragment.absolute_rect());
     }
 
     if (!is<Painting::PaintableWithLines>(*containing_block))
         return;
     static_cast<Painting::PaintableWithLines const&>(*containing_block).for_each_fragment([&](auto& fragment) {
-        navigable->set_needs_display(fragment.absolute_rect());
+        document.set_needs_display(fragment.absolute_rect());
         return IterationDecision::Continue;
     });
 }

+ 1 - 1
Userland/Libraries/LibWeb/Painting/Paintable.h

@@ -198,7 +198,7 @@ public:
 
     JS::GCPtr<HTML::Navigable> navigable() const;
 
-    virtual void set_needs_display() const;
+    virtual void set_needs_display();
 
     PaintableBox* containing_block() const
     {

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

@@ -907,10 +907,9 @@ TraversalDecision PaintableWithLines::hit_test(CSSPixelPoint position, HitTestTy
     return TraversalDecision::Continue;
 }
 
-void PaintableBox::set_needs_display() const
+void PaintableBox::set_needs_display()
 {
-    if (auto navigable = this->navigable())
-        navigable->set_needs_display(absolute_rect());
+    document().set_needs_display(absolute_rect());
 }
 
 Optional<CSSPixelRect> PaintableBox::get_masking_area() const

+ 1 - 1
Userland/Libraries/LibWeb/Painting/PaintableBox.h

@@ -128,7 +128,7 @@ public:
     DOM::Node const* dom_node() const { return layout_box().dom_node(); }
     DOM::Node* dom_node() { return layout_box().dom_node(); }
 
-    virtual void set_needs_display() const override;
+    virtual void set_needs_display() override;
 
     virtual void apply_scroll_offset(PaintContext&, PaintPhase) const override;
     virtual void reset_scroll_offset(PaintContext&, PaintPhase) const override;

+ 1 - 1
Userland/Libraries/LibWeb/SVG/SVGDecodedImageData.cpp

@@ -92,7 +92,7 @@ RefPtr<Gfx::Bitmap> SVGDecodedImageData::render(Gfx::IntSize size) const
     m_document->navigable()->set_viewport_size(size.to_type<CSSPixels>());
     m_document->update_layout();
 
-    auto display_list = m_document->navigable()->record_display_list({});
+    auto display_list = m_document->record_display_list({});
     if (!display_list)
         return {};
 

+ 1 - 1
Userland/Services/WebContent/ConnectionFromClient.cpp

@@ -359,7 +359,7 @@ void ConnectionFromClient::debug_request(u64 page_id, ByteString const& request,
     if (request == "set-line-box-borders") {
         bool state = argument == "on";
         page->set_should_show_line_box_borders(state);
-        page->page().top_level_traversable()->set_needs_display(page->page().top_level_traversable()->viewport_rect());
+        page->page().top_level_traversable()->set_needs_display();
         return;
     }