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.
Previously, the label called `HTMLElement::click()` which dispatched a
synthetic event with all properties set to their default values. We now
preserve the properties of the original mouse event.
This clamps the interval of repeating timers to 4ms after they have run
5 times. This prevents CPU spinning for `setInterval()` calls with low
timeouts.
Previously only input elements were matched. Add placeholder_value()
to HTMLTextAreaElement mirroring the HTMLInputElement API and update
both selector matching code paths to handle textarea.
Browsers seem to make it convenient to replace an <input>'s contents by
selecting all text on focusing, but only if you used keyboard
navigation. Programmatic focus and clicking on the field do not show
this behavior.
We don't have a text node in these, so no fragments either. Maintaining
a special case for this situation seems much simpler than reworking
`contenteditable`s to always have a fragment.
Our change to generate spans in PaintableWithLines from fragments also
broke drawing the caret for empty <input>s and <textarea>s, since spans
was empty in that case.
Fix this by moving caret drawing to PaintableWithLines, and only
invoking it if we have a cursor position set.
When the mouse is dragged from inside a scrollable container to outside
of it, we now automatically scroll the container so the selection can be
extended. Scroll speed scales with the distance past the scrollport
edge, capped at a maximum. Edges close to the viewport boundary get a
wider activation zone so the speed ramp works predictably even when the
mouse has limited room to move.
The logic is encapsulated in AutoScrollHandler, which EventHandler
creates lazily on mouse selection start.
This allows us to consider fragments for hit testing even though the
cursor moved fully above them. This will allow us to select all the
contents in a <textarea> when you drag the mouse all the way to the top,
beyond the <textarea>'s top edge.
When editing or changing the selection inside an <input> or <textarea>,
we should scroll the container so the cursor is always visible. Note
that currently the cursor might still become invisible at the end of the
container since we do not reserve enough space for it to be made
visible.
Add 6 text tests that verify correct behavior when image loading
callbacks fire after a document has been destroyed. These tests
check that load/error events are properly suppressed and that
no additional network activity occurs after the document becomes
inactive.
The caching RFC is quite strict about the format of date strings. If we
received a revalidation attribute with an invalid date string, we would
previously fail a runtime assertion. This was because to start a
revalidation request, we would simply check for the presence of any
revalidation header; but then when we issued the request, we would fail
to parse the header, and end up with all attributes being null.
We now don't parse the revalidation attributes at all. Whatever we
receive in the Last-Modified response header is what we will send in the
If-Modified-Since request header, verbatim. For better or worse, this is
how other browsers behave. So if the server sends us an invalid date
string, it can receive its own date format for revalidation.
Test all major code paths in the CSS2 10.6.4 algorithm for computing
height of absolutely positioned non-replaced elements:
- Rules 4, 5, 6 (one auto among top/height/bottom)
- Over-constrained case (none auto)
- Auto margin solving (one auto, both auto)
- Min-height and max-height re-solve for rules 4, 5, 6
- Min/max with auto margins
- Borders and padding interaction with min-height
Per the CSSOM specification, throw a NotFoundError DOMException when
the specified medium is not found in the collection. Invalid input
that fails to parse continues to return silently per step 2.