Commit Graph

8321 Commits

Author SHA1 Message Date
Pierre Tachoire
5c0c2920db release previous oncurrententrychange on overwrite 2026-07-17 11:23:03 +02:00
Pierre Tachoire
bf775696de don't skip dispose dispatch when ondispose is unset 2026-07-17 11:17:05 +02:00
Pierre Tachoire
a59abc7f4f Merge pull request #2972 from lightpanda-io/sanitize-utf8-headers
cdp: emit non-UTF-8 header values as Latin-1 strings, not byte arrays
2026-07-17 10:06:35 +02:00
Muki Kiboigo
1bea30ac4e clear callbacks on onRemoveFrame for Navigation 2026-07-17 01:03:47 -07:00
Muki Kiboigo
b0c0b3fe3a release on dispose 2026-07-17 01:01:25 -07:00
Muki Kiboigo
9ba8d8c564 fix reentrancy on dispose and clean up 2026-07-17 01:00:06 -07:00
Muki Kiboigo
35f128d264 use hasDirectListeners for fireDispose 2026-07-17 00:57:08 -07:00
Karl Seguin
b19b57250a Merge pull request #2719 from navidemad/css-layer-cascade
css: apply @layer block rules to the cascade
2026-07-17 11:49:24 +08:00
Karl Seguin
28b4a31b59 Merge pull request #2963 from lightpanda-io/dom-pr-22-allocation-lifetimes
webapi: bound scroll task allocations; tighten DOM allocation lifetimes
2026-07-17 11:28:20 +08:00
Francis Bouvier
50a896f4c0 webapi: tighten DOM allocation lifetimes
Use the call arena only for the AbortSignal dependent list that must survive re-entrant abort handlers, and move scratch-only DOM reads to the local arena. Store BeforeUnloadEvent.returnValue in the event-owned arena so it remains valid without accumulating in the longer-lived frame arena.

These allocator changes bound temporary memory to the shortest safe lifetime while preserving existing Web API behavior. Add coverage for replacing BeforeUnloadEvent.returnValue.
2026-07-17 10:52:10 +08:00
Francis Bouvier
8f42b72d18 webapi: bound element scroll task allocations
Keep one slab-allocated scheduler task per active element scroll sequence and recycle it on completion or scheduler cancellation. This prevents repeated programmatic scrolling from growing the frame arena and task queue without bound.

Advance the throttle state before dispatching scroll and scrollend so nested JavaScript callbacks cannot be overwritten, and avoid scheduling events for clamped no-op scrollBy calls. Add coverage for coalescing, both re-entrant event paths, and no-op scrolling.
2026-07-17 10:52:09 +08:00
Karl Seguin
1cebd1c1ce Merge pull request #2962 from lightpanda-io/dom-pr-21-handler-return-fragment-nav
webapi: handler return-false cancels events; same-fragment navigations don't reload
2026-07-17 10:51:28 +08:00
Karl Seguin
51dbad5a6a allow location.reload() on fragmented url to cause navigation 2026-07-17 10:40:08 +08:00
Francis Bouvier
65a3ce33c0 webapi: use the local arena for the normalized hash
Review pattern from #2943: prefer the local arena for scratch-only
allocations. scheduleNavigation dupes the URL into its own arena
synchronously at entry, so the normalized fragment does not need to
survive the call.

Co-Authored-By: Karl Seguin <karlseguin@users.noreply.github.com>
2026-07-17 10:12:44 +08:00
Francis Bouvier
027936ef90 webapi: same-fragment navigations must not reload the page
After rebasing onto main, WPT
/dom/events/Event-dispatch-single-activation-behavior.html went from
3/132 to 0/0 (harness never reported): the test repeatedly clicks
`<a href="#link">` anchors and resets with `location.hash = ""`, and
both patterns ended up scheduling full same-URL reloads, putting the
page in a reload loop. As with the previous commit, the pre-rebase
code masked this because queued navigations rarely executed; the
HttpClient refactor made them reliable.

Two fixes, per the HTML navigate steps (a navigation is a fragment
navigation when the URL equals the document's URL excluding fragments
and its fragment is non-null) and the Location hash setter (if the
fragment doesn't change, no navigation happens):

- Frame.scheduleNavigationWithArena: re-navigating to the exact
  current URL is only a reload when the URL has no fragment. With a
  fragment (e.g. re-clicking the same `#link` anchor) it's now a
  no-op fragment navigation: no reload, and since the fragment didn't
  change, no hashchange and no history entry. Upstream's "identical
  URL reloads" behavior (iframe.src = "about:blank" twice) is
  untouched — those URLs carry no fragment.

- Location.setHash: skip the navigation entirely when the normalized
  fragment equals the current one, so `location.hash = ""` on a
  fragment-less URL (and re-assigning the current fragment) no longer
  schedules a same-URL reload. Assigning "" still strips the fragment
  from the URL, matching the existing tests/window/location.html
  expectations.

Unit test added in tests/window/location.html: href stays stable
across repeated `hash = ""` and same-fragment re-assignments.

Coverage: /dom/events/Event-dispatch-single-activation-behavior.html
0/0 -> 83/132 (3/132 before the rebase; the gain past 3 comes from
the handler-return-value fix in the previous commit).
2026-07-17 10:12:44 +08:00
Francis Bouvier
daa3b1d451 webapi: event handlers returning false cancel the event
After rebasing onto main (HttpClient refactor: queued navigations now
reliably execute), WPT /dom/events/Event-dispatch-click.html went from
33/33 to 0/0: its form subtests cancel submission with
`form.onsubmit = () => { ...; return false }`, but the inline-handler
invocation discarded the return value, so the form really submitted,
the scheduled form navigation reloaded the page in a loop and the
harness never reported. Before the refactor the queued navigation
never ran, which masked the missing behavior.

Per the HTML "event handler processing algorithm" (§8.1.8.1, "Process
the return value"), an event handler attached via an on* property or
attribute that returns exactly false cancels the event — unlike
addEventListener listeners, whose return value is ignored. The
inverted onerror special case only applies to the global's onerror,
which is invoked via Window.reportError, not through node dispatch.

Implementation: the two inline-handler invocation sites in
EventManager.dispatchNode (at-target and bubble phase) now call the
handler with a js.Value return type and route it through a new
processHandlerReturnValue helper, which calls event.preventDefault()
when the returned value is strictly false (skipping "error" events).

Unit test added in tests/events.html covering: at-target handler,
ancestor (bubble-phase) handler, other falsy return values not
canceling, and addEventListener return values staying ignored.

Coverage: /dom/events/Event-dispatch-click.html 0/0 -> 33/33
(restores the previously claimed 33/33); also a prerequisite for
/dom/events/Event-dispatch-single-activation-behavior.html (see next
commit).
2026-07-17 10:12:44 +08:00
Karl Seguin
5160735508 Merge pull request #2961 from lightpanda-io/dom-pr-20-html-elements
webapi: cookie-averse docs, script insertion steps, moveBefore reactions, outerText
2026-07-17 10:09:25 +08:00
Karl Seguin
f5ace3701f Improve gating around nodeIsReadySubtree to prevent unnecessary calls
Free temp DocumentFragment when possible
2026-07-17 09:44:19 +08:00
Karl Seguin
ef91047983 Merge pull request #2964 from rohitsux/feat/cdp-navigated-within-document
feat(cdp): emit Page.navigatedWithinDocument for same-document navigations
2026-07-17 09:30:51 +08:00
Karl Seguin
0e49d6f280 Remove unused timestamp field
Move notification directly into history. Improve test.
2026-07-17 09:13:33 +08:00
Karl Seguin
7671732451 Merge pull request #2982 from lightpanda-io/focus-visible-only
reject focus() on non-rendered elements (display:none)
2026-07-17 07:50:48 +08:00
Karl Seguin
9205edb1f4 Merge pull request #2965 from lightpanda-io/script-preload
perf: Pre-parse HTML to find and preload scripts
2026-07-17 07:49:39 +08:00
Karl Seguin
8d3bfeaa11 Merge pull request #2977 from lightpanda-io/SharedWorker
webapi: Add SharedWorker
2026-07-17 07:49:19 +08:00
Karl Seguin
0098b12fce Merge pull request #2980 from lightpanda-io/class-selector-fix
fix: Prevent class selector from doing substring match
2026-07-17 07:48:48 +08:00
Francis Bouvier
cb23ad7cbb webapi: moveBefore fires connectedCallback without a disconnectedCallback
Fixes the failing subtest of WPT
/dom/nodes/moveBefore/custom-element-move-reactions.html (5/6 -> 6/6):
when a moved custom element defines no connectedMoveCallback, the
fallback is disconnectedCallback + connectedCallback - and either may
be undefined. The error from invoking the missing disconnectedCallback
returned early and skipped connectedCallback entirely.

Both fallback invocations now tolerate a missing method and let the
other one run.

Coverage: /dom/nodes/moveBefore/custom-element-move-reactions.html
5/6 -> 6/6 (fully green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 07:47:50 +08:00
Francis Bouvier
d8bc0bacf2 webapi: spec-conformant script insertion/execution steps
Fixes 10 failing files under /dom/nodes/insertion-removing-steps/
(5/20 -> 15/20 files passing), which pin down when dynamically inserted
scripts execute:

- Scripts (and iframes/links/styles) appended to a DETACHED parent no
  longer activate; the ready work is gated on the node being connected,
  and runs later if the subtree gets inserted into the document.
- Inserting a subtree runs the ready work for its descendant elements
  too, in tree order (nodeIsReadySubtree), after the node is in place.
- Multi-node insertions (fragments, and ParentNode.append/prepend with
  several arguments, which now convert to a fragment per spec) run all
  the ready work only after every node is inserted: an earlier script
  observes its later siblings connected, and can remove one to prevent
  it from running.
- Inserting into a not-yet-started connected script runs the script's
  children-changed steps (once, with the full content) before the
  inserted nodes' own ready work, per whatwg/html#10188: the outer
  script executes before an inner one.
- Mutation records queue before any script runs, so an inserted script
  observes its own insertion record via takeRecords. The script
  manager's pre-execution microtask drain now only happens at a real
  checkpoint (empty JS stack): a script executed synchronously from a
  running script must not flush the queue mid-task.

The remaining files in the directory need meta-referrer /
meta-default-style / media <source> insertion steps and style/iframe
load interleavings.

Coverage: /dom/nodes/insertion-removing-steps/: 15/20 files passing
(10 newly); /dom/nodes and /dom/events regressions clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 07:47:50 +08:00
Francis Bouvier
7f9a3071d1 webapi: cookie-averse documents; HTMLElement.accessKeyLabel
Fixes two WPT files:

- /html/dom/documents/resource-metadata-management/document-cookie.html
  (4/5 -> 5/5, fully green): a cookie-averse document (one without a
  browsing context, e.g. createHTMLDocument) must read document.cookie
  as the empty string and silently ignore writes. Both accessors now
  no-op for documents that aren't a frame's active document.
- /html/dom/access-key-label.html (1/2 -> 2/2, fully green):
  HTMLElement.accessKeyLabel was missing. It reports an Alt+ chord for
  a valid single-character accesskey, like Chromium, and the empty
  string otherwise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 07:47:49 +08:00
Francis Bouvier
7bbfc1a871 webapi: assigning outerText to a MathML element leaves the tree alone
Fixes the last failing subtest of WPT /html/dom/elements/
the-innertext-and-outertext-properties/outertext-setter.html
(42/43 -> 43/43): outerText is an HTMLElement property, so assigning it
on a MathML <math> element must not replace the element.

MathML elements currently share the HTML wrapper types (giving them a
plain Element wrapper is part of the pending element-interface work),
so they expose the outerText setter; it now stays inert for non-HTML
namespaces.

Coverage: outertext-setter.html 42/43 -> 43/43 (fully green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 07:47:49 +08:00
Karl Seguin
e23a5adacc Merge pull request #2960 from lightpanda-io/dom-pr-19-document-misc
webapi: foreign-element attribute matching, document.head/getElementsByName, lastModified
2026-07-17 07:47:12 +08:00
Pierre Tachoire
8d1a09317b reject focus() on non-rendered elements (display:none)
Per HTML spec, elements inside display:none containers are not
focusable. This prevented third-party popups from stealing focus
mid-typing, fixing kitandace.js integration flakiness.

fix kitandace integration test
2026-07-16 17:13:31 +02:00
Karl Seguin
ab357b354e Move localtime to datetime module
avoid uncessary attribute dump

Prefer childrenIterator
2026-07-16 18:54:59 +08:00
Francis Bouvier
6e4028a446 webapi: use the local arena for the lastModified string
Review pattern from #2943: prefer the local arena for scratch-only
allocations. The formatted date is converted to a JS string by the
bridge before the local arena resets, like other local_arena-backed
return values (e.g. getClientRects).

Co-Authored-By: Karl Seguin <karlseguin@users.noreply.github.com>
2026-07-16 17:48:46 +08:00
Francis Bouvier
556ac4319c webapi: implement document.lastModified
Fixes WPT /html/dom/documents/resource-metadata-management/
document-lastModified.html (0/1 -> 1/1) and document-lastModified-01.html
(0/3 -> 3/3): document.lastModified was missing entirely.

The getter reports the navigation response's Last-Modified header
(already captured on the frame), parsed as an RFC 822 date and
formatted in the user's local time zone as "MM/DD/YYYY hh:mm:ss" via
libc localtime_r, matching what scripts derive from `new Date(...)`.
Documents without such a header - including script-created ones, which
don't inherit the frame's headers - report the current time, as the
spec requires.

Coverage: both files above fully green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 17:48:45 +08:00
Francis Bouvier
867fd9bc2e webapi: document.head matches by local name; getElementsByName is HTML-only
Fixes two WPT files (1 subtest each, both fully green):

- /html/dom/documents/dom-tree-accessors/document.head-02.html:
  document.head is the first html-namespace child of the document
  element whose LOCAL name is head. A createElementNS(HTML_NS,
  "blah:head") element is an HTMLUnknownElement in our type system, so
  the old is(Html.Head) walk skipped it; getHead now matches on
  namespace + local name (and returns *Element accordingly).
- .../document.getElementsByName/document.getElementsByName-namespace.html:
  getElementsByName must only consider HTML-namespace elements; the
  live collection's name filter now rejects foreign elements, matching
  the earlier fix for name-based access on HTMLCollections.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 17:48:45 +08:00
Francis Bouvier
9ff221e2c0 selector: attribute names match case-sensitively on foreign elements
Fixes WPT /dom/nodes/querySelector-mixed-case.html: per the Selectors
spec, attribute names in selectors match ASCII case-insensitively
against HTML elements (in an HTML document) but case-sensitively
against foreign (SVG/MathML) elements. We lowercased the selector's
attribute name at parse time for everyone, so [viewBox] never matched
the case-preserved viewBox attribute on an SVG element.

The parsed attribute selector now also keeps the name as written;
matching picks the lowercased name for HTML elements (whose stored
attributes are normalized) and the original for foreign elements
(whose attributes are stored as written).

Coverage: /dom/nodes/querySelector-mixed-case.html 0/1 -> 1/1 (fully
green); Element-matches.html stays 669/669.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 17:48:45 +08:00
Karl Seguin
122b5bdf06 Merge pull request #2959 from lightpanda-io/dom-pr-18-html-misc
webapi: response content type, element scroll events, translate, SVGAElement.relList
2026-07-16 17:41:08 +08:00
Adrià Arrufat
d06731d8fb cli: page help output through $PAGER when stdout is a tty
Explicitly requested help (help, help <cmd>, --help) now goes to stdout
instead of stderr, and is piped through $PAGER (fallback: less -FIRX)
when stdout is an interactive terminal, so long help like 'help agent'
(~225 lines) no longer clobbers the screen. Piped or redirected output
stays plain, and error-path usage remains unpaged on stderr.
2026-07-16 11:27:32 +02:00
Karl Seguin
40c18f6142 Fix UAF on ScrollTask
Free ScrollTask on shutdown / when complete.

Skip content_type logic when type is known to be html.
2026-07-16 17:23:33 +08:00
Adrià Arrufat
f97b224662 Merge remote-tracking branch 'origin/main' into pr-2719-update 2026-07-16 10:10:21 +02:00
Karl Seguin
dcd8a6ed07 fix: Prevent class selector from doing substring match
Previously, "aa" would have matched "baaa". Now the matching is strict equality
on tokenized words.
2026-07-16 16:07:20 +08:00
Karl Seguin
1a0767d934 Merge pull request #2979 from lightpanda-io/cleanup-cells-match
minor: cleanup cells matching logic.
2026-07-16 16:02:45 +08:00
Adrià Arrufat
7c7df999bf Merge pull request #2967 from lightpanda-io/agent-terminal-refactor
agent: split Terminal.zig into picker and prompt_assist
2026-07-16 10:02:08 +02:00
Karl Seguin
39dda124ae minor: cleanup cells matching logic. 2026-07-16 15:45:02 +08:00
Francis Bouvier
3fd9149917 webapi: move SVGAElement.getRelList out of the JsApi bridge block
Review pattern: the JsApi struct is for JS/v8 bridging only; the relList
getter is plain delegation with no v8 adaptation, so it moves to the
type and the bridge accessor references it.

Co-Authored-By: Karl Seguin <karlseguin@users.noreply.github.com>
2026-07-16 15:35:58 +08:00
Francis Bouvier
1a51a2ec1d webapi: element scroll state lives in the element's own frame
Review pattern from #2944: an injected `frame` parameter is the frame of
the calling realm, not the frame owning the element. The element scroll
positions map, the scheduled scroll/scrollend events and the
scrolling-element (root) comparison all used the caller's frame, so a
same-origin script scrolling an element inside an iframe stored the
position in the wrong frame's map (the iframe's own reads returned 0),
fired the events through the wrong frame, and compared against the wrong
document's root.

All scroll accessors (scrollTop/scrollLeft getters and setters, scrollTo,
scrollBy) now resolve Element.ownerFrame first; scheduleScrollEvents and
the ScrollEventTask receive that owner frame.

Co-Authored-By: Karl Seguin <karlseguin@users.noreply.github.com>
2026-07-16 15:35:58 +08:00
Francis Bouvier
4bd52eb32c webapi: SVGAElement exposes relList
Fixes the last failing subtest of WPT
/dom/lists/DOMTokenList-coverage-for-attributes.html (174/175 ->
175/175): an <a> element in the SVG namespace must expose relList as a
DOMTokenList (while SVG <area>/<link> have none).

Main now provides the full SVGAElement type (SVGGraphicsElement
hierarchy, href as SVGAnimatedString); this commit only adds the
relList accessor, reflecting the rel attribute through the shared
Element.getRelList.

(As originally written, this commit also created the SVGAElement type
and its factory/tag wiring; the rebase keeps main's implementation.)

Coverage: /dom/lists/DOMTokenList-coverage-for-attributes.html 174/175
-> 175/175 (fully green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 15:35:58 +08:00
Francis Bouvier
d5c57479a8 webapi: implement the translate IDL attribute
Fixes 7 failing files under /html/dom/elements/global-attributes/
(the-translate-attribute-007 through -012 and
translate-enumerated-ascii-case-insensitive, 1 subtest each): the
HTMLElement.translate property was missing entirely.

The getter computes the element's translation mode per the HTML spec:
translate="yes" or "" enables it, "no" disables it (both ASCII
case-insensitively), anything else inherits from the closest ancestor
with a valid value, defaulting to enabled. The setter reflects back as
"yes"/"no".

Coverage: the 7 files above each 0/1 -> 1/1 (fully green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 15:35:58 +08:00
Francis Bouvier
5f8e910312 webapi: element scrolls fire scroll and scrollend events
Fixes 16 failing files under /dom/events/scrolling/: all 8 variants of
scrollend-event-fired-for-programmatic-scroll.html and all 8 variants
of scrollend-event-fired-for-scroll-attr-change.html.

Window scrolls already dispatched throttled scroll + scrollend events,
but Element.scrollTo/scrollBy and the scrollTop/scrollLeft setters only
updated the stored position. They now schedule the same
scroll-then-scrollend pair (10ms/20ms, throttled through a per-element
state on the scroll position entry) when the position actually changes:

- events fired at the element don't bubble, per the UI Events
  cancelability rules the tests assert ("Event targeting element does
  not bubble");
- scrolling the document's scrolling element dispatches at the
  document instead, where the events do bubble.

The remaining files in the directory need real layout
(scrollIntoView offsets, scroll snapping) or gesture scrolling.

Coverage: /dom/events/scrolling/: 20 files passing (16 newly), no
regressions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 15:35:58 +08:00
Francis Bouvier
bf56adeb16 webapi: documents report the navigation response's content type
Fixes 9 failing files under /dom/nodes/Document-contentType/contentType/
(bmp, css, gif, jpg, mimeheader_01, png, txt, xml, and keeps the rest
green): a document created from a non-HTML response (the synthesized
image/text/raw documents) reported the text/html default from
document.contentType instead of the response's MIME type.

The frame records the response's MIME essence (type/subtype, lowercased,
parameters stripped) when the first chunk arrives, and applies it to
the new document's _content_type override once the navigation commits.
text/html responses keep the default.

The remaining file in the directory (contenttype_javascripturi) needs
iframes to navigate to javascript: URLs and document their string
result, which is a different mechanism.

Coverage: /dom/nodes/Document-contentType/: 14/15 files passing (9
newly passing, 1 subtest each).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 15:35:57 +08:00
Karl Seguin
f40fd3a0bc Merge pull request #2958 from lightpanda-io/dom-pr-17-testdriver-actions
webapi: wheel/touch actions, javascript: links, GamepadEvent, actionSequence timing
2026-07-16 15:34:58 +08:00