commits
GIF LZW uses "early change" — the code size must bump when next_code
reaches (1 << code_size), not after it exceeds it. Without this fix,
the decoder would read codes with the wrong bit width for GIFs with
enough unique codes to trigger a code size increase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust GIF decoder in the image crate supporting:
- GIF87a and GIF89a format parsing
- LZW decompression with variable-width codes, clear/EOI codes
- Global and local color tables
- Graphic Control Extension (transparency, delay, disposal methods)
- Multi-frame animated GIFs with canvas compositing
- Interlaced image support (4-pass Adam7-style deinterlacing)
- Sub-frame positioning (frames smaller than logical screen)
- Application, comment, and plain text extension skipping
- API: decode_gif() for first frame, decode_gif_frames() for all frames
31 unit tests covering LZW decompression, deinterlacing, frame decoding,
transparency, animation, local color tables, extensions, and error cases.
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust PNG decoder supporting all color types (grayscale, RGB,
indexed, grayscale+alpha, RGBA), bit depths 1-16, scanline filtering
(None/Sub/Up/Average/Paeth), Adam7 interlacing, tRNS transparency,
CRC-32 validation, and multiple IDAT chunk concatenation.
40+ unit tests covering all color types, bit depths, filter types,
interlacing, transparency, error cases, and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Image struct (always RGBA8) with conversions from grayscale,
grayscale+alpha, RGB, RGBA, indexed color, and indexed+alpha.
29 unit tests covering all conversion paths and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse zlib header (CMF/FLG), validate header checksum, delegate to
DEFLATE for compressed data, verify Adler-32 checksum of output.
21 unit tests covering Adler-32, header validation, round-trip
decompression, error propagation, and all window sizes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust DEFLATE decompression supporting all three block types:
- Non-compressed blocks (BTYPE=00) with LEN/NLEN validation
- Fixed Huffman codes (BTYPE=01) per RFC 1951 §3.2.6
- Dynamic Huffman codes (BTYPE=10) with code length decoding
Implementation details:
- LSB-first bit reader with peek/consume pattern for Huffman decoding
- Two-level Huffman lookup table (primary + subtable for long codes)
- LZ77 back-reference decoding with overlapping copy support
- Handles end-of-stream gracefully when final code needs fewer bits
than the primary table width
33 unit tests covering BitReader, Huffman trees, all block types,
back-references, error cases, and round-trip verification against
zlib-generated test vectors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace strip_prefix-based header matching (only matched exact case and
lowercase) with a proper case-insensitive helper that splits on the
first colon and compares the header name using eq_ignore_ascii_case.
Adds tests for all-caps header names (CONTENT-LENGTH, TRANSFER-ENCODING).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
High-level HTTP client in the net crate bringing together TCP, TLS 1.3,
DNS, URL parsing, and HTTP message handling:
- HttpClient with get(), post(), request() methods
- Scheme handling: http:// (plain TCP) and https:// (TLS)
- Connection pooling by (host, port, is_tls) with max idle time and
max connections per host
- Redirect following (301, 302, 307, 308) with configurable max
- Configurable connect and read timeouts
- Streaming response reader: header detection, Content-Length,
chunked Transfer-Encoding, and read-until-close strategies
- std::io::Read and Write trait impls for TcpConnection
30+ unit tests covering error types, configuration, connection pool,
URL path building, header parsing, body strategy selection, and
chunked terminator detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HTTP/1.1 message parser (RFC 7230, 7231) for the net crate:
- Request serialization (GET, POST, HEAD, PUT, DELETE, OPTIONS, PATCH)
- Response parsing: status line, headers, body
- Headers collection with case-insensitive name lookup
- Content-Length body reading
- Chunked Transfer-Encoding decoding (RFC 7230 §4.1)
- Content-Type parsing with charset extraction
- Proper handling of 1xx/204/304 no-body responses
55 tests covering all acceptance criteria.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The application traffic secrets (RFC 8446 §7.1) must be derived from
the transcript hash covering ClientHello...server Finished, not
including the client Finished message. The code was using
transcript.current_hash() after updating with client_finished_msg,
producing incorrect application keys that would fail against real
servers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- random_bytes: panic instead of silently using zero-filled buffers when
/dev/urandom fails — using all-zero keys is a critical security issue
- Rename _ee_body to ee_body since the variable is actually used
- Fix wildcard hostname matching to reject empty labels (e.g. ".example.com"
should not match "*.example.com")
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full TLS 1.3 client handshake: ClientHello with SNI/supported_versions/
key_share/signature_algorithms extensions, ServerHello processing,
ECDHE key exchange (X25519), encrypted handshake message processing
(EncryptedExtensions, Certificate, CertificateVerify, Finished),
certificate chain validation, server name verification with wildcard
matching, key phase transitions, and TlsStream type for application data.
Supports RSA PKCS#1 v1.5 and ECDSA (P-256/P-384) signature verification
in CertificateVerify. Validates server certificates against embedded
root CA store (ISRG Root X1, DigiCert, GlobalSign).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Key schedule for deriving encryption keys from shared secrets using HKDF.
Includes HKDF-Expand-Label, Derive-Secret, transcript hashing, traffic
key/IV derivation, and Finished verify data computation. Supports all
three TLS 1.3 cipher suites (AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305).
Also adds Clone derive to SHA-256, SHA-384, SHA-512 hashers in the crypto
crate to support transcript hash snapshotting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Record layer protocol in the net crate for framing and encrypting TLS
records. ContentType enum (ChangeCipherSpec, Alert, Handshake,
ApplicationData). Plaintext record read/write with header framing and
size enforcement. Encrypted record support via RecordCryptoState with
per-record nonce construction (XOR base IV with sequence number),
inner content type hiding, and AEAD using AES-128-GCM, AES-256-GCM,
or ChaCha20-Poly1305. Alert protocol with close_notify and fatal error
handling. RecordLayer type combining plaintext and encrypted modes with
runtime crypto state switching.
36 tests covering content types, alert encode/decode, nonce construction,
plaintext record I/O, encrypted roundtrips for all cipher suites,
sequence numbering, tamper detection, record overflow, and RecordLayer
integration with plaintext-to-encrypted transitions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DNS resolver in the net crate for resolving hostnames to IP addresses
via UDP queries to system nameservers. Parses /etc/resolv.conf for
nameserver discovery with fallback to Google DNS. Supports A and AAAA
record types, DNS name compression pointers, NXDOMAIN handling, timeout
and retry across multiple nameservers, and direct IP address passthrough.
DnsResolver type with system() and with_nameservers() constructors,
configurable timeout, and resolve() method. Convenience resolve()
function for one-shot lookups. 38 tests covering name encoding, query
building, response parsing, compression pointers, resolv.conf parsing,
address extraction, error types, and real hostname resolution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TcpConnection type wrapping std::net::TcpStream with connect,
connect_timeout, read, write, read_exact, write_all, flush, timeout
configuration, and shutdown. NetError enum with automatic mapping
from io::Error (ConnectionRefused, TimedOut variants). BufferedReader
and BufferedWriter wrappers for efficient line-oriented I/O with
split read/write support via stream cloning.
15 tests covering error types, connection failures, loopback echo,
buffered line reading, buffered read/write pairs, timeouts, and
debug formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
URL record type with scheme, username, password, host, port, path,
query, fragment. State-machine parser handling special schemes (http,
https, ftp, ws, wss, file) with default ports. Host parsing for
domains, IPv4 (decimal/hex/octal), and IPv6 (including IPv4-mapped
and :: compression). Percent-encoding/decoding per spec encode sets
(C0, fragment, query, path, userinfo). Relative URL resolution via
base URL. URL serialization with round-trip fidelity. Origin
derivation (tuple for special schemes, opaque otherwise).
88 tests covering absolute URLs, scheme handling, host types,
IPv4/IPv6 parsing and serialization, percent encoding, path dot
resolution, relative URL resolution, serialization round-trips,
file URLs, and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PEM decoding with custom Base64 decoder, X.509v3 certificate parsing
extracting version, serial, issuer, subject, validity, SPKI, and
extensions (Basic Constraints, Key Usage, SAN, AKI, SKI). Certificate
chain validation with signature verification (RSA + ECDSA), validity
period checks, and CA constraint enforcement. Embedded root CA store
with ISRG Root X1, DigiCert Global Root G2, and GlobalSign Root R3.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Elliptic curve arithmetic in Jacobian coordinates with point addition,
doubling, and Montgomery ladder scalar multiplication. Field arithmetic
over the prime fields of P-256 (secp256r1) and P-384 (secp384r1) using
the existing BigUint type.
ECDSA verification per FIPS 186-4 §4.1.4 with Shamir's trick for
multi-scalar multiplication. Parses EC public keys from uncompressed
point format and SubjectPublicKeyInfo DER. Parses DER-encoded
ECDSA signatures.
34 tests including: curve parameter validation, point arithmetic,
RFC 6979 test vectors (P-256/SHA-256), self-generated test vectors
for both P-256 and P-384, signature rejection, and DER parsing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BigUint type with arbitrary-precision arithmetic backed by little-endian
u64 limbs. Supports modular exponentiation via Montgomery multiplication
for odd moduli (RSA) with fallback for even moduli.
RSA public key parsing from both PKCS#1 RSAPublicKey and PKCS#8
SubjectPublicKeyInfo DER formats. RSASSA-PKCS1-v1_5-VERIFY with
EMSA-PKCS1-v1_5 encoding for SHA-256, SHA-384, and SHA-512.
Constant-time signature comparison. Key sizes 2048-4096 bits.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DerParser reads TLV structures from DER-encoded byte slices. Supports
all primitive types needed for X.509 certificates: BOOLEAN, INTEGER,
BIT STRING, OCTET STRING, NULL, OID, UTF8String, PrintableString,
IA5String, UTCTime, GeneralizedTime. Constructed types: SEQUENCE, SET.
Context-specific tags with explicit/implicit tagging.
Includes well-known OID constants for RSA, ECDSA, SHA-2, X.509
extensions, and X.500 attribute types. OID encode/decode with dotted
notation. Rejects non-DER encodings (indefinite length, non-minimal
integers/lengths).
45 tests covering all types, DER validation, real certificate fragments,
and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Field arithmetic in GF(2^255 - 19) using 5x51-bit limb representation.
Montgomery ladder scalar multiplication on Curve25519. Constant-time
implementation with no secret-dependent branches or memory accesses.
Passes RFC 7748 §6.1 DH test vectors and §5.2 iterated test vector
(1,000 iterations).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The constant-time conditional select between h and g in the Poly1305
final reduction was missing h4/g4. When h >= p (2^130-5), the code
selected g for h0-h3 but left h4 unchanged, producing incorrect tags
for inputs where the accumulator exceeds the prime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust ChaCha20-Poly1305 authenticated encryption in the crypto crate:
- ChaCha20 stream cipher: quarter round, block function (20 rounds),
counter-mode encryption with 256-bit key, 96-bit nonce, 32-bit counter
- Poly1305 one-time MAC: GF(2^130-5) using 5 limbs of 26 bits,
clamped r key, constant-time final reduction
- AEAD construction: Poly1305 key generation from ChaCha20 block 0,
encrypt-then-MAC with RFC 8439 padding and length encoding
- Constant-time tag comparison for secure decryption
- 13 tests: RFC 8439 test vectors (§2.1.1, §2.3.2, §2.4.2, §2.5.2,
§2.6.2, §2.8.2), tag tamper detection, and round-trip tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust AES-GCM authenticated encryption in the crypto crate:
- AES block cipher (FIPS 197): key expansion and encrypt for 128/256-bit keys
- GHASH: constant-time GF(2^128) multiplication using bit masking
- GCM encrypt/decrypt with 96-bit nonce, 128-bit authentication tag, and AAD
- Constant-time tag comparison for secure decryption
- 25 tests including NIST SP 800-38D test vectors (cases 1-4, 13-16),
tag tamper detection, and encrypt/decrypt round-trips
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust HKDF implementation in the crypto crate, generic over
hash function via the existing HashFunction trait:
- hkdf_extract(salt, IKM) -> PRK
- hkdf_expand(PRK, info, L) -> OKM with length validation
- hkdf() combined convenience function
- HKDF-SHA-256, HKDF-SHA-384, HKDF-SHA-512 via generics
- Empty salt defaults to HashLen zeros per RFC 5869 §2.2
- Output length validated: L <= 255 * HashLen
- 14 tests including all RFC 5869 SHA-256 test vectors (cases 1-3)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust HMAC implementation in the crypto crate, generic over
hash function via a HashFunction trait:
- HMAC-SHA-256, HMAC-SHA-384, HMAC-SHA-512
- Streaming API: new(key), update(&[u8]), finalize() -> Vec<u8>
- One-shot: hmac_sha256(), hmac_sha384(), hmac_sha512()
- Key handling: long keys hashed, short keys zero-padded
- Inner/outer padding (ipad/opad) per RFC 2104 §2
- 25 tests including all RFC 4231 test vectors (cases 1-7)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust implementations of the SHA-2 family per FIPS 180-4
in the crypto crate:
- SHA-256: 256-bit digest, 64-byte blocks, 64 rounds
- SHA-512: 512-bit digest, 128-byte blocks, 80 rounds
- SHA-384: truncated SHA-512 with different initial values
All three provide streaming (new/update/finalize) and one-shot APIs.
21 tests including NIST test vectors (empty, abc, 448-bit, 896-bit,
million-a) plus streaming and edge-case coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When both underline and background were present, bg_idx pointed to
the underline rect instead of the DrawGlyphs command, causing the
background to paint after the text. Capture glyph_idx before pushing
any commands to ensure correct painter's order.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the simplified inline text layout with a proper inline
formatting context (IFC):
Layout crate:
- Flatten inline tree into items (words, spaces, breaks, inline starts/ends)
- Word-wrap into line boxes respecting per-fragment font sizes
- Handle <br> as forced line breaks
- Apply text-align (left, center, right) via horizontal offset
- Use computed line-height instead of hardcoded font_size * 1.2
- Inline box model: margin/padding/border offsets for inline elements
- TextLine now carries per-fragment styling (font_size, color,
text_decoration, background_color) instead of inheriting from parent
- Store text_align and line_height on LayoutBox
Render crate:
- paint_text uses per-TextLine styling (color, font_size, text_decoration)
- Render inline fragment backgrounds when not transparent
- Underline uses per-fragment font_size for baseline calculation
Tests: 7 new (per-fragment styling, <br>, text-align center/right,
inline padding, font_size per fragment, line-height)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded tag-based defaults in the layout crate with CSS
computed styles from the style crate. The layout engine now accepts
a StyledNode tree instead of walking the DOM directly.
Layout crate changes:
- layout() takes &StyledNode + &Document instead of &Document alone
- Remove hardcoded display_type(), default_font_size(), default_margin()
- Read display, margin, padding, border, font-size from ComputedStyle
- Carry color, background-color, text-decoration, border styles/colors
on LayoutBox for the renderer to use
Render crate changes:
- Use CSS color for text (instead of hardcoded black)
- Use CSS background-color for box backgrounds (skip transparent)
- Render borders with correct width, style, and color
- Support text-decoration: underline
- Replace render-local Color type with we_css::values::Color
Browser pipeline:
- Full: HTML → DOM → extract CSS → resolve styles → layout → render
6 new tests across layout (3) and render (3) crates verifying CSS
properties flow through to layout positions and paint commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add extract_stylesheets() to the style crate that walks the DOM tree,
finds all <style> elements, extracts their text content, and parses
each as a CSS stylesheet in document order.
Update the browser pipeline to extract CSS from <style> elements and
resolve computed styles via the cascade. The styled tree is computed
but layout integration is deferred to a separate issue.
- extract_stylesheets() in style::computed walks DOM for <style> elements
- Browser render_page() now runs: parse HTML → extract CSS → resolve styles → layout → render
- Default HTML page updated with <style> block to demonstrate CSS parsing
- 10 new unit tests for extract_stylesheets (single/multiple/empty/body)
- 6 integration tests using parse_html for full HTML→DOM→CSS→styled tree pipeline
- Tests cover: style element extraction, multiple stylesheets cascade,
inline style overrides, UA defaults, display:none removal, class selectors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix em unit resolution for non-font-size properties: em now resolves
relative to the element's own computed font-size (per CSS spec) instead
of the parent's font-size. Font-size itself already correctly uses
parent font-size for em resolution in its own handler.
- Add missing 'right' and 'left' position offset property handling in
apply_property (only 'top' and 'bottom' were handled).
- Update em_margin_relative_to_font_size test to assert correct value
(2em * 20px = 40px, not 2em * 16px = 32px).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds the `computed` module to the `style` crate with:
- `ComputedStyle` struct with typed fields for all CSS properties:
display, margin, padding, border (width/style/color), width, height,
color, font-size, font-weight, font-style, font-family, text-align,
text-decoration, line-height, background-color, position, top/right/
bottom/left, overflow, visibility
- Cascade algorithm:
1. Collects matching rules via selector matching (from existing matching module)
2. Sorts by origin (UA < author) and specificity
3. Separates normal vs !important declarations
4. Applies inline styles (from style attribute) with highest priority
5. Expands shorthand properties (margin, padding, border, background)
- Property inheritance:
- Inherited properties (color, font-size, font-weight, font-style,
font-family, text-align, text-decoration, line-height, visibility)
automatically inherit from parent computed values
- Non-inherited properties reset to initial values
- `inherit`, `initial`, `unset` keyword support
- User-agent default stylesheet with standard HTML element defaults:
display types, body margin, heading sizes/weights/margins,
paragraph margins, bold/italic/underline for semantic elements
- Relative value resolution:
- `em` units relative to parent font-size (for font-size) or
current font-size (for other properties)
- `rem` units relative to root (16px)
- Physical unit conversion (pt, cm, mm, in, pc)
- Percentage resolution for font-size
- `resolve_styles()` API that builds a styled tree (StyledNode) from
a DOM document and author stylesheets
- 34 comprehensive tests covering UA defaults, author overrides,
cascade ordering, specificity, inheritance, inherit/initial/unset
keywords, em resolution, inline styles, shorthand expansion,
multiple stylesheets, and display:none removal
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Simple selectors: type, universal, class, ID, attribute, pseudo-class
- Compound selectors: all parts must match
- Complex selectors with combinators: descendant, child, adjacent/general sibling
- Selector list matching (comma-separated)
- Specificity calculation (a, b, c) with Ord implementation
- Rule collection: gather matching rules sorted by specificity and source order
- Declaration collection with !important separation
- Right-to-left matching for correct combinator evaluation
- All attribute operators: exact, includes, dash-match, prefix, suffix, substring
- 34 tests covering all selector types, combinators, specificity, and rule collection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add values module to the css crate that converts raw ComponentValue token
lists into typed CssValue variants. Supports all CSS length units (px, pt,
cm, mm, in, pc, em, rem, vw, vh, vmin, vmax), percentages, hex colors
(#rgb, #rrggbb, #rgba, #rrggbbaa), rgb()/rgba() functions, 17 named colors,
keywords (auto, inherit, initial, unset, none, transparent, currentColor),
and shorthand expansion for margin, padding, border, border-width/style/color,
and background. 63 unit tests covering all value types and shorthands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full CSS parser per CSS Syntax Module Level 3 §5 that consumes tokens from the
tokenizer and produces a structured stylesheet AST. Supports type, universal,
class, ID, attribute, and pseudo-class selectors with all combinators
(descendant, child, adjacent sibling, general sibling). Parses declarations
with !important, component values including functions, and @-rules (@media
with nested rules, @import). Includes error recovery for invalid declarations
and unknown at-rules. 37 unit tests covering all selector types, declarations,
@-rules, error recovery, and real CSS patterns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full tokenizer state machine producing all CSS token types: ident, function,
at-keyword, hash, string, url, number, percentage, dimension, whitespace,
delimiters, CDO/CDC. Handles escape sequences, comments, number consumption
(integer/float/exponent), url tokens, and input preprocessing (CRLF
normalization, null replacement). 43 unit tests covering all token types,
edge cases, and real CSS patterns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Connect all Phase 3 components to display a rendered HTML page in the
AppKit window. The browser now runs the full pipeline: parse HTML into
a DOM, run block layout, paint via the software renderer, and display
the result in the window.
- Default "Hello from we!" page when run with no arguments
- Load HTML from a file path via command-line argument
- Window resize triggers full re-layout and re-render at new dimensions
- Platform crate: add set_resize_handler() and BitmapView::update_bitmap()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Color struct with BLACK/WHITE constants
- Display list with FillRect and DrawGlyphs paint commands
- Display list generation from layout tree (painter's order)
- Software renderer: BGRA pixel buffer with rect filling and glyph compositing
- Source-over alpha blending for anti-aliased text rendering
- 11 tests covering backgrounds, text rendering, clipping, BGRA format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Build layout trees from DOM documents with block-level element stacking,
text word-wrapping, and hardcoded default styles for Phase 3.
- LayoutBox tree with Block, Inline, TextRun, and Anonymous box types
- Block layout: children stack vertically, take full parent width
- Inline layout: collect text from inline children, word-wrap at container width
- Default styles: body margin 8px, p margins 1em, h1-h6 font sizes
- Anonymous block wrapping for mixed block/inline children
- Line height 1.2em, whitespace collapsing
- LayoutTree iterator for depth-first traversal
- 17 unit tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Simplified HTML5 tree construction algorithm that processes tokenizer
output and builds a DOM tree. Handles insertion modes (Initial through
AfterAfterBody), implicit html/head/body creation, void elements,
p-in-p auto-closing, heading scope, and the "any other end tag" algorithm.
Supports: html, head, body, title, p, h1-h6, div, span, a, br, pre,
text nodes, comment nodes, and attributes.
17 unit tests covering full documents, implicit elements, void elements,
misnesting, inline nesting, headings, comments, pre, attributes,
text merging, and step-by-step token processing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Spec-compliant HTML5 tokenizer per WHATWG §13.2.5 with:
- Full state machine: Data, TagOpen, EndTagOpen, TagName, attributes,
comments, DOCTYPE (with PUBLIC/SYSTEM), character references
- Named character references: 2125 entities with binary search lookup
- Numeric character references: decimal, hex, Windows-1252 replacements
- Proper token coalescing (adjacent Character tokens merged)
- 34 unit tests, 6661/6807 html5lib tokenizer tests passing (97.7%)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Arena-based tree with NodeId handles and linked parent/child/sibling pointers
- Document, Element (with attributes + namespace), Text, Comment node types
- Full tree manipulation: append_child, insert_before, remove_child
- Nodes automatically detach from old parent when moved
- Element attribute API: get/set/remove_attribute
- Text content API for Text and Comment nodes
- Children iterator for traversal
- 32 comprehensive unit tests including HTML tree construction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- GlyphCache stores rasterized bitmaps keyed by (glyph_id, size_px)
- Size quantized to integer pixels to bound cache size
- Font::get_glyph_bitmap() checks cache before rasterizing
- Font::render_text() combines shaping with cached bitmap lookup
- PositionedGlyph struct with x/y position and optional bitmap
- 9 new tests: cache hit/miss, size quantization, render_text behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- FontRegistry scans /System/Library/Fonts/ and /Library/Fonts/ on init
- TTC collection parsing (ttcf header, per-font offsets)
- Font selection by family name (case-insensitive)
- Style-aware selection (bold/italic via macStyle, OS/2 weight, subfamily name)
- Fallback mechanism: Helvetica -> Arial -> Geneva -> any available
- FontEntry metadata: path, offset, family, subfamily, bold, italic
- 10 new tests for registry discovery, TTC parsing, style selection, fallback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add kern table parser (version 0, format 0 subtables) with binary
search lookup for kerning pair values
- Add ShapedGlyph type and Font::shape_text() method that maps
Unicode text to positioned glyph runs using cmap, hmtx advances,
and kern pair adjustments
- Add Font::kern() and Font::kern_pair() public API methods
- Fonts without kern tables work correctly (zero kerning)
- Comprehensive tests for kern parsing, shaping pipeline, scaling,
empty input, and space handling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The raster.rs file was an earlier draft of the glyph rasterizer that was
never wired into the module system. It contained an incomplete
plot_line_analytic function and a buggy add_quadratic implementation.
The proper implementation lives in rasterizer.rs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse TrueType glyph outlines from the glyf table:
- Simple glyphs: contour endpoints, flags, delta-encoded coordinates
- Compound/composite glyphs: recursive component flattening with
translation, scale, and 2x2 matrix transforms
- Public API: Font::glyph_outline(glyph_id) -> Option<GlyphOutline>
Parse OS/2 table for font-wide metrics:
- Typographic ascender/descender/line gap
- Weight class, width class, embedding flags
- Strikeout size/position, sub/superscript offsets
- sxHeight, sCapHeight (version >= 2)
Data structures: Point (x, y, on_curve), Contour, GlyphOutline
7 new tests against real system fonts, all passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GIF LZW uses "early change" — the code size must bump when next_code
reaches (1 << code_size), not after it exceeds it. Without this fix,
the decoder would read codes with the wrong bit width for GIFs with
enough unique codes to trigger a code size increase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust GIF decoder in the image crate supporting:
- GIF87a and GIF89a format parsing
- LZW decompression with variable-width codes, clear/EOI codes
- Global and local color tables
- Graphic Control Extension (transparency, delay, disposal methods)
- Multi-frame animated GIFs with canvas compositing
- Interlaced image support (4-pass Adam7-style deinterlacing)
- Sub-frame positioning (frames smaller than logical screen)
- Application, comment, and plain text extension skipping
- API: decode_gif() for first frame, decode_gif_frames() for all frames
31 unit tests covering LZW decompression, deinterlacing, frame decoding,
transparency, animation, local color tables, extensions, and error cases.
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust PNG decoder supporting all color types (grayscale, RGB,
indexed, grayscale+alpha, RGBA), bit depths 1-16, scanline filtering
(None/Sub/Up/Average/Paeth), Adam7 interlacing, tRNS transparency,
CRC-32 validation, and multiple IDAT chunk concatenation.
40+ unit tests covering all color types, bit depths, filter types,
interlacing, transparency, error cases, and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse zlib header (CMF/FLG), validate header checksum, delegate to
DEFLATE for compressed data, verify Adler-32 checksum of output.
21 unit tests covering Adler-32, header validation, round-trip
decompression, error propagation, and all window sizes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust DEFLATE decompression supporting all three block types:
- Non-compressed blocks (BTYPE=00) with LEN/NLEN validation
- Fixed Huffman codes (BTYPE=01) per RFC 1951 §3.2.6
- Dynamic Huffman codes (BTYPE=10) with code length decoding
Implementation details:
- LSB-first bit reader with peek/consume pattern for Huffman decoding
- Two-level Huffman lookup table (primary + subtable for long codes)
- LZ77 back-reference decoding with overlapping copy support
- Handles end-of-stream gracefully when final code needs fewer bits
than the primary table width
33 unit tests covering BitReader, Huffman trees, all block types,
back-references, error cases, and round-trip verification against
zlib-generated test vectors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace strip_prefix-based header matching (only matched exact case and
lowercase) with a proper case-insensitive helper that splits on the
first colon and compares the header name using eq_ignore_ascii_case.
Adds tests for all-caps header names (CONTENT-LENGTH, TRANSFER-ENCODING).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
High-level HTTP client in the net crate bringing together TCP, TLS 1.3,
DNS, URL parsing, and HTTP message handling:
- HttpClient with get(), post(), request() methods
- Scheme handling: http:// (plain TCP) and https:// (TLS)
- Connection pooling by (host, port, is_tls) with max idle time and
max connections per host
- Redirect following (301, 302, 307, 308) with configurable max
- Configurable connect and read timeouts
- Streaming response reader: header detection, Content-Length,
chunked Transfer-Encoding, and read-until-close strategies
- std::io::Read and Write trait impls for TcpConnection
30+ unit tests covering error types, configuration, connection pool,
URL path building, header parsing, body strategy selection, and
chunked terminator detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HTTP/1.1 message parser (RFC 7230, 7231) for the net crate:
- Request serialization (GET, POST, HEAD, PUT, DELETE, OPTIONS, PATCH)
- Response parsing: status line, headers, body
- Headers collection with case-insensitive name lookup
- Content-Length body reading
- Chunked Transfer-Encoding decoding (RFC 7230 §4.1)
- Content-Type parsing with charset extraction
- Proper handling of 1xx/204/304 no-body responses
55 tests covering all acceptance criteria.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The application traffic secrets (RFC 8446 §7.1) must be derived from
the transcript hash covering ClientHello...server Finished, not
including the client Finished message. The code was using
transcript.current_hash() after updating with client_finished_msg,
producing incorrect application keys that would fail against real
servers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- random_bytes: panic instead of silently using zero-filled buffers when
/dev/urandom fails — using all-zero keys is a critical security issue
- Rename _ee_body to ee_body since the variable is actually used
- Fix wildcard hostname matching to reject empty labels (e.g. ".example.com"
should not match "*.example.com")
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full TLS 1.3 client handshake: ClientHello with SNI/supported_versions/
key_share/signature_algorithms extensions, ServerHello processing,
ECDHE key exchange (X25519), encrypted handshake message processing
(EncryptedExtensions, Certificate, CertificateVerify, Finished),
certificate chain validation, server name verification with wildcard
matching, key phase transitions, and TlsStream type for application data.
Supports RSA PKCS#1 v1.5 and ECDSA (P-256/P-384) signature verification
in CertificateVerify. Validates server certificates against embedded
root CA store (ISRG Root X1, DigiCert, GlobalSign).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Key schedule for deriving encryption keys from shared secrets using HKDF.
Includes HKDF-Expand-Label, Derive-Secret, transcript hashing, traffic
key/IV derivation, and Finished verify data computation. Supports all
three TLS 1.3 cipher suites (AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305).
Also adds Clone derive to SHA-256, SHA-384, SHA-512 hashers in the crypto
crate to support transcript hash snapshotting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Record layer protocol in the net crate for framing and encrypting TLS
records. ContentType enum (ChangeCipherSpec, Alert, Handshake,
ApplicationData). Plaintext record read/write with header framing and
size enforcement. Encrypted record support via RecordCryptoState with
per-record nonce construction (XOR base IV with sequence number),
inner content type hiding, and AEAD using AES-128-GCM, AES-256-GCM,
or ChaCha20-Poly1305. Alert protocol with close_notify and fatal error
handling. RecordLayer type combining plaintext and encrypted modes with
runtime crypto state switching.
36 tests covering content types, alert encode/decode, nonce construction,
plaintext record I/O, encrypted roundtrips for all cipher suites,
sequence numbering, tamper detection, record overflow, and RecordLayer
integration with plaintext-to-encrypted transitions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DNS resolver in the net crate for resolving hostnames to IP addresses
via UDP queries to system nameservers. Parses /etc/resolv.conf for
nameserver discovery with fallback to Google DNS. Supports A and AAAA
record types, DNS name compression pointers, NXDOMAIN handling, timeout
and retry across multiple nameservers, and direct IP address passthrough.
DnsResolver type with system() and with_nameservers() constructors,
configurable timeout, and resolve() method. Convenience resolve()
function for one-shot lookups. 38 tests covering name encoding, query
building, response parsing, compression pointers, resolv.conf parsing,
address extraction, error types, and real hostname resolution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TcpConnection type wrapping std::net::TcpStream with connect,
connect_timeout, read, write, read_exact, write_all, flush, timeout
configuration, and shutdown. NetError enum with automatic mapping
from io::Error (ConnectionRefused, TimedOut variants). BufferedReader
and BufferedWriter wrappers for efficient line-oriented I/O with
split read/write support via stream cloning.
15 tests covering error types, connection failures, loopback echo,
buffered line reading, buffered read/write pairs, timeouts, and
debug formatting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
URL record type with scheme, username, password, host, port, path,
query, fragment. State-machine parser handling special schemes (http,
https, ftp, ws, wss, file) with default ports. Host parsing for
domains, IPv4 (decimal/hex/octal), and IPv6 (including IPv4-mapped
and :: compression). Percent-encoding/decoding per spec encode sets
(C0, fragment, query, path, userinfo). Relative URL resolution via
base URL. URL serialization with round-trip fidelity. Origin
derivation (tuple for special schemes, opaque otherwise).
88 tests covering absolute URLs, scheme handling, host types,
IPv4/IPv6 parsing and serialization, percent encoding, path dot
resolution, relative URL resolution, serialization round-trips,
file URLs, and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PEM decoding with custom Base64 decoder, X.509v3 certificate parsing
extracting version, serial, issuer, subject, validity, SPKI, and
extensions (Basic Constraints, Key Usage, SAN, AKI, SKI). Certificate
chain validation with signature verification (RSA + ECDSA), validity
period checks, and CA constraint enforcement. Embedded root CA store
with ISRG Root X1, DigiCert Global Root G2, and GlobalSign Root R3.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Elliptic curve arithmetic in Jacobian coordinates with point addition,
doubling, and Montgomery ladder scalar multiplication. Field arithmetic
over the prime fields of P-256 (secp256r1) and P-384 (secp384r1) using
the existing BigUint type.
ECDSA verification per FIPS 186-4 §4.1.4 with Shamir's trick for
multi-scalar multiplication. Parses EC public keys from uncompressed
point format and SubjectPublicKeyInfo DER. Parses DER-encoded
ECDSA signatures.
34 tests including: curve parameter validation, point arithmetic,
RFC 6979 test vectors (P-256/SHA-256), self-generated test vectors
for both P-256 and P-384, signature rejection, and DER parsing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BigUint type with arbitrary-precision arithmetic backed by little-endian
u64 limbs. Supports modular exponentiation via Montgomery multiplication
for odd moduli (RSA) with fallback for even moduli.
RSA public key parsing from both PKCS#1 RSAPublicKey and PKCS#8
SubjectPublicKeyInfo DER formats. RSASSA-PKCS1-v1_5-VERIFY with
EMSA-PKCS1-v1_5 encoding for SHA-256, SHA-384, and SHA-512.
Constant-time signature comparison. Key sizes 2048-4096 bits.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DerParser reads TLV structures from DER-encoded byte slices. Supports
all primitive types needed for X.509 certificates: BOOLEAN, INTEGER,
BIT STRING, OCTET STRING, NULL, OID, UTF8String, PrintableString,
IA5String, UTCTime, GeneralizedTime. Constructed types: SEQUENCE, SET.
Context-specific tags with explicit/implicit tagging.
Includes well-known OID constants for RSA, ECDSA, SHA-2, X.509
extensions, and X.500 attribute types. OID encode/decode with dotted
notation. Rejects non-DER encodings (indefinite length, non-minimal
integers/lengths).
45 tests covering all types, DER validation, real certificate fragments,
and edge cases.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Field arithmetic in GF(2^255 - 19) using 5x51-bit limb representation.
Montgomery ladder scalar multiplication on Curve25519. Constant-time
implementation with no secret-dependent branches or memory accesses.
Passes RFC 7748 §6.1 DH test vectors and §5.2 iterated test vector
(1,000 iterations).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The constant-time conditional select between h and g in the Poly1305
final reduction was missing h4/g4. When h >= p (2^130-5), the code
selected g for h0-h3 but left h4 unchanged, producing incorrect tags
for inputs where the accumulator exceeds the prime.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust ChaCha20-Poly1305 authenticated encryption in the crypto crate:
- ChaCha20 stream cipher: quarter round, block function (20 rounds),
counter-mode encryption with 256-bit key, 96-bit nonce, 32-bit counter
- Poly1305 one-time MAC: GF(2^130-5) using 5 limbs of 26 bits,
clamped r key, constant-time final reduction
- AEAD construction: Poly1305 key generation from ChaCha20 block 0,
encrypt-then-MAC with RFC 8439 padding and length encoding
- Constant-time tag comparison for secure decryption
- 13 tests: RFC 8439 test vectors (§2.1.1, §2.3.2, §2.4.2, §2.5.2,
§2.6.2, §2.8.2), tag tamper detection, and round-trip tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust AES-GCM authenticated encryption in the crypto crate:
- AES block cipher (FIPS 197): key expansion and encrypt for 128/256-bit keys
- GHASH: constant-time GF(2^128) multiplication using bit masking
- GCM encrypt/decrypt with 96-bit nonce, 128-bit authentication tag, and AAD
- Constant-time tag comparison for secure decryption
- 25 tests including NIST SP 800-38D test vectors (cases 1-4, 13-16),
tag tamper detection, and encrypt/decrypt round-trips
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust HKDF implementation in the crypto crate, generic over
hash function via the existing HashFunction trait:
- hkdf_extract(salt, IKM) -> PRK
- hkdf_expand(PRK, info, L) -> OKM with length validation
- hkdf() combined convenience function
- HKDF-SHA-256, HKDF-SHA-384, HKDF-SHA-512 via generics
- Empty salt defaults to HashLen zeros per RFC 5869 §2.2
- Output length validated: L <= 255 * HashLen
- 14 tests including all RFC 5869 SHA-256 test vectors (cases 1-3)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust HMAC implementation in the crypto crate, generic over
hash function via a HashFunction trait:
- HMAC-SHA-256, HMAC-SHA-384, HMAC-SHA-512
- Streaming API: new(key), update(&[u8]), finalize() -> Vec<u8>
- One-shot: hmac_sha256(), hmac_sha384(), hmac_sha512()
- Key handling: long keys hashed, short keys zero-padded
- Inner/outer padding (ipad/opad) per RFC 2104 §2
- 25 tests including all RFC 4231 test vectors (cases 1-7)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure Rust implementations of the SHA-2 family per FIPS 180-4
in the crypto crate:
- SHA-256: 256-bit digest, 64-byte blocks, 64 rounds
- SHA-512: 512-bit digest, 128-byte blocks, 80 rounds
- SHA-384: truncated SHA-512 with different initial values
All three provide streaming (new/update/finalize) and one-shot APIs.
21 tests including NIST test vectors (empty, abc, 448-bit, 896-bit,
million-a) plus streaming and edge-case coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When both underline and background were present, bg_idx pointed to
the underline rect instead of the DrawGlyphs command, causing the
background to paint after the text. Capture glyph_idx before pushing
any commands to ensure correct painter's order.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the simplified inline text layout with a proper inline
formatting context (IFC):
Layout crate:
- Flatten inline tree into items (words, spaces, breaks, inline starts/ends)
- Word-wrap into line boxes respecting per-fragment font sizes
- Handle <br> as forced line breaks
- Apply text-align (left, center, right) via horizontal offset
- Use computed line-height instead of hardcoded font_size * 1.2
- Inline box model: margin/padding/border offsets for inline elements
- TextLine now carries per-fragment styling (font_size, color,
text_decoration, background_color) instead of inheriting from parent
- Store text_align and line_height on LayoutBox
Render crate:
- paint_text uses per-TextLine styling (color, font_size, text_decoration)
- Render inline fragment backgrounds when not transparent
- Underline uses per-fragment font_size for baseline calculation
Tests: 7 new (per-fragment styling, <br>, text-align center/right,
inline padding, font_size per fragment, line-height)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded tag-based defaults in the layout crate with CSS
computed styles from the style crate. The layout engine now accepts
a StyledNode tree instead of walking the DOM directly.
Layout crate changes:
- layout() takes &StyledNode + &Document instead of &Document alone
- Remove hardcoded display_type(), default_font_size(), default_margin()
- Read display, margin, padding, border, font-size from ComputedStyle
- Carry color, background-color, text-decoration, border styles/colors
on LayoutBox for the renderer to use
Render crate changes:
- Use CSS color for text (instead of hardcoded black)
- Use CSS background-color for box backgrounds (skip transparent)
- Render borders with correct width, style, and color
- Support text-decoration: underline
- Replace render-local Color type with we_css::values::Color
Browser pipeline:
- Full: HTML → DOM → extract CSS → resolve styles → layout → render
6 new tests across layout (3) and render (3) crates verifying CSS
properties flow through to layout positions and paint commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add extract_stylesheets() to the style crate that walks the DOM tree,
finds all <style> elements, extracts their text content, and parses
each as a CSS stylesheet in document order.
Update the browser pipeline to extract CSS from <style> elements and
resolve computed styles via the cascade. The styled tree is computed
but layout integration is deferred to a separate issue.
- extract_stylesheets() in style::computed walks DOM for <style> elements
- Browser render_page() now runs: parse HTML → extract CSS → resolve styles → layout → render
- Default HTML page updated with <style> block to demonstrate CSS parsing
- 10 new unit tests for extract_stylesheets (single/multiple/empty/body)
- 6 integration tests using parse_html for full HTML→DOM→CSS→styled tree pipeline
- Tests cover: style element extraction, multiple stylesheets cascade,
inline style overrides, UA defaults, display:none removal, class selectors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix em unit resolution for non-font-size properties: em now resolves
relative to the element's own computed font-size (per CSS spec) instead
of the parent's font-size. Font-size itself already correctly uses
parent font-size for em resolution in its own handler.
- Add missing 'right' and 'left' position offset property handling in
apply_property (only 'top' and 'bottom' were handled).
- Update em_margin_relative_to_font_size test to assert correct value
(2em * 20px = 40px, not 2em * 16px = 32px).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds the `computed` module to the `style` crate with:
- `ComputedStyle` struct with typed fields for all CSS properties:
display, margin, padding, border (width/style/color), width, height,
color, font-size, font-weight, font-style, font-family, text-align,
text-decoration, line-height, background-color, position, top/right/
bottom/left, overflow, visibility
- Cascade algorithm:
1. Collects matching rules via selector matching (from existing matching module)
2. Sorts by origin (UA < author) and specificity
3. Separates normal vs !important declarations
4. Applies inline styles (from style attribute) with highest priority
5. Expands shorthand properties (margin, padding, border, background)
- Property inheritance:
- Inherited properties (color, font-size, font-weight, font-style,
font-family, text-align, text-decoration, line-height, visibility)
automatically inherit from parent computed values
- Non-inherited properties reset to initial values
- `inherit`, `initial`, `unset` keyword support
- User-agent default stylesheet with standard HTML element defaults:
display types, body margin, heading sizes/weights/margins,
paragraph margins, bold/italic/underline for semantic elements
- Relative value resolution:
- `em` units relative to parent font-size (for font-size) or
current font-size (for other properties)
- `rem` units relative to root (16px)
- Physical unit conversion (pt, cm, mm, in, pc)
- Percentage resolution for font-size
- `resolve_styles()` API that builds a styled tree (StyledNode) from
a DOM document and author stylesheets
- 34 comprehensive tests covering UA defaults, author overrides,
cascade ordering, specificity, inheritance, inherit/initial/unset
keywords, em resolution, inline styles, shorthand expansion,
multiple stylesheets, and display:none removal
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Simple selectors: type, universal, class, ID, attribute, pseudo-class
- Compound selectors: all parts must match
- Complex selectors with combinators: descendant, child, adjacent/general sibling
- Selector list matching (comma-separated)
- Specificity calculation (a, b, c) with Ord implementation
- Rule collection: gather matching rules sorted by specificity and source order
- Declaration collection with !important separation
- Right-to-left matching for correct combinator evaluation
- All attribute operators: exact, includes, dash-match, prefix, suffix, substring
- 34 tests covering all selector types, combinators, specificity, and rule collection
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add values module to the css crate that converts raw ComponentValue token
lists into typed CssValue variants. Supports all CSS length units (px, pt,
cm, mm, in, pc, em, rem, vw, vh, vmin, vmax), percentages, hex colors
(#rgb, #rrggbb, #rgba, #rrggbbaa), rgb()/rgba() functions, 17 named colors,
keywords (auto, inherit, initial, unset, none, transparent, currentColor),
and shorthand expansion for margin, padding, border, border-width/style/color,
and background. 63 unit tests covering all value types and shorthands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full CSS parser per CSS Syntax Module Level 3 §5 that consumes tokens from the
tokenizer and produces a structured stylesheet AST. Supports type, universal,
class, ID, attribute, and pseudo-class selectors with all combinators
(descendant, child, adjacent sibling, general sibling). Parses declarations
with !important, component values including functions, and @-rules (@media
with nested rules, @import). Includes error recovery for invalid declarations
and unknown at-rules. 37 unit tests covering all selector types, declarations,
@-rules, error recovery, and real CSS patterns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Full tokenizer state machine producing all CSS token types: ident, function,
at-keyword, hash, string, url, number, percentage, dimension, whitespace,
delimiters, CDO/CDC. Handles escape sequences, comments, number consumption
(integer/float/exponent), url tokens, and input preprocessing (CRLF
normalization, null replacement). 43 unit tests covering all token types,
edge cases, and real CSS patterns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Connect all Phase 3 components to display a rendered HTML page in the
AppKit window. The browser now runs the full pipeline: parse HTML into
a DOM, run block layout, paint via the software renderer, and display
the result in the window.
- Default "Hello from we!" page when run with no arguments
- Load HTML from a file path via command-line argument
- Window resize triggers full re-layout and re-render at new dimensions
- Platform crate: add set_resize_handler() and BitmapView::update_bitmap()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Color struct with BLACK/WHITE constants
- Display list with FillRect and DrawGlyphs paint commands
- Display list generation from layout tree (painter's order)
- Software renderer: BGRA pixel buffer with rect filling and glyph compositing
- Source-over alpha blending for anti-aliased text rendering
- 11 tests covering backgrounds, text rendering, clipping, BGRA format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Build layout trees from DOM documents with block-level element stacking,
text word-wrapping, and hardcoded default styles for Phase 3.
- LayoutBox tree with Block, Inline, TextRun, and Anonymous box types
- Block layout: children stack vertically, take full parent width
- Inline layout: collect text from inline children, word-wrap at container width
- Default styles: body margin 8px, p margins 1em, h1-h6 font sizes
- Anonymous block wrapping for mixed block/inline children
- Line height 1.2em, whitespace collapsing
- LayoutTree iterator for depth-first traversal
- 17 unit tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Simplified HTML5 tree construction algorithm that processes tokenizer
output and builds a DOM tree. Handles insertion modes (Initial through
AfterAfterBody), implicit html/head/body creation, void elements,
p-in-p auto-closing, heading scope, and the "any other end tag" algorithm.
Supports: html, head, body, title, p, h1-h6, div, span, a, br, pre,
text nodes, comment nodes, and attributes.
17 unit tests covering full documents, implicit elements, void elements,
misnesting, inline nesting, headings, comments, pre, attributes,
text merging, and step-by-step token processing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Spec-compliant HTML5 tokenizer per WHATWG §13.2.5 with:
- Full state machine: Data, TagOpen, EndTagOpen, TagName, attributes,
comments, DOCTYPE (with PUBLIC/SYSTEM), character references
- Named character references: 2125 entities with binary search lookup
- Numeric character references: decimal, hex, Windows-1252 replacements
- Proper token coalescing (adjacent Character tokens merged)
- 34 unit tests, 6661/6807 html5lib tokenizer tests passing (97.7%)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Arena-based tree with NodeId handles and linked parent/child/sibling pointers
- Document, Element (with attributes + namespace), Text, Comment node types
- Full tree manipulation: append_child, insert_before, remove_child
- Nodes automatically detach from old parent when moved
- Element attribute API: get/set/remove_attribute
- Text content API for Text and Comment nodes
- Children iterator for traversal
- 32 comprehensive unit tests including HTML tree construction
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- GlyphCache stores rasterized bitmaps keyed by (glyph_id, size_px)
- Size quantized to integer pixels to bound cache size
- Font::get_glyph_bitmap() checks cache before rasterizing
- Font::render_text() combines shaping with cached bitmap lookup
- PositionedGlyph struct with x/y position and optional bitmap
- 9 new tests: cache hit/miss, size quantization, render_text behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- FontRegistry scans /System/Library/Fonts/ and /Library/Fonts/ on init
- TTC collection parsing (ttcf header, per-font offsets)
- Font selection by family name (case-insensitive)
- Style-aware selection (bold/italic via macStyle, OS/2 weight, subfamily name)
- Fallback mechanism: Helvetica -> Arial -> Geneva -> any available
- FontEntry metadata: path, offset, family, subfamily, bold, italic
- 10 new tests for registry discovery, TTC parsing, style selection, fallback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add kern table parser (version 0, format 0 subtables) with binary
search lookup for kerning pair values
- Add ShapedGlyph type and Font::shape_text() method that maps
Unicode text to positioned glyph runs using cmap, hmtx advances,
and kern pair adjustments
- Add Font::kern() and Font::kern_pair() public API methods
- Fonts without kern tables work correctly (zero kerning)
- Comprehensive tests for kern parsing, shaping pipeline, scaling,
empty input, and space handling
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The raster.rs file was an earlier draft of the glyph rasterizer that was
never wired into the module system. It contained an incomplete
plot_line_analytic function and a buggy add_quadratic implementation.
The proper implementation lives in rasterizer.rs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse TrueType glyph outlines from the glyf table:
- Simple glyphs: contour endpoints, flags, delta-encoded coordinates
- Compound/composite glyphs: recursive component flattening with
translation, scale, and 2x2 matrix transforms
- Public API: Font::glyph_outline(glyph_id) -> Option<GlyphOutline>
Parse OS/2 table for font-wide metrics:
- Typographic ascender/descender/line gap
- Weight class, width class, embedding flags
- Strikeout size/position, sub/superscript offsets
- sxHeight, sCapHeight (version >= 2)
Data structures: Point (x, y, on_curve), Contour, GlyphOutline
7 new tests against real system fonts, all passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>