SGavrl
9c8d62e13b
fix(render): lay out text nodes in taffy and implement inline flow
2026-07-02 20:02:07 +00:00
SGavrl
193e30deb5
feat(render): implement basic CSS cascade matching from <style> blocks
2026-07-02 19:47:08 +00:00
SGavrl
bed6d6f619
feat(render): implement full image rendering for screenshots
2026-07-02 19:42:41 +00:00
SGavrl
6d33783ddf
perf(render): optimize text rendering & feat(render): add border support
2026-07-02 19:38:00 +00:00
SGavrl
dec56fa42f
feat(render): implement text rendering using ab_glyph
2026-07-02 19:34:52 +00:00
SGavrl
48e3fac55a
docs: add RENDER.md with usage and benchmark
...
Documents the obscura-render layer: how to enable it (--features render),
the CLI --screenshot and CDP Page.captureScreenshot paths, what it
renders, the architecture, and a head-to-head benchmark.
Benchmark vs headless Chrome (same page, 1280x720, warmed):
- local fixture: obscura ~0.06s/33MB vs chrome ~0.90s/195MB
- example.com: obscura ~0.10s/34MB vs chrome ~0.98s/199MB
Roughly 10-15x faster and ~6x less memory. Chrome's larger PNG on the
real page reflects that it paints text, which obscura does not yet.
2026-07-01 21:37:38 +00:00
SGavrl
cdd52ade43
render: PNG screenshots via CLI and CDP
...
End-to-end rasterization behind the render feature (which now enables
obscura-render/paint):
- obscura-render: screenshot_png(dom, viewport) paints and encodes to PNG
via tiny-skia's encode_png (no extra dep).
- obscura-browser: Page::screenshot renders the live DOM at a viewport.
- CLI: obscura fetch --screenshot out.png writes the settled page to a PNG.
- CDP: Page.captureScreenshot returns the PNG base64-encoded, so
Puppeteer/Playwright page.screenshot() works. captureSnapshot still
errors (it is a DOM/layer snapshot, not an image).
Verified: both paths produce correct 1280x720 RGBA PNGs with elements
laid out and colored as the CSS specifies (block stacking, backgrounds,
white page). Default build unchanged; obstacle course 33/33.
Text, borders, and images are not yet painted; the box layout and
background colors are rendered.
2026-07-01 21:34:15 +00:00
SGavrl
4ca85e87d8
render: paint backgrounds to a tiny-skia pixmap
...
Adds a paint feature to obscura-render (tiny-skia: pure Rust, CPU,
deterministic, no system deps). paint_dom lays out the DOM and fills
each element's border box with its parsed background-color over a white
page, in tree order so descendants paint over ancestors.
Style parsing now also extracts background-color (hex #rgb/#rgba/
later enhancements.
2026-07-01 15:58:27 +00:00
SGavrl
399181b975
render: expose real geometry to JS behind the render feature
...
getBoundingClientRect, offsetWidth/Height, and offsetTop/Left now read
real box geometry from the obscura-render layout cache when the render
feature is compiled in. elementFromPoint inherits correct hit-testing
because it already delegates to getBoundingClientRect per element.
Adds a render feature on obscura-js (propagated through obscura-browser
and obscura-cli), a lazily-computed layout cache and viewport in
ObscuraState (feature-gated, cleared on navigation), and an
op_layout_geometry op. bootstrap.js probes the op with typeof, so the
default scraping build is unchanged and falls through to the synthetic
rect.
With --features render, block siblings stack and flex children place
horizontally at correct positions, and elementFromPoint resolves the
right element. Default build returns the synthetic rect unchanged.
Obstacle course 33/33; obscura-js unit failures identical to main.
2026-06-30 20:36:43 +00:00
SGavrl
f0f9b048d0
render: DOM to layout tree and per-node geometry
...
Walk a live DomTree, compute each element's style (tag UA defaults plus
inline style), build a taffy layout tree, and return border-box geometry
keyed by NodeId. Block/flex structure, explicit sizes, and the box model
are correct; text nodes do not yet contribute to size (inline/text
layout lands with the paint phase).
This completes the layout core: a real DOM now produces real geometry,
pure Rust, behind the opt-in render crate. JS exposure is next.
2026-06-30 16:30:18 +00:00
SGavrl
5ed34ea8d4
render: computed-style lite (inline + UA defaults)
...
Parse inline style attributes into the layout-relevant subset of
LayoutStyle: display, width/height, margin, padding, and border width,
including box shorthands (1-4 values) and per-side longhands. !important
is stripped; auto and percentages leave the size unset for phase 1.
Layered on a small built-in UA default sheet. A compact hand-rolled
tokenizer handles inline attributes without a cssparser dependency; a
real cascade can harden it later.
2026-06-30 16:26:42 +00:00
SGavrl
1971380da8
render: scaffold obscura-render crate with taffy layout core
...
New optional crate obscura-render, the scoped render layer for Obscura.
Phase 1 adds the layout core: a LayoutNode tree plus a viewport is laid
out with taffy (pure Rust) and border-box geometry is returned per node,
mirroring the input tree.
The crate is a workspace member but not yet a dependency of any other
crate, so the default scraping build is unchanged. Geometry-from-DOM,
JS integration, text, paint, and screenshot capture land in later
phases.
Unit tests cover block stacking, flex row layout, and padding.
2026-06-30 16:20:10 +00:00
SGavrl
9d0e7d63dc
Merge pull request #515 from mnaza/fix/domparser-xml-504
...
fix(js): surface a parsererror for malformed XML in DOMParser
2026-08-07 16:52:28 +00:00
SGavrl
d361e41185
Merge pull request #548 from mnaza/fix/cssstyledeclaration-global-546
...
fix(js): expose CSSStyleDeclaration as a real global interface
2026-08-07 16:51:57 +00:00
SGavrl
44fd3dc65b
Merge pull request #549 from mnaza/fix/set-attribute-qualified-name-547
...
fix(dom): match setAttribute by qualified name, not local name only
2026-08-07 16:51:32 +00:00
SGavrl
e3c39e5989
Merge pull request #553 from mnaza/fix/fill-form-native-setter-550
...
fix(mcp): fill_form check/uncheck/select use the native setter and trusted events
2026-08-07 16:50:45 +00:00
SGavrl
215861b30f
Merge pull request #554 from mnaza/fix/stealth-empty-ssl-cert-env-551
...
fix(net): treat empty SSL_CERT_FILE/SSL_CERT_DIR as unset in the stealth client
2026-08-07 16:50:04 +00:00
SGavrl
8cd9a001f1
Merge pull request #555 from mnaza/fix/event-constructor-conformance-552
...
fix(js): make Event/CustomEvent constructors match WebIDL
2026-08-07 16:49:41 +00:00
SGavrl
750d54ce56
Merge pull request #559 from mnaza/fix/documentelement-innerhtml-head-556
...
fix(dom): keep <head> content when setting documentElement.innerHTML
2026-08-07 16:47:55 +00:00
SGavrl
8cd131fbae
Merge pull request #561 from mnaza/fix/string-timer-global-scope-558
...
fix(js): run string timer handlers as global-scope scripts at fire time
2026-08-07 16:46:52 +00:00
SGavrl
f234ff9e0b
Merge pull request #567 from alectimison-maker/fix/meta-charset-sniffing
...
fix(net): reject unrelated meta charset hints
2026-08-07 16:45:51 +00:00
SGavrl
0d48afe1e0
Merge pull request #564 from ibukanov/fix/stealth-content-encoding-563
...
fix(net): decode Content-Encoding on the stealth client
2026-08-07 16:45:24 +00:00
SGavrl
70062e0870
Update README.md
2026-08-05 16:57:21 +02:00
SGavrl
f0541f40a4
fix(js): isolate bootstrap declarations ( #544 )
2026-08-03 16:36:19 +00:00
SGavrl
6a55b63fa6
fix(js): isolate bootstrap declarations
2026-08-03 16:31:30 +00:00
SGavrl
5912c37c57
Merge pull request #514 from mnaza/fix/attribute-ns-503
...
fix(js): make setAttributeNS/getAttributeNS/removeAttributeNS namespace-aware
2026-08-03 16:10:58 +00:00
SGavrl
73fe8b91ae
test namespace style synchronization
2026-08-03 15:36:52 +00:00
SGavrl
1518ca2a70
Merge remote-tracking branch 'origin/main' into maintainer/pr-514-review
...
# Conflicts:
# crates/obscura-js/js/bootstrap.js
2026-08-03 15:35:42 +00:00
SGavrl
42f7fad709
Merge pull request #507 from mnaza/fix/insert-adjacent-html-495
...
fix(js): case-insensitive insertAdjacentHTML that keeps table/select fragments
2026-08-03 15:33:34 +00:00
SGavrl
62ada5ebb9
Merge pull request #494 from mnaza/fix/clonenode-structural-490
...
fix(js): clone nodes structurally instead of via div.innerHTML
2026-08-03 15:32:18 +00:00
SGavrl
624b98c7ad
Merge pull request #542 from lisa0314/fix/531-scroll-into-view-if-needed
...
feat(cdp): support DOM.scrollIntoViewIfNeeded
2026-08-03 15:31:59 +00:00
SGavrl
becb8816e8
Merge pull request #539 from dgcavalcante-png/fix/stealth-honors-ssl-cert-file
...
fix(net): honor SSL_CERT_FILE / SSL_CERT_DIR in the stealth client (#525 follow-up)
2026-08-03 15:31:19 +00:00
SGavrl
57cedbf069
Merge pull request #540 from dgcavalcante-png/fix/webidl-globals-non-enumerable
...
fix(js): expose WebIDL interfaces as non-enumerable, like a real browser
2026-08-03 15:30:45 +00:00
SGavrl
eab2a5eea1
Merge pull request #535 from h4ckf0r0day/fix/492-style-sync
...
Fix/492 style sync
2026-08-01 19:58:18 +00:00
SGavrl
108e777418
Merge remote-tracking branch 'origin/main' into maintainer/pr-492-fix
2026-08-01 19:51:52 +00:00
SGavrl
4b41d7c746
Merge pull request #534 from h4ckf0r0day/fix/517-string-timers
...
Fix/517 string timers
2026-08-01 19:51:23 +00:00
SGavrl
037e321a79
Merge remote-tracking branch 'origin/main' into maintainer/pr-517-tests
2026-08-01 19:47:51 +00:00
SGavrl
92576571ef
Merge pull request #533 from h4ckf0r0day/fix/509-performance-clock
...
Fix/509 performance clock
2026-08-01 19:46:49 +00:00
SGavrl
2275d8fea0
Merge remote-tracking branch 'origin/main' into maintainer/pr-509-fix
...
# Conflicts:
# crates/obscura-js/src/runtime.rs
2026-08-01 19:39:24 +00:00
SGavrl
bbc4980eba
Merge pull request #510 from mnaza/fix/childnode-coerce-498
...
fix(js): coerce non-string primitives in before/after/replaceWith
2026-08-01 17:18:11 +00:00
SGavrl
389de72d1b
Merge remote-tracking branch 'origin/main' into maintainer/pr-510-review
2026-08-01 17:14:05 +00:00
SGavrl
31ac297a48
Merge pull request #508 from mnaza/fix/history-preserve-url-496
...
fix(js): keep the current URL when pushState/replaceState omit url
2026-08-01 17:12:59 +00:00
SGavrl
e9f783b3cf
Merge pull request #511 from mnaza/fix/quirks-mode-selectors-499
...
fix(dom): honor quirks mode for class/id selector case-sensitivity
2026-08-01 17:12:44 +00:00
SGavrl
ec7334d91b
Merge pull request #512 from mnaza/fix/remove-double-free-500
...
fix(dom): guard DomTree::remove() against OOB and double-free
2026-08-01 17:12:28 +00:00
SGavrl
0428099b0f
Merge remote-tracking branch 'origin/main' into maintainer/pr-509-fix
2026-08-01 16:04:37 +00:00
SGavrl
76e5280c32
fix(dom): preserve namespaced attribute qualified names
2026-08-01 16:00:52 +00:00
SGavrl
1e305135e3
Merge remote-tracking branch 'origin/main' into maintainer/pr-514-review
2026-08-01 15:58:03 +00:00
SGavrl
a2fd4d1735
fix(js): parse fragments in their insertion context
2026-08-01 15:54:51 +00:00
SGavrl
35fa61032b
Merge remote-tracking branch 'origin/main' into maintainer/pr-507-review
2026-08-01 15:50:23 +00:00
SGavrl
907e15d85d
perf(js): avoid per-element style sync objects
2026-08-01 15:46:25 +00:00
SGavrl
82aa320084
Merge remote-tracking branch 'origin/main' into maintainer/pr-492-fix
2026-08-01 15:44:40 +00:00
SGavrl
5d7a02041a
fix(js): preserve inline styles when cloning
2026-08-01 15:41:45 +00:00
SGavrl
c327354911
Merge remote-tracking branch 'origin/main' into maintainer/pr-494-review
2026-08-01 15:40:11 +00:00
SGavrl
16b6a09546
Merge remote-tracking branch 'origin/main' into maintainer/pr-517-tests
2026-08-01 15:37:17 +00:00
SGavrl
dbc87e86f9
test(js): cover string timer handlers
2026-08-01 15:37:17 +00:00
SGavrl
b5c2f9cc4e
Merge branch 'maintainer/pr-508-review' into maintainer/pr-510-review
...
# Conflicts:
# crates/obscura-js/src/runtime.rs
2026-08-01 15:30:32 +00:00
SGavrl
caf51975bb
Merge remote-tracking branch 'origin/main' into maintainer/pr-508-review
2026-08-01 15:28:07 +00:00
SGavrl
3f5dd23778
Merge remote-tracking branch 'origin/main' into maintainer/pr-510-review
2026-08-01 15:28:02 +00:00
SGavrl
d93ff517fc
fix(js): keep performance clock bounded
2026-08-01 15:20:35 +00:00
SGavrl
d66e5ec110
Merge pull request #526 from marcoripa96/native-ca-roots
...
feat(net): trust platform CA roots alongside bundled webpki roots
2026-07-31 17:44:01 +00:00
SGavrl
bb21452f90
Merge pull request #532 from alectimison-maker/fix/dynamic-script-data-urls
...
fix(js): execute dynamic data URL scripts
2026-07-31 17:43:45 +00:00
SGavrl
0def838088
Merge pull request #523 from stack3mpty/fix/missing-event-constructors-521-522
...
fix(js): add global PromiseRejectionEvent and StorageEvent constructors
2026-07-31 17:43:25 +00:00
SGavrl
f46f741e8c
fix(net): load configured CA roots without default cost
2026-07-30 21:57:18 +00:00
SGavrl
0ff1ba0ea9
fix(js): match event constructor semantics
2026-07-30 21:43:33 +00:00
SGavrl
f84120591e
fix(js): match Chromium data URL handling
2026-07-30 21:40:13 +00:00
SGavrl
3a68457c0b
Merge pull request #530 from lisa0314/fix/524-react-controlled-inputs
...
fix(mcp): fill React controlled inputs
2026-07-29 22:24:20 +00:00
SGavrl
f153487030
Update README.md
2026-07-29 01:31:08 +02:00
SGavrl
450eaa3b88
Added sponsor logo
2026-07-28 23:27:45 +00:00
SGavrl
e78b5e6026
Merge pull request #516 from h4ckf0r0day/fix/macos-stealth-sdk-506
...
ci(release): use active macOS SDK for stealth builds
2026-07-26 11:50:20 +00:00
SGavrl
0670e738a0
ci(release): use active macOS SDK for stealth builds
2026-07-26 11:47:15 +00:00
SGavrl
8078cc3070
Merge pull request #506 from h4ckf0r0day/fix/release-stealth-build-483
...
ci(release): publish explicit stealth artifacts
2026-07-26 11:21:54 +00:00
SGavrl
19aeb1eddb
Merge pull request #505 from h4ckf0r0day/fix/mcp-read-timeout-501
...
fix(mcp): bound HTTP request read time
2026-07-26 11:21:22 +00:00
SGavrl
78a3e997e7
ci(release): publish explicit stealth artifacts
2026-07-26 11:05:13 +00:00
SGavrl
750ffa62a9
fix(mcp): bound HTTP request read time
2026-07-26 11:05:04 +00:00
SGavrl
6ad8eb9040
Merge pull request #502 from h4ckf0r0day/fix/op-reentrancy-453-v2
...
fix(js): scope fetch clients to browser contexts
2026-07-26 10:32:16 +00:00
SGavrl
ab6fa0e39b
fix(js): scope fetch clients to browser contexts
2026-07-26 10:20:25 +00:00
SGavrl
4af658351d
Merge pull request #493 from mnaza/fix/mcp-sse-wedge-489
...
fix(mcp): detach SSE keep-alive so it cannot wedge the HTTP server
2026-07-26 10:18:38 +00:00
SGavrl
08d7b5e254
Merge pull request #485 from ulises2k/fix/svg-parsed-namespace
...
fix(js,dom): keep parsed SVG in the SVG namespace so href reflects an SVGAnimatedString
2026-07-26 10:18:19 +00:00
SGavrl
e023cc87cb
Merge pull request #487 from ulises2k/security/quinn-proto-GHSA-4w2j-m93h-cj5j
...
security(deps): bump quinn-proto 0.11.14 -> 0.11.15 (GHSA-4w2j-m93h-cj5j)
2026-07-26 10:17:59 +00:00
SGavrl
e314b9b0f3
Merge pull request #471 from mnaza/fix/treewalker-movers-469
...
fix(js): descend on FILTER_SKIP in TreeWalker child/sibling movers (#469 )
2026-07-24 15:21:58 +00:00
SGavrl
0df158ec9d
Merge remote-tracking branch 'origin/main' into pr471-push
...
# Conflicts:
# crates/obscura-js/js/bootstrap.js
2026-07-24 15:19:29 +00:00
SGavrl
dd9f3ec41f
Merge pull request #480 from h4ckf0r0day/fix/template-serialize-perf
...
perf(dom): avoid per-element node clone when serializing template contents
2026-07-24 15:16:02 +00:00
SGavrl
becb3d941f
perf(dom): avoid per-element node clone when serializing template contents
...
The template.content bridge (#463 ) routed every element through
content_source(), which called get_node().clone() to read the Copy
template_contents field. That deep-cloned each element's Node (its attrs
Vec plus a String per attribute) on every innerHTML/outerHTML/dump-html
serialization, once per non-void element.
template_contents is already destructured from the node in the serialize
loop, so read it there directly. content_source() (inner_html path) now
reads it through with_node() by reference. Serialization output is
byte-identical; ~10% faster on serialization-heavy pages.
2026-07-24 14:37:42 +00:00
SGavrl
98f4efae1c
Merge pull request #470 from mnaza/fix/window-scroll-468
...
fix(js): make window-level scrolling actually scroll (#468 )
2026-07-24 14:31:00 +00:00
SGavrl
3f820c48c9
Merge pull request #458 from asap-cool/fix/scroll-event-on-assignment
...
fix(js): fire a scroll event when scrollTop/scrollLeft are assigned
2026-07-24 14:30:47 +00:00
SGavrl
4c8213a62c
Merge pull request #479 from j00jun/fix/iframe-event-dispatch
...
fix(js): make iframe events reach registered listeners
2026-07-24 14:30:31 +00:00
SGavrl
85a6b7bc85
Merge pull request #477 from lisa0314/fix/474-dynamic-script-settle
...
fix(js): allow pending dynamic scripts to finish settling
2026-07-24 14:30:13 +00:00
SGavrl
a9c25976b2
Merge pull request #476 from mnaza/fix/treewalker-parentnode-475
...
fix(js): implement DOM parentNode() traversal in TreeWalker (#475 )
2026-07-24 14:29:57 +00:00
SGavrl
3c94d69870
Merge pull request #472 from mnaza/fix/node-iterator-467
...
fix(js): implement a real NodeIterator instead of aliasing TreeWalker (#467 )
2026-07-24 14:29:41 +00:00
SGavrl
be18346a96
Merge pull request #466 from mnaza/fix/template-content-463
...
fix(dom): bridge <template> contents to JS so .content is not always empty (#463 )
2026-07-24 14:29:23 +00:00
SGavrl
485497393d
Merge pull request #465 from mnaza/fix/treewalker-previousnode-462
...
fix(js): walk reverse document order in TreeWalker.previousNode() (#462 )
2026-07-23 10:32:49 +00:00
SGavrl
61dd2f764e
Merge pull request #473 from lisa0314/test/js-runtime-page-init
...
test(js): initialize runtime fixtures before evaluation
2026-07-23 10:31:10 +00:00
SGavrl
36d8e43140
Update AGENTS.md
2026-07-22 19:12:44 +02:00
SGavrl
45aba21165
Update README.md
2026-07-22 19:11:35 +02:00
SGavrl
2974a71f3c
Merge pull request #456 from h4ckf0r0day/fix/cdp-context-isolation-449
...
Isolate CDP browser contexts
2026-07-22 11:36:49 +00:00
SGavrl
68d5824c8b
Merge pull request #455 from h4ckf0r0day/fix/networkinformation-eventtarget-277
...
Fix NetworkInformation event listeners
2026-07-22 11:35:52 +00:00
SGavrl
409ac781d2
Isolate CDP browser contexts
2026-07-22 10:45:36 +00:00
SGavrl
fc9f5248f7
Fix NetworkInformation event listeners
2026-07-22 10:29:51 +00:00
SGavrl
730bd01f57
Merge pull request #454 from lisa0314/fix/452-document-fragment-insertion
...
fix(js): flatten DocumentFragment during node insertion
2026-07-22 10:13:02 +00:00
SGavrl
43d542da37
Merge pull request #435 from asap-cool/upstream-430
...
fix(cdp): confine V8 isolates per connection to end the #430 concurrency abort
2026-07-22 10:12:35 +00:00