When a tab or nested traversable navigable is closed, there might be
messages still in the pipe from the UI process that we need to
gracefully drop, rather than crash trying to access an invalid pointer.
Double-clicking the edges of a window results in the edge being extended
until it latches to the screen edge. This used to violate the fixed
aspect ratio property of certain windows because of only extending the
window in one dimension.
This commit adds a special case to the latching logic that makes sure to
also extend the other dimension of the window such that the fixed aspect
ratio is maintained.
The IPC layer between chromes and LibWeb now understands that multiple
top level traversables can live in each WebContent process.
This largely mechanical change adds a billion page_id/page_index
arguments to make sure that pages that end up opening new WebViews
through mechanisms like window.open() still work properly with those
extra windows.
WIFEXITED() returns a bool, so previously we were setting
exited_successfully to true when the service was terminated by a signal,
and false if it exited, regardless of the exit status. To test the exit
status, we have to use WEXITSTATUS() instead.
This causes us to correctly use the "3 tries then give up" logic for
services that crash, instead of infinitely attempting to respawn them.
The layout system can't currently answer the question "what height does
this Label want to be, if it has a certain width available?" Instead it
relies on counting newlines, which doesn't work in a lot of cases. This
made the notification windows look and behave in a funky way when their
text wraps onto multiple lines.
This patch uses TextLayout to measure how many lines we need, and then
manually sets the Label and Window heights to match. It's a bit hacky,
hence the FIXME, but it does make things behave the way they are
supposed to.
This refactoring makes WebContent less aware of LibWeb internals.
The code that initializes paint recording commands now resides in
`Navigable::paint()`. Additionally, we no longer need to reuse
PaintContext across iframes, allowing us to avoid saving and restoring
its state before recursing into an iframe.
This really just takes the [App].Name config value and removes the
ampersands `&` from the name. These ampersands are hotkeys for the
system menu. Instead of typing them twice - error prone - use the
fact that name is just menu_name without the ampersand. Remove the
ampersand to use as the name and use it as is as the menu_name.
`JsonValue::to_byte_string` has peculiar type-erasure semantics which is
not usually intended. Unfortunately, it also has a very stereotypical
name which does not warn about unexpected behavior. So let's prefix it
with `deprecated_` to make new code use `as_string` if it just wants to
get string value or `serialized<StringBuilder>` if it needs to do proper
serialization.
Instead of trying to acquire from an individual mouse device, let's read
from /dev/input/mice, where all mouse packets are blended together from
all mouse devices that are attached to the machine.
Instead of spawning these processes from the WebContent process, we now
create them in the Browser chrome.
Part 1/N of "all processes are owned by the chrome".
Considering an operation like the following:
document.cookie = "cookie=value";
const value = document.cookie;
If the IPC for the cookie setter is asynchronous, the getter can execute
while the browser/SQLServer processes are still handling the setter.
This is often seen when hammering the document with cookie requests.
The architecture of SQLServer is currently such that it sends results
over IPC one row at a time. After the rows are exhausted, it sends a
completion IPC. However, it does not wait for the client to finish
processing a row before sending another row or the completion signal.
This can result in clients hanging if the completion comes in while a
row is being processed. At least in the case of WebView::Database, the
result is that the completion signal is dropped, and the browser then
hangs forever waiting for that signal (after it finishes processing the
row).
This patch makes SQLServer asynchronously wait for the client to tell it
that the row has been processed and the next row (or completion) may be
sent. We repurpose the `m_ongoing_executions` in SQLStatement for this
purpose (this member was oddly being written to, but otherwise unused).
This really only implements a heuristic, assuming that HTTP/1.0 servers
cannot handle having multiple active connections; this assumption has
lots of false positives, but ultimately HTTP/1.0 is an out-of-date HTTP
version and people using it should just switch to a newer standard
anyway.
Specifically, python's "SimpleHTTPRequestHandler" utilises a
single-threaded HTTP/1.0 server, which means no keepalive and more
importantly, hangs and races with more than a single connection present.
This commit makes it so we serialise all requests to servers that are
known to serve only a single request per connection (aka HTTP/1.0 with
our setup, as we unconditionally request keepalive)
When the WebContent process has painted to its shared bitmaps, it sends
a synchronous IPC to the browser process to let the chrome paint. It is
synchronous to ensure the WC process doesn't paint onto the backing
bitmap again while it is being displayed.
However, this can cause a crash at exit if the browser process quits
while the WC process is waiting for a response to this IPC.
This patch makes the painting logic asynchronous by letting the browser
process broadcast when it has finished handling the paint IPC. The WC
process will not paint anything again until it receives that message. If
it had tried to repaint while waiting for that message, that paint will
be deferred until it arrives.
Fixes#22582
Previously, the job and the (cache of them) would lead to a UAF, as
after `.start()` was called on the job it'd be immediately destroyed.
Example of previous bug:
```
// Note due to the cache &jobA == &jobB
auto& jobA = Job::ensure("https://r.bing.com/");
auto& jobB = Job::ensure("https://r.bing.com/");
// Previously, the first .start() free'd the job
jobA.start();
// So the second .start() was a UAF
jobB.start();
```