If our UI informed the page of a DPI change, we would store the new
device pixel ratio and leave it at that. It would take a layout/style
update (e.g. by clicking the page) to actually render the page using the
new DPI. This is very visible on macOS when moving the Ladybird window
from a 1x resolution monitor to a HiDPI 2x monitor.
We now instantly update the backing stores and mark media queries for
reevaluation. Moving the Ladybird window on macOS now immediately
updates the page when dragging it to a HiDPI monitor.
In preparation for handling input events on the rendering thread, move
backpressure management to RenderingThread. The rendering thread needs
to manage this independently without querying the main thread.
Previously, the main thread would block when the UI process hadn't yet
released the backing surface. Now, the main thread can continue
producing display lists while the UI process is busy, allowing more work
to happen in parallel. When rasterization is slow and display lists are
produced faster than they can be consumed, presentation requests are
naturally coalesced using a flag-based approach -
multiple present_frame() calls simply update the pending state,
resulting in a single rasterization with the latest display list.
This change prepares for a future where the rendering thread handles
input events directly, allowing it to trigger repainting without
waiting for the main thread. To support this, the compositor needs to
own the display list, scroll state, and backing stores rather than
receiving them per-frame from the main thread.
A version of this was added in a610639119
and reverted in 70671b4c11. The bugs
there (confusing scroll-to-position and scroll-by-delta, and not having
an execution context in some cases) have been fixed in this version.
A lot of our scrolling code is quite old, and doesn't match the spec,
but does use some similar names. This is quite confusing. In particular
`perform_scroll_of_viewport()` is not the same as the spec algorithm.
That algorithm is actually almost implemented in
`scroll_viewport_by_delta()`.
To clarify things, this commit makes a few changes:
- Rename perform_scroll_of_viewport() to
perform_scroll_of_viewport_scrolling_box(). This is a better match
for how we use this method, even if it's not actually a match for the
algorithm. (:yakbait:)
- Move `scroll_viewport_by_delta()`'s code into a new
`perform_a_scroll_of_the_viewport()` method, and make it take a
position like it should. `scroll_viewport_by_delta()` now calls it
with a calculated position.
I've avoided reusing the original `perform_scroll_of_viewport()` name to
avoid accidents.
Fixes crashing introduced in a610639 when `scroll_viewport_by_delta()`
is called from `EventHandler::handle_mousewheel()` and there's no
running execution context to grab current realm from to allocate a
promise.
If multiple cross-document navigations are queued on
SessionHistoryTraversalQueue, running the next entry before the current
document load is finished may result in a deadlock. If the new document
has a navigable element of its own, it will append steps to SHTQ and
hang in nested spin_until.
This change uses promises to ensure that the current document loads
before the next entry is executed.
Fixes timeouts in the imported tests.
Co-authored-by: Sam Atkins <sam@ladybird.org>
NavigationObserver register itself in Navigable from constructor and
unregister itself from `finalize()`. The problem is that `finalize()`
won't be invoked for as long as NavigationObserver is visited by
Navigable, leading to GC leaks.
Implements spec algorithm for viewport scrolling that first checks if
it's possible to use delta to move the visual viewport before falling
back to scrolling the layout viewport. This is a part of pinch-to-zoom
support.
Partly corresponds to 80ebad5fbf
This is mostly to handle null source_documents, which is something that
needs more work elsewhere. The spec change above is about the deferred
fetch quota.
Recently, we moved the backing store manager into Navigable, which means
we now try to allocate a backing store for all navigables, including
those corresponding to SVG image documents. This change disables that
behavior for all navigables except top-level non-SVG traversables,
because otherwise it causes issues when we stop repainting: the browser
process was notified about an allocated backing stores that does not
correspond to the page, and then all subsequent repaints are ignored
until the window is resized.
Now, when Skia backend context is available by the time backing stores
are allocated, there is no need to have a separate BackingStore class.
This allows us to get rid of BackingStore -> PaintingSurface cache.
Making navigables responsible for backing store allocation will allow us
to have separate backing stores for iframes and run paint updates for
them independently, which is a step toward isolating them into separate
processes.
Another nice side effect is that now Skia backend context is ready by
the time backing stores are allocated, so we will be able to get rid of
BackingStore class in the upcoming changes and allocate PaintingSurface
directly.
All other viewport-related dimensions are referenced to by 'viewport',
so let's rename the member that stores the viewport size to prevent
further confusion.
This is very clearly a very dangerous API to have, and was causing
a crash on Linux as a result of a stack use-after-free when visiting
https://www.index.hr/.
Fixes#3901
Previously, all `GC::Cell` derived classes were Weakable. Marking only
those classes that require this functionality as Weakable allows us to
reduce the memory footprint of some frequently used classes.
This change fixes a bug that can be reproduced with the following steps:
```js
const iframe = document.createElement("iframe");
document.body.appendChild(iframe);
iframe.contentWindow.location.href = ("http://localhost:8080/demo.html");
```
These steps are executed in the following order:
1. Create iframe and schedule session history traversal task that adds
session history entry for the iframe.
2. Generate navigation id for scheduled navigation to
`http://localhost:8080/demo.html`.
3. Execute the scheduled session history traversal task, which adds
session history entry for the iframe.
4. Ooops, navigation to `http://localhost:8080/demo.html` is aborted
because addings SHE for the iframe resets the navigation id.
This change fixes this by delaying all navigations until SHE for a
navigable is created.
This reduces the number of `.cpp` files that need to be recompiled when
one of the below header files changes as follows:
Painting/Command.h: 1030 -> 61
Painting/DisplayList.h: 1030 -> 60
Painting/DisplayListRecorder.h: 557 -> 59
This is required to store Content Security Policies, as their
Directives are implemented as subclasses with overridden virtual
functions. Thus, they cannot be stored as generic Directive classes, as
it'll lose the ability to call overridden functions when they are
copied.
Before this change, `m_needs_repaint` was reset in
`Document::record_display_list()` only when the cached display list was
absent. This meant that if the last triggered repaint used the cached
display list, we would keep repainting indefinitely until the display
list was invalidated (We schedule a task that checks if repainting is
required 60/s).
This change also moves `m_needs_repaint` from Document to
TraversableNavigable as we only ever need to repaint a document that
belongs to traversable.
The use of this HashMap looks very spooky, but let's at least use
finalize when cleaning them up on destruction to make things slightly
less dangerous looking.
Corresponds to https://github.com/whatwg/html/pull/10683
As part of this, I noticed we incorrectly were setting the "is popup"
flag on the Navigable instead of the BrowsingContext. I've fixed that
and removed the erroneous flag from Navigable.
To check whether a NavigationParams is null, we have to check whether
it's `Empty` or `NullWithError`. Instead, we can merge both of these
possible variants into an optional error. If `NullOrError` has no
value it's null, otherwise it contains an error message.
Resulting in a massive rename across almost everywhere! Alongside the
namespace change, we now have the following names:
* JS::NonnullGCPtr -> GC::Ref
* JS::GCPtr -> GC::Ptr
* JS::HeapFunction -> GC::Function
* JS::CellImpl -> GC::Cell
* JS::Handle -> GC::Root