The `pattern` IDL attribute had no accessor registered on
`HTMLInputElement.prototype` (returned undefined despite getAttribute
working), and `Input.suffersPatternMismatch` was a TODO stub returning
false. As a result, `validity.patternMismatch` never fired for
`<input pattern="…">` and `validationMessage` was always empty for
pattern violations.
This change registers `pattern = bridge.accessor(Input.getPattern,
Input.setPattern, .{})` and rewrites `suffersPatternMismatch` to
evaluate `new RegExp("^(?:" + pattern + ")$", "v").test(value)` via
`ls.local.exec` on the owner frame. Strings are JSON-encoded for safe
interpolation. Per HTML §4.10.5.3.5, the constraint applies only to
text-like input types and skips empty values; an unparseable pattern
is ignored. `ValidityState.getPatternMismatch` now takes a `*Frame` so
the regex evaluation can reach the owner frame's V8 scope.
Closes#2351
config.h already has a hand-added _LIBIDN2_LP_DECLS guarded block at
the end declaring extern strverscmp for the same gnulib-overlay reason.
Move the strchrnul prototype into that block (still #ifdef __APPLE__
since glibc Linux already declares it) so all project-added externs
live in one place, the autoconf-generated section stays untouched, and
the precedent for "how this codebase handles missing glibc extensions"
is one consistent pattern instead of two.
Refresh the build.zig and strchrnul.c comments to point at the
relocated declaration.
No functional change — verified across -target x86_64-macos.{13.0,
14.0,15.4} (lookup.c pattern + the three TUs that include both
<config.h> and <string.h>) plus x86_64-linux-gnu, all under
-Wall -Wextra -Werror.
Move the macOS strchrnul declaration from a side-channel header injected
via -include into vendor/libidn2/config.h itself, gated on __APPLE__.
config.h is the canonical place where libidn2 documents its
HAVE_STRCHRNUL detection — co-locating the platform fallback prototype
there mirrors gnulib's own approach (which declares missing symbols in
its substituted <string.h>) and removes the per-platform build-flag
asymmetry plus the dedicated include path.
The Darwin-only strchrnul.c implementation is unchanged; build.zig now
just adds it on Darwin without touching the lib/ flags array.
Verified that on both `-target x86_64-macos.14.0` (no libc strchrnul)
and `-target x86_64-macos.15.4` (libc has it) a TU mimicking lookup.c
(`#include "config.h"` then call strchrnul) compiles cleanly with no
implicit-declaration error and no redeclaration warning.
libidn2's lib/lookup.c calls strchrnul() unconditionally — a glibc
extension that macOS libc neither defines nor declares. Upstream's
portable build relies on gnulib substituting <string.h> with a
declaration and linking gl/strchrnul.c, but that overlay is not wired
up here. The result was an "implicit function declaration" hard error
on every macOS nightly build.
Add a Darwin-only shim under vendor/libidn2/darwin/ and inject its
prototype into the libidn2 lib/ sources via -include. The shim mirrors
strchrnul's semantics without falling through to rawmemchr (also
glibc-only) since libidn2 only ever searches for '.'.
Per HTML §4.11.1.2, a <summary>'s activation behavior runs the
toggle-details-state algorithm on its parent <details>, but only when
the summary is the first summary child of that details.
Frame.handleClick previously had no arm for .generic, so summary clicks
fell into `else => {}` and details.open never changed. Add a .generic
arm gated on `_tag == .summary` that walks the parent's element
children to confirm first-summary-child, then flips details.open via
the existing Details.setOpen.
Out of scope (tracked separately): firing ToggleEvent on the parent
(no ToggleEvent type yet); activating when a descendant of <summary>
is clicked (same gap exists for <a>/<label>; needs a broader walk-up
refactor of handleClick).
Tests: src/browser/tests/element/html/summary_click.html covers
closed→open, open→closed, non-first summary no-op, and orphan summary
no-op.
This comes from a WPT crash in /content-security-policy/blob/self-doesnt-match-blob.sub.html
The core issue is double-free on the request header list. This is a fundamental
issue about ambiguous ownership. On error, who's responsible for freeing the
request? The caller or the HttpClient. Answer: it depends when/where the error
happens. That just doesnt' work, and needs to be fixed. BUT....
There's also the issue that this specific test is failing because we aren't
properly encoding script URLs. This is a real and separate issue that also needs
to be fixed. That's what this commit does. In some ways, it's a bit superficial
because there's a real double-free issue, but this is a real issue to fix.
Follow up to https://github.com/lightpanda-io/browser/pull/2335 which hooks
into the tick's GC hint to close any closed window (rather than having to wait
until page unload).
Also, use schedule task for dispatchLoad which removes an check in every tick.
- Cache `ValidityState` per element so repeated `el.validity` access
returns the same instance (also avoids allocating a struct per
per-keystroke call).
- Use `Event.initTrusted` for the `invalid` event — browser-generated.
- Use `frame.dupeString(message)` (interns short strings) instead of
`frame.arena.dupe(u8, message)` for `setCustomValidity` storage.
- Cascade `*const Input` / `*const Select` through `getValidationMessage`,
`suffersValueMissing`, and Select.effectiveOption.
- Factor radio-group walking into a shared `radioGroupIterator`; add the
same-form check to `radioGroupHasChecked` (was only in
`uncheckRadioGroup`). The form comparison uses a frame-less helper so
it can run from the const validation path.
- Narrow `numericRangeBreach` to `.number, .range` — date/time/month/
week/datetime-local need type-specific conversion before comparison
(was silently returning false). TODO comment left in place.
- Add `getMinLength`/`setMinLength` getters to Input and TextArea, plus
`getMaxLength`/`setMaxLength` to TextArea (Input already had them).
Used internally by `suffersTooLong`/`suffersTooShort` and exposed via
IDL.
- TODO prefix on the file-input value-missing comment so the limitation
is greppable.
Tests cover the new IDL surface (`minLength`/`maxLength` on Input and
TextArea), the validity-state caching guarantee
(`el.validity === el.validity`), and the trusted-event flag on the
`invalid` event for Input, Select, TextArea, and Button.
Cannot Frame.deinit in window.close() as that's happening inside JS runtime.
Instead, defer on Page.deinit. This is MUCH later than necessary, but I'd like
to address the timing separately. This commit, as-is, prevents real crashes.
This is a follow up to https://github.com/lightpanda-io/browser/pull/2290. That
PR spit ScriptManager into ScriptManager and ScriptManagerBase, with the
goal of letting a Worker have a ScriptManagerBase that works without needing
a frame.
But the Script object was still a large object meant to work with any type of
script invocation, e.g. it has a nullable element. This commit swaps out these
fields for a better-typed "extra" union field. So that Element only exists in
the extra.frame tag. In the end, it just makes it more explicit about what
fields are valid under specific conditions.
Per maintainer review (PR #2310), Lightpanda has no caret/keyboard editing
pipeline, so honoring the spec-correct value risks routing downstream CDP
clients (notably Puppeteer's dispatchKeyEvent path) into an input pipeline
that silently no-ops. Switch to always returning false and emit
log.info(.not_implemented, "IsContentEditable", .{}) when the spec walk
would have produced true, so the unsupported case surfaces in telemetry
rather than masquerading as a working state.
The HTML §7.7.5.2 walk is preserved (nearest ancestor with `contenteditable`
wins, "false" disables) but only used to gate the log emission. The fixture
is reduced to assert the always-false return across the same shape of
inputs, with a comment pointing back at the rationale.
This change causes lightpanda to display the actual port number (instead of 0)
when binding a dynamic port (--port 0), which makes automating based on
scraping lightpanda output simple.
Extract module-loading plumbing into ScriptManagerBase so workers can
use it. Previously Context.script_manager was null for worker contexts,
which crashed on dynamic import() via the unwrap in dynamicModuleCallback.
ScriptManagerBase owns the HTTP fetch + V8 module resolution path
(preloadImport, waitForImport, getAsyncImport, resolveSpecifier, the
Script struct) and reaches per-owner fields through an Owner union.
ScriptManager wraps it for Frame and keeps the parser/DOM-bound surface
(addFromElement, parseImportmap, Frame-specific evaluate tail via
tail_hook). WorkerGlobalScope gets its own ScriptManagerBase directly.
This is similar to the work done in https://github.com/lightpanda-io/browser/pull/2093
which split EventManager into EventManager + EventManagerBase (for the same
reason).
add tests
`Frame.handleClick` had no `.label` arm, so clicking an `HTMLLabelElement`
fired the click event but never dispatched the synthetic click activation
on the labeled control. Per HTML §4.10.4 "The label element", a label's
activation behavior is to run the synthetic click activation steps on the
labeled control; without it `cb.checked` stays unchanged when the click
target is a `<label>`.
Resolve the labeled control via the existing `Label.getControl(frame)`
(handles both `for=` and the wrapping-descendant case) and call `.click()`
on it, mirroring Chrome's `HTMLLabelElement::DefaultEventHandler`.
Closes#2323