diff --git a/Cargo.lock b/Cargo.lock index 545f907dc8..ad7eade98f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -482,6 +482,7 @@ dependencies = [ "async-trait", "clap", "criterion", + "csscascade", "flatbuffers", "futures", "gl", @@ -499,6 +500,7 @@ dependencies = [ "serde", "serde_json", "skia-safe", + "stylo", "taffy", "tokio", "unicode-segmentation", diff --git a/crates/csscascade/README.md b/crates/csscascade/README.md index 9f936e8773..e4cdc3b947 100644 --- a/crates/csscascade/README.md +++ b/crates/csscascade/README.md @@ -1,263 +1,136 @@ # csscascade -A modern, Rust-native **CSS Cascade & Style Resolution Engine** designed for building browser‑like rendering pipelines. `csscascade` takes an HTML (and later SVG) DOM tree and produces a **style-resolved static tree** ready for layout and painting. +A Rust CSS cascade & style resolution engine for building non-browser rendering pipelines. -Today the crate is powered by [**Stylo**](https://github.com/servo/stylo) — Servo’s production CSS engine. Stylo handles parsing, selectors, specificity, and computed values (and compiles cleanly for `wasm32-unknown-emscripten`), while `csscascade` focuses on DOM adapters, HTML/SVG attribute normalization, font parsing/selection, layout hand-off, and everything else outside the CSS engine’s scope. +Given an HTML DOM tree and CSS, `csscascade` produces a **style-resolved static tree** — every node carrying its fully computed CSS — ready for layout and painting. -This crate implements the hardest and most fundamental part of a rendering engine: the transformation from loosely-typed DOM nodes + CSS rules into a **fully computed, normalized, strongly-typed tree**. +Powered by [Stylo](https://github.com/servo/stylo) (Servo/Firefox's CSS engine). Stylo is the only production-grade, embeddable CSS engine available in Rust; reimplementing the cascade (selectors, specificity, inheritance, shorthand expansion, `!important`, `var()`, `@media`, ...) from scratch is not viable. -Future support for SVG is planned (HTML + SVG share >90% of style logic). +## Pipeline ---- - -### “Isn’t a full CSS engine overkill?” - -Not really. Stylo stays surprisingly lean—our builds land around ~1.5 MB when compiled with `wasm-unknown-unknown` and roughly ~2.5 MB when targeting `wasm32-unknown-emscripten`. More importantly, reproducing the entirety of CSS3 (selectors, cascade rules, media queries, shorthand expansion, inheritance, etc.) is phenomenally difficult; sooner or later any serious renderer ends up needing a browser-grade engine. Stylo already solves that problem with production-ready accuracy, so we embrace it and focus on the rest of the pipeline. - ---- - -## What this crate does - -### ✔ 1. Parse and walk an HTML/XML tree - -Accepts a DOM-like tree (any structure implementing the crate's DOM traits). - -### ✔ 2. Perform full CSS cascade - -Backed by Stylo’s battle-tested cascade implementation: - -- Selector matching -- Specificity and importance resolution -- Inheritance -- Initial values -- Presentation attribute mapping (SVG-ready) -- Shorthand expansion - -### ✔ 3. Produce a Style‑Resolved Tree - -A new tree where **every node has its final computed style** attached. -This tree contains: - -- resolved display modes -- resolved text properties -- resolved sizing/box model values -- resolved transforms & opacity -- fully computed inline and block styles - -### ✔ 4. Ready for layout engine consumption - -`csscascade` does **not** perform layout. -It outputs a static, fully resolved element tree specifically designed to be fed into your layout engine (block/inline/flex/grid/etc.). - -### ✔ 5. Ready for painting after layout - -Since the style is computed and normalized, the next stages can be: - -- layout engine -- display list generation -- painting/rendering - ---- - -## Why this crate exists - -Rendering HTML and SVG is deceptively hard. Even before layout and paint, a renderer must: - -- parse the DOM -- run the CSS cascade -- normalize presentation attributes -- compute final styles -- build a static, render‑ready tree - -None of these steps are specific to a browser — they are fundamental requirements for **any** engine that wants to render HTML or SVG, whether for graphics, documents, UI, or design tools. - -The goal of `csscascade` is **not** to help you build a browser. Instead, it’s designed for developers building: - -- static HTML/SVG renderers -- document processors -- canvas-based UI engines -- PDF or image generators -- design tools (like Figma‑style or illustration tools) -- “bring your own renderer” pipelines - -It handles the universally hard parts (CSS cascade, style normalization, static tree production) by delegating the CSS engine to Stylo and layering our own DOM/font/layout glue on top, so your engine can focus on **layout and painting**, not CSS correctness. - ---- - -## Intended Audience - -### ✔ 1. Engine and renderer authors (non‑browser) - -This crate is specifically for people building a **static** renderer — not a real DOM, not a browser, not an interactive layout engine. - -If you: - -- want to parse HTML/SVG once -- resolve styles correctly -- produce a clean, immutable tree -- feed it to your own layout + painting pipeline - -…then `csscascade` is designed for you. +``` +HTML string + │ + ▼ +html5ever ─── parse ──► RcDom (reference-counted DOM) + │ + ▼ +csscascade ── cascade ─► StyledTree (computed styles per node) + │ + ▼ +taffy ─────── layout ──► positioned boxes + │ + ▼ +grida-canvas ─ convert ► IR nodes (rectangles, text, etc.) +``` -### ✔ 2. Tools that need correct CSS without a browser +This mirrors the SVG import path (`usvg` → `from_usvg` → IR), but for HTML/CSS each stage is a separate crate because no single library (like `usvg` for SVG) handles the full pipeline. -For example: +## Current State -- SVG → PNG converters -- HTML → PDF generators -- print engines -- design tools -- WASM/canvas engines +**Working:** -### ✖ Not for browser makers +- HTML parsing via html5ever into `RcDom` +- DOM tree representation (`rcdom` module) +- `Tree` / `StyledNode` abstractions for style-resolved output +- Stylo infrastructure wired up (`Device`, `Stylist`, `SharedRwLock`) +- Serialization — re-emit HTML, optionally with computed styles inlined +- Builder pattern for programmatic tree construction +- Working examples: `print_tree`, `print_rcdom`, `html2html` -If you need: +**Proof-of-concept (not yet integrated):** -- live DOM mutation -- dynamic style recalculation -- reflow/repaint cycles -- incremental layout -- event-driven DOM +- `examples/exp_impl_telement.rs` — demonstrates full per-element cascade via Stylo's `TElement` trait. This works but has not been promoted to the main crate API. -…this crate intentionally does **not** target that use case. +**Stubbed / not yet functional:** ---- +- `StyleRuntime::compute_for()` returns default `ComputedValues` instead of actually resolving per-element styles +- `SimpleFontProvider` returns hardcoded metrics, not real font data -## What this crate produces +## Roadmap -`csscascade` outputs a **style‑resolved static tree** — every node has fully computed CSS (straight from Stylo) applied, ready for layout. +### Phase 1 — Cascade Resolution ✅ -### (planned) Optional layout integration +Per-element style resolution via Stylo's `TElement` trait. -A future feature flag will allow the crate to output a **layout‑computed, render‑ready tree**, so you can plug it directly into your painter. +- [x] Promote `TElement` implementation into the crate (`adapter.rs`) +- [x] Collect CSS from ` + +
+This paragraph should be 14px #555.
+This is hidden.
+