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.
This adds menu items to open an interactive JavaScript console for a web
page. This more or less mimics the Qt implementation of the console.
Hooks are included to tie the lifetime of the console window with the
tab it belongs to; if the tab is closed, the console window is closed.
This creates WebView::ConsoleClient to handle functionality that will be
common to the JS consoles of all Ladybird chromes. This will let each
chrome focus on just the UI.
Note that this includes the `console.group` functionality that only the
Serenity chrome previously had. This was a FIXME in the Qt chrome, and
it is implemented such that all chromes will receive this functionality
for free.
The LadybirdWebView currently assumed it is viewed with a Tab instance.
This will not be true with the JavaScript console. This patch removes
this assumption by plumbing WebContent callbacks through a new protocol.
The Tab interface then implements this protocol.
For example, the JavaScript console will invoke window.scrollTo(0, INF)
to scroll to the bottom of the console after updating its contents. The
NSScrollView being scrolled here seems to behave oddly if we scroll
beyond its limit (e.g. mouse events stop working). Prevent this by
limiting scrolling to the NSScrollView's document rect.
We were relying on TabController setting the web view's initial viewport
in [TabController windowDidResize], which has been triggered when the
Tab is first created. However, it turns out that only happens due to the
toolbar being added to the Tab window, causing a resize event. When the
web view is embedded in a window without a toolbar, this resize event is
not triggered. Therefore, we must set the viewport ourselves when the
web view is added to a window.
Currently, the only NSWindow type in the AppKit chrome is the Tab. Once
we have other window types (e.g. Inspector), commands which assume they
are used on a Tab will either crash or behave weirdly.
This changes the createNewTab: command to accept the tab from which the
new tab is created, rather than assuming that tab is the key window. So
if some JS on a page calls window.open() while a non-Tab window is key,
the new tab will be opened within the same tab group.
This also changes closeCurrentTab: to work on any key window. Regardless
of whether the key window is a Tab or some other window, pressing cmd+W
should just close that window.
This lets the user choose a color scheme which differs from the active
system theme. Upon changing the color scheme, the scheme is broadcast to
all active tabs, and will be used in new tabs.
Without setting the --resources flag, headless-browser defaults to /res
for all resources it tries to find, including the theme. It will not
find this path on Lagom, so our attempt to load the default theme does
not accomplish anything.
The old names sounded like awkward English to me, as they implied the
WebContent process is asking for information. In reality, WebContent is
*providing* the information.
We can easily add hooks to notify the browsers of these events if any
implementation-specific handling is needed in the future, but for now,
these only repaint the client, which we can do in ViewImplementation.
Storing the backup bitmap is the same across Browser and Ladybird. Just
peform that work in LibWebView, and handle only the implementation-
specific nuances within the browsers.
This also sets the default callback to do what every non-Serenity
browser is doing, rather than copy-pasting this callback into every
implementation. The callback is still available for any platform which
might want to override the default behavior. For example, OOPWV now
overrides this callback to use FileSystemAccessClient.
This adds an alternative Ladybird chrome for macOS using the AppKit
framework. Just about everything needed for normal web browsing has
been implemented. This includes:
* Tabbed, scrollable navigation
* History navigation (back, forward, reload)
* Keyboard / mouse events
* Favicons
* Context menus
* Cookies
* Dialogs (alert, confirm, prompt)
* WebDriver support
This does not include debugging tools like the JavaScript console and
inspector, nor theme support.
The Qt chrome is still used by default. To use the AppKit chrome, set
the ENABLE_QT CMake option to OFF.
By running ctest -C Integration -R WPT, you can run WPT. Adding just
-C Integration will run all other tests *and* the WPT test.
Also add support for ./Meta/serenity.sh test lagom WPT to serenity.sh
The error.html page now uses the resource_directory_url this
variable contains the relative path to /Base/res/ on the host
system as a file:// url. This is needed for future pages to load
resource files like icons. For the error.html page this was not
really needed because it lies over this own URL in FrameLoader.cpp.
Non-Qt chromes will want to use the same Info.plist and bundle info as
the Qt chrome. This patch puts the CMake setup for the bundle into a
function that non-Qt chromes may call in their CMakeLists.txt. The Qt
chrome calls it automatically.
This will allow us to bring the WebContent process into non-Qt macOS
chromes. This branch is only reached when creating an <audio> element,
so while the chrome is heavily under development, we can just avoid
these elements.
We were still missing the resources and the libraries inside the actual
bundle directory. Do it at install time to not make a mess of all the
rules. The gn build lists all the libraries in a massive list, which
is quite a pain. We can over-copy a few libraries like this to make the
install script a bit easier to follow.
We weren't installing a lot of generated sources for the top level Lagom
build or for LibWeb, making it impossible to use LibWeb from a
find_package. ...And also Kernel/API/KeyCode.h, which is included by
no less than 8 different files in Userland/Libraries. We also weren't
installing any Ladybird header files.
We already do this for headless-browser. There's no need to open any URL
other than about:blank when starting a WebDriver session. We should also
do this from WebDriver code, rather than in special logic in Browser's
main.cpp.
The issue noted in the removed comment no longer seems to apply. The URL
loaded here is triggered before WebDriver even issues the POST /session
command.
When we launch Ladybird, we currently:
1. Create a BrowserWindow, whose constructor navigates to the configured
new tab page URL.
2. Then navigate to either "about:blank" or whatever URL is provided via
the command line.
This patch removes step 2 and forwards the URL from the command line (if
any) to BrowserWindow. BrowserWindow's constructor then either navigates
to that URL or the new tab page URL.
Currently, if the JS console is open and tied to the last opened tab in
the browser window, it will prevent the main process from exiting when
the last tab is closed. This change explicitly closes that tab before
closing the window (if it's the last tab), allowing Qt to delete the
Tab object.
This will help a lot with developing chromes for different UI frameworks
where we can see which helper classes and processes are really using Qt
vs just using it to get at helper data.
As a bonus, remove Qt dependency from WebDriver.
With the CMake build, the ladybird binary ends up in
$build/bin/ladybird.app/Contents/MacOS. Which is a bit unfortunate for
a few reasons, but the main one is that --enable-lagom-networking
doesn't work with ./Meta/serenity.sh run lagom ladybird.
Let's copy the file to the expected location. There's very likely better
solutions we can use in the future.
This object is available as `window.internals` (or just `internals`) and
is only accessible while running in "test mode".
This first version only has one API: gc(), which triggers a garbage
collection immediately.
In the future, we can add more APIs here to help us test parts of the
engine that are hard or impossible to reach via public web APIs.
The Qt docs are not that clear, but to get the number of steps the
wheel was scrolled you divide by 120 (which when multiplied by
wheelScrollLines() gives the scroll offset).
Documentation says that pixelDelta() is not reliable across platforms
so always using angleDelta() should produce more predictable scrolling
behaviour.
Rather than directing mouse wheel events to the QAbstractScrollArea,
send them to the WebContent process, allowing it to determine if they
should be consumed by the element or used for page scrolling.
The implementation of this plugin is meant to eventually replace all
current audio plugins in Ladybird. The benefits over the current Qt-
based audio playback plugin in Ladybird are:
- Low latency: With direct access to PulseAudio, we can ask for a
specific latency to output to allow minimal delay when pausing or
seeking a stream.
- Accurate timestamps: The Qt audio playback API does not expose audio
time properly. When we have access directly to PulseAudio APIs, we can
enable their timing interpolation to get an accurate monotonically-
increasing timestamp of the playing audio.
- Resiliency: With more control over how the underlying audio API is
called, we have the power to fix most bugs we might encounter. The
PulseAudio wrappers already avoid some bugs that occur with QAudioSink
when running through WSLg.
Previously, a QTimer was used to start processing of our event queue in
the main Qt event loop. Unfortunately, QTimers are not thread-safe, and
disallow starting of a timer from a different thread than it was
created in.
Instead, use a dummy QObject to post a custom QEvent to the main loop
from whatever thread we like, and process our event queue when it is
received by our dummy object.
The logic for `EventLoopImplementationQt::pump()` caused calls to
`EventLoop::pump(PumpMode::DontWaitForEvents)` to not consume events
posted to the Qt event queue. This caused the window to be unresponsive
even when polling the event loop, if waiting was not desired.
If a URL is not valid we try navigating to https:// + the url. It's
better to ask AK::Url if it thinks the url is valid than put a big list
of prefixes here, with this obscure protocols like Gemini are now
recognised and with `--enable-lagom-networking` can be viewed in
Ladybird (thanks to #2218).
Now that all the classes for Ladybird are in the Ladybird namespace, we
don't need them named as Ladybird::FooBarLadybird. For the Qt-specific
classes, we can tack on a Qt at the end for clarity, but FontPlugin and
ImageCodecPlugin no longer have anything to do with Qt.
We were super inconsistent about this, with most "new" classes living in
the Ladybird namespace, while "old" ones were in the global namespace,
or even sitting in the Browser namespace.
Ladybird's RequestServer needs to depend on its generated IPC header
files to ensure they are generated before RequestServer is compiled,
which we currently bundle into LibWebView.
LibTLS still can't access many parts of the web, so let's hide this
behind a flag (with all the plumbing that entails).
Hopefully this can encourage folks to improve LibTLS's algorithm support
:^).
Re-organize our helper files here a bit, to make a clearer distinction
between Qt-specific helpers and generic non-serenity helpers.
A future commit will move Lagom specific code from LibSQL to ladybird
as well, so that we can see about future generic apis for spawning
helper procesess.
The spawn_helper_process method was introduced together with
get_paths_for_helper_process but was only ever used briefly to spawn
WebContent. Other helper processes (SqlServer, headless_browser etc)
are either execed or spawned with their own helpers & custom arguments.
The Qt relationship was removed in de31a8a4, so let's acknowledge that
and make it clearer to potential non-Qt ports that this file is usable
by them :^).
Rather than set a hacky scale factor on our QIconEngine, just set the
icon size for the toolbar icons. This avoids the icons being
unnecessarily scaled in other places (i.e. the context menu).
In order to follow spec text to achieve this, we need to change the
underlying representation of a host in AK::URL to deserialized format.
Before this, we were parsing the host and then immediately serializing
it again.
Making that change resulted in a whole bunch of fallout.
After this change, callers can access the serialized data through
this concept-host-serializer. The functional end result of this
change is that IPv6 hosts are now correctly serialized to be
surrounded with '[' and ']'.
Now that we no longer use QFont from LibWeb, we can also stop using
QGuiApplication in the WebContent process entirely.
This removes a whole bunch of unnecessary work from the event loop,
and also allows nice things like running headless-browser while
*actually* headless. :^)
Rather than render the icons to a 16x16 bitmap, keep them as vector
graphics and render them on request. This keeps the icons crisp on high
DPI displays.
The Qt StyleHint system didn't work on X11 anyway, and we ended up with
the default UI font being used for both `serif` and `sans-serif`.
Instead of asking Qt for something it can't do properly, let's just grab
the first available font from our list of fallbacks. This should give us
better results everywhere.
WebView::ViewImplementation now remembers which JS interpreter it
started with, and uses the same setting if the WebContent process
crashes and we have to spawn a new one.
In some places in the code QAction instances are added to a parent
directly on instantiation. In the case they are not, Valgrind
reports them as leaking.
We don't need the extra gradle files in our sources, the Qt CMake
integration will generate suitable ones for us.
Make sure that assets is always a folder, so that we can get the proper
layout for the ladybird-assets.tar.gz and CMake doesn't create a gzip
file with the name "assets".
Fix up the AndroidPlatform file and make sure it's linked into all the
applications that need it. Also make sure to copy all the application
shared libraries into the ladybird APK so that when we make them into
proper Services, the libs are already there.
This implementation detail of audio support in ladybird is a QObject
that needs moc'd by the moc tools. Putting it in its own file follows
the pattern we have for all the other QObjects in Ladybird.
Doing this removes the qt6-svg dependency and allows our rasterizer to
be used for these little icons (and happens to be a fair bit smaller
than the old SVGs).
We currently drop events which do not have text associated with them.
This prevents e.g. arrow keys from being able to be handled by web
elements. We now match Browser's behavior on Serenity, where these key
events are already propagated.
This change was a long time in the making ever since we obtained sample
rate awareness in the system. Now, each client has its own sample rate,
accessible via new IPC APIs, and the device sample rate is only
accessible via the management interface. AudioServer takes care of
resampling client streams into the device sample rate. Therefore, the
main improvement introduced with this commit is full responsiveness to
sample rate changes; all open audio programs will continue to play at
correct speed with the audio resampled to the new device rate.
The immediate benefits are manifold:
- Gets rid of the legacy hardware sample rate IPC message in the
non-managing client
- Removes duplicate resampling and sample index rescaling code
everywhere
- Avoids potential sample index scaling bugs in SoundPlayer (which have
happened many times before) and fixes a sample index scaling bug in
aplay
- Removes several FIXMEs
- Reduces amount of sample copying in all applications (especially
Piano, where this is critical), improving performance
- Reduces number of resampling users, making future API changes (which
will need to happen for correct resampling to be implemented) easier
I also threw in a simple race condition fix for Piano's audio player
loop.
For example, on https://xboygeniusx.bandcamp.com/album/the-record, a
song with a duration of 03:52 would actually complete in 03:33 on my
machine. This issue only affects Ladybird on Lagom; on Serenity, we
already take the entire 03:52 to play the song.
It's currently possible to seek to the total sample count of an audio
loader. We must limit seeking to one less than that count.
This mistake was duplicated in both AudioCodecPluginSerenity/Ladybird,
so the computation was moved to a helper in the base AudioCodecPlugin.
When the default audio device changes on the host, it's convenient to
automatically switch to that device rather than needing to reload the
page to update.
We are currently forcing audio to play with a sample size of 16 bits. We
are also feeding the output audio device a hard-set amount of samples
without considering the actual size of its sample buffer. This would
cause a wide array of issues when playing audio elements. On my Linux
machine, we would hear some cracking; on my macOS machine, audio was
quite garbled.
We now write samples of the size requested by the output audio device.
We also limit the samples we provide to the audio device to however many
bytes are available in its buffer.
The main thread in the WebContent process is often busy with layout and
running JavaScript. This can cause audio to sound jittery and crack. To
avoid this behavior, we now drive audio on a secondary thread.
Note: Browser on Serenity uses AudioServer, the connection for which is
already handled on a secondary thread within LibAudio. So this only
applies to Lagom.
Rather than using LibThreading, our hands are tied to QThread for now.
Internally, the Qt media objects use a QTimer, which is forbidden from
running on a thread that is not a QThread (the debug console is spammed
with messages pointing this out). Ideally, in the future AudioServer
will be able to run for non-Serenity platforms, and most of this can be
aligned with the Serenity implementation.
The data we want to send out of the WebContent process is identical for
audio and video elements. Rather than just duplicating all of this for
audio, generalize the names used for this IPC for all media elements.
This also encapsulates that data into a struct. This makes adding new
fields to be sent much easier (such as an upcoming field for muting the
element).
This makes pages that use CSS rules like '@media (max-device-width:
600px)' render more correctly.
Without this change device-width and height queries would return 0.
This creates (and installs upon WebContent startup) a platform plugin to
play audio data.
On Serenity, we use AudioServer to play audio over IPC. Unfortunately,
AudioServer is currently coupled with Serenity's audio devices, and thus
cannot be used in Ladybird on Lagom. Instead, we use a Qt audio device
to play the audio, which requires the Qt multimedia package.
While we use Qt to play the audio, note that we can still use LibAudio
to decode the audio data and retrieve samples - we simply send Qt the
raw PCM signals.
On macOS, CMake incorrectly tries to add and/or remove rpaths from files
that it has already processed when it performs installation. Setting the
rpaths during the build process ensures that they are only set once, and
as a bonus, makes installation slightly more performant.
Fixes#10055.
Currently, we only look at the relative path `./{helper}/{helper}`,
which fails if the working directory is not the same as the directory
where the ladybird binary lives.
This will make it a lot easier to understand what went wrong, especially
when the failure occurs on CI but not at home.
And of course, use LibDiff to generate the diff! :^)
Instead of starting a new headless-browser for every layout & text test,
headless-browser now gets a mode where it runs all the tests in a single
process.
This is massively faster on my machine, taking a full LibWeb test run
from 14 seconds to less than 1 second. Hopefully it will be a similarly
awesome improvement on CI where it has been soaking up more and more
time lately. :^)
This looks a lot more "at home" than usual pixel art logo on
non-SerenityOS systems. :^)
Also, stop using site favicons as the app icon as that made it
annoyingly hard to find Ladybird in task switchers sometimes.
This allows us to create "text tests" in addition to "layout tests".
Text tests work the same as layout tests, but dump the document content
as text and exit upon receiving the window "load" event.
Previously, calling `.right()` on a `Gfx::Rect` would return the last
column's coordinate still inside the rectangle, or `left + width - 1`.
This is called 'endpoint inclusive' and does not make a lot of sense for
`Gfx::Rect<float>` where a rectangle of width 5 at position (0, 0) would
return 4 as its right side. This same problem exists for `.bottom()`.
This changes `Gfx::Rect` to be endpoint exclusive, which gives us the
nice property that `width = right - left` and `height = bottom - top`.
It enables us to treat `Gfx::Rect<int>` and `Gfx::Rect<float>` exactly
the same.
All users of `Gfx::Rect` have been updated accordingly.
The goal here is to reduce the amount of WebContent client APIs that are
duplicated across every ViewImplementation. Across our three browsers,
we currently:
Ladybird - Mix some AK::Function callbacks and Qt signals to notify
tabs of WebContent events.
Browser - Use only AK::Function callbacks.
headless-browser - Drop most events on the floor.
Instead, let's only use AK::Function callbacks across all three browsers
to propagate events to tabs. This allows us to invoke those callbacks
directly from LibWebView instead of all three browsers needing to define
a trivial `if (callback) callback();` override of a LibWebView virtual
function. For headless-browser, we can simply not set these callbacks.
As a first pass, this only converts WebContent events that are trivial
to this approach. That is, events that were simply passed onto the tab
or handled without much fuss.
This is to match Browser, where ownership of all "subwidgets" is placed
on the tab as well. This further lets us align the web view callbacks to
match Browser's OOPWV as well, which will later let us move them into
the base LibWebView class.
Note that the real implementations of these functions are:
notify_server_did_output_js_console_message
notify_server_did_get_js_console_messages
Which have the same method bodies as these unused variants.
The implementations of handle_web_content_process_crash and
take_screenshot are exactly the same across Browser and Ladybird. Let's
reduce some code duplication and move them to LibWebView.
Previously, we were doing mapToGlobal() via the Tab widget, but the
widget position was actually relative to the WebContentView. This
meant context menus appeared slightly vertically offset from where
you clicked.
This just sets up the IPC to notify the browser process of context menu
requests on video elements. The IPC contains a few pieces of information
about the state of the video element.
While resizing, we now pad the shared bitmap allocations with 256 pixels
extra in both axes. This avoids churning through huge allocations for
every single resize step.
We also don't reallocate at all when making the window smaller.
3 seconds after the user stops resizing, we resize the backing stores
again so they fit the window perfectly.
This fixes an unpleasant visual glitch when resizing the window.
When the user makes our QAbstractScrollArea larger, the scroll bars can
end up with negative values, which we were happily forwarding to the
WebContent process and asking it to paint the whole page at an offset.
This commit adds the common actions you'd expect to the Ladybird context
menu, arranged like so:
┌──────────────────────────────┐
│ Go Back Alt+Left │
│ Go Forward Alt+Right │
│ Reload Ctrl+R │
│ ──────────────────────────── │
│ Copy Ctrl+C │
│ Select All Ctrl+A │
│ ──────────────────────────── │
│ View Source Ctrl+U │
│ Inspect Element │
└──────────────────────────────┘
The asynchronous query execution keeps causing bugs with document.cookie
so let's make the SQL database backend default off until we can trust it
to do what we need.
This adds "Inspect Element" (currently the only entry) to the context
menu for the page, which will do what you expect (most of the time),
and bring up the Inspector with hovered element selected.
We should only rely on LibGfx to decode images for us, if LibGfx
can't decode an image that should be motivation to improve LibGfx,
not hidden by Qt picking up the slack :^)
While it's nice to see <img src="foo.svg"> suddenly work in Ladybird
after linking with the Qt SVG module, this is cheating.
We should implement SVG-as-image ourselves instead of relying on 3rd
party code to do it. :^)
For some reason, this was causing incomplete HTTP loads in some cases.
As an example, we would only load half of the "Ahem" CSS font from the
wpt.live server when running Acid3.
I only enabled pipelining in the first place because I assumed it would
be a performance boost, but it appears to do more than that.
I suppose there's a reason it's off by default (and most Qt API users
don't bother enabling it.)
We now load SVG icons (via the Qt resource system) and render them into
a QIcon (with normal and disabled variants) using system colors.
We also re-render them if the system color theme changes.
This instantly makes Ladybird look less foreign on my Linux box.
I drew the icons myself, and they could definitely be more optimized,
but this was my first time using Inkscape. :^)
The WebContent process behaves a bit awkwardly on macOS. When we launch
the process, we have to create a QGuiApplication to access system fonts.
But on macOS, doing so creates an entry in the Dock, and also causes the
WebContent to be focused. So if you enter cmd+Q without first focusing
the Ladybird GUI, WebContent is closed, while the Ladybird process keeps
running.
This shouldn't have been moved to EventLoopManager, as the manager is
global and one-per-process, and the implementation is one-per-loop.
This makes cross-thread event posting work again, and unbreaks
SoundPlayer (and probably other things as well.)
We currently query Qt for system fonts using QFont::setStyleHint(). The
docs from Qt have the following note regarding this API on X11:
Qt does not support style hints on X11 since this information is not
provided by the window system.
This prevents any monospace font from working on X11 systems. For now,
work around this by specifying the font-family for fonts which Qt has
listed as mapping to a CSS generic font-family.
Things such as timers and notifiers aren't specific to one instance of
Core::EventLoop, so let's not tie them down to EventLoopImplementation.
Instead, move those APIs + signals & a few other things to a new
EventLoopManager interface. EventLoopManager also knows how to create a
new EventLoopImplementation object.
Using QEventLoop works for everything but it breaks *one* little feature
that we care about: automatically quitting the app when all windows have
been closed.
That only works if you drive the outermost main event loop with a
QCoreApplication instead of a QEventLoop. This is unfortunate, as it
complicates our API a little bit, but I'm sure we can think of a way to
make this nicer someday.
In order for QCoreApplication::exec() to process our own
ThreadEventQueue, we now have a zero-timer that we kick whenever new
events are posted to the thread queue.
Now that the Core::EventLoop is driven by a QEventLoop in Ladybird,
we don't need to patch LibWeb with Web::Platform plugins.
This patch removes EventLoopPluginQt and TimerQt.
Note that we can't just replace the Web::Platform abstractions with
LibCore stuff immediately, since the Web::Platform APIs use
JS::SafeFunction for callbacks.
This patch adds EventLoopImplementationQt which is a full replacement
for the Core::EventLoopImplementationUnix that uses Qt's event loop
as a backend instead.
This means that Core::Timer, Core::Notifier, and Core::Event delivery
are all driven by Qt primitives in the Ladybird UI and WC processes.
Not a single client of this API actually used the event mask feature to
listen for readability AND writability.
Let's simplify the API and have only one hook: on_activation.
This aligns the Ladybird console implementation with the Browser console
a bit more, which uses OutOfProcessWebView for rendering console output.
This allows us to style the console output to try and match the system
theme.
Using a WebContentView is simpler than trying to style the old QTextEdit
widget, as the console output is HTML with built-in "-libweb-palette-*"
colors. These will override any color we set on the QTextEdit widget.
We never clear content filters on either end of the Browser-WebContent
IPC connection. So when the filters change, we re-append all filters to
the Vector holding them. This incidentally makes it impossible to remove
a filter.
Change both sides to clear their filter lists when receiving a new set
of filters.
This adds a -P option to run Ladybird under callgrind. It starts with
instrumentation disabled. To start capturing a profile (once Ladybird
has launched) run `callgrind_control -i on` and to stop it again run
`callgrind_control -i off`.
P.s. This is pretty much stolen from Andreas (and is based on the patch
everyone [that wants a profile] have been manually applying).
We had a mismatch in the GUI Identifier property, causing warnings in
Xcode. It was also missing the Product Identifier Xcode property on
ladybird itself, causing another warning.
Copy all our helper processes to the ladybird.app bundle directory so
that they can be found by ``open ladybird.app`` and the Xcode debugger.
For the future, we should look in ../Resources for resources on macOS.
Copying resources to that directory requires more CMake-fu.
Fix the problem that `cmake --build Build/ladybird` started
failing with:
fatal error: 'WebContent/WebDriverConnection.h' file not found
after 11fe34ce0f
Generate handle UUID for top-level context that is going to
run in created WebContent process and sent it over IPC.
Co-authored-by: Timothy Flynn <trflynn89@pm.me>
Currently, on Serenity, we connect to WebDriver from the browser-side of
the WebContent connection for both Browser and headless-browser.
On Lagom, we connect from within the WebContent process itself, signaled
by a command line flag.
This patch changes Lagom browsers to connect to WebDriver the same way
that Serenity browsers do. This will ensure we can do other initializers
in the same order across all platforms and browsers.
There isn't a 1:1 equivalent for all ColorRoles between Qt and LibGfx,
but we can at least make an effort to translate the various QPalette
preferred colors.
This makes text selection look a lot more "native" in Ladybird. :^)
This patch replaces the usage of QPalette::PlaceholderText with
QPalette::Text with opacity reduced to roughly 50%. This fixes the non
highlighted spans having an extremely low contrast compared to the
background in dark mode.
LibGUI and WebDriver (read: JSON) API boundaries use DeprecatedString,
so that is as far as these changes can reach.
The one change which isn't just a DeprecatedString to String replacement
is handling the "null" prompt response. We previously checked for the
null DeprecatedString, whereas we now represent this as an empty
Optional<String>.
headless-browser currently uses its own PageClient to load web pages
in-process. Due to this, it also needs to set up a whole bunch of other
objects needed to run LibWeb, e.g. image decoders, request servers, etc.
This changes headless-browser to instead implement a WebView to launch
WebContent out-of-process. This implementation is almost entirely empty,
but can be filled in as-needed. For example, we may want to print
JavaScript console messages.
We should be able to run this locally, as long as ENABLE_LAGOM_LADYBIRD
is true, or if building ladybird from the ladybird source directory.
This removes a special case from the Lagom CI yml file.
The QNetworkReply::NetworkError enum mixes all kinds of errors into one
enum, HTTP errors, network errors, proxy errors, etc.
Instead of caring about it, we now say that HTTP requests were
successful if their response has any HTTP status code attached.
This allows LibWeb to display error pages when using Qt networking.