This patch adds an event handler to the main window which allows it to
respond to a user closing the window. This event is then passed on to
the LibCore event loop, which allows the application quit itself.
Previously the application would hang, only running in the background,
until killed by an external force.
On high-dpi systems QT will automatically scale up painting operations.
This results in an ugly blurry browser window surrounded by a nicely
scaled window frame. This patch applies an inverse scale to the WebView
widget, ensuring the painting and mouse events are lined up and draw
with a 1:1 pixel ratio with respect to the display's device pixels.
This fixes a bug where hackstudio's language server will crash upon
clicking the 'cut' button when no text is selected. This was because
the actions were not disabled on empty selection.
We now disable the actions depending on if there is empty selection
inside current tab. We update the cut/copy/paste buttons' actions when
changing tabs.
Previously gradient painting was dominated by the clipping checks in
Painter::set_pixel(). This commit changes gradient painting to use the
new Painter::fill_pixels() function (which does all these checks outside
the hot loop).
With this change gradient painting drops from 96% of the profile to 51%
when scrolling around on gradients.html. A nice 45% reduction :^)
This function fills a region of pixels with the result of a callback
function. This is an alternative to a for loop that repeatedly calls
Painter::set_pixel(), which can get very expensive due to the clipping
checks set_pixel() does each call.
This is fixed by making the "about to be notified rejected promises
list" use JS::Handle instead of JS::NonnullGCPtr. This UAF happens
because notify_about_rejected_promises makes a local copy of this list,
empties the member variable list and then moves the local copy into a
JS::SafeFunction lambda. JS::SafeFunction can only see GC pointers that
are in its storage, not external storage.
Example exploit (requires fixed microtask timing by removing the dummy
execution context):
```html
<script>
Promise.reject(new Error);
// Exit the script block, causing a microtask checkpoint and thus
// queuing of a task to fire the unhandled rejection event for the
// above promise.
// During the time after being queued but before being ran, these
// promises are not kept alive. This is because JS::SafeFunction cannot
// see into a Vector, meaning it can't visit the stored NonnullGCPtrs.
</script>
<script defer>
// Cause a garbage collection, destroying the above promise.
const b = [];
for (var i = 0; i < 200000; i++)
b.push({});
// Some time after this script block, the queued unhandled rejection
// event task will fire, with the event object containing the dead
// promise.
window.onunhandledrejection = (event) => {
let value = event.promise;
console.log(value);
}
</script>
```
They currently reside under Build/<arch>, meaning that they would be
redownloaded for each architecture/toolchain build combo. Move them to a
location that can be re-used for all builds.
Not a huge deal because this at least would still differ from the UCD
cache due to the locale_data.cmake. But this will use the same cache key
as other CI jobs.
Previously we were doing this at the painting stage, which meant that
layout potentially used the wrong glyphs when measuring text.
This would lead to incorrect layout metrics and was visible on the
HTML5Test score display, for example. :^)
This change adds functionality to open the current file in the File
Manager from the File menu or through a button on the toolbar. If
there is no saved data then the functionality is disabled.
In order to debug WebServer and responses we can't handle yet, it's
beneficial to being able to see what we request and what we get back.
As a first measure, we just log URL, response code, reason phrase and
headers.
We couldn't compile a project after creating it, because the project
builder was still holding a reference to the previous freed project.
Fixes: #15715
This change also removes the path argument from the GitWidget
constructor because otherwise, the app wouldn't work now, as it doesn't
yet know the project path.
But it'll be set right away in open_project(), so nothing's lost. :^)
The food bitmaps would sometimes be placed underneath the score text,
which was a bit hard to see. Use a statusbar like we do in other games
like Solitaire.
Note the default height change of the Snake window is to make the inner
game widget fit exactly 20x20 cells.
Unfortunately, GML widget registration requires a non-fallible construct
method to create the widget. So this does a bit of manual error checking
when loading the food bitmaps.
The former is required for GML, and the latter is to avoid the verbosity
and redundancy of Snake::SnakeGame (and matches most other games in the
system).
About half of the usages were not using `force` anyways, and the other
half presumably just got confused about what "force" really means in
this context (which is "ignore nonexistent files").
The only 'legitimate' user, which is `rm`, instead now handles this
completely internally instead.