mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 19:17:44 +00:00
LibWeb: Change viewport ownership from BrowsingContext
to Navigable
This commit is contained in:
parent
4356d37b2c
commit
dd7bba66ed
23 changed files with 196 additions and 129 deletions
|
@ -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({});
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 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();
|
||||
|
||||
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)) {
|
||||
auto& layout_box = verify_cast<Layout::Box>(layout_node);
|
||||
auto padding_box = layout_box.box_model().padding_box();
|
||||
|
|
|
@ -138,16 +138,6 @@ public:
|
|||
Page* page() { 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 const& loader() const { return m_loader; }
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <LibWeb/HTML/StructuredSerialize.h>
|
||||
#include <LibWeb/HTML/TraversableNavigable.h>
|
||||
#include <LibWeb/Infra/Strings.h>
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
#include <LibWeb/Platform/EventLoopPlugin.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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibWeb/Bindings/NavigationPrototype.h>
|
||||
|
@ -19,6 +20,7 @@
|
|||
#include <LibWeb/HTML/SourceSnapshotParams.h>
|
||||
#include <LibWeb/HTML/StructuredSerialize.h>
|
||||
#include <LibWeb/HTML/TokenizedFeatures.h>
|
||||
#include <LibWeb/PixelUnits.h>
|
||||
#include <LibWeb/XHR/FormDataEntry.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
@ -134,6 +136,19 @@ public:
|
|||
[[nodiscard]] bool has_been_destroyed() const { return m_has_been_destroyed; }
|
||||
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:
|
||||
Navigable();
|
||||
|
||||
|
@ -146,6 +161,8 @@ private:
|
|||
bool allowed_by_sandboxing_to_navigate(Navigable const& target, SourceSnapshotParams const&);
|
||||
TargetSnapshotParams snapshot_target_snapshot_params();
|
||||
|
||||
void scroll_offset_did_change();
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/document-sequences.html#nav-id
|
||||
String m_id;
|
||||
|
||||
|
@ -168,6 +185,9 @@ private:
|
|||
JS::GCPtr<NavigableContainer> m_container;
|
||||
|
||||
bool m_has_been_destroyed { false };
|
||||
|
||||
CSSPixelSize m_size;
|
||||
CSSPixelPoint m_viewport_scroll_offset;
|
||||
};
|
||||
|
||||
HashTable<Navigable*>& all_navigables();
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include <LibWeb/HTML/Scripting/ExceptionReporter.h>
|
||||
#include <LibWeb/HTML/Storage.h>
|
||||
#include <LibWeb/HTML/TokenizedFeatures.h>
|
||||
#include <LibWeb/HTML/TraversableNavigable.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/HTML/WindowProxy.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),
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -1122,7 +1123,7 @@ double Window::scroll_x() const
|
|||
// 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.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1132,7 +1133,7 @@ double Window::scroll_y() const
|
|||
// 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.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1158,12 +1159,12 @@ void Window::scroll(ScrollToOptions const& options)
|
|||
auto* page = this->page();
|
||||
if (!page)
|
||||
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. 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
|
||||
// position on the x axis otherwise.
|
||||
|
@ -1206,7 +1207,7 @@ void Window::scroll(ScrollToOptions const& options)
|
|||
// smooth scroll, abort these steps.
|
||||
|
||||
// 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
|
||||
// one, or null otherwise, and the scroll behavior being the value of the behavior dictionary member of options.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue