commits
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>
Parse the OpenType/TrueType table directory and essential font tables:
- head: font header (units per em, bounding box, loca index format)
- maxp: maximum profile (number of glyphs)
- hhea: horizontal header (ascent, descent, line gap, metrics count)
- hmtx: horizontal metrics (advance width + left side bearing per glyph)
- cmap: character to glyph mapping (format 4 for BMP, format 12 for full Unicode)
- name: naming table (family name, subfamily, full name with UTF-16BE and Mac Roman decoding)
- loca: glyph location index (short and long offset formats)
Includes a binary reader utility for big-endian parsing and a
system font loader for macOS. All parsers are tested against real
system fonts (Geneva/Monaco).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add html5lib-tests and Test262 as git submodules under tests/.
Create integration test harnesses for both suites:
- html5lib tokenizer harness (we-html): reads JSON test files,
runs each case against our tokenizer stub, reports pass/fail/skip.
Includes a minimal JSON parser (no external crates).
- Test262 harness (we-js): walks JS test files, parses YAML
frontmatter for metadata, runs each case against our evaluate()
stub, reports pass/fail/skip grouped by category.
Both harnesses work with empty implementations (0% pass rate on
positive tests) and will track progress as features are implemented.
Adds Token enum and tokenize() stub to we-html.
Adds JsError and evaluate() stub to we-js.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add event handling to WeView (custom NSView subclass):
- acceptsFirstResponder override (returns YES for key event delivery)
- keyDown: logs key character and keyCode to stdout
- mouseDown:/mouseUp:/mouseMoved: log view-local coordinates to stdout
Add WeWindowDelegate (NSWindowDelegate):
- windowDidResize: marks content view as needing display
- windowShouldClose: returns YES (explicit close handling)
Add Window helper methods:
- set_delegate() for installing window delegates
- set_accepts_mouse_moved_events() for mouse move tracking
Update browser main.rs:
- Install window delegate for resize handling
- Enable mouse-moved event delivery
5 new tests for class registration, selector response, and first responder.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add platform/src/cg.rs with:
- CGColorSpace (device RGB), CGBitmapContext, CGImage wrappers
- CGRect/CGPoint/CGSize geometry types
- BitmapContext: Rust-owned pixel buffer wrapped in CGBitmapContext
- fill_rect(), clear(), create_image(), pixels/pixels_mut accessors
- draw_image_in_context() for blitting into a view's CG context
- 8 unit tests covering context creation, drawing, and edge cases
Add custom NSView subclass (WeView) in appkit.rs:
- Overrides drawRect: to blit CGImage from BitmapContext
- Overrides isFlipped for top-left coordinate origin
- BitmapView wrapper with set_needs_display() for redraw requests
- Uses ivar to store BitmapContext pointer per-instance
- Window::set_content_view() for installing custom views
- 2 new tests for WeView class registration and BitmapView creation
Add ivar support to objc.rs:
- class_addIvar FFI binding
- object_setInstanceVariable / object_getInstanceVariable FFI
- Id::set_ivar() and Id::get_ivar() helper methods
- Class::add_ivar() helper method
Update browser main.rs:
- Creates 800x600 BitmapContext
- Fills dark gray background with centered blue rectangle
- Installs BitmapView as window content view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add platform/src/appkit.rs with:
- NSRect/NSPoint/NSSize geometry types matching AppKit's C layout
- NSWindow style mask and backing store constants
- NSApplicationActivationPolicy constants
- AutoreleasePool RAII wrapper (creates on new, drains on drop)
- App wrapper: sharedApplication, setActivationPolicy:,
activateIgnoringOtherApps:, run
- Window wrapper: initWithContentRect:styleMask:backing:defer:,
setTitle: (via toll-free bridged CfString), makeKeyAndOrderFront:,
contentView
- WeAppDelegate custom ObjC class implementing
applicationShouldTerminateAfterLastWindowClosed: -> YES
- create_standard_window() convenience (800x600, titled/closable/
miniaturizable/resizable)
- 6 unit tests covering geometry, constants, and autorelease pool
Update browser main.rs to open a native macOS window titled "we".
Closing the window terminates the application.
Also fix pre-existing clippy macro_metavars_in_unsafe lint in msg_send!
macro by binding metavariables to locals outside unsafe blocks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add platform/src/cf.rs with:
- Raw extern "C" bindings to CoreFoundation.framework: CFStringCreateWithBytes,
CFRetain, CFRelease, CFStringGetLength, CFStringGetCString
- CFStringRef type alias and CFStringEncoding constants
- CfString RAII wrapper: creates CFStringRef from &str, calls CFRelease on drop
- Clone impl that calls CFRetain for proper reference counting
- Debug/Display impls, len/is_empty helpers, to_string_lossy for round-tripping
- cf_retain/cf_release public wrappers for manual reference counting
- 10 unit tests covering creation, length, empty strings, unicode, emoji,
clone/drop, debug/display formatting, and pointer validity
This is needed for passing string parameters to AppKit APIs (window titles,
menu items, etc).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements issue 3mfkgyov6gf2k: Raw extern "C" bindings to libobjc.dylib,
Sel/Class/Id wrappers, msg_send!/sel!/class! macros, and 12 unit tests.
Use the same clean pattern as the other msg_send! variants instead of
the roundabout split_last + from_raw_parts approach.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add platform/src/objc.rs with:
- Raw extern "C" bindings to libobjc.dylib: objc_msgSend, objc_getClass,
sel_registerName, class_addMethod, objc_allocateClassPair,
objc_registerClassPair, class_getName
- Sel wrapper: registered selector with interned pointer equality
- Class wrapper: class lookup, dynamic class creation, method addition
- Id wrapper: non-null Objective-C object pointer
- msg_send! macro: type-safe(ish) message dispatch via transmuted
objc_msgSend (0-4 argument variants)
- sel! and class! convenience macros
- 12 unit tests covering class lookup, selector registration, alloc/init,
custom class creation, method addition, and message dispatch
This is the foundation all other platform FFI builds on.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust web browser engine targeting macOS ARM. Zero external
dependencies. Workspace with 15 crates: platform, url, encoding,
html, css, dom, style, layout, text, net, crypto, image, render,
js, browser. All inter-crate dependencies wired. Builds clean
with clippy and fmt.
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>
Parse the OpenType/TrueType table directory and essential font tables:
- head: font header (units per em, bounding box, loca index format)
- maxp: maximum profile (number of glyphs)
- hhea: horizontal header (ascent, descent, line gap, metrics count)
- hmtx: horizontal metrics (advance width + left side bearing per glyph)
- cmap: character to glyph mapping (format 4 for BMP, format 12 for full Unicode)
- name: naming table (family name, subfamily, full name with UTF-16BE and Mac Roman decoding)
- loca: glyph location index (short and long offset formats)
Includes a binary reader utility for big-endian parsing and a
system font loader for macOS. All parsers are tested against real
system fonts (Geneva/Monaco).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add html5lib-tests and Test262 as git submodules under tests/.
Create integration test harnesses for both suites:
- html5lib tokenizer harness (we-html): reads JSON test files,
runs each case against our tokenizer stub, reports pass/fail/skip.
Includes a minimal JSON parser (no external crates).
- Test262 harness (we-js): walks JS test files, parses YAML
frontmatter for metadata, runs each case against our evaluate()
stub, reports pass/fail/skip grouped by category.
Both harnesses work with empty implementations (0% pass rate on
positive tests) and will track progress as features are implemented.
Adds Token enum and tokenize() stub to we-html.
Adds JsError and evaluate() stub to we-js.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add event handling to WeView (custom NSView subclass):
- acceptsFirstResponder override (returns YES for key event delivery)
- keyDown: logs key character and keyCode to stdout
- mouseDown:/mouseUp:/mouseMoved: log view-local coordinates to stdout
Add WeWindowDelegate (NSWindowDelegate):
- windowDidResize: marks content view as needing display
- windowShouldClose: returns YES (explicit close handling)
Add Window helper methods:
- set_delegate() for installing window delegates
- set_accepts_mouse_moved_events() for mouse move tracking
Update browser main.rs:
- Install window delegate for resize handling
- Enable mouse-moved event delivery
5 new tests for class registration, selector response, and first responder.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add platform/src/cg.rs with:
- CGColorSpace (device RGB), CGBitmapContext, CGImage wrappers
- CGRect/CGPoint/CGSize geometry types
- BitmapContext: Rust-owned pixel buffer wrapped in CGBitmapContext
- fill_rect(), clear(), create_image(), pixels/pixels_mut accessors
- draw_image_in_context() for blitting into a view's CG context
- 8 unit tests covering context creation, drawing, and edge cases
Add custom NSView subclass (WeView) in appkit.rs:
- Overrides drawRect: to blit CGImage from BitmapContext
- Overrides isFlipped for top-left coordinate origin
- BitmapView wrapper with set_needs_display() for redraw requests
- Uses ivar to store BitmapContext pointer per-instance
- Window::set_content_view() for installing custom views
- 2 new tests for WeView class registration and BitmapView creation
Add ivar support to objc.rs:
- class_addIvar FFI binding
- object_setInstanceVariable / object_getInstanceVariable FFI
- Id::set_ivar() and Id::get_ivar() helper methods
- Class::add_ivar() helper method
Update browser main.rs:
- Creates 800x600 BitmapContext
- Fills dark gray background with centered blue rectangle
- Installs BitmapView as window content view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add platform/src/appkit.rs with:
- NSRect/NSPoint/NSSize geometry types matching AppKit's C layout
- NSWindow style mask and backing store constants
- NSApplicationActivationPolicy constants
- AutoreleasePool RAII wrapper (creates on new, drains on drop)
- App wrapper: sharedApplication, setActivationPolicy:,
activateIgnoringOtherApps:, run
- Window wrapper: initWithContentRect:styleMask:backing:defer:,
setTitle: (via toll-free bridged CfString), makeKeyAndOrderFront:,
contentView
- WeAppDelegate custom ObjC class implementing
applicationShouldTerminateAfterLastWindowClosed: -> YES
- create_standard_window() convenience (800x600, titled/closable/
miniaturizable/resizable)
- 6 unit tests covering geometry, constants, and autorelease pool
Update browser main.rs to open a native macOS window titled "we".
Closing the window terminates the application.
Also fix pre-existing clippy macro_metavars_in_unsafe lint in msg_send!
macro by binding metavariables to locals outside unsafe blocks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add platform/src/cf.rs with:
- Raw extern "C" bindings to CoreFoundation.framework: CFStringCreateWithBytes,
CFRetain, CFRelease, CFStringGetLength, CFStringGetCString
- CFStringRef type alias and CFStringEncoding constants
- CfString RAII wrapper: creates CFStringRef from &str, calls CFRelease on drop
- Clone impl that calls CFRetain for proper reference counting
- Debug/Display impls, len/is_empty helpers, to_string_lossy for round-tripping
- cf_retain/cf_release public wrappers for manual reference counting
- 10 unit tests covering creation, length, empty strings, unicode, emoji,
clone/drop, debug/display formatting, and pointer validity
This is needed for passing string parameters to AppKit APIs (window titles,
menu items, etc).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add platform/src/objc.rs with:
- Raw extern "C" bindings to libobjc.dylib: objc_msgSend, objc_getClass,
sel_registerName, class_addMethod, objc_allocateClassPair,
objc_registerClassPair, class_getName
- Sel wrapper: registered selector with interned pointer equality
- Class wrapper: class lookup, dynamic class creation, method addition
- Id wrapper: non-null Objective-C object pointer
- msg_send! macro: type-safe(ish) message dispatch via transmuted
objc_msgSend (0-4 argument variants)
- sel! and class! convenience macros
- 12 unit tests covering class lookup, selector registration, alloc/init,
custom class creation, method addition, and message dispatch
This is the foundation all other platform FFI builds on.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pure Rust web browser engine targeting macOS ARM. Zero external
dependencies. Workspace with 15 crates: platform, url, encoding,
html, css, dom, style, layout, text, net, crypto, image, render,
js, browser. All inter-crate dependencies wired. Builds clean
with clippy and fmt.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>