فهرست منبع

LibWeb: Change viewport ownership from `BrowsingContext` to `Navigable`

Aliaksandr Kalenik 1 سال پیش
والد
کامیت
dd7bba66ed

+ 2 - 2
Userland/Libraries/LibWeb/CSS/Length.cpp

@@ -137,7 +137,7 @@ Length::ResolutionContext Length::ResolutionContext::for_layout_node(Layout::Nod
     VERIFY(root_element);
     VERIFY(root_element);
     VERIFY(root_element->layout_node());
     VERIFY(root_element->layout_node());
     return Length::ResolutionContext {
     return Length::ResolutionContext {
-        .viewport_rect = node.browsing_context().viewport_rect(),
+        .viewport_rect = node.navigable()->viewport_rect(),
         .font_metrics = { node.computed_values().font_size(), node.font().pixel_metrics(), node.line_height() },
         .font_metrics = { node.computed_values().font_size(), node.font().pixel_metrics(), node.line_height() },
         .root_font_metrics = { root_element->layout_node()->computed_values().font_size(), root_element->layout_node()->font().pixel_metrics(), root_element->layout_node()->line_height() },
         .root_font_metrics = { root_element->layout_node()->computed_values().font_size(), root_element->layout_node()->font().pixel_metrics(), root_element->layout_node()->line_height() },
     };
     };
@@ -182,7 +182,7 @@ CSSPixels Length::to_px(Layout::Node const& layout_node) const
     }
     }
 
 
     VERIFY(is_viewport_relative());
     VERIFY(is_viewport_relative());
-    auto const& viewport_rect = layout_node.document().browsing_context()->viewport_rect();
+    auto const& viewport_rect = layout_node.document().viewport_rect();
     return viewport_relative_length_to_px(viewport_rect);
     return viewport_relative_length_to_px(viewport_rect);
 }
 }
 
 

+ 2 - 2
Userland/Libraries/LibWeb/CSS/StyleComputer.cpp

@@ -2617,8 +2617,8 @@ void StyleComputer::invalidate_rule_cache()
 
 
 CSSPixelRect StyleComputer::viewport_rect() const
 CSSPixelRect StyleComputer::viewport_rect() const
 {
 {
-    if (auto const* browsing_context = document().browsing_context())
-        return browsing_context->viewport_rect();
+    if (auto const navigable = document().navigable())
+        return navigable->viewport_rect();
     return {};
     return {};
 }
 }
 
 

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

@@ -41,8 +41,8 @@ void ImageStyleValue::load_any_resources(DOM::Document& document)
                 return;
                 return;
 
 
             // FIXME: Do less than a full repaint if possible?
             // FIXME: Do less than a full repaint if possible?
-            if (auto* browsing_context = m_document->browsing_context())
-                browsing_context->set_needs_display();
+            if (auto navigable = m_document->navigable())
+                navigable->set_needs_display();
 
 
             auto image_data = m_image_request->image_data();
             auto image_data = m_image_request->image_data();
             if (image_data->is_animated() && image_data->frame_count() > 1) {
             if (image_data->is_animated() && image_data->frame_count() > 1) {

+ 8 - 8
Userland/Libraries/LibWeb/CSS/VisualViewport.cpp

@@ -46,8 +46,8 @@ double VisualViewport::offset_left() const
         return 0;
         return 0;
 
 
     // 2. Otherwise, return the offset of the left edge of the visual viewport from the left edge of the layout viewport.
     // 2. Otherwise, return the offset of the left edge of the visual viewport from the left edge of the layout viewport.
-    VERIFY(m_document->browsing_context());
-    return m_document->browsing_context()->viewport_rect().left().to_double();
+    VERIFY(m_document->navigable());
+    return m_document->viewport_rect().left().to_double();
 }
 }
 
 
 // https://drafts.csswg.org/cssom-view/#dom-visualviewport-offsettop
 // https://drafts.csswg.org/cssom-view/#dom-visualviewport-offsettop
@@ -58,8 +58,8 @@ double VisualViewport::offset_top() const
         return 0;
         return 0;
 
 
     // 2. Otherwise, return the offset of the top edge of the visual viewport from the top edge of the layout viewport.
     // 2. Otherwise, return the offset of the top edge of the visual viewport from the top edge of the layout viewport.
-    VERIFY(m_document->browsing_context());
-    return m_document->browsing_context()->viewport_rect().top().to_double();
+    VERIFY(m_document->navigable());
+    return m_document->viewport_rect().top().to_double();
 }
 }
 
 
 // https://drafts.csswg.org/cssom-view/#dom-visualviewport-pageleft
 // https://drafts.csswg.org/cssom-view/#dom-visualviewport-pageleft
@@ -95,8 +95,8 @@ double VisualViewport::width() const
 
 
     // 2. Otherwise, return the width of the visual viewport
     // 2. Otherwise, return the width of the visual viewport
     //    FIXME: excluding the width of any rendered vertical classic scrollbar that is fixed to the visual viewport.
     //    FIXME: excluding the width of any rendered vertical classic scrollbar that is fixed to the visual viewport.
-    VERIFY(m_document->browsing_context());
-    return m_document->browsing_context()->viewport_rect().width().to_double();
+    VERIFY(m_document->navigable());
+    return m_document->viewport_rect().width().to_double();
 }
 }
 
 
 // https://drafts.csswg.org/cssom-view/#dom-visualviewport-height
 // https://drafts.csswg.org/cssom-view/#dom-visualviewport-height
@@ -108,8 +108,8 @@ double VisualViewport::height() const
 
 
     // 2. Otherwise, return the height of the visual viewport
     // 2. Otherwise, return the height of the visual viewport
     //    FIXME: excluding the height of any rendered vertical classic scrollbar that is fixed to the visual viewport.
     //    FIXME: excluding the height of any rendered vertical classic scrollbar that is fixed to the visual viewport.
-    VERIFY(m_document->browsing_context());
-    return m_document->browsing_context()->viewport_rect().height().to_double();
+    VERIFY(m_document->navigable());
+    return m_document->viewport_rect().height().to_double();
 }
 }
 
 
 // https://drafts.csswg.org/cssom-view/#dom-visualviewport-scale
 // https://drafts.csswg.org/cssom-view/#dom-visualviewport-scale

+ 5 - 4
Userland/Libraries/LibWeb/DOM/Document.cpp

@@ -962,7 +962,7 @@ void Document::update_layout()
     if (m_created_for_appropriate_template_contents)
     if (m_created_for_appropriate_template_contents)
         return;
         return;
 
 
-    if (!browsing_context())
+    if (!navigable())
         return;
         return;
 
 
     auto viewport_rect = this->viewport_rect();
     auto viewport_rect = this->viewport_rect();
@@ -1005,7 +1005,8 @@ void Document::update_layout()
     // Broadcast the current viewport rect to any new paintables, so they know whether they're visible or not.
     // 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();
     inform_all_viewport_clients_about_the_current_viewport_rect();
 
 
-    browsing_context()->set_needs_display();
+    if (navigable())
+        navigable()->set_needs_display();
 
 
     if (navigable()->is_traversable()) {
     if (navigable()->is_traversable()) {
         if (auto* page = this->page())
         if (auto* page = this->page())
@@ -3034,8 +3035,8 @@ HTML::ListOfAvailableImages const& Document::list_of_available_images() const
 
 
 CSSPixelRect Document::viewport_rect() const
 CSSPixelRect Document::viewport_rect() const
 {
 {
-    if (auto* browsing_context = this->browsing_context())
-        return browsing_context->viewport_rect();
+    if (auto const navigable = this->navigable())
+        return navigable->viewport_rect();
     return CSSPixelRect {};
     return CSSPixelRect {};
 }
 }
 
 

+ 8 - 8
Userland/Libraries/LibWeb/DOM/Element.cpp

@@ -833,8 +833,8 @@ JS::NonnullGCPtr<Geometry::DOMRect> Element::get_bounding_client_rect() const
     if (!paintable_box)
     if (!paintable_box)
         return Geometry::DOMRect::construct_impl(realm(), 0, 0, 0, 0).release_value_but_fixme_should_propagate_errors();
         return Geometry::DOMRect::construct_impl(realm(), 0, 0, 0, 0).release_value_but_fixme_should_propagate_errors();
 
 
-    VERIFY(document().browsing_context());
-    auto viewport_offset = document().browsing_context()->viewport_scroll_offset();
+    VERIFY(document().navigable());
+    auto viewport_offset = document().navigable()->viewport_scroll_offset();
 
 
     return Geometry::DOMRect::create(realm(), paintable_box->absolute_rect().translated(-viewport_offset.x(), -viewport_offset.y()).to_type<float>());
     return Geometry::DOMRect::create(realm(), paintable_box->absolute_rect().translated(-viewport_offset.x(), -viewport_offset.y()).to_type<float>());
 }
 }
@@ -907,7 +907,7 @@ int Element::client_width() const
     //    return the viewport width excluding the size of a rendered scroll bar (if any).
     //    return the viewport width excluding the size of a rendered scroll bar (if any).
     if ((is<HTML::HTMLHtmlElement>(*this) && !document().in_quirks_mode())
     if ((is<HTML::HTMLHtmlElement>(*this) && !document().in_quirks_mode())
         || (is<HTML::HTMLBodyElement>(*this) && document().in_quirks_mode())) {
         || (is<HTML::HTMLBodyElement>(*this) && document().in_quirks_mode())) {
-        return document().browsing_context()->viewport_rect().width().to_int();
+        return document().viewport_rect().width().to_int();
     }
     }
 
 
     // NOTE: Ensure that layout is up-to-date before looking at metrics.
     // NOTE: Ensure that layout is up-to-date before looking at metrics.
@@ -932,7 +932,7 @@ int Element::client_height() const
     //    return the viewport height excluding the size of a rendered scroll bar (if any).
     //    return the viewport height excluding the size of a rendered scroll bar (if any).
     if ((is<HTML::HTMLHtmlElement>(*this) && !document().in_quirks_mode())
     if ((is<HTML::HTMLHtmlElement>(*this) && !document().in_quirks_mode())
         || (is<HTML::HTMLBodyElement>(*this) && document().in_quirks_mode())) {
         || (is<HTML::HTMLBodyElement>(*this) && document().in_quirks_mode())) {
-        return document().browsing_context()->viewport_rect().height().to_int();
+        return document().viewport_rect().height().to_int();
     }
     }
 
 
     // NOTE: Ensure that layout is up-to-date before looking at metrics.
     // NOTE: Ensure that layout is up-to-date before looking at metrics.
@@ -1262,8 +1262,8 @@ int Element::scroll_width() const
 
 
     // 3. Let viewport width be the width of the viewport excluding the width of the scroll bar, if any,
     // 3. Let viewport width be the width of the viewport excluding the width of the scroll bar, if any,
     //    or zero if there is no viewport.
     //    or zero if there is no viewport.
-    auto viewport_width = document.browsing_context()->viewport_rect().width().to_int();
-    auto viewport_scroll_width = document.browsing_context()->size().width().to_int();
+    auto viewport_width = document.viewport_rect().width().to_int();
+    auto viewport_scroll_width = document.navigable()->size().width().to_int();
 
 
     // 4. If the element is the root element and document is not in quirks mode
     // 4. If the element is the root element and document is not in quirks mode
     //    return max(viewport scrolling area width, viewport width).
     //    return max(viewport scrolling area width, viewport width).
@@ -1295,8 +1295,8 @@ int Element::scroll_height() const
 
 
     // 3. Let viewport height be the height of the viewport excluding the height of the scroll bar, if any,
     // 3. Let viewport height be the height of the viewport excluding the height of the scroll bar, if any,
     //    or zero if there is no viewport.
     //    or zero if there is no viewport.
-    auto viewport_height = document.browsing_context()->viewport_rect().height().to_int();
-    auto viewport_scroll_height = document.browsing_context()->size().height().to_int();
+    auto viewport_height = document.viewport_rect().height().to_int();
+    auto viewport_scroll_height = document.navigable()->size().height().to_int();
 
 
     // 4. If the element is the root element and document is not in quirks mode
     // 4. If the element is the root element and document is not in quirks mode
     //    return max(viewport scrolling area height, viewport height).
     //    return max(viewport scrolling area height, viewport height).

+ 2 - 68
Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp

@@ -540,73 +540,6 @@ void BrowsingContext::set_active_document(JS::NonnullGCPtr<DOM::Document> docume
         previously_active_document->did_stop_being_active_document_in_browsing_context({});
         previously_active_document->did_stop_being_active_document_in_browsing_context({});
 }
 }
 
 
-void BrowsingContext::set_viewport_rect(CSSPixelRect const& rect)
-{
-    bool did_change = false;
-
-    if (m_size != rect.size()) {
-        m_size = rect.size();
-        if (auto* document = active_document()) {
-            // NOTE: Resizing the viewport changes the reference value for viewport-relative CSS lengths.
-            document->invalidate_style();
-            document->set_needs_layout();
-        }
-        did_change = true;
-    }
-
-    if (m_viewport_scroll_offset != rect.location()) {
-        m_viewport_scroll_offset = rect.location();
-        scroll_offset_did_change();
-        did_change = true;
-    }
-
-    if (did_change && active_document()) {
-        active_document()->inform_all_viewport_clients_about_the_current_viewport_rect();
-    }
-
-    // Schedule the HTML event loop to ensure that a `resize` event gets fired.
-    HTML::main_thread_event_loop().schedule();
-}
-
-void BrowsingContext::set_size(CSSPixelSize size)
-{
-    if (m_size == size)
-        return;
-    m_size = size;
-
-    if (auto* document = active_document()) {
-        document->invalidate_style();
-        document->set_needs_layout();
-    }
-
-    if (auto* document = active_document()) {
-        document->inform_all_viewport_clients_about_the_current_viewport_rect();
-    }
-
-    // Schedule the HTML event loop to ensure that a `resize` event gets fired.
-    HTML::main_thread_event_loop().schedule();
-}
-
-void BrowsingContext::set_needs_display()
-{
-    set_needs_display(viewport_rect());
-}
-
-void BrowsingContext::set_needs_display(CSSPixelRect const& rect)
-{
-    if (!viewport_rect().intersects(rect))
-        return;
-
-    if (is_top_level()) {
-        if (m_page)
-            m_page->client().page_did_invalidate(to_top_level_rect(rect));
-        return;
-    }
-
-    if (container() && container()->layout_node())
-        container()->layout_node()->set_needs_display();
-}
-
 void BrowsingContext::scroll_to(CSSPixelPoint position)
 void BrowsingContext::scroll_to(CSSPixelPoint position)
 {
 {
     // NOTE: Scrolling to a position requires up-to-date layout *unless* we're scrolling to (0, 0)
     // NOTE: Scrolling to a position requires up-to-date layout *unless* we're scrolling to (0, 0)
@@ -647,7 +580,8 @@ void BrowsingContext::scroll_to_anchor(DeprecatedString const& fragment)
 
 
     auto& layout_node = *element->layout_node();
     auto& layout_node = *element->layout_node();
 
 
-    CSSPixelRect target_rect { layout_node.box_type_agnostic_position(), { viewport_rect().width(), viewport_rect().height() } };
+    auto const viewport_rect = document->viewport_rect();
+    CSSPixelRect target_rect { layout_node.box_type_agnostic_position(), { viewport_rect.width(), viewport_rect.height() } };
     if (is<Layout::Box>(layout_node)) {
     if (is<Layout::Box>(layout_node)) {
         auto& layout_box = verify_cast<Layout::Box>(layout_node);
         auto& layout_box = verify_cast<Layout::Box>(layout_node);
         auto padding_box = layout_box.box_model().padding_box();
         auto padding_box = layout_box.box_model().padding_box();

+ 0 - 10
Userland/Libraries/LibWeb/HTML/BrowsingContext.h

@@ -138,16 +138,6 @@ public:
     Page* page() { return m_page; }
     Page* page() { return m_page; }
     Page const* page() const { return m_page; }
     Page const* page() const { return m_page; }
 
 
-    CSSPixelSize size() const { return m_size; }
-    void set_size(CSSPixelSize);
-
-    void set_needs_display();
-    void set_needs_display(CSSPixelRect const&);
-
-    CSSPixelPoint viewport_scroll_offset() const { return m_viewport_scroll_offset; }
-    CSSPixelRect viewport_rect() const { return { m_viewport_scroll_offset, m_size }; }
-    void set_viewport_rect(CSSPixelRect const&);
-
     FrameLoader& loader() { return m_loader; }
     FrameLoader& loader() { return m_loader; }
     FrameLoader const& loader() const { return m_loader; }
     FrameLoader const& loader() const { return m_loader; }
 
 

+ 108 - 0
Userland/Libraries/LibWeb/HTML/Navigable.cpp

@@ -25,6 +25,7 @@
 #include <LibWeb/HTML/StructuredSerialize.h>
 #include <LibWeb/HTML/StructuredSerialize.h>
 #include <LibWeb/HTML/TraversableNavigable.h>
 #include <LibWeb/HTML/TraversableNavigable.h>
 #include <LibWeb/Infra/Strings.h>
 #include <LibWeb/Infra/Strings.h>
+#include <LibWeb/Layout/Node.h>
 #include <LibWeb/Platform/EventLoopPlugin.h>
 #include <LibWeb/Platform/EventLoopPlugin.h>
 #include <LibWeb/XHR/FormData.h>
 #include <LibWeb/XHR/FormData.h>
 
 
@@ -1548,4 +1549,111 @@ void perform_url_and_history_update_steps(DOM::Document& document, AK::URL new_u
     });
     });
 }
 }
 
 
+void Navigable::scroll_offset_did_change()
+{
+    // https://w3c.github.io/csswg-drafts/cssom-view-1/#scrolling-events
+    // Whenever a viewport gets scrolled (whether in response to user interaction or by an API), the user agent must run these steps:
+
+    // 1. Let doc be the viewport’s associated Document.
+    auto doc = active_document();
+    VERIFY(doc);
+
+    // 2. If doc is already in doc’s pending scroll event targets, abort these steps.
+    for (auto& target : doc->pending_scroll_event_targets()) {
+        if (target.ptr() == doc)
+            return;
+    }
+
+    // 3. Append doc to doc’s pending scroll event targets.
+    doc->pending_scroll_event_targets().append(*doc);
+}
+
+CSSPixelRect Navigable::to_top_level_rect(CSSPixelRect const& a_rect)
+{
+    auto rect = a_rect;
+    rect.set_location(to_top_level_position(a_rect.location()));
+    return rect;
+}
+
+CSSPixelPoint Navigable::to_top_level_position(CSSPixelPoint a_position)
+{
+    auto position = a_position;
+    for (auto ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
+        if (is<TraversableNavigable>(*ancestor))
+            break;
+        if (!ancestor->container())
+            return {};
+        if (!ancestor->container()->layout_node())
+            return {};
+        position.translate_by(ancestor->container()->layout_node()->box_type_agnostic_position());
+    }
+    return position;
+}
+
+void Navigable::set_viewport_rect(CSSPixelRect const& rect)
+{
+    bool did_change = false;
+
+    if (m_size != rect.size()) {
+        m_size = rect.size();
+        if (auto document = active_document()) {
+            // NOTE: Resizing the viewport changes the reference value for viewport-relative CSS lengths.
+            document->invalidate_style();
+            document->set_needs_layout();
+        }
+        did_change = true;
+    }
+
+    if (m_viewport_scroll_offset != rect.location()) {
+        m_viewport_scroll_offset = rect.location();
+        scroll_offset_did_change();
+        did_change = true;
+    }
+
+    if (did_change && active_document()) {
+        active_document()->inform_all_viewport_clients_about_the_current_viewport_rect();
+    }
+
+    // Schedule the HTML event loop to ensure that a `resize` event gets fired.
+    HTML::main_thread_event_loop().schedule();
+}
+
+void Navigable::set_size(CSSPixelSize size)
+{
+    if (m_size == size)
+        return;
+    m_size = size;
+
+    if (auto document = active_document()) {
+        document->invalidate_style();
+        document->set_needs_layout();
+    }
+
+    if (auto document = active_document()) {
+        document->inform_all_viewport_clients_about_the_current_viewport_rect();
+    }
+
+    // Schedule the HTML event loop to ensure that a `resize` event gets fired.
+    HTML::main_thread_event_loop().schedule();
+}
+
+void Navigable::set_needs_display()
+{
+    set_needs_display(viewport_rect());
+}
+
+void Navigable::set_needs_display(CSSPixelRect const& rect)
+{
+    if (!viewport_rect().intersects(rect))
+        return;
+
+    if (is<TraversableNavigable>(*this)) {
+        static_cast<TraversableNavigable*>(this)->page()->client().page_did_invalidate(to_top_level_rect(rect));
+        return;
+    }
+
+    if (container() && container()->layout_node())
+        container()->layout_node()->set_needs_display();
+}
+
 }
 }

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

@@ -7,6 +7,7 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <AK/HashTable.h>
 #include <AK/String.h>
 #include <AK/String.h>
 #include <LibJS/Heap/Cell.h>
 #include <LibJS/Heap/Cell.h>
 #include <LibWeb/Bindings/NavigationPrototype.h>
 #include <LibWeb/Bindings/NavigationPrototype.h>
@@ -19,6 +20,7 @@
 #include <LibWeb/HTML/SourceSnapshotParams.h>
 #include <LibWeb/HTML/SourceSnapshotParams.h>
 #include <LibWeb/HTML/StructuredSerialize.h>
 #include <LibWeb/HTML/StructuredSerialize.h>
 #include <LibWeb/HTML/TokenizedFeatures.h>
 #include <LibWeb/HTML/TokenizedFeatures.h>
+#include <LibWeb/PixelUnits.h>
 #include <LibWeb/XHR/FormDataEntry.h>
 #include <LibWeb/XHR/FormDataEntry.h>
 
 
 namespace Web::HTML {
 namespace Web::HTML {
@@ -134,6 +136,19 @@ public:
     [[nodiscard]] bool has_been_destroyed() const { return m_has_been_destroyed; }
     [[nodiscard]] bool has_been_destroyed() const { return m_has_been_destroyed; }
     void set_has_been_destroyed() { m_has_been_destroyed = true; }
     void set_has_been_destroyed() { m_has_been_destroyed = true; }
 
 
+    CSSPixelPoint to_top_level_position(CSSPixelPoint);
+    CSSPixelRect to_top_level_rect(CSSPixelRect const&);
+
+    CSSPixelSize size() const { return m_size; }
+    void set_size(CSSPixelSize);
+
+    CSSPixelPoint viewport_scroll_offset() const { return m_viewport_scroll_offset; }
+    CSSPixelRect viewport_rect() const { return { m_viewport_scroll_offset, m_size }; }
+    void set_viewport_rect(CSSPixelRect const&);
+
+    void set_needs_display();
+    void set_needs_display(CSSPixelRect const&);
+
 protected:
 protected:
     Navigable();
     Navigable();
 
 
@@ -146,6 +161,8 @@ private:
     bool allowed_by_sandboxing_to_navigate(Navigable const& target, SourceSnapshotParams const&);
     bool allowed_by_sandboxing_to_navigate(Navigable const& target, SourceSnapshotParams const&);
     TargetSnapshotParams snapshot_target_snapshot_params();
     TargetSnapshotParams snapshot_target_snapshot_params();
 
 
+    void scroll_offset_did_change();
+
     // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-id
     // https://html.spec.whatwg.org/multipage/document-sequences.html#nav-id
     String m_id;
     String m_id;
 
 
@@ -168,6 +185,9 @@ private:
     JS::GCPtr<NavigableContainer> m_container;
     JS::GCPtr<NavigableContainer> m_container;
 
 
     bool m_has_been_destroyed { false };
     bool m_has_been_destroyed { false };
+
+    CSSPixelSize m_size;
+    CSSPixelPoint m_viewport_scroll_offset;
 };
 };
 
 
 HashTable<Navigable*>& all_navigables();
 HashTable<Navigable*>& all_navigables();

+ 10 - 9
Userland/Libraries/LibWeb/HTML/Window.cpp

@@ -46,6 +46,7 @@
 #include <LibWeb/HTML/Scripting/ExceptionReporter.h>
 #include <LibWeb/HTML/Scripting/ExceptionReporter.h>
 #include <LibWeb/HTML/Storage.h>
 #include <LibWeb/HTML/Storage.h>
 #include <LibWeb/HTML/TokenizedFeatures.h>
 #include <LibWeb/HTML/TokenizedFeatures.h>
+#include <LibWeb/HTML/TraversableNavigable.h>
 #include <LibWeb/HTML/Window.h>
 #include <LibWeb/HTML/Window.h>
 #include <LibWeb/HTML/WindowProxy.h>
 #include <LibWeb/HTML/WindowProxy.h>
 #include <LibWeb/HighResolutionTime/Performance.h>
 #include <LibWeb/HighResolutionTime/Performance.h>
@@ -1101,8 +1102,8 @@ i32 Window::inner_width() const
 {
 {
     // The innerWidth attribute must return the viewport width including the size of a rendered scroll bar (if any),
     // The innerWidth attribute must return the viewport width including the size of a rendered scroll bar (if any),
     // or zero if there is no viewport.
     // or zero if there is no viewport.
-    if (auto const* browsing_context = associated_document().browsing_context())
-        return browsing_context->viewport_rect().width().to_int();
+    if (auto const navigable = associated_document().navigable())
+        return navigable->viewport_rect().width().to_int();
     return 0;
     return 0;
 }
 }
 
 
@@ -1111,8 +1112,8 @@ i32 Window::inner_height() const
 {
 {
     // The innerHeight attribute must return the viewport height including the size of a rendered scroll bar (if any),
     // The innerHeight attribute must return the viewport height including the size of a rendered scroll bar (if any),
     // or zero if there is no viewport.
     // or zero if there is no viewport.
-    if (auto const* browsing_context = associated_document().browsing_context())
-        return browsing_context->viewport_rect().height().to_int();
+    if (auto const navigable = associated_document().navigable())
+        return navigable->viewport_rect().height().to_int();
     return 0;
     return 0;
 }
 }
 
 
@@ -1122,7 +1123,7 @@ double Window::scroll_x() const
     // The scrollX attribute must return the x-coordinate, relative to the initial containing block origin,
     // The scrollX attribute must return the x-coordinate, relative to the initial containing block origin,
     // of the left of the viewport, or zero if there is no viewport.
     // of the left of the viewport, or zero if there is no viewport.
     if (auto* page = this->page())
     if (auto* page = this->page())
-        return page->top_level_browsing_context().viewport_scroll_offset().x().to_double();
+        return page->top_level_traversable()->viewport_scroll_offset().x().to_double();
     return 0;
     return 0;
 }
 }
 
 
@@ -1132,7 +1133,7 @@ double Window::scroll_y() const
     // The scrollY attribute must return the y-coordinate, relative to the initial containing block origin,
     // The scrollY attribute must return the y-coordinate, relative to the initial containing block origin,
     // of the top of the viewport, or zero if there is no viewport.
     // of the top of the viewport, or zero if there is no viewport.
     if (auto* page = this->page())
     if (auto* page = this->page())
-        return page->top_level_browsing_context().viewport_scroll_offset().y().to_double();
+        return page->top_level_traversable()->viewport_scroll_offset().y().to_double();
     return 0;
     return 0;
 }
 }
 
 
@@ -1158,12 +1159,12 @@ void Window::scroll(ScrollToOptions const& options)
     auto* page = this->page();
     auto* page = this->page();
     if (!page)
     if (!page)
         return;
         return;
-    auto const& top_level_browsing_context = page->top_level_browsing_context();
+    auto top_level_traversable = page->top_level_traversable();
 
 
     // 1. If invoked with one argument, follow these substeps:
     // 1. If invoked with one argument, follow these substeps:
 
 
     // 1. Let options be the argument.
     // 1. Let options be the argument.
-    auto viewport_rect = top_level_browsing_context.viewport_rect().to_type<float>();
+    auto viewport_rect = top_level_traversable->viewport_rect().to_type<float>();
 
 
     // 2. Let x be the value of the left dictionary member of options, if present, or the viewport’s current scroll
     // 2. Let x be the value of the left dictionary member of options, if present, or the viewport’s current scroll
     //    position on the x axis otherwise.
     //    position on the x axis otherwise.
@@ -1206,7 +1207,7 @@ void Window::scroll(ScrollToOptions const& options)
     //            smooth scroll, abort these steps.
     //            smooth scroll, abort these steps.
 
 
     // 11. Let document be the viewport’s associated Document.
     // 11. Let document be the viewport’s associated Document.
-    auto const* document = top_level_browsing_context.active_document();
+    auto const document = top_level_traversable->active_document();
 
 
     // 12. Perform a scroll of the viewport to position, document’s root element as the associated element, if there is
     // 12. Perform a scroll of the viewport to position, document’s root element as the associated element, if there is
     //     one, or null otherwise, and the scroll behavior being the value of the behavior dictionary member of options.
     //     one, or null otherwise, and the scroll behavior being the value of the behavior dictionary member of options.

+ 3 - 3
Userland/Libraries/LibWeb/IntersectionObserver/IntersectionObserver.cpp

@@ -173,12 +173,12 @@ CSSPixelRect IntersectionObserver::root_intersection_rectangle() const
     if (intersection_root.has<JS::Handle<DOM::Document>>()) {
     if (intersection_root.has<JS::Handle<DOM::Document>>()) {
         auto document = intersection_root.get<JS::Handle<DOM::Document>>();
         auto document = intersection_root.get<JS::Handle<DOM::Document>>();
 
 
-        // Since the spec says that this is only reach if the document is fully active, that means it must have a browsing context.
-        VERIFY(document->browsing_context());
+        // Since the spec says that this is only reach if the document is fully active, that means it must have a navigable.
+        VERIFY(document->navigable());
 
 
         // NOTE: This rect is the *size* of the viewport. The viewport *offset* is not relevant,
         // NOTE: This rect is the *size* of the viewport. The viewport *offset* is not relevant,
         //       as intersections are computed using viewport-relative element rects.
         //       as intersections are computed using viewport-relative element rects.
-        rect = CSSPixelRect { CSSPixelPoint { 0, 0 }, document->browsing_context()->viewport_rect().size() };
+        rect = CSSPixelRect { CSSPixelPoint { 0, 0 }, document->viewport_rect().size() };
     } else {
     } else {
         VERIFY(intersection_root.has<JS::Handle<DOM::Element>>());
         VERIFY(intersection_root.has<JS::Handle<DOM::Element>>());
         auto element = intersection_root.get<JS::Handle<DOM::Element>>();
         auto element = intersection_root.get<JS::Handle<DOM::Element>>();

+ 4 - 1
Userland/Libraries/LibWeb/Layout/Box.cpp

@@ -63,8 +63,11 @@ bool Box::is_user_scrollable() const
 
 
 void Box::set_needs_display()
 void Box::set_needs_display()
 {
 {
+    if (!navigable())
+        return;
+
     if (paintable_box())
     if (paintable_box())
-        browsing_context().set_needs_display(paintable_box()->absolute_rect());
+        navigable()->set_needs_display(paintable_box()->absolute_rect());
 }
 }
 
 
 bool Box::is_body() const
 bool Box::is_body() const

+ 2 - 2
Userland/Libraries/LibWeb/Layout/FrameBox.cpp

@@ -32,8 +32,8 @@ void FrameBox::did_set_content_size()
 {
 {
     ReplacedBox::did_set_content_size();
     ReplacedBox::did_set_content_size();
 
 
-    VERIFY(dom_node().nested_browsing_context());
-    dom_node().nested_browsing_context()->set_size(paintable_box()->content_size());
+    VERIFY(dom_node().content_navigable());
+    dom_node().content_navigable()->set_size(paintable_box()->content_size());
 }
 }
 
 
 JS::GCPtr<Painting::Paintable> FrameBox::create_paintable() const
 JS::GCPtr<Painting::Paintable> FrameBox::create_paintable() const

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

@@ -196,6 +196,11 @@ HTML::BrowsingContext& Node::browsing_context()
     return *m_browsing_context;
     return *m_browsing_context;
 }
 }
 
 
+JS::GCPtr<HTML::Navigable> Node::navigable() const
+{
+    return document().navigable();
+}
+
 Viewport const& Node::root() const
 Viewport const& Node::root() const
 {
 {
     VERIFY(document().layout_node());
     VERIFY(document().layout_node());
@@ -219,7 +224,8 @@ void Node::set_needs_display()
         return;
         return;
     static_cast<Painting::PaintableWithLines const&>(*containing_block->paintable_box()).for_each_fragment([&](auto& fragment) {
     static_cast<Painting::PaintableWithLines const&>(*containing_block->paintable_box()).for_each_fragment([&](auto& fragment) {
         if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
         if (&fragment.layout_node() == this || is_ancestor_of(fragment.layout_node())) {
-            browsing_context().set_needs_display(fragment.absolute_rect());
+            if (navigable())
+                navigable()->set_needs_display(fragment.absolute_rect());
         }
         }
         return IterationDecision::Continue;
         return IterationDecision::Continue;
     });
     });

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

@@ -77,6 +77,8 @@ public:
     HTML::BrowsingContext const& browsing_context() const;
     HTML::BrowsingContext const& browsing_context() const;
     HTML::BrowsingContext& browsing_context();
     HTML::BrowsingContext& browsing_context();
 
 
+    JS::GCPtr<HTML::Navigable> navigable() const;
+
     Viewport const& root() const;
     Viewport const& root() const;
     Viewport& root();
     Viewport& root();
 
 

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

@@ -517,7 +517,7 @@ bool EventHandler::handle_mousemove(CSSPixelPoint position, CSSPixelPoint screen
                     else
                     else
                         (void)selection->set_base_and_extent(*hit->paintable->dom_node(), hit->index_in_node, *hit->paintable->dom_node(), hit->index_in_node);
                         (void)selection->set_base_and_extent(*hit->paintable->dom_node(), hit->index_in_node, *hit->paintable->dom_node(), hit->index_in_node);
                 }
                 }
-                m_browsing_context->set_needs_display();
+                document.navigable()->set_needs_display();
             }
             }
             if (auto* page = m_browsing_context->page())
             if (auto* page = m_browsing_context->page())
                 page->client().page_did_change_selection();
                 page->client().page_did_change_selection();
@@ -822,7 +822,7 @@ CSSPixelPoint EventHandler::compute_mouse_event_client_offset(CSSPixelPoint even
     // https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-clientx
     // https://w3c.github.io/csswg-drafts/cssom-view/#dom-mouseevent-clientx
     // The clientX attribute must return the x-coordinate of the position where the event occurred relative to the origin of the viewport.
     // The clientX attribute must return the x-coordinate of the position where the event occurred relative to the origin of the viewport.
 
 
-    auto scroll_offset = m_browsing_context->viewport_scroll_offset();
+    auto scroll_offset = m_browsing_context->active_document()->navigable()->viewport_scroll_offset();
     return event_page_position.translated(-scroll_offset);
     return event_page_position.translated(-scroll_offset);
 }
 }
 
 
@@ -832,7 +832,7 @@ CSSPixelPoint EventHandler::compute_mouse_event_page_offset(CSSPixelPoint event_
     // FIXME: 1. If the event’s dispatch flag is set, return the horizontal coordinate of the position where the event occurred relative to the origin of the initial containing block and terminate these steps.
     // FIXME: 1. If the event’s dispatch flag is set, return the horizontal coordinate of the position where the event occurred relative to the origin of the initial containing block and terminate these steps.
 
 
     // 2. Let offset be the value of the scrollX attribute of the event’s associated Window object, if there is one, or zero otherwise.
     // 2. Let offset be the value of the scrollX attribute of the event’s associated Window object, if there is one, or zero otherwise.
-    auto scroll_offset = m_browsing_context->viewport_scroll_offset();
+    auto scroll_offset = m_browsing_context->active_document()->navigable()->viewport_scroll_offset();
 
 
     // 3. Return the sum of offset and the value of the event’s clientX attribute.
     // 3. Return the sum of offset and the value of the event’s clientX attribute.
     return event_client_offset.translated(scroll_offset);
     return event_client_offset.translated(scroll_offset);

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

@@ -129,7 +129,7 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
         // Attachment and Origin
         // Attachment and Origin
         switch (layer.attachment) {
         switch (layer.attachment) {
         case CSS::BackgroundAttachment::Fixed:
         case CSS::BackgroundAttachment::Fixed:
-            background_positioning_area = layout_node.root().browsing_context().viewport_rect();
+            background_positioning_area = layout_node.root().navigable()->viewport_rect();
             break;
             break;
         case CSS::BackgroundAttachment::Local:
         case CSS::BackgroundAttachment::Local:
             background_positioning_area = get_box(layer.origin).rect;
             background_positioning_area = get_box(layer.origin).rect;

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

@@ -56,7 +56,7 @@ void NestedBrowsingContextPaintable::paint(PaintContext& context, PaintPhase pha
         auto absolute_device_rect = context.enclosing_device_rect(absolute_rect);
         auto absolute_device_rect = context.enclosing_device_rect(absolute_rect);
         context.painter().translate(absolute_device_rect.x().value(), absolute_device_rect.y().value());
         context.painter().translate(absolute_device_rect.x().value(), absolute_device_rect.y().value());
 
 
-        context.set_device_viewport_rect({ {}, context.enclosing_device_size(layout_box().dom_node().nested_browsing_context()->size()) });
+        context.set_device_viewport_rect({ {}, context.enclosing_device_size(layout_box().dom_node().content_navigable()->size()) });
         const_cast<ViewportPaintable*>(hosted_paint_tree)->paint_all_phases(context);
         const_cast<ViewportPaintable*>(hosted_paint_tree)->paint_all_phases(context);
 
 
         context.set_device_viewport_rect(old_viewport_rect);
         context.set_device_viewport_rect(old_viewport_rect);

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

@@ -542,7 +542,7 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
     auto transformed_position = affine_transform_matrix().inverse().value_or({}).map(offset_position).to_type<CSSPixels>() + transform_origin;
     auto transformed_position = affine_transform_matrix().inverse().value_or({}).map(offset_position).to_type<CSSPixels>() + transform_origin;
 
 
     if (paintable_box().is_fixed_position()) {
     if (paintable_box().is_fixed_position()) {
-        auto scroll_offset = paintable_box().document().browsing_context()->viewport_scroll_offset();
+        auto scroll_offset = paintable_box().document().navigable()->viewport_scroll_offset();
         transformed_position.translate_by(-scroll_offset);
         transformed_position.translate_by(-scroll_offset);
     }
     }
 
 

+ 2 - 1
Userland/Libraries/LibWeb/WebDriver/Screenshot.cpp

@@ -13,6 +13,7 @@
 #include <LibWeb/HTML/BrowsingContext.h>
 #include <LibWeb/HTML/BrowsingContext.h>
 #include <LibWeb/HTML/HTMLCanvasElement.h>
 #include <LibWeb/HTML/HTMLCanvasElement.h>
 #include <LibWeb/HTML/TagNames.h>
 #include <LibWeb/HTML/TagNames.h>
+#include <LibWeb/HTML/TraversableNavigable.h>
 #include <LibWeb/HTML/Window.h>
 #include <LibWeb/HTML/Window.h>
 #include <LibWeb/Namespace.h>
 #include <LibWeb/Namespace.h>
 #include <LibWeb/Page/Page.h>
 #include <LibWeb/Page/Page.h>
@@ -54,7 +55,7 @@ Response capture_element_screenshot(Painter const& painter, Page& page, DOM::Ele
     Optional<Response> encoded_string_or_error;
     Optional<Response> encoded_string_or_error;
 
 
     element.document().window().animation_frame_callback_driver().add([&](auto) {
     element.document().window().animation_frame_callback_driver().add([&](auto) {
-        auto viewport_rect = page.top_level_browsing_context().viewport_rect();
+        auto viewport_rect = page.top_level_traversable()->viewport_rect();
         rect.intersect(page.enclosing_device_rect(viewport_rect).to_type<int>());
         rect.intersect(page.enclosing_device_rect(viewport_rect).to_type<int>());
 
 
         auto canvas_element = DOM::create_element(element.document(), HTML::TagNames::canvas, Namespace::HTML).release_value_but_fixme_should_propagate_errors();
         auto canvas_element = DOM::create_element(element.document(), HTML::TagNames::canvas, Namespace::HTML).release_value_but_fixme_should_propagate_errors();

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

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

+ 2 - 1
Userland/Services/WebContent/PageHost.cpp

@@ -13,6 +13,7 @@
 #include <LibWeb/CSS/SystemColor.h>
 #include <LibWeb/CSS/SystemColor.h>
 #include <LibWeb/Cookie/ParsedCookie.h>
 #include <LibWeb/Cookie/ParsedCookie.h>
 #include <LibWeb/HTML/BrowsingContext.h>
 #include <LibWeb/HTML/BrowsingContext.h>
+#include <LibWeb/HTML/TraversableNavigable.h>
 #include <LibWeb/Layout/Viewport.h>
 #include <LibWeb/Layout/Viewport.h>
 #include <LibWeb/Painting/PaintableBox.h>
 #include <LibWeb/Painting/PaintableBox.h>
 #include <LibWeb/Painting/ViewportPaintable.h>
 #include <LibWeb/Painting/ViewportPaintable.h>
@@ -146,7 +147,7 @@ void PageHost::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& targ
 
 
 void PageHost::set_viewport_rect(Web::DevicePixelRect const& rect)
 void PageHost::set_viewport_rect(Web::DevicePixelRect const& rect)
 {
 {
-    page().top_level_browsing_context().set_viewport_rect(page().device_to_css_rect(rect));
+    page().top_level_traversable()->set_viewport_rect(page().device_to_css_rect(rect));
 }
 }
 
 
 void PageHost::page_did_invalidate(Web::CSSPixelRect const& content_rect)
 void PageHost::page_did_invalidate(Web::CSSPixelRect const& content_rect)