Stress-test the isContentEditable property across various scenarios:
dynamic contenteditable changes, node moves between editable/noneditable
subtrees, insertion/removal, design mode toggle, deep nesting, nested
contenteditable overrides, and plaintext-only mode.
There are actually a couple of bugs here:
1. As of commit ebda8fcf11, editing hosts
are now excluded from Node::is_editable. Since this special hit test
handling is specifically for contenteditable nodes, we would not
enter this branch for these nodes.
2. We were not checking if the contenteditable node actually contained
the hit testing position. So if a page had multiple empty editable
nodes, we would just return whichever was hit test first.
These bugs were exposed by 7c9b3c08fa.
This commit resulted in the text cursor hit test node being set as the
document focus node. If we returned the wrong result, we would not set
the correct node.
This was seen on discord, where clicking the message box would result in
the search box being focused.
The grammar groups this component together meaning that all
sub-components must occur together i.e.
`ordinal slashed-zero small-caps` is valid but
`ordinal small-caps slashed-zero` is not.
We also reuse the logic for parsing from the longhand
`font-variant-numeric` property for simplicity.
The grammar groups this component together meaning that all
sub-components must occur together i.e.
`common-ligatures no-contextual small-caps` is valid but
`common-ligatures small-caps no-contextual` is not.
We also reuse the logic for parsing from the longhand
`font-variant-ligatures` property for simplicity.
The grammar groups this component together meaning that all
sub-components must occur together i.e. `jis78 full-width small-caps` is
valid but `jis78 small-caps full-width` is not.
We also reuse the logic for parsing from the longhand
`font-variant-east-asian` property for simplicity.
Our HTTP test server supports a limited amount of byte range request
formats. The format we were using was incorrect, causing the server to
fail an assertion. We now ensure the response body is piped as expected
to catch issues like this in the future.
The constraint equations for absolutely positioned replaced elements
only subtracted content width/height from the containing block size,
omitting padding and border.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/7820
The HTML event loop spec explicitly provides guidance for reentrancy in
the "perform a microtask checkpoint" algorithm, so we cannot VERIFY
for empty execution context before this early exit (as much as we'd
like to).
https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint
See the microtask-checkpoint-reentrancy-via-responsexml-script test for
an example of how this can happen from user scripts.
When z-index changes from 0 to a positive value on a positioned element,
the stacking context tree is not rebuilt, causing the element to be
painted twice. This test captures the current (incorrect) behavior.
We were previously not allowing the user to select text when the clicked
position represented a click-focusable area. This included text within
dialogs (as the dialog element is click-focusable) and labels (as the
associated input element would be considered click-focusable).
We now no longer consider associated input elements when clicking on a
label. This is handled separately already by the label's activation
behavior steps, so there is no loss of functionality here. In those
steps, though, we now no longer propagate the click event to the input
element if a selection was made during the click. This matches the
behavior of Firefox and Chrome.
With label elements no longer considered here, we can then enter the
character selection mode when click-focusable areas are clicked.
Absolutely positioned elements inside SVG foreignObject were being
positioned relative to an ancestor containing block outside the SVG,
instead of relative to the foreignObject itself. Per a W3C resolution
and the behavior of other browsers, foreignObject should establish a
containing block for absolutely and fixed positioned elements.
With this fix, the `has_abspos_with_external_containing_block` check
in `set_needs_layout_update()` and the abspos preservation loop in
`relayout_svg_root()` become dead code — remove both and simplify the
ancestor loops. Rename related tests to reflect the new behavior.
Fixes https://github.com/LadybirdBrowser/ladybird/issues/3241
Chrome and Firefox inflate this rect to accommodate for the font's
ascenders and descenders, while the absolute rect for the fragment
remains unaffected. This fixes ascenders/descenders in text being
clipped when selecting text.
We were mimicking Firefox' behavior that whenever a programmatic change
to an <input>'s or <textarea>'s selection happened, the new selection
focus is brought into view by scrolling. Currently we run a layout
update synchronously for that to make sure we have the fragment's
correct dimensions, which caused a significant performance regression in
Speedometer.
Since this is non-standard behavior, let's mimic Chromium instead which
does not scroll at all - only for direct user initiated input such as
typing.
Relevant issues:
* https://github.com/whatwg/html/issues/6217
* https://bugzilla.mozilla.org/show_bug.cgi?id=232405
* https://issues.chromium.org/issues/41081857
Implement the `dense` keyword for `grid-auto-flow` so auto-placed items
backfill earlier gaps in the grid. The sparse/dense cursor logic is now
centralized in `place_grid_items()` step 4: dense resets the cursor to
the grid start before each search, while sparse keeps advancing forward.
Also fix a pre-existing bug where `find_unoccupied_place()` and several
placement helpers only checked if a single cell was unoccupied, ignoring
multi-cell spans. Add `OccupationGrid::is_area_occupied()` and use it
throughout to correctly verify the entire rectangular area is available.
Previously we didn't clear the computation context caches after:
- Recomputing inherited style
- Computing keyframe values
We now clear the caches in those two cases and verify it has been
cleared before using it.
Fixes#7959
The test triggers repeated partial relayout inside a nested SVG and
checks paintables on an outside-subtree SVG ancestor via
`internals.dumpPaintableTree()`. The count should stay stable, but
currently grows, revealing that partial relayout is creating extra
ancestor paintables instead of preserving existing ones.
No fix in this commit; this commit only captures the failing behavior.
Expose the paintable tree dump through the internals object, analogous
to the existing dumpLayoutTree(). This is useful for testing and
debugging painting behavior.
Unfortunately this is a bit of a pain to test as it is surprisingly
difficult to create a non secure context in our test harness.
This is because both file scheme URLs and localhost are considered
secure contexts.
To test this, add a very specific internals setter to change the
top level origin of the environment for the current realm.
This aligns our implementation with the specification. Doing this
fixes a number of WPT tests because this sets
`m_ongoing_api_method_tracker` to null, avoiding an assertion that
previously caused a crash.
When a CharacterData mutation inside a foreignObject triggered partial
SVG relayout, sibling absolutely positioned elements whose containing
block is outside the SVG were not being repositioned. This happened
because the check only walked ancestors of the changed node looking for
abspos elements — it never saw abspos siblings.
Fix by querying contained_abspos_children() on boxes outside the SVG
subtree, which finds all abspos elements regardless of their position
in the tree relative to the changed node.
Move the dispatch_events_for_animation_if_necessary() calls into step 1
of update_animations_and_send_events(), where the spec note says
updating timelines involves "Queueing animation events for any such
animations." Previously, these calls ran after step 7 (event dispatch),
causing newly queued events to be deferred by an extra rendering update.
This meant that e.g. a CSS transition triggered during an earlier
rendering step would not have its transitionrun event fired until the
next frame, instead of the current one.
The WebDriver clear handler for textarea elements sets the raw
value to child_text_content() instead of an empty string. This
is a copy-paste from the adjacent reset handler, which correctly
uses child_text_content() per its own spec. The clear spec says
"set the raw value of element to an empty string".
When a text node changes inside an absolutely positioned element within
an SVG <foreignObject>, and the abspos element's containing block is
outside the SVG subtree, the layout invalidation was incorrectly
stopping at the SVG root boundary. This triggered partial SVG relayout,
which cannot re-layout the abspos element since it's laid out by its
containing block's formatting context (outside the SVG).
The previous check only tested whether `this` (the node triggering
invalidation, e.g. a text node) was absolutely positioned, missing the
case where an abspos *ancestor* in the path has its containing block
outside the SVG. Fix this by walking from `this` up to the SVG root and
checking every abspos node in the path. If any has a containing block
outside the SVG subtree, skip the SVG boundary so layout propagation
continues upward and a full layout runs.
The full constructor for NotificationsAPI::Notification is implemented
along with the getter methods.
It is now possible to call the elements of Notification in JS without
getting undefined but the default values (or the ones passed in
options).
The method `current_wall_time` is added in EnvironmentSettingsObject.
This passes a least a few more tests because of the getter methods
that are created.
https://wpt.live/notifications/constructor-basic.https.htmlhttps://wpt.live/notifications/idlharness.https.any.html
Replace per-element OrderedHashMap storage for custom properties with
a RefCounted chain (CustomPropertyData) that enables structural
sharing. Each chain node stores only the properties declared directly
on its element, with a parent pointer to the inherited chain.
Elements that don't override any custom properties share the parent's
data directly (just a RefPtr copy). During cascade, only entries that
actually differ from the parent are stored in own_values - the rest
are inherited through the chain. During var() resolution, resolved
values are compared against the parent's and matching entries are
dropped, enabling further sharing.
The chain uses a depth limit (max 32) with flattening, plus
absorption of small parent nodes (threshold 8) to keep lookups fast.
This reduces custom property memory from ~79 MB to ~5.7 MB on
cloudflare.com.
Test that slotted elements correctly inherit styles from their
assigned slot in various scenarios: inline styles, CSS rules,
named slots, nested shadow hosts, own style overrides, deep
inheritance chains, dynamic slot reassignment, JS-created shadow
DOM, class toggles on slots, and moving elements between hosts.
Two issues prevented slotted elements from correctly inheriting
styles from their assigned slot:
1. Element::element_to_inherit_style_from() was skipping the slot
element and returning the shadow host instead. This meant slotted
elements inherited from the host, completely ignoring any styles
on the slot itself.
2. When a slot element's style changed during the style tree walk,
its assigned (slotted) nodes were never marked for recomputation.
The tree walk follows the DOM tree, but slotted elements are DOM
children of the shadow host, not the slot, so they were missed.
Fix (1) by returning the slot directly as the inheritance parent.
Fix (2) by marking assigned nodes dirty in update_style_recursively
when a slot's style changes.
Cover various scenarios: element's own style change, ancestor style
change affecting inheritance, sibling changes not affecting our element,
shadow DOM elements, pseudo-elements, and repeated reads.
Also documents a pre-existing bug where slotted elements don't pick up
inherited style changes from their assigned slot.
Previously, we fired the load event immediately, without waiting for
anything. This was good for not timing out, but bad for anything that
wanted to wait for the load to complete.
CSSStyleSheet now maintains a list of critical subresources, and waits
for all of them to complete before it then tells its owner that it is
ready. "Complete" here means the network request completed with or
without an error. This is done by having those subresources (just
`@import` for now) notify their style sheet when they complete. This
then propagates up as an `@import` tells its style sheet, which then
would tell its parent `@import` if it had one.
There are other subresources we should wait for (specifically fonts and
background images) but this commit just adds `@import` as a first step.