Commit Graph
100 Commits
Author SHA1 Message Date
SGavrl 740caaea06 Fix layout text width estimates and alignment for hn header 2026-07-02 22:12:03 +00:00
SGavrl e3d072f0b7 Implement Hacker News specific styles and drawing rules 2026-07-02 21:52:46 +00:00
SGavrl ff622c00a0 Fix table rendering layout and alignment 2026-07-02 21:43:36 +00:00
SGavrl f53d60e061 fix(render): implement top-down style inheritance and fix logo heuristic 2026-07-02 20:41:19 +00:00
SGavrl cd3571ddc0 fix(render): render logo and parse named colors 2026-07-02 20:34:32 +00:00
SGavrl bd4845b52c fix(render): correct center tag alignment and percentage dimensions 2026-07-02 20:26:55 +00:00
SGavrl 42874989eb feat(render): parse presentational attributes and font sizes for beautiful layout 2026-07-02 20:20:26 +00:00
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