Commit Graph
8859 Commits
Author SHA1 Message Date
Karl Seguin e4a36552b8 mem: Optional CSSStyleDeclaration materialization
StyleManager ultimately ends up calling el.getOrCreateStyle() which either
returns the element's CSSStyleProperties OR (creates it AND stores it in the
Frame._element_styles for future lookups).

The goal behind this caching is twofold:
1 - Performance of not having to reparse the "style" attribute
2 - Identity: two calls from JS to get the properties should return the same
    value

(2) is non-negotiable, so the 'getOrCreate' _has_ to exist for JS-facing APIs.

But (1) is CPU vs memory optimization that we've decided should always favor the
CPU. But, in any case where we dump an entire tree, that memory cost can be
significant (# of elements with a style attribute) and the CPU gains are
questionable (it isn't like a JS loop re-checking an element's properties, it's
a one-time dump). So, the StyleManager now takes a comptime `InlineAccess` which
is either `.scan` or `.materialize`. When it's `.materialize` it behaves as
before. When it's `.scan` is will use an existing `_element_styles` if available
else it will re-parse but not store the value.
2026-08-26 13:23:11 +08:00
Adrià Arrufat e76cc816c0 markdown: skip hidden elements
The renderer's only visibility test was the tag (metadata/svg), so
display:none, [hidden], aria-hidden="true", closed <details> content and
closed <dialog>s all ended up in the output.

Check each element's own computed display:none through StyleManager plus
aria-hidden="true"; the dump root is exempt so a scoped dump of a hidden
subtree still renders it. analyzeContent/isStandaloneAnchor use the same
predicate so an anchor whose only content is hidden falls back to its label.

Also adds the missing dialog:not([open]) { display: none } UA rule.
2026-08-26 13:22:50 +08:00
Karl Seguin 67a5b23dc6 Merge pull request #3270 from lightpanda-io/css-keyword-case
css: compare visibility keyword values case-insensitively
2026-08-26 13:22:03 +08:00
Adrià Arrufat 0590bd0f80 Merge pull request #3265 from lightpanda-io/search-cleanup
search: default to Keenable's keyless endpoint, drop the DuckDuckGo scrape
2026-08-26 03:45:54 +02:00
Karl Seguin fa36fb5a69 Merge pull request #3280 from lightpanda-io/dev-fast-host-glibc
build: pin dev_fast to the host's glibc version
2026-08-26 09:40:14 +08:00
Karl Seguin 3f155f2c4b Merge pull request #3281 from lightpanda-io/fix-orderfile-debug-build
Build: Fix linux debug build
2026-08-26 09:22:14 +08:00
Karl Seguin b8c9fa3d76 Build: Fix linux debug build
https://github.com/lightpanda-io/browser/pull/3271 broke linux debug builds
2026-08-26 09:10:49 +08:00
Karl Seguin a3ab6b0b7e glibc build version
So we're trying to limit glibc to 2.43.0 do to an issue in Zig's self-hosted
compiler. I'm on 2.44.0 and I hard-coded 2.43.0. But for anyone on a version
prior to 2.43.0, that causes issues. So this takes the host version but limits
it to 2.43.0
2026-08-26 06:47:17 +08:00
Karl Seguin 53e1db66d0 Merge pull request #3273 from lightpanda-io/driver-guidance-rendering
tools: drop the 'no rendering' claim from the driver guidance
2026-08-26 06:36:32 +08:00
Karl Seguin 64cdead237 Merge pull request #3271 from lightpanda-io/mem-vmhwm
mem: On linux CI builds, use an orderfile
2026-08-26 06:35:25 +08:00
Karl Seguin a9d93a87df Merge pull request #3264 from lightpanda-io/wpt-webdriver-keyboard
webdriver: Improve WebDriver keyboard handling
2026-08-26 06:33:59 +08:00
Karl Seguin 22e02f5070 Merge pull request #3263 from lightpanda-io/usp-invalid-escapes
webapi: URLSearchParams passes invalid percent-escapes through
2026-08-26 06:33:49 +08:00
Adrià Arrufat 5dc2535aae build: pin dev_fast to the host's glibc version, not 2.43
The explicit version only exists to force Zig's bundled CRT (zig#31272),
but it also selects symbol versions. PR #3231 added tiny-skia, which
calls acosf, and glibc 2.43 re-versioned that symbol, so the binary now
fails to load on hosts with an older glibc:

  libm.so.6: version `GLIBC_2.43' not found

Use the detected host glibc instead: still an explicit version, so the
bundled CRT is still used, but never newer than what the binary runs on.
2026-08-25 17:02:18 +02:00
Pierre Tachoire a01e148ab0 Merge pull request #3268 from lightpanda-io/mcp-http-close-after-reject
mcp: close the connection after a keep_alive=false response
2026-08-25 15:38:12 +02:00
Karl Seguin 2929660ae7 Merge pull request #3272 from lightpanda-io/fix-make-test-filter
Makefile: fix test filtering
2026-08-25 21:24:19 +08:00
Adrià Arrufat 4583066b2f tools: drop the 'no rendering' claim from the driver guidance
The engine renders PNGs since #3231. What is still true for the model is
that no tool exposes pixels, so say that instead.
2026-08-25 15:24:01 +02:00
Adrià Arrufat 04484f287f Makefile: fix test filtering
- Stop re-exporting command-line variables via MAKEFLAGS: tikv-jemalloc-sys's
  build script appends its jobserver flags after the inherited "-- F=..."
  separator, so a cold cargo cache failed with "No rule to make target '-j'"
  whenever any VAR=value was passed to make.
- `TEST_FILTER=... make test` was silently clobbered by the empty F and ran
  the full suite; fall back to the environment value when F is unset.
2026-08-25 15:16:02 +02:00
Karl Seguin ee1fd9207c mem: On linux CI builds, use an orderfile
CI build, for e2e-test and nightly now build with:
-Dorderfile/lightpanda.ld

This file informs the build on how to organize the code in the binary, grouping
hot code together so that we have to load less of the binary into memory.

lightpanda.ld will drift: we'll refactor our code, add new features, update
dependencies, update Zig, ... So it has to be re-generated. But we can do that
automatically in the CI (say, before the nightly build). That's for a follow up
PR.

This does not currently cover V8. V8 is being build with
`-no-unique-section-names`, so we don't get names that we can correctly
organize. The real win comes from doing this in V8, since a lot of V8 is cold.
This PR can land as-is, a zig-v8-fork PR will remove that flag, and then we can
have a follow up PR with an lightpanda.ld that includes the v8 symbols.

This is opt-in (via the -Dorderfile flag) because it adds ~20 seconds of
linking time.
2026-08-25 21:02:31 +08:00
Adrià Arrufat f37d96c285 css: compare visibility keyword values case-insensitively
CSS keywords are ASCII case-insensitive, but StyleManager matched
display:none / visibility:hidden|collapse / opacity:0 / pointer-events:none
with exact String.eql, so `style="DISPLAY: NONE"` or a `.x { Visibility:
Hidden }` rule left the element visible to checkVisibility,
getComputedStyle, the semantic tree and interactiveElements.

Compare at the check sites via a new String.eqlSliceIgnoreCase rather than
lowercasing declared values, which would corrupt content, url() and custom
property values that el.style must reflect verbatim.
2026-08-25 14:53:35 +02:00
Halil Durak 08219f91d6 Merge pull request #3230 from lightpanda-io/nikneym/mimic-image-fetch
Introduce `--load-resources`, supporting `image` parameter
2026-08-25 14:41:21 +03:00
Halil Durak ef7dc313e6 update tests 2026-08-25 14:20:39 +03:00
Halil Durak eb9080be16 Session: update stale comment 2026-08-25 14:20:39 +03:00
Halil Durak f07f818d2f Image: fix generation update order 2026-08-25 14:20:39 +03:00
Halil Durak 87a87ba62e HttpClient: remove pending_low_queue, separate keys for headers_only in cache, more eager connection reuse 2026-08-25 14:20:38 +03:00
Halil Durak 3265d66052 change how --load-resources are provided from CLI 2026-08-25 14:18:47 +03:00
Halil Durak 9b9ecedc7d Image: cover src changes on attributeRemove 2026-08-25 14:18:47 +03:00
Halil Durak 4c946fd172 pendingLoadCompleted can reach documentIsComplete
which results in running events on a destroyed object.
2026-08-25 14:18:47 +03:00
Halil Durak add0f1729f move loadImage and ImageLoad to resource_load.zig 2026-08-25 14:18:47 +03:00
Halil Durak 46f230a44d remove unnecessary import 2026-08-25 14:18:47 +03:00
Halil Durak 2a1659b967 Frame: remove unreachable in dataCallback of ImageLoad 2026-08-25 14:18:46 +03:00
Halil Durak c1079444c4 addHeader -> setHeader + enable low prio for images 2026-08-25 14:18:46 +03:00
Halil Durak d254302f6d update tests 2026-08-25 14:18:46 +03:00
Halil Durak 24019ef1a7 testing interface should respect --load-resources 2026-08-25 14:18:46 +03:00
Halil Durak 6f7aa67c21 update help.zon 2026-08-25 14:18:45 +03:00
Halil Durak e58f99da18 add --load-resources CLI arg, supporting image param 2026-08-25 14:18:45 +03:00
Karl Seguin feb8d17863 Merge pull request #3260 from staylor/fix/termination-async-module-reentry
stability: drop async module completions after termination
2026-08-25 18:49:26 +08:00
Karl Seguin b7f1a2d6cd check terminatePending on Frame.isGoingAway 2026-08-25 18:38:05 +08:00
Karl Seguin 289502e19a Merge pull request #3231 from lightpanda-io/screenshot
Screenshot
2026-08-25 18:12:00 +08:00
Karl Seguin 0c24db4a00 mem: try lto=thin
Try lto=thin in rust so that the html5ever code sits together and triggers less
misses which result in more memory being used.
2026-08-25 17:02:56 +08:00
Adrià Arrufat ec396f5dc1 mcp: close the connection after a keep_alive=false response
std.http.Server's respond() only drains the request body when the server
keeps the connection alive; with keep_alive=false it leaves the body
unread, sets reader.state = .closing, and expects the caller to sever the
connection ("the connection will be severed after the response is sent").

handleConn looped on the client's keep_alive flag instead, which is true
for any HTTP/1.1 request, so after a 405/413/415/417/403 it called
receiveHead() again and fed the unread POST body to the head parser. The
server advertised `connection: close` but held the socket open until the
peer gave up.

Honour the reader's closing state so the socket is closed right after the
rejection response.
2026-08-25 10:33:39 +02:00
Karl Seguin de422a72f5 Embed DejaVuSansMono-Bold.ttf for bold headings
fix slant direction for italics
2026-08-25 16:02:51 +08:00
Adrià Arrufat c8534b7afa search: trim comments to the non-obvious why 2026-08-25 09:48:44 +02:00
Adrià Arrufat c3b8f43f5f search: resolve the engine key once, retries off in one place
`engineKey` (on `lp.environ().getPosix`) replaces the env-var wrapper and
the three hand-spelled set/keyless/missing decisions in the cascade, the
explicit path, and the REPL query. `.auto`'s "always a rung" invariant is
now a comptime assert instead of an unreachable sentinel. HTTP retries are
disabled in `apiSearch` for every path — the cascade or the model is the
retry, and the tool's `timeout` argument bounds one attempt — rather than
threaded through as a parameter the table no longer set. The cascade
sentence is one shared constant for the tool description and the REPL
help, and search gets its own default timeout instead of borrowing the
navigation one.
2026-08-25 09:43:06 +02:00
Adrià Arrufat 42c3cbf20b search: default to Keenable's keyless endpoint, drop the DuckDuckGo scrape
The DuckDuckGo HTML endpoint the search tool fell back to is disallowed by
its robots.txt, so it is removed: the `duckduckgo` engine, the scrape via
`performGoto`, and the tool's browser-side dependency (`execSearch` no
longer needs a session). In its place `.auto` is a single walk over the
API engines in table order — each when its key is set — with Keenable
last, keyed if `KEENABLE_API_KEY` is set and its public endpoint
otherwise. Search therefore always has a rung with zero configuration,
and a set key is never shadowed by a keyless retry.

Every search now goes through zenai's `std.http.Client`, which had no
timeout at all; a stalled response would have blocked the MCP server's
shared browser thread for every session. zenai now bounds each attempt
(lightpanda-io/zenai#10, pinned here), and the tool's `timeout` argument
drives it, defaulting to 10 s. Retries are a property of the call path:
off in the cascade, where the next rung is the retry, and the engine
default for an explicit engine.

Cleanups from the #3252 review: `keyless` is derived from the client's
`api_key` type instead of a hand-set table flag; `engineIndex` no longer
depends on enum declaration order; one `searchKeyStatus` query replaces
three pub helpers for the REPL; the engine order and env-var list in the
tool description and `/searchEngine` help are generated from the table;
an empty result title renders as its URL instead of `****`.
2026-08-25 09:35:26 +02:00
Adrià Arrufat dbe89c1b31 Merge pull request #3252 from keenableai/feat/keenable-search-engine
search: add Keenable engine with a keyless rung above the DDG scrape
2026-08-25 08:53:24 +02:00
Ilya Bogin 887e4108bb Merge pull request #1 from lightpanda-io/keenable-review-followups
search: repin zenai to the merged commit and finish the review follow-ups
2026-08-25 09:01:39 +03:00
Karl Seguin 8a951d4f0e webdriver: Improve WebDriver keyboard handling
Normalize key codepoints for the "Private Use Areas" keyboard.

Page holds a `input_modifiers` map so that multiple action sequence preserve
modifier keep states (this is only active with -Dwpt_extensions).

We now generate a keypress and synthentic click on specific keyboard events.
E.g. A trusted "enter" on keydown where the target is an anchor.

Improves various /uievents/ WPT cases.
2026-08-25 13:03:57 +08:00
Karl Seguin 99c8744458 webapi: URLSearchParams passes invalid percent-escapes through
A '%' followed by two non-hex digits is passed through literally. So %2sf ->
%2sf, not a hex decode error.
2026-08-25 12:24:30 +08:00
Karl Seguin 341a015708 Merge pull request #3259 from navidemad/fix-mouseevent-coordinate-flooring
webapi: floor MouseEvent coordinate getters to integers, Chrome-style
2026-08-25 09:32:04 +08:00
Karl Seguin 5d4b01e3a7 add flooring to click-like pointer events 2026-08-25 08:36:32 +08:00