The cascade expanded overscroll-behavior into longhands but
CSSStyleDeclaration didn't, so setting the shorthand left
overscrollBehaviorX reading empty and a style= block round-tripped
through the object lost it.
CssParser.axis_shorthands is now the one list, with axisShorthand and
axisLonghand as the lookups both sides use: the CSSOM's overflow-only
special cases (set, apply, remove, priority, serialize) became that
lookup, and OverflowPair became AxisPair. Verified against Chrome 153:
`overscroll-behavior: contain auto` reads back per axis, collapses to
`contain` when both match, and serializes as one declaration.
writeScroll held the map entry across the clamp, which reads styles and
walks children, and it created an entry even for a write that changed
nothing. It now clamps both axes against a plain lookup and only takes
the entry when an offset actually moves.
That makes the write itself the answer to "can this container move?", so
the wheel walk asks by writing instead of recomputing the extent first,
and canScrollAxis is gone.
Adds the ability to execute JavaScript via WebDriver. The other webdriver
endpoints were able to re-use the existing BiDi code (e.g. navigating via
webdriver or bidi quickly ends up in the same function). But for execute, it's
completely different, from input parameters, to running the code, to the result
that's returned. So there's a dedicated handler for this: `execute.zig`. But
the rest of the infrastructure (the http waiting for a reply, the routing, the
parameter parsing, ... are all the same).
TryCatchRethrow, JsException and ExecutionTerminated all mean V8 already
has something pending: creating an error value and aborting the stream
would replace the exception the script is meant to see, or hand a killed
script a catchable Error. Drop the streaming handle instead, matching the
early exit in Caller.handleError.
Element.focus() would "focus" the element even when it shouldn't. We already
have the logic to determine if an element is focusable in `user_input.zig`, so
this was moved to Element and is now used in el.focus().
Some status-codes should never have a body except for a single trailing blank
line. If we don't handle these, then we end up with a dirty connection in our
connection pool:
1 - read the header, but not the body
2 - put the connection back in the pool
3 - try to read the header, but actually get the body from #1
WPT /fetch/api/basic/response-null-body.any.html exercises this path and is
flaky (because it depends whether the request goes back out on a keep-alive
connection)..but for a given run,you'll almost always get 1-3 failures.
This commit processes the request, but tells libcurl not to re-use the
connection.
wheelScroll handed the whole delta to the nearest scroll container on
each axis, whatever state it was in, so a saturated inner scroller
trapped the wheel and the page never moved.
scrollAxis walks outward per axis and gives the whole delta to the first
container that can still move along it. A delta is never split: a
container that can only take part of it keeps the rest, and the page
moves on the next wheel. That is Chrome's rule in FindNodeToLatch
(cc/input/input_handler.cc), confirmed against Chrome 153 - one wheel of
1000px over a container with 416px of travel leaves window.scrollY at 0.
A container whose overscroll-behavior doesn't propagate takes the latch
even when it can't move, which ends the walk.
Chaining a wheel out of a saturated container is exactly what sites use
`overscroll-behavior: contain` to prevent, so the cascade needs to know
about it before the wheel can chain.
Two flags follow the overflow-x/overflow-y pattern: a shorthand arm in
Slots.apply covers both fold paths, and overscrollContainAxes is the
probe. `contain` and `none` both stop propagation, only `auto` lets it
through. Props was exactly full at u8.
splitOverflow serves two shorthands now, so it is splitAxisPair.
Every scroll write clamped at zero and nothing else, so an offset could
exceed the scrollable extent without limit and a page probing
`scrollTop >= scrollHeight - clientHeight` got a number Chrome would
never produce.
Element.scrollExtent is that bound, and setScrollTop/setScrollLeft/
scrollTo/scrollBy now share one writer that applies it. The extent is
optional and null means unbounded: without a layout engine there is no
honest box for an element sized by a stylesheet (getElementAxis reads
only inline width/height) or one holding text (contentAxis sums element
children), and refusing a scroll we can't prove impossible is worse than
allowing one too many. html and body are excluded outright, so the
viewport keeps its fabricated extent and stays unbounded.
Chrome clamps all three, so the HTML fixture asserts the limit
relationally - a real browser reserves scrollbar space in clientHeight
and lands a few px lower. The gap we keep is pinned in a Zig test
instead.
The write path also does its arithmetic in i64: the old relative path
could panic on an offset stored above maxInt(i32).
The http max default was 4K with a 16KB hard limit. The default limit is now 1MB
with an initial default of 4K. This is to accommodate larger WebDriver payloads.
1 - Centralized cache-awareness into Cache and pulled header details out of
SqliteCache and HttpClient
2 - Added support for expires header
3 - Support caching more status types (but not all, since HttpClient would need
to be aware of what caching a 3xx/206 means)
4 - Revalidate cares about "not specified" vs "no-store" vs "stale"
(e.g. expires=0 means "stale", not fallthrough the last-modified logic)
Responses with specific status (e.g. 204) should always have a null body. Also
adds validation to Response constructor (e.g. can't provide an invalid status).
Improves a handful of WPT tests:
fetch/api/response/response-error.any.html
fetch/api/response/response-static-json.any.html
Return TypeError on an invalid method and guard against invalid headers. This
2nd change just uses the guards added in https://github.com/lightpanda-io/browser/pull/3460
from XHR.
Fixes a handful of cases, e.g. /fetch/api/request/forbidden-method.any.html
Previously, our window.isSecureContext was hard-coded to false. This commit
(a) reports the correct value and (b) disables [some] secure-context-only APIs
in a non-secure context. This change is somewhat related to the ongoing Service
Worker work and will need to be adjusted accordingly, e.g. when #3562 lands,
the Cache will need to be disabled when isSecureContext == false.
DOM.getFrameOwner answered with the child frame's document instead of the
element hosting it. Clients that map an <iframe> to its frame compare the
backendNodeId it returns with the one they resolved in the parent
(Stagehand's frameLocator/deepLocator, Playwright's contentFrame), so the
lookup never matched and they could not descend into frames.
Return the owner element, as Chrome does, and error for the main frame.
The node writer now emits frameId on frame-owner elements and on document
nodes, which is the other half of that pairing.
Directly improve a couple slow tests (crash_handler actually generating crash
dumps on some systems, e.g. mine). The runWebApiTest prefers to poll for work
when possible rather than a blind sleep -> check loop. (e.g. if we have
websocket connections, prefer an http tick).
For me, it's 22s -> 17s.
Continuation of cleaning up frame ownership (#3549, #3536, #3520, ...).
Element.blur/focus are noop on a frameless element.
AXNode.Writer rejects frameless nodes. DOM.resolveNodes keeps its fallback
bacause it's stateless - just needs the context.