commits
Thread viewport dimensions through style resolution so viewport units
resolve correctly: 1vw = 1% of viewport width, 1vh = 1% of viewport
height, vmin/vmax use the smaller/larger dimension.
For layout properties (width, height, margin, padding), percentages are
now preserved as LengthOrAuto::Percentage through style computation and
resolved during layout against the containing block width. Height
percentages resolve against viewport height. Per CSS spec, even vertical
margins and padding resolve against containing block width.
Changes:
- Add Percentage(f32) variant to LengthOrAuto
- Change ComputedStyle padding fields from f32 to LengthOrAuto
- Add viewport parameter to resolve_styles, threaded through resolution
- resolve_length_unit now computes vw/vh/vmin/vmax from viewport dims
- Layout resolves percentage width/height/margin/padding against
containing block; nested percentages compound correctly
- Store css_margin/css_padding/css_offsets on LayoutBox for deferred
resolution during layout
- 9 new tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire up visibility property through the layout and render pipeline:
- Add visibility field to LayoutBox, populated from ComputedStyle
- Renderer skips painting (background, borders, text, images) for
hidden/collapse elements but still recurses into children
- Children can override with visibility:visible per CSS spec
- display:none already worked (excluded from layout tree); verified
9 new tests: 5 layout tests (display:none exclusion, hidden preserves
space, inheritance, visible override, collapse behavior) and 4 render
tests (hidden not painted, visible child of hidden parent painted,
collapse not painted, display:none not in display list).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add BoxSizing enum and box_sizing field to ComputedStyle with CSS
parsing support. Layout engine now respects explicit CSS width/height
and adjusts content dimensions based on box-sizing mode:
- content-box (default): width/height apply to content area only
- border-box: width/height include padding and border
Content area clamps to 0 when padding+border exceeds specified size
in border-box mode. Property is not inherited per spec.
9 new tests covering both modes, clamping, non-inheritance, and height.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements CSS2 §8.3.1 margin collapsing:
- Adjacent sibling margins collapse (gap = max, not sum)
- Parent-child margin collapsing via pre_collapse_margins pass
- Empty block self-collapsing (top+bottom margins fold together)
- Negative margin handling (positive+negative=sum, both negative=min)
- Collapsing blocked by border, padding, or overflow!=visible (BFC)
Adds overflow field to LayoutBox for BFC detection. Updates existing
tests to reflect correct collapsed margin behavior and adds 9 new
tests covering all collapsing scenarios.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add relative positioning support to the layout engine. After normal-flow
layout, elements with position: relative are visually shifted by their
top/right/bottom/left offset values without affecting surrounding elements.
- Add position and relative_offset fields to LayoutBox
- Resolve offset conflicts per CSS spec (top wins over bottom, left over right)
- Recursively shift box rect, text lines, and all descendants
- Add 7 tests covering offsets, sibling independence, conflicts, and auto values
Wire together all Phase 8 components into the browser's navigation flow:
- Use css_loader::collect_stylesheets for external <link> and inline <style>
- Use img_loader::collect_images to fetch and decode <img> elements
- Store pre-fetched PageState (DOM, stylesheet, images) so window resizes
only re-style/re-layout/re-render without re-fetching
- Show error page for network failures instead of process::exit
- Preserve base URL from HTTP response for resolving relative subresources
- Generate file:// base URL for local file paths
Implements issue 3mhktaciaf42q.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add about: scheme handling to ResourceLoader:
- Recognize about:blank and return a minimal empty HTML document
(<!DOCTYPE html><html><head></head><body></body></html>)
- UTF-8 encoding, no network requests
- Unsupported about: URLs return InvalidUrl error
Update browser main to use about:blank as default:
- No URL argument opens about:blank instead of hardcoded demo page
- URL arguments (http://, https://, about:, data:) load via ResourceLoader
- File path arguments still work as before
4 tests covering fetch/fetch_url paths, DOM structure validation,
and unsupported about: URL rejection.
Implements issue 3mhkt7vaxsb23
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add data_url module to the url crate:
- Base64 decoder (RFC 4648): standard alphabet, whitespace stripping, padding
- Data URL parser: extract MIME type, charset, base64/percent-encoded payload
- Default MIME type text/plain;charset=US-ASCII when omitted
Integrate with ResourceLoader in browser crate:
- Handle data: URLs in both fetch() and fetch_url() without network access
- Classify decoded content into Html/Css/Image/Other resource types
- Decode text resources using charset from data URL parameters
44 tests covering base64 decoding, data URL parsing, MIME extraction,
percent decoding, and ResourceLoader integration.
Implements issue 3mhkt7m45472x
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add img_loader module to the browser crate that loads images from the DOM:
- Scan DOM for <img src="..."> elements in document order
- Fetch image data via ResourceLoader with URL resolution
- Detect format from magic bytes (PNG: 89504E47, JPEG: FFD8, GIF: GIF8)
- Decode using image crate decoders (PNG, JPEG, GIF)
- Parse width/height attributes with proportional scaling
- Graceful degradation: failed loads store alt text, no crash
Layout integration:
- Add replaced_size field to LayoutBox for replaced elements
- Accept image_sizes map in layout() for intrinsic/attribute dimensions
- Replaced elements use their dimensions instead of child layout
Render integration:
- Add DrawImage variant to PaintCommand
- Nearest-neighbor scaling with RGBA→BGRA conversion
- Alpha compositing for semi-transparent image pixels
37 tests covering format detection, dimension parsing/resolution,
DOM scanning, graceful failure, error display, and PNG decoding.
Implements issue 3mhkt7br4jx25
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add css_loader module to the browser crate that collects CSS from the DOM:
- Scan DOM for <style> elements (inline CSS) and <link rel="stylesheet"> (external)
- Fetch external stylesheets via ResourceLoader with encoding detection
- Resolve @import rules recursively (max depth 5 to prevent cycles)
- Basic media attribute support (screen, all)
- Type attribute validation (text/css default)
- Graceful degradation: failed loads are silently skipped
- Merge all rules into a single Stylesheet in document order
37 tests covering DOM scanning, classification, media matching, text
collection, import resolution, error handling, and edge cases.
Implements issue 3mhkt6vtv3q2g
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ResourceLoader to the browser crate that integrates the net, encoding,
url, and image crates into a unified resource fetching API:
- ResourceLoader wraps HttpClient for HTTP/HTTPS fetching
- Content-Type parsing determines resource type (HTML, CSS, image, other)
- WHATWG encoding sniffing for HTML (BOM > HTTP > meta prescan > default)
- BOM/HTTP charset detection for non-HTML text resources (default UTF-8)
- Relative URL resolution via base URL support
- HTTP error status handling (4xx, 5xx)
- Resource enum: Html, Css, Image, Other with appropriate metadata
30 tests covering MIME classification, text decoding (BOM, HTTP charset,
meta prescan, Windows-1252 special chars), URL resolution, and error types.
Implements issue 3mhkt6hnbhp25
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add encoding detection per WHATWG Encoding Standard and HTML spec:
- BOM sniffing for UTF-8, UTF-16LE, UTF-16BE
- HTTP Content-Type charset extraction (quoted/unquoted values)
- HTML meta prescan: scan first 1024 bytes for <meta charset> and
<meta http-equiv="Content-Type" content="...;charset=...">
- Priority: BOM > HTTP header > meta prescan > default (Windows-1252)
- UTF-16 from HTTP/meta overridden to UTF-8 per spec
- EncodingSource enum for tracking detection method confidence
39 new tests covering all detection methods and priority ordering.
Implements issue 3mhkt62ryxo2l
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add all 27 WHATWG single-byte encodings to the encoding crate:
- Windows-1252 (with ISO-8859-1 and US-ASCII aliases per WHATWG spec)
- ISO-8859-2 through ISO-8859-16 (excluding 8859-9 which maps to Windows-1254)
- Windows-874, Windows-1250 through Windows-1258
- KOI8-R, KOI8-U
- macintosh, x-mac-cyrillic
- IBM866
Each encoding uses a 128-entry u16 lookup table for bytes 0x80-0xFF.
All WHATWG label aliases are registered for case-insensitive lookup.
32 new tests covering per-encoding correctness and error handling.
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure Rust implementation of UTF-8 and UTF-16 text encoding/decoding
per the WHATWG Encoding Standard:
- UTF-8 decoder (streaming state machine with replacement/fatal modes)
- UTF-8 encoder
- UTF-16LE/BE decoders with surrogate pair handling and BOM stripping
- Encoding label lookup (case-insensitive, whitespace-trimmed)
- BOM sniffing utility
- Public API: decode(), decode_strict(), encode(), lookup(), bom_sniff()
- 93 unit tests covering edge cases (overlong, surrogates, truncated, BOM)
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure Rust baseline JPEG decoder in the image crate supporting:
- JFIF marker parsing (SOI, APP0/APP1, DQT, SOF0, DHT, SOS, DRI, EOI)
- Huffman entropy decoding (DC and AC coefficients)
- 8x8 block-based inverse DCT (Loeffler algorithm, integer fixed-point)
- Dequantization with DQT tables
- Chroma subsampling: 4:4:4, 4:2:2, 4:2:0
- YCbCr to RGB color conversion (BT.601 fixed-point)
- Restart marker support
- Grayscale JPEG support
- 28 unit tests covering Huffman, IDCT, color conversion, parsing, and
end-to-end decoding of hand-crafted JPEG streams
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <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>
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>
Thread viewport dimensions through style resolution so viewport units
resolve correctly: 1vw = 1% of viewport width, 1vh = 1% of viewport
height, vmin/vmax use the smaller/larger dimension.
For layout properties (width, height, margin, padding), percentages are
now preserved as LengthOrAuto::Percentage through style computation and
resolved during layout against the containing block width. Height
percentages resolve against viewport height. Per CSS spec, even vertical
margins and padding resolve against containing block width.
Changes:
- Add Percentage(f32) variant to LengthOrAuto
- Change ComputedStyle padding fields from f32 to LengthOrAuto
- Add viewport parameter to resolve_styles, threaded through resolution
- resolve_length_unit now computes vw/vh/vmin/vmax from viewport dims
- Layout resolves percentage width/height/margin/padding against
containing block; nested percentages compound correctly
- Store css_margin/css_padding/css_offsets on LayoutBox for deferred
resolution during layout
- 9 new tests covering all acceptance criteria
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire up visibility property through the layout and render pipeline:
- Add visibility field to LayoutBox, populated from ComputedStyle
- Renderer skips painting (background, borders, text, images) for
hidden/collapse elements but still recurses into children
- Children can override with visibility:visible per CSS spec
- display:none already worked (excluded from layout tree); verified
9 new tests: 5 layout tests (display:none exclusion, hidden preserves
space, inheritance, visible override, collapse behavior) and 4 render
tests (hidden not painted, visible child of hidden parent painted,
collapse not painted, display:none not in display list).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add BoxSizing enum and box_sizing field to ComputedStyle with CSS
parsing support. Layout engine now respects explicit CSS width/height
and adjusts content dimensions based on box-sizing mode:
- content-box (default): width/height apply to content area only
- border-box: width/height include padding and border
Content area clamps to 0 when padding+border exceeds specified size
in border-box mode. Property is not inherited per spec.
9 new tests covering both modes, clamping, non-inheritance, and height.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implements CSS2 §8.3.1 margin collapsing:
- Adjacent sibling margins collapse (gap = max, not sum)
- Parent-child margin collapsing via pre_collapse_margins pass
- Empty block self-collapsing (top+bottom margins fold together)
- Negative margin handling (positive+negative=sum, both negative=min)
- Collapsing blocked by border, padding, or overflow!=visible (BFC)
Adds overflow field to LayoutBox for BFC detection. Updates existing
tests to reflect correct collapsed margin behavior and adds 9 new
tests covering all collapsing scenarios.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add relative positioning support to the layout engine. After normal-flow
layout, elements with position: relative are visually shifted by their
top/right/bottom/left offset values without affecting surrounding elements.
- Add position and relative_offset fields to LayoutBox
- Resolve offset conflicts per CSS spec (top wins over bottom, left over right)
- Recursively shift box rect, text lines, and all descendants
- Add 7 tests covering offsets, sibling independence, conflicts, and auto values
Wire together all Phase 8 components into the browser's navigation flow:
- Use css_loader::collect_stylesheets for external <link> and inline <style>
- Use img_loader::collect_images to fetch and decode <img> elements
- Store pre-fetched PageState (DOM, stylesheet, images) so window resizes
only re-style/re-layout/re-render without re-fetching
- Show error page for network failures instead of process::exit
- Preserve base URL from HTTP response for resolving relative subresources
- Generate file:// base URL for local file paths
Implements issue 3mhktaciaf42q.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add about: scheme handling to ResourceLoader:
- Recognize about:blank and return a minimal empty HTML document
(<!DOCTYPE html><html><head></head><body></body></html>)
- UTF-8 encoding, no network requests
- Unsupported about: URLs return InvalidUrl error
Update browser main to use about:blank as default:
- No URL argument opens about:blank instead of hardcoded demo page
- URL arguments (http://, https://, about:, data:) load via ResourceLoader
- File path arguments still work as before
4 tests covering fetch/fetch_url paths, DOM structure validation,
and unsupported about: URL rejection.
Implements issue 3mhkt7vaxsb23
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add data_url module to the url crate:
- Base64 decoder (RFC 4648): standard alphabet, whitespace stripping, padding
- Data URL parser: extract MIME type, charset, base64/percent-encoded payload
- Default MIME type text/plain;charset=US-ASCII when omitted
Integrate with ResourceLoader in browser crate:
- Handle data: URLs in both fetch() and fetch_url() without network access
- Classify decoded content into Html/Css/Image/Other resource types
- Decode text resources using charset from data URL parameters
44 tests covering base64 decoding, data URL parsing, MIME extraction,
percent decoding, and ResourceLoader integration.
Implements issue 3mhkt7m45472x
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add img_loader module to the browser crate that loads images from the DOM:
- Scan DOM for <img src="..."> elements in document order
- Fetch image data via ResourceLoader with URL resolution
- Detect format from magic bytes (PNG: 89504E47, JPEG: FFD8, GIF: GIF8)
- Decode using image crate decoders (PNG, JPEG, GIF)
- Parse width/height attributes with proportional scaling
- Graceful degradation: failed loads store alt text, no crash
Layout integration:
- Add replaced_size field to LayoutBox for replaced elements
- Accept image_sizes map in layout() for intrinsic/attribute dimensions
- Replaced elements use their dimensions instead of child layout
Render integration:
- Add DrawImage variant to PaintCommand
- Nearest-neighbor scaling with RGBA→BGRA conversion
- Alpha compositing for semi-transparent image pixels
37 tests covering format detection, dimension parsing/resolution,
DOM scanning, graceful failure, error display, and PNG decoding.
Implements issue 3mhkt7br4jx25
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add css_loader module to the browser crate that collects CSS from the DOM:
- Scan DOM for <style> elements (inline CSS) and <link rel="stylesheet"> (external)
- Fetch external stylesheets via ResourceLoader with encoding detection
- Resolve @import rules recursively (max depth 5 to prevent cycles)
- Basic media attribute support (screen, all)
- Type attribute validation (text/css default)
- Graceful degradation: failed loads are silently skipped
- Merge all rules into a single Stylesheet in document order
37 tests covering DOM scanning, classification, media matching, text
collection, import resolution, error handling, and edge cases.
Implements issue 3mhkt6vtv3q2g
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add ResourceLoader to the browser crate that integrates the net, encoding,
url, and image crates into a unified resource fetching API:
- ResourceLoader wraps HttpClient for HTTP/HTTPS fetching
- Content-Type parsing determines resource type (HTML, CSS, image, other)
- WHATWG encoding sniffing for HTML (BOM > HTTP > meta prescan > default)
- BOM/HTTP charset detection for non-HTML text resources (default UTF-8)
- Relative URL resolution via base URL support
- HTTP error status handling (4xx, 5xx)
- Resource enum: Html, Css, Image, Other with appropriate metadata
30 tests covering MIME classification, text decoding (BOM, HTTP charset,
meta prescan, Windows-1252 special chars), URL resolution, and error types.
Implements issue 3mhkt6hnbhp25
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add encoding detection per WHATWG Encoding Standard and HTML spec:
- BOM sniffing for UTF-8, UTF-16LE, UTF-16BE
- HTTP Content-Type charset extraction (quoted/unquoted values)
- HTML meta prescan: scan first 1024 bytes for <meta charset> and
<meta http-equiv="Content-Type" content="...;charset=...">
- Priority: BOM > HTTP header > meta prescan > default (Windows-1252)
- UTF-16 from HTTP/meta overridden to UTF-8 per spec
- EncodingSource enum for tracking detection method confidence
39 new tests covering all detection methods and priority ordering.
Implements issue 3mhkt62ryxo2l
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add all 27 WHATWG single-byte encodings to the encoding crate:
- Windows-1252 (with ISO-8859-1 and US-ASCII aliases per WHATWG spec)
- ISO-8859-2 through ISO-8859-16 (excluding 8859-9 which maps to Windows-1254)
- Windows-874, Windows-1250 through Windows-1258
- KOI8-R, KOI8-U
- macintosh, x-mac-cyrillic
- IBM866
Each encoding uses a 128-entry u16 lookup table for bytes 0x80-0xFF.
All WHATWG label aliases are registered for case-insensitive lookup.
32 new tests covering per-encoding correctness and error handling.
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure Rust implementation of UTF-8 and UTF-16 text encoding/decoding
per the WHATWG Encoding Standard:
- UTF-8 decoder (streaming state machine with replacement/fatal modes)
- UTF-8 encoder
- UTF-16LE/BE decoders with surrogate pair handling and BOM stripping
- Encoding label lookup (case-insensitive, whitespace-trimmed)
- BOM sniffing utility
- Public API: decode(), decode_strict(), encode(), lookup(), bom_sniff()
- 93 unit tests covering edge cases (overlong, surrogates, truncated, BOM)
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pure Rust baseline JPEG decoder in the image crate supporting:
- JFIF marker parsing (SOI, APP0/APP1, DQT, SOF0, DHT, SOS, DRI, EOI)
- Huffman entropy decoding (DC and AC coefficients)
- 8x8 block-based inverse DCT (Loeffler algorithm, integer fixed-point)
- Dequantization with DQT tables
- Chroma subsampling: 4:4:4, 4:2:2, 4:2:0
- YCbCr to RGB color conversion (BT.601 fixed-point)
- Restart marker support
- Grayscale JPEG support
- 28 unit tests covering Huffman, IDCT, color conversion, parsing, and
end-to-end decoding of hand-crafted JPEG streams
No external dependencies, no unsafe.
Co-Authored-By: Claude Opus 4.6 (1M context) <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>