If the Inspector widget already exists, be sure to inspect the page when
it is re-opened. However, this should be a no-op if the page was already
inspected (as any existing Inspector will be reset if a new page load
began).
Note this is not an issue in the AppKit chrome.
It was a bit short-sighted to combine the tag and attribute names into
one string when the Inspector requests a context menu. We will want both
values for some context menu actions. Send both names, as well as the
attribute value, when requesting the context menu.
Pages like the new tab page, error page, etc. all belong solely to
Ladybird, but are scattered across a couple of subfolders in Base. This
moves them all to Base/res/ladybird.
When a QObject subclass (widgets, etc.) are provided a parent, then
ownership of that object is passed to the parent. Similarly, objects
added to a QLayout are owned by the layout.
Thus, do not store these objects in an OwnPtr.
QString is UTF-16, thus QString::size returns the number of UTF-16 code
units. Thus, we would fail to perform, for example:
ak_string_from_qstring(QString("😀"));
Which is 2 UTF-16 code units, but 4 UTF-8 code units.
There's no need for 2 overloads for String and DeprecatedString, we can
just use a StringView. This also avoids some cases of needlessly
allocating a DeprecatedString from a StringView when calling this
method.
Ladybird on Serenity currently only uses F12, and on other platforms
only uses ctrl+shift+I. Most browsers support both hotkeys, so let's do
the same for consistency.
Note that the AppKit chrome cannot support both shortcuts. macOS does
not allow setting multiple "key equivalent" strings on an action. There
are some questionable hacks we could do to support this eventually, but
for now, just ctrl+shift+I is supported on macOS.
It is currently a bit messy to pass these options along from main() to
where WebContent is actually launched. If a new flag were to be added,
there are a couple dozen files that need to be updated to pass that flag
along. With this change, the flag can just be added to the struct, set
in main(), and handled in launch_web_content_process().
In order for same-origin NavigableContainers (iframe, frame, embed, ...)
and window.open() WindowProxies to have the proper JS access to their
embedder/opener, we need to host multiple top level traversables in the
same WebContent process. As a first step, make WebContent::PageHost hold
a HashMap of PageClient objects, each holding their own Web::Page that
represents a TraversableNavigable's API surface with the UI process.
The `page_did_request_scroll_to` API takes a CSS position, and thus
callers should not scale to device pixels before invoking it. Instead,
align this API with (most) other PageHost APIs which scale to device
pixels before sending the corresponding IPC message.
In the AppKit chrome, convert the provided device pixel position to a
widget position.
This matches the negation of the vertical scroll delta value. This makes
the scroll events behave as follows on macOS:
Natural scrolling enabled:
* Scrolling up on the trackpad scrolls down on the page.
* Scrolling right on the trackpad scrolls left on the page.
Natural scrolling disabled:
* Scrolling up on the trackpad scrolls up on the page.
* Scrolling right on the trackpad scrolls right on the page.
This was used to provided base functionality for model-based chromes for
viewing the DOM and accessibility trees. All chromes now use the WebView
inspector model for those trees, thus this class is unused.
When the `--dump-failed-ref-tests` flag is provided, screenshots of the
actual and reference pages will be placed in
`Build/lagom/ladbybird/test-dumps`. This makes it a lot easier to spot
what's wrong with a failing test. :^)
We call [NSApp activateIgnoringOtherApps:YES] to ensure the application
is brought into view and focused when launched from a terminal. But in
a macOS environment, we're better off using the `open` command to launch
the application (in which case, it does take foreground focus).
We now create a WorkerAgent for the parent context, which is currently
only a Window. Note that Workers can have Workers per the spec.
The WorkerAgent spawns a WebWorker process to hold the actual
script execution of the Worker. This is modeled with the
DedicatedWorkerHost object in the WebWorker process.
A start_dedicated_worker IPC method in the WebWorker IPC creates the
WorkerHost object. Future different worker types may use different IPC
messages to create their WorkerHost instance.
This implementation cannot yet postMessage between the parent and the
child processes.
Co-Authored-By: Andreas Kling <kling@serenityos.org>
This allows Ladybird to be the default browser on macOS, and allows for
opening some file types (.html, .svg, .md, etc.) with Ladybird.
Note this currently only works in the GN build (and thus the Qt chrome).
The CMake build does not set up the Resources directory properly for
macOS to run the Ladybird app without $SERENITY_SOURCE_DIR set.
If PulseAudio is available, the Qt6 audio plugin will never be used. So
let's remove it from the build.
Note that on macOS, the Qt6 audio plugin will be used if the Qt chrome
is enabled. Otherwise, Audio Unit will be used for the AppKit chrome.
This follows the pattern for the other services spawned by WebContent.
The notable quirk about this service is that it's actually spawned by
the ImageCodecPlugin rather than in main.cpp in the non-Android port.
As a result we needed to do some ifdef surgery to get all the pieces
in place. But we can now load images in the Android port again :^).
Instead of relying on AK_OS_LINUX, actually use the more accurate
HAS_ACCELERATED_GRAPHICS define to figure out if we should try to use
the generic LibAccelGfx GPU painter.
This patch brings a service to handle image decompression. With it comes
security enhancement due to the process boundary. Indeed, consequences
of a potential attack is reduced as only the decoder will crash without
perturbing the WebContent process.
It also allows us to display pages containing images that we claim to
support but still make us crash, like for not-finished-yet decoders.
As an example, we can now load https://jpegxl.info/jxl-art.html without
crashing the WebContent process.
The setting for the search engine to use is currently ephemeral. Once we
have a settings dialog, we can implement this setting there, and persist
that setting.
The default behavior of QPushButton is much closer to what we want from
a drop-down menu, as shown in the QPushButton::setMenu documentation:
https://doc.qt.io/qt-6/qpushbutton.html#setMenu
This also results in much less of a "squished" look than before.
The current size is too small to be able to read the new tab URL. Use
the `resize` API rather than setting a fixed-size as well, to allow the
user to resize the dialog themselves.
This lets the user zoom in and out on a web page using the View menu or
keyboard shortcuts. This does not implement zooming with ctrl+scroll.
In the future, it'd be nice to embed the zoom level display inside the
location toolbar. But to do that, we will need to invent our own custom
search field and all of the UI classes (controller, cell, etc.) to draw
the field. So for now, this places the zoom level display to the right
of the location toolbar.
This is in the spirit of commit a4692a6c978a6e66d171e003063449790a6c5879
(and the history behind that commit).
We will need to perform lookups from an integral node ID to the JSON for
that node frequently in the Inspector. We will also need to traverse the
DOM tree from a node, through its ancestors, to the root node. These are
essentially the same maps stored by the Qt Inspector widget.
This commit includes only fetching the DOM tree from the WebContent
process and displaying it in an NSOutlineView. The displayed tree
includes some basic styling (e.g. colors).
Instead of having an annoying loop that constantly reschedules a
Core::EventLoop trigger, have the ALooperEventLoopManager do it itself
in the did_post_event() function.
We cannot simply re-use the Unix implementation directly because that
implementation expects to actually be called all the time in order to
service timers. If you don't call its' pump() method, timers do not get
triggered. So, we do still need the seconary thread for Timers that was
added earlier.
Similar to the RequestServer, bind this from the WebContentService
implementation and have it work the same way. Deduplicate some code
while we're here.
Add a RequestServerService class that uses the LadybirdServiceBase class
added previously. Bind to it from the WebContentService's service_main()
during startup.
Create LadybirdServiceBase to hold the standard "set resource dir" and
"init ipc sockets" service functionality that will be common between the
WebContent, RequestServer, and WebSocket services.
Refactor the handler class slightly to avoid the HandlerLeak lint by
making the class a static class inside the companion object and use a
WeakReference to the service instead of a strong one.
After moving to navigables, we started reusing the code that populates
session history entries with the srcdoc attribute value from iframes
in `Page::load_html()` for loading HTML.
This change addresses a crash in `determine_the_origin` which occurred
because this method expected the URL to be `about:srcdoc` if we also
provided HTML content (previously, it was the URL passed along with the
HTML content into `load_html()`).
The FIXME at the bottom of Timer.nativeRun was on the money, and was
the cause of some leaked timers. Solve the issue by passing the
EventLoopImplementation to the JVM Timer object and retrieving it's
thread_local timer list, and posting the events to the Impl rather than
trying to invoke the receiver's timer event callback directly in
the Timer thread. Because the implementation of
ALooperEventLoopManager::did_post_event() reaches for
EventLoop::current(), we also need to make sure that the timer thread
acutally *has* an EventLoop, even if we don't expect to use it for
anything. And we need to make sure to pump it to clear out any of the
poke() invocations sending 4 bytes to the wake pipe for that thread.
This function used to live in AndroidPlatform.cpp, but was removed
during the transition to the new app. We still need to extract the
assets from the tarball that CMake creates. At least, until we come
up with a generic "Resource" concept in LibCore.
Timers run in their own thread, to take advantage of existing Java
Executor features. By hooking into ALooper, we can spin the main
Activity's UI thread event loop without causing a fuss, or spinning the
CPU by just polling our event loop constantly.
This will let us spawn a new process for an Android Service to handle
all our WebContent needs. The ServiceConnection is manged by each
WebView. The lifecycle of the Service is not quite clear yet, but each
bindService call will get a unique Messenger that can be used to
transfer the WebContent side of the LibIPC socketpair we use in other
ports.
The simple smoke test makes sure that we can boot up an android emulator
with our package in it, and that the WebView is visible on boot.
More tests to come with more features :^)
This folder is gitignored because we copy a generated tar file to it
during the build so that the android build tools will add it to our
APK file. However, the gitkeep was not re-added when the folder moved.
This allows our WebViewImplementationNative class to paint into an
Android Bitmap class from the onDraw() view event. We also set the
viewport geometry from the view since we're setting the Kotlin Bitmap
at the same time.
This ports over the `LADYBIRD_USE_LLD` option from the standalone
Ladybird build and generalizes it to work for mold as well: the
`LAGOM_USE_LINKER` variable can be set to the desired name of the
linker. If it's empty, we default to trying LLD and Mold on ELF
platforms (in this order).
This template app from Android Studio should hopefully be more fun to
work on than the Qt wrapped application we were using before. :^)
It currently builds the native code using gradle rules, and has a stub
WebViewImplementationNative class that will wrap a c++ class of the same
name that inhertis from WebView::ViewImplementation. Spawning helper
processes and creating proper views in Kotlin is next on the list.
These classes are used as-is in all chromes. Move them to LibWebView so
that non-Serenity chromes don't have to awkwardly reach into its headers
and sources.