Sign in

    mizchi/crater-layout/tree does not have a README file

    CacheStats

    pub struct CacheStats {
    cache_hits : Int
    cache_misses : Int
    nodes_computed : Int
    }

    Statistics for cache performance

    CacheStats::hit_rate

    fn CacheStats::hit_rate(self : CacheStats) -> Double

    CacheStats::new

    fn CacheStats::new() -> CacheStats

    ConstraintKey

    pub struct ConstraintKey {
    available_width : Double
    available_height : Double?
    sizing_mode :
    SizingMode

    } derive(Eq)

    Constraint key for cache lookup

    ConstraintKey::approx_eq

    fn ConstraintKey::approx_eq(self : ConstraintKey, other : ConstraintKey) -> Bool

    Check if two constraints are approximately equal

    ConstraintKey::new

    fn ConstraintKey::new(available_width : Double, available_height : Double?, sizing_mode :
    SizingMode
    ) -> ConstraintKey

    ConstraintSpace

    pub struct ConstraintSpace {
    available_width : Double
    available_height : Double?
    sizing_mode :
    SizingMode

    parent_width : Double
    parent_height : Double?
    viewport_width : Double
    viewport_height : Double
    }

    Extended constraint space for cache comparison

    ConstraintSpace::new

    fn ConstraintSpace::new(available_width : Double, available_height : Double?, sizing_mode :
    SizingMode
    , parent_width : Double, parent_height : Double?, viewport_width? : Double, viewport_height? : Double) -> ConstraintSpace

    ConstraintSpace::to_context

    Convert to LayoutContext for existing compute functions

    ConstraintSpace::to_key

    Convert to ConstraintKey for cache lookup

    DependencyKind

    pub(all) enum DependencyKind {
    Static
    ParentWidth
    ParentHeight
    ParentBoth
    Intrinsic
    Viewport
    } derive(Eq,
    Debug
    )

    What a node's layout depends on

    DependencyKind::merge

    Merge two dependency kinds into a combined dependency

    IntrinsicState

    pub(all) enum IntrinsicState {
    Resolved(width~ : Double, height~ : Double)
    Pending(placeholder_width~ : Double, placeholder_height~ : Double)
    Error
    }

    State of an intrinsic resource

    LayoutCache

    pub struct LayoutCache {
    constraint : ConstraintKey
    result :
    Layout

    }

    Cached layout result

    LayoutNode

    pub struct LayoutNode {
    id : String
    uid : Int
    style :
    Style

    children : Array[LayoutNode]
    measure :
    MeasureFunc
    ?
    text : String?
    dirty : Bool
    children_dirty : Bool
    cached_layout : LayoutCache?
    dependencies : DependencyKind
    computed_x : Double
    computed_y : Double
    computed_width : Double
    computed_height : Double
    has_new_layout : Bool
    intrinsic_state : IntrinsicState?
    on_dirty : (Int) -> Unit?
    }

    Mutable layout node with dirty tracking

    LayoutNode::add_child

    fn LayoutNode::add_child(self : LayoutNode, child : LayoutNode) -> LayoutNode

    Add child at end

    LayoutNode::clear_dirty

    fn LayoutNode::clear_dirty(self : LayoutNode) -> Unit

    Clear dirty bits after layout

    LayoutNode::create

    fn LayoutNode::create() -> LayoutNode

    Create a new node with default style (Yoga-compatible)

    LayoutNode::create_with_id

    fn LayoutNode::create_with_id(id : String) -> LayoutNode

    Create a new node with ID

    LayoutNode::from_node

    Create LayoutNode from immutable Node

    LayoutNode::get_child

    fn LayoutNode::get_child(self : LayoutNode, index : Int) -> LayoutNode?

    Get child at index

    LayoutNode::get_child_count

    fn LayoutNode::get_child_count(self : LayoutNode) -> Int

    Get number of children

    LayoutNode::get_has_new_layout

    fn LayoutNode::get_has_new_layout(self : LayoutNode) -> Bool

    Check if node has new layout since last mark_layout_seen

    LayoutNode::get_layout_height

    fn LayoutNode::get_layout_height(self : LayoutNode) -> Double

    Get computed height

    LayoutNode::get_layout_width

    fn LayoutNode::get_layout_width(self : LayoutNode) -> Double

    Get computed width

    LayoutNode::get_layout_x

    fn LayoutNode::get_layout_x(self : LayoutNode) -> Double

    Get computed X position (relative to parent)

    LayoutNode::get_layout_y

    fn LayoutNode::get_layout_y(self : LayoutNode) -> Double

    Get computed Y position (relative to parent)

    LayoutNode::insert_child

    fn LayoutNode::insert_child(self : LayoutNode, child : LayoutNode, index : Int) -> LayoutNode

    Insert child at index

    LayoutNode::is_dirty

    fn LayoutNode::is_dirty(self : LayoutNode) -> Bool

    Check if node is dirty

    LayoutNode::leaf

    fn LayoutNode::leaf(id : String, style :
    Style
    ) -> LayoutNode

    LayoutNode::mark_children_dirty

    fn LayoutNode::mark_children_dirty(self : LayoutNode) -> Unit

    Mark that children need re-layout

    LayoutNode::mark_dirty

    fn LayoutNode::mark_dirty(self : LayoutNode) -> Unit

    Mark this node as dirty and invalidate cache Also propagates children_dirty to parent chain via callback

    LayoutNode::mark_layout_seen

    fn LayoutNode::mark_layout_seen(self : LayoutNode) -> Unit

    Mark that layout has been read (for incremental updates)

    LayoutNode::needs_layout

    fn LayoutNode::needs_layout(self : LayoutNode) -> Bool

    Check if this node or any children need layout

    LayoutNode::new

    fn LayoutNode::new(id : String, style :
    Style
    , children : Array[LayoutNode]) -> LayoutNode

    LayoutNode::remove_all_children

    fn LayoutNode::remove_all_children(self : LayoutNode) -> Unit

    Remove all children

    LayoutNode::remove_child_at

    fn LayoutNode::remove_child_at(self : LayoutNode, index : Int) -> LayoutNode?

    Remove child at index

    LayoutNode::set_align_content

    fn LayoutNode::set_align_content(self : LayoutNode, value :
    Alignment
    ) -> LayoutNode

    Set align content

    LayoutNode::set_align_items

    Set align items

    LayoutNode::set_align_self

    Set align self

    LayoutNode::set_border

    fn LayoutNode::set_border(self : LayoutNode, value : Double) -> LayoutNode

    Set all border widths

    LayoutNode::set_column_gap

    fn LayoutNode::set_column_gap(self : LayoutNode, value : Double) -> LayoutNode

    Set column gap in pixels

    LayoutNode::set_display

    Set display type

    LayoutNode::set_flex_basis

    fn LayoutNode::set_flex_basis(self : LayoutNode, value : Double) -> LayoutNode

    Set flex basis in pixels

    LayoutNode::set_flex_basis_auto

    fn LayoutNode::set_flex_basis_auto(self : LayoutNode) -> LayoutNode

    Set flex basis to auto

    LayoutNode::set_flex_direction

    Set flex direction

    LayoutNode::set_flex_grow

    fn LayoutNode::set_flex_grow(self : LayoutNode, value : Double) -> LayoutNode

    Set flex grow

    LayoutNode::set_flex_shrink

    fn LayoutNode::set_flex_shrink(self : LayoutNode, value : Double) -> LayoutNode

    Set flex shrink

    LayoutNode::set_flex_wrap

    Set flex wrap

    LayoutNode::set_gap

    fn LayoutNode::set_gap(self : LayoutNode, value : Double) -> LayoutNode

    Set both row and column gap

    LayoutNode::set_grid_area

    fn LayoutNode::set_grid_area(self : LayoutNode, area : String?) -> LayoutNode

    Set grid area by name

    LayoutNode::set_grid_auto_columns

    Set grid auto columns

    LayoutNode::set_grid_auto_flow

    Set grid auto flow

    LayoutNode::set_grid_auto_rows

    Set grid auto rows

    LayoutNode::set_grid_column

    Set grid column placement

    LayoutNode::set_grid_row

    Set grid row placement

    LayoutNode::set_grid_template_areas

    fn LayoutNode::set_grid_template_areas(self : LayoutNode, areas : Array[String]) -> LayoutNode

    Set grid template areas

    LayoutNode::set_grid_template_columns

    Set grid template columns

    LayoutNode::set_grid_template_rows

    Set grid template rows

    LayoutNode::set_height

    fn LayoutNode::set_height(self : LayoutNode, value : Double) -> LayoutNode

    Set height in pixels

    LayoutNode::set_height_auto

    fn LayoutNode::set_height_auto(self : LayoutNode) -> LayoutNode

    Set height to auto

    LayoutNode::set_height_percent

    fn LayoutNode::set_height_percent(self : LayoutNode, value : Double) -> LayoutNode

    Set height as percentage (0.0-1.0)

    LayoutNode::set_intrinsic_pending

    fn LayoutNode::set_intrinsic_pending(self : LayoutNode, placeholder_width : Double, placeholder_height : Double) -> Unit

    Configure a node to use a pending intrinsic placeholder size.

    LayoutNode::set_intrinsic_resolved

    fn LayoutNode::set_intrinsic_resolved(self : LayoutNode, width : Double, height : Double) -> Unit

    Configure a node to use a resolved intrinsic size.

    LayoutNode::set_justify_content

    fn LayoutNode::set_justify_content(self : LayoutNode, value :
    Alignment
    ) -> LayoutNode

    Set justify content

    LayoutNode::set_justify_items

    fn LayoutNode::set_justify_items(self : LayoutNode, value :
    Alignment
    ) -> LayoutNode

    Set justify items (grid container)

    LayoutNode::set_justify_self

    Set justify self (grid item)

    LayoutNode::set_margin

    fn LayoutNode::set_margin(self : LayoutNode, value : Double) -> LayoutNode

    Set all margins

    LayoutNode::set_margin_bottom

    fn LayoutNode::set_margin_bottom(self : LayoutNode, value : Double) -> LayoutNode

    Set margin bottom

    LayoutNode::set_margin_left

    fn LayoutNode::set_margin_left(self : LayoutNode, value : Double) -> LayoutNode

    Set margin left

    LayoutNode::set_margin_right

    fn LayoutNode::set_margin_right(self : LayoutNode, value : Double) -> LayoutNode

    Set margin right

    LayoutNode::set_margin_top

    fn LayoutNode::set_margin_top(self : LayoutNode, value : Double) -> LayoutNode

    Set margin top

    LayoutNode::set_max_height

    fn LayoutNode::set_max_height(self : LayoutNode, value : Double) -> LayoutNode

    Set max-height in pixels

    LayoutNode::set_max_width

    fn LayoutNode::set_max_width(self : LayoutNode, value : Double) -> LayoutNode

    Set max-width in pixels

    LayoutNode::set_min_height

    fn LayoutNode::set_min_height(self : LayoutNode, value : Double) -> LayoutNode

    Set min-height in pixels

    LayoutNode::set_min_width

    fn LayoutNode::set_min_width(self : LayoutNode, value : Double) -> LayoutNode

    Set min-width in pixels

    LayoutNode::set_padding

    fn LayoutNode::set_padding(self : LayoutNode, value : Double) -> LayoutNode

    Set all padding

    LayoutNode::set_padding_bottom

    fn LayoutNode::set_padding_bottom(self : LayoutNode, value : Double) -> LayoutNode

    Set padding bottom

    LayoutNode::set_padding_left

    fn LayoutNode::set_padding_left(self : LayoutNode, value : Double) -> LayoutNode

    Set padding left

    LayoutNode::set_padding_right

    fn LayoutNode::set_padding_right(self : LayoutNode, value : Double) -> LayoutNode

    Set padding right

    LayoutNode::set_padding_top

    fn LayoutNode::set_padding_top(self : LayoutNode, value : Double) -> LayoutNode

    Set padding top

    LayoutNode::set_position_type

    fn LayoutNode::set_position_type(self : LayoutNode, value :
    Position
    ) -> LayoutNode

    Set position type

    LayoutNode::set_row_gap

    fn LayoutNode::set_row_gap(self : LayoutNode, value : Double) -> LayoutNode

    Set row gap in pixels

    LayoutNode::set_width

    fn LayoutNode::set_width(self : LayoutNode, value : Double) -> LayoutNode

    Set width in pixels

    LayoutNode::set_width_auto

    fn LayoutNode::set_width_auto(self : LayoutNode) -> LayoutNode

    Set width to auto

    LayoutNode::set_width_percent

    fn LayoutNode::set_width_percent(self : LayoutNode, value : Double) -> LayoutNode

    Set width as percentage (0.0-1.0)

    LayoutNode::to_node

    Convert LayoutNode to immutable Node (for existing layout functions) Preserves uid for cache lookup

    LayoutNode::with_measure

    LayoutTree

    pub struct LayoutTree {
    root : LayoutNode
    parent_map : Map[Int, Int]
    node_map : Map[Int, LayoutNode]
    viewport_width : Double
    viewport_height : Double
    resources : ResourceRegistry
    }

    Layout tree with parent tracking for dirty propagation

    LayoutTree::attach_resource

    fn LayoutTree::attach_resource(self : LayoutTree, rid : ResourceId, node_uid : Int, placeholder_width? : Double, placeholder_height? : Double) -> Unit

    Attach an additional node to an existing resource (for shared resources like same src)

    LayoutTree::calculate_layout

    fn LayoutTree::calculate_layout(self : LayoutTree, width : Double, height : Double) ->
    Layout

    Calculate layout (Yoga-compatible name) Returns the root layout and stores computed layouts on each node

    LayoutTree::collect_dirty_rects

    Collect bounding rects of all nodes that have new layouts Returns absolute positions (relative to viewport origin) Use this after calculate_layout() to get regions that need redrawing

    LayoutTree::collect_dirty_union

    Collect dirty rects and merge overlapping ones into a single union rect More efficient when many small regions change

    LayoutTree::compute_full

    Compute layout using existing layout system (full recomputation)

    LayoutTree::compute_incremental

    fn LayoutTree::compute_incremental(self : LayoutTree) ->
    Layout

    Compute layout with incremental optimization Uses per-node caching for better performance

    LayoutTree::compute_with_stats

    fn LayoutTree::compute_with_stats(self : LayoutTree, stats : CacheStats) ->
    Layout

    Compute with stats tracking (for testing/debugging)

    LayoutTree::fail_resource

    fn LayoutTree::fail_resource(self : LayoutTree, rid : ResourceId) -> Unit

    Mark a resource as failed (e.g., image load error)

    LayoutTree::find_node

    fn LayoutTree::find_node(self : LayoutTree, uid : Int) -> LayoutNode?

    Find a node by uid

    LayoutTree::find_node_by_id

    fn LayoutTree::find_node_by_id(self : LayoutTree, node_id : String) -> LayoutNode?

    Find a node by string id

    LayoutTree::flow_dirty_uids

    fn LayoutTree::flow_dirty_uids(self : LayoutTree, seed : Array[Int]) -> Array[Int]

    Expand a seed set of directly-changed node uids into the full set that must be re-laid-out, accounting for crater's absolute geometry cache: resizing a box shifts the absolute position of every box that comes after it in flow. So for each changed node, every following sibling (and its whole subtree) at that node's level — and, walking up, at every ancestor's level — must also be dirtied, because their absolute positions move. Ancestors themselves are handled by mark_node_dirty's children_dirty propagation, so they need not be listed here.

    Feed the result to reconcile_from as dirty_uids: with a correct seed (the nodes whose own layout inputs changed) this makes the incremental result equal a full recompute while still reusing everything before the change.

    LayoutTree::from_node

    fn LayoutTree::from_node(node :
    Node
    , viewport_width : Double, viewport_height : Double) -> LayoutTree

    Create tree from immutable Node

    LayoutTree::get_parent

    fn LayoutTree::get_parent(self : LayoutTree, uid : Int) -> LayoutNode?

    Get parent of a node

    LayoutTree::get_pending_resources

    fn LayoutTree::get_pending_resources(self : LayoutTree) -> Array[ResourceId]

    Get all pending resources

    LayoutTree::get_resources

    fn LayoutTree::get_resources(self : LayoutTree) -> ResourceRegistry

    Get the resource registry for external management This allows decoupling resource management from LayoutTree

    LayoutTree::is_resource_pending

    fn LayoutTree::is_resource_pending(self : LayoutTree, rid : ResourceId) -> Bool

    Check if a resource is still pending

    LayoutTree::mark_all_layouts_seen

    fn LayoutTree::mark_all_layouts_seen(self : LayoutTree) -> Unit

    Mark all nodes' layouts as seen (clear has_new_layout flags) Call this after processing dirty regions

    LayoutTree::mark_node_dirty

    fn LayoutTree::mark_node_dirty(self : LayoutTree, uid : Int) -> Unit

    Mark a node as dirty and propagate to ancestors

    LayoutTree::needs_layout

    fn LayoutTree::needs_layout(self : LayoutTree) -> Bool

    Check if any layout is needed

    LayoutTree::new

    fn LayoutTree::new(root : LayoutNode, viewport_width : Double, viewport_height : Double) -> LayoutTree

    LayoutTree::reconcile_from

    fn LayoutTree::reconcile_from(prev : LayoutTree, new_root :
    Node
    , dirty_uids : Array[Int], viewport_width : Double, viewport_height : Double) -> LayoutTree

    Incremental reflow across a rebuilt render node tree.

    The dynamic-rendering path rebuilds the render node tree from the mutated DOM on each change (full cascade — correct for every selector), which would normally throw away all cached geometry. reconcile_from bridges a freshly built LayoutTree to a prior one: it migrates each node's cached layout from the previous tree by matching uid (the stable dom_id-derived identity — see docs/incremental-reflow-design.md phase A), so unchanged subtrees stay cache hits, while nodes that actually changed are dirtied and recomputed.

    Two sources of dirtiness:
    • dirty_uids: nodes whose computed style / content changed (the caller determines these — e.g. by comparing computed styles after the cascade).
    • structural changes: a node whose set of child uids differs from the prior tree (a child added / removed / reordered) is detected here and dirtied.

    Correctness contract: if dirty_uids is a superset of the nodes whose layout inputs changed, the layout computed from the returned tree equals a full from-scratch recompute. (Unlisted changes would read stale cache — hence the dynamic path pairs this with a conservative dirty set + fall-back to full.)

    LayoutTree::register_pending_images

    fn LayoutTree::register_pending_images(self : LayoutTree) -> Map[String, ResourceId]

    Scan the tree for nodes with Pending intrinsic state and register them as resources Returns a map from uid (as string) to ResourceId This is useful after building a tree from HTML to register all pending images

    LayoutTree::register_pending_images_with_src

    fn LayoutTree::register_pending_images_with_src(self : LayoutTree, uid_to_src : Map[Int, String]) -> Map[String, ResourceId]

    Scan the tree for nodes with Pending intrinsic state and register them as resources Uses provided src->uid mapping to share resources for same src Returns a map from src to ResourceId

    LayoutTree::register_resource

    fn LayoutTree::register_resource(self : LayoutTree, node_uid : Int, placeholder_width? : Double, placeholder_height? : Double) -> ResourceId

    Register a pending resource for an intrinsic-sized element (e.g., image) Returns a ResourceId that can be used to resolve the size later

    LayoutTree::resize_viewport

    fn LayoutTree::resize_viewport(self : LayoutTree, width : Double, height : Double) -> Unit

    Update viewport size and mark dependent nodes dirty

    LayoutTree::resolve_resource

    fn LayoutTree::resolve_resource(self : LayoutTree, rid : ResourceId, width : Double, height : Double) -> Unit

    Resolve a resource with its actual size

    ResourceId

    pub(all) struct ResourceId(Int) derive(Eq, Hash,
    Debug
    )

    Opaque resource identifier for external reference
    impl Show for ResourceId

    ResourceRegistry

    pub struct ResourceRegistry {
    next_id : Int
    resource_nodes : Map[Int, Array[Int]]
    pending :
    HashSet
    [Int]
    }

    Resource registry - tracks pending resources and their associated nodes

    ResourceRegistry::add_node

    fn ResourceRegistry::add_node(self : ResourceRegistry, rid : ResourceId, node_uid : Int) -> Unit

    Associate a node UID with a resource ID

    ResourceRegistry::get_all_pending

    fn ResourceRegistry::get_all_pending(self : ResourceRegistry) -> Array[ResourceId]

    Get all pending resource IDs

    ResourceRegistry::get_nodes

    fn ResourceRegistry::get_nodes(self : ResourceRegistry, rid : ResourceId) -> Array[Int]

    Get all node UIDs associated with a resource

    ResourceRegistry::is_pending

    fn ResourceRegistry::is_pending(self : ResourceRegistry, rid : ResourceId) -> Bool

    Check if a resource is still pending

    ResourceRegistry::mark_pending

    fn ResourceRegistry::mark_pending(self : ResourceRegistry, rid : ResourceId) -> Unit

    Mark a resource as pending (not yet resolved)

    ResourceRegistry::mark_resolved

    fn ResourceRegistry::mark_resolved(self : ResourceRegistry, rid : ResourceId) -> Unit

    Mark a resource as resolved (size known)

    ResourceRegistry::new

    ResourceRegistry::next_resource_id

    fn ResourceRegistry::next_resource_id(self : ResourceRegistry) -> ResourceId

    Generate a new unique resource ID

    analyze_style_dependencies

    fn analyze_style_dependencies(style :
    Style
    ) -> DependencyKind

    Analyze what a style depends on for layout

    compute_node

    fn compute_node(node : LayoutNode, constraint : ConstraintSpace, stats : CacheStats) ->
    Layout

    Compute layout for a LayoutNode with caching This wraps the existing compute functions with cache logic

    compute_tree_incremental

    fn compute_tree_incremental(tree : LayoutTree, stats : CacheStats) ->
    Layout

    Compute layout for entire tree with incremental optimization Uses cached dispatcher to enable child-level cache hits

    create_fixed_measure

    fn create_fixed_measure(width : Double, height : Double) ->
    MeasureFunc

    Create a fixed MeasureFunc for intrinsic sizing

    default_placeholder_height

    let default_placeholder_height : Double

    default_placeholder_width

    let default_placeholder_width : Double

    HTML default placeholder size (per specification)

    error_placeholder_height

    let error_placeholder_height : Double

    error_placeholder_width

    let error_placeholder_width : Double

    Error placeholder size (broken image icon)