If we end up in a situation where the navigable no longer has an active
window, we can't perform navigation or many other navigable operations.
These are all ad-hoc, since the navigables spec is basically all written
as if there's always an active window. Unfortunately, the active window
comes from the active document's browsing context, which is a nullable
concept even in the spec, so we do need to deal with null here.
This removes all the locally reproducible crashes when running WPT over
the legacy Japanese encoding directory on my computer.
Yes, this is a bit of a monkey patch, but it should be harmless since
we're (as I understand it) dealing with navigables that are still
hanging around with related tasks queued on them. Once all these tasks
have been completed, the navigables will go away anyway.
While Origin is defined in the HTML spec - this leaves us with quite an
awkward relationship as the URL spec makes use of AO's from what is
defined in the HTML spec.
To simplify this factoring, relocate Origin into LibURL.
...if only the scroll offset is updated.
Currently, on any document with a large amount of content, the process
of building a display list is often more expensive than its
rasterization. This is because the amount of work required to build a
display list is proportional to the size of the paintable tree, whereas
rasterization only occurs for the portion visible in the viewport.
This change is the first step toward improving this process by caching
the display list across repaints when neither style nor layout requires
invalidation. This means that repainting while scrolling becomes
significantly less expensive, as we only need to reapply the scroll
offsets to the existing display list.
The performance improvement is especially visible on pages like
https://ziglang.org/documentation/master/ or
https://www.w3.org/TR/css-grid-2/
This allows us to use HeapFunction all of the way down, allowing us
to remove the Handle usage in after_session_callback for
create_new_child_navigable.
...For the completion steps. This is quite nice, as we can simply
capture this in the heap function where it is used instead of
needing to establish a new root.
Note that with these changes, to represent 'an empty algorithm', we now
use a null HeapFunction and do not invoke the steps.
While introducing clip and scroll frame trees, I made a mistake by
assuming that the paintable tree includes boxes from nested navigables.
Therefore, this comment in the code was incorrect, and clip/scroll
frames were simply not assigned for iframes:
// NOTE: We only need to refresh the scroll state for traversables
// because they are responsible for tracking the state of all
// nested navigables.
As a result, anything with "overflow: scroll" is currently not
scrollable inside an iframe
This change fixes that by ensuring clip and scroll frames are assigned
and refreshed for each navigable. To achieve this, I had to modify the
display list building process to record a separate display list for each
navigable. This is necessary because scroll frame ids are local to a
navigable, making it impossible to call
`DisplayList::apply_scroll_offsets()` on a display list that contains
ids from multiple navigables.
This change is a preparation for the upcoming changes where display
list will be nested and the same display could be owned by multiple
display list items.
With this change display list player will be able to recurse into
executing another display list, without having to construct new display
list player. It is going to be useful in the upcoming changes to paint
a mask from a display list owned by a command.
Enforce the use of the CPU backend in test mode to ensure that ref-tests
produce consistent results across different computers, as this
consistency cannot be achieved with the GPU backend.
Skia now uses GPU-accelerated painting on Linux if Vulkan is available.
Most of the performance gain is currently negated by reading the GPU
backend back into RAM to pass it to the Browser process. In the future,
this could be improved by sharing GPU-allocated memory across the
Browser and WebContent processes.
GPU painter that uses AccelGfx is slower and way less complete compared
to both default Gfx::Painter and Skia painter. It does not make much
sense to keep it, considering Skia painter already uses Metal backend on
macOS by default and there is an option to enable GPU-accelerated
backend on linux.
If Metal context and IOSurface are available, Skia painter will use
Ganesh GPU backend on macOS, which is noticeably faster than the default
CPU backend.
Painting pipeline:
1. (WebContent) Allocate IOSurface for backing store
2. (WebContent) Allocate MTLTexture that wraps IOSurface
3. (WebContent) Paint into MTLTexture using Skia
4. (Browser) Wrap IOSurface into Gfx::Painter and use
QPainter/CoreGraphics to blit backing store into viewport.
Things we should improve in the future:
1. Upload textures for images in advance instead of doing that before
every repaint.
2. Teach AppKit client to read directly from IOSurface instead of
copying.
This change introduces Skia painter available under a flag. It's not
yet match capabilities of Gfx::Painter and is not ready to replace it.
Motivation:
- The current CPU painter is a performance bottleneck on most websites.
Our own GPU painter implementation is very immature and has received
relatively little attention.
- There is ongoing effort on building painter that supports affine
transforms (AffineCommandExecutorCPU) but it is far from being on par
with the default CPU painter. Skia will allow us to immediately get
full transformation support for all painting commands.
GPU painting:
I experimented with Ganesh GPU-backend, however profiling revealed that
without sharing viewport texture between WebContent and Browser
processes, it won't bring much performance improvement compared to
CPU-backend. Therefore, I decided to keep this PR focused on
implementing most of painting commands and switch to GPU-backend in
future changes.
Text rendring:
Skia painter uses glyph bitmaps produced by LibGfx. Using Skia for text
rendering will require large refactoring of the font rendering
subsystem. Currently, it's impossible to construct SkFont right before
rendering because Gfx::VectorFont can't be serialized back into sequence
of bytes.
There is a problem with ugly include paths like:
`#include <core/SkBitmap.h>`.
I would prefer to have skia prefix in the path. There was an attempt to
fix that but PR was rejected https://github.com/microsoft/vcpkg/pull/32660
Regressions compared to Gfx::Painter:
- DrawText is not implemented
- PaintTextShadow is not implemented
- PaintRadialGradient and PaintLinearGradient do not support "transition
hints" and repeat length
- PaintConicGradient is not implemented
- DrawTriangleWave is not implemented
- DrawLine does not account for line style property
- DrawScaledBitmap and DrawScaledImmutableBitmap do not account for
scaling mode property
Capturing a struct that owns bunch of JS::Handle makes it very hard to
understand what keeps these handles alive in the GC-graph.
Instead let's capture only members of a struct used in the callback.
Changes the signature of queue_global_task() from AK:Function to
JS::HeapFunction to be more clear to the user of the function that this
is what it uses internally.
Fixes bug when "navigate forward" button in UI is disabled after
performing following steps:
1. Load page with an iframe (top step = 0, iframe step = 0)
2. Navigate iframe to different document (top step = 0, iframe step = 1)
3. Navigate back from browser UI (top step = 0, iframe step = 0)
No test because change is only observable from browser UI.
It is going to be used to communicate whether it is possible to navigate
back or forward after session history stored on browser side will no
longer be used to driver navigation.
See spec issue https://github.com/whatwg/html/issues/9869
Previous attempt on fixing reload had to be reverted because it broke
Soundcloud and GitHub, but this change does not seem to introduce new
crashes.
"apply the history step" initiated by reloading or back/forward
navigation might require doing fetching while populating a document,
so it is not possible to restrict spin_until() to process only
NavigationAndTraversal task source.
"apply the history step" initiated by synchronous navigation keeps
processing only NavigationAndTraversal task source because it will
never have to populate a document. Another reason to keep synchronous
navigation blocking other task sources is that we crash if active SHE
changes in the middle of "apply the history step" initiated by sync
navigation. The new test is added to makes sure we don't regress that.
Workaround spec bug by explicitly carrying information whether
navigation is sync (History api, fragment change) or not.
See for more details https://github.com/whatwg/html/issues/10232
These changes do not solve hanging `location.reload()` and
`location.go()` but only align implementation with the latest edits in
the specification.
`WindowProxy-Get-after-detaching-from-browsing-context` test output is
affected because `iframe.remove();` no longer synchronously does
destruction of a document, but queues a task on event loop.
Co-Authored-By: Andrew Kaster <akaster@serenityos.org>