Skip to content

Commit 1e13eaa

Browse files
AndrewAltimitAI Agent BotclaudeAI Review AgentAI Pipeline Agent
authored
feat(browser): comprehensive engine improvements — rendering, JS, networking, SVG, canvas (#89)
* feat(browser): comprehensive engine improvements — rendering, animation, layout, networking Paint pipeline: - CSS filter effects engine (grayscale, invert, sepia, brightness, contrast, saturate, hue-rotate, opacity) applied to backgrounds and text - Multi-stop gradient interpolation with banded rendering per stop pair - True diagonal gradient rendering (per-pixel for arbitrary angles) - Rounded box shadows (fill_rounded_rect when border_radius > 0) - Inset box shadow support (edge strips inside padding box) Animation & transitions: - Wire TransitionEngine.tick() and AnimationEngine.tick() into frame loop with Instant-based delta time tracking - Register @Keyframes animations from UA + author stylesheets on page load - Active animations/transitions trigger layout invalidation Layout: - margin: auto on flex items absorbs free space before justify-content - tab-size CSS property (parsed, default 8, tabs expanded in pre/pre-wrap) Networking & security: - Brotli decompression (Accept-Encoding: gzip, br) - RFC 6265 cookie path/domain validation with boundary checking - CSP: style-src, img-src, connect-src directives with default-src fallback Images: - WebP format detection (RIFF/WEBP magic bytes) - loading="lazy" defers image loading after eager images Developer experience: - BrowserError API (Network/Parse/Script errors, cleared per navigation) - Focus indicator (2px blue outline on focused form element) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(browser): JS interactivity, connection pooling, SVG rendering, event dispatch JavaScript DOM & timers: - removeChild / insertBefore bindings with JS-side Element.prototype wrappers - Wire setTimeout/setInterval via existing TimerQueue in oasis-js engine - Timer callbacks evaluated each tick(), layout marked dirty on fire Event dispatch: - mouseover/mouseout dispatched on hover node changes - keydown + input events dispatched on focused form elements - All events use bubbling dispatch with stopPropagation support HTTP connection pooling: - Thread-local ConnectionPool with per-host reuse (max 2/host, 8 total) - 30-second idle timeout with stale connection detection - Changed Connection header from close to keep-alive - Graceful fallback to fresh connection on pooled stream failure SVG basic shapes: - New svg.rs module: parser + renderer for rect, circle, ellipse, line, text - Color parsing: named colors (21), #RGB, #RRGGBB, rgb(r,g,b), none - ViewBox scaling for proper coordinate mapping - Integrated as ReplacedContent::Svg in layout pipeline - 13 unit tests for SVG parsing and color handling Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(browser): fetch API, canvas 2D, radial gradients, form submission, getComputedStyle JavaScript APIs: - fetch() with synchronous HTTP GET, thenable response with .text()/.json() - getComputedStyle() returning ~30 CSS properties via ComputedStyle serialization - Inline event handlers (onclick, onchange, onsubmit, etc.) auto-registered - localStorage/sessionStorage backed by in-memory HashMap - Canvas 2D context: fillRect, strokeRect, clearRect, fillText, beginPath, moveTo, lineTo, arc, fill, stroke with fillStyle/strokeStyle/lineWidth CSS rendering: - radial-gradient() with circle/ellipse shape, multi-stop interpolation - repeating-linear-gradient() with tiled stop pattern - RadialGradient type + parser + pixel-by-pixel rendering Forms & images: - Form submission on Enter/submit button (GET query string + POST body) - srcset attribute parsing with width/density descriptor selection - WebP decoding via optional image crate (behind webp feature flag) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf(browser): fix gradient rendering freeze — replace pixel-by-pixel with band-based Diagonal linear gradients were rendering pixel-by-pixel with O(w*h) individual fill_rect(1,1) calls, causing multi-second freezes on pages like Wikipedia. Replaced with axis-snapping approach using a single fill_rect_gradient call. Radial gradients similarly replaced: pixel-by-pixel O(w*h) rendering replaced with concentric rounded-rect bands (max 128 bands), reducing draw calls from ~130K to ~128 for a typical element. Fixes app freeze when navigating to https://www.wikipedia.com. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(browser): HTTP keep-alive response hang + performance regression test The Connection: keep-alive change caused read_response() to block for the full 15-second READ_TIMEOUT on every request. With keep-alive the server doesn't close the connection, so reading until EOF hangs. Fixed by making read_response() content-length-aware: once headers arrive, it parses Content-Length or detects chunked encoding and stops reading when the body is complete. Falls back to EOF/timeout only when neither is present. Also added an integration test that runs a complex page (with CSS gradients, tables, nested structure) through the full parse → cascade → layout pipeline and asserts completion within 500ms. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(browser): back/forward navigation uses cache instead of re-fetching go_back() and go_forward() previously called navigate_vfs() which always re-fetches from the network. For HTTPS pages like Wikipedia, this caused a second TLS handshake + full page download, freezing the UI. Added navigate_cached_or_fetch() which checks the in-memory ResourceCache first. On cache hit for HTML content, re-renders directly from cached body with zero network latency. Falls back to navigate_vfs() on cache miss. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(browser): forward button after back, defensive srcset fallback Forward button was broken because navigate_cached_or_fetch() called load_html() which calls nav.navigate() — clearing the forward stack. Added skip_nav_push flag so cache-restored pages don't push new navigation entries. Also made srcset URL selection more defensive: filters out empty and data: URLs before preferring srcset over src, preventing cases where a bad srcset candidate would suppress the working src URL. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(browser): Wikipedia images not loading — 303 redirect + srcset key mismatch Two bugs prevented most images from loading on Wikipedia: 1. Missing 303 (See Other) in redirect handling. Wikipedia's image CDN (upload.wikimedia.org) returns 303 redirects for thumbnails. The browser wasn't following them, receiving empty bodies that failed to decode. Added 303 to is_redirect(). 2. srcset/src URL key mismatch. collect_page_image_requests() stored decoded images under srcset-derived URLs, but ensure_image_textures() and assign_textures_recursive() only looked up by elem.src(). When both attributes were present (nearly all Wikipedia images), textures were never created. Extracted effective_img_src() helper used consistently across all three code paths. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(browser): address all Gemini AI review findings + flaky CI test Fixes all 5 bugs and 2 suggestions from the Gemini code review: 1. Chunked stream parsing false-positive (CRITICAL): Changed from find_subsequence scanning entire buffer to ends_with checks on buffer tail, preventing binary data mid-stream from triggering premature response truncation. 2. CSP bypass in fetch API (CRITICAL): __oasis_fetch now checks connect-src CSP directives before making HTTP requests. Added install_document_global_with_csp() that accepts the page CspPolicy. 3. Unsafe JS character escaping (BUG): dispatch_js_key_event now escapes backslash, single quote, newline, and carriage return to prevent JS syntax errors on special key presses. 4. Alpha over-accumulation in radial gradients (BUG): Force gradient band colors to alpha=255 since element-level opacity is handled separately by apply_opacity at the call site. 5. Stroked arcs silently ignored (BUG): Canvas Arc command now handles stroke case via stroke_rounded_rect. 6. SVG diagonal lines (SUGGESTION): Diagonal lines now use Bresenham-like plotting instead of bounding-box fill_rect. 7. Wire repeating-linear-gradient (SUGGESTION): Axis-aligned path now tiles stop bands when grad.repeating is true. Also fixes flaky CI test oasis-net::listener_max_connections_reached by adding retry loop with fresh ports on bind failure. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address AI review feedback (iteration 2) Automated fix by Claude in response to Gemini/Codex review. Iteration: 2/5 Co-Authored-By: AI Review Agent <noreply@anthropic.com> * fix: address AI review feedback (iteration 3) Automated fix by Claude in response to Gemini/Codex review. Iteration: 3/5 Co-Authored-By: AI Review Agent <noreply@anthropic.com> * fix: resolve CI pipeline failures Automated fix by Claude in response to pipeline failures. Failures addressed: - format - lint - test-suite Actions taken: - Ran autoformat (ruff format, cargo fmt) - Fixed remaining lint issues Iteration: 2/5 Co-Authored-By: AI Pipeline Agent <noreply@anthropic.com> * fix: address AI review feedback (iteration 5) Automated fix by Claude in response to Gemini/Codex review. Iteration: 5/5 Co-Authored-By: AI Review Agent <noreply@anthropic.com> * fix: resolve CI pipeline failures Automated fix by Claude in response to pipeline failures. Failures addressed: - format - lint - test-suite Actions taken: - Ran autoformat (ruff format, cargo fmt) - Fixed remaining lint issues Iteration: 3/5 Co-Authored-By: AI Pipeline Agent <noreply@anthropic.com> --------- Co-authored-by: AI Agent Bot <ai-agent@localhost> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: AI Review Agent <ai-review-agent@localhost> Co-authored-by: AI Pipeline Agent <ai-pipeline-agent@localhost>
1 parent 12de3ea commit 1e13eaa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3815
-208
lines changed

Cargo.lock

Lines changed: 90 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ wasm-bindgen-futures = "0.4"
115115

116116
# Compression
117117
flate2 = "1"
118+
brotli = { version = "7", default-features = false, features = ["std"] }
118119

119120
# Fast hashing
120121
rustc-hash = "2.1"

crates/oasis-backend-psp/Cargo.lock

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/oasis-browser/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ documentation = "https://docs.rs/oasis-browser"
1111
[features]
1212
default = []
1313
javascript = ["dep:oasis-js"]
14+
webp = ["dep:image"]
1415

1516
[dependencies]
1617
oasis-types = { workspace = true }
@@ -22,9 +23,11 @@ rustc-hash = { workspace = true }
2223
serde = { workspace = true }
2324
log = { workspace = true }
2425
flate2 = { workspace = true }
26+
brotli = { workspace = true }
2527
png = { workspace = true }
2628
jpeg-decoder = { workspace = true }
2729
gif = { workspace = true }
30+
image = { version = "0.25", default-features = false, features = ["webp"], optional = true }
2831

2932
[dev-dependencies]
3033
proptest.workspace = true

0 commit comments

Comments
 (0)