oxipdf-ir 0.1.0

Intermediate representation types for the oxipdf PDF engine
Documentation
//! Layout-related style properties: display mode, position, sizing, spacing.

use crate::units::{Dimension, LengthPercentage, Pt};

/// Layout style properties governing box model and spatial positioning.
///
/// These map to the corresponding CSS layout properties and are consumed
/// by the spatial layout engine (taffy or equivalent) during Milestone 2.
#[derive(Debug, Clone, PartialEq)]
pub struct LayoutStyle {
    /// Display mode for this node's children.
    pub display: Display,
    /// Positioning scheme.
    pub position: Position,
    /// Box sizing model.
    pub box_sizing: BoxSizing,

    // --- Sizing ---
    /// Width of the content box (or border box if `box_sizing` is `BorderBox`).
    pub width: Dimension,
    /// Height.
    pub height: Dimension,
    /// Minimum width.
    pub min_width: Dimension,
    /// Minimum height.
    pub min_height: Dimension,
    /// Maximum width. `Dimension::Auto` means no constraint.
    pub max_width: Dimension,
    /// Maximum height. `Dimension::Auto` means no constraint.
    pub max_height: Dimension,

    // --- Margin (supports Auto for centering) ---
    pub margin_top: Dimension,
    pub margin_right: Dimension,
    pub margin_bottom: Dimension,
    pub margin_left: Dimension,

    // --- Padding (no Auto) ---
    pub padding_top: LengthPercentage,
    pub padding_right: LengthPercentage,
    pub padding_bottom: LengthPercentage,
    pub padding_left: LengthPercentage,

    // --- Position offsets (for Position::Relative / Absolute) ---
    pub inset_top: Dimension,
    pub inset_right: Dimension,
    pub inset_bottom: Dimension,
    pub inset_left: Dimension,

    /// Overflow behavior.
    pub overflow: Overflow,

    /// Number of columns for multi-column layout.
    /// 1 (default) means no column layout. Values ≥ 2 distribute children
    /// across that many columns, flowing top-to-bottom then left-to-right.
    pub column_count: u32,
    /// Gap between columns. Only used when `column_count >= 2`.
    pub column_gap: Pt,
    /// Optional divider line between columns.
    pub column_rule: Option<ColumnRule>,

    /// Aspect ratio constraint. When set, if only one dimension (width or
    /// height) is specified, the other is computed from this ratio.
    pub aspect_ratio: Option<f32>,

    /// Visibility of the element. `Hidden` keeps layout space but skips rendering.
    pub visibility: Visibility,

    /// Float behavior. Floated elements are taken out of normal flow and
    /// positioned at the left or right edge of their container. Subsequent
    /// content wraps around them.
    pub float: Float,

    /// Clear behavior. Moves the element below any preceding floats on the
    /// specified side(s).
    pub clear: Clear,

    /// Stacking order for overlapping elements. Higher values paint on top.
    /// Only meaningful for positioned elements (`position: relative/absolute`).
    /// Elements with equal z-index paint in document order.
    /// Default is 0 (auto — follows document order).
    pub z_index: i32,
}

/// A divider line between columns.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ColumnRule {
    /// Width of the rule line.
    pub width: Pt,
    /// Color of the rule line.
    pub color: crate::color::Color,
}

/// Element visibility.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Visibility {
    /// Element is painted normally.
    #[default]
    Visible,
    /// Element takes layout space but is not painted.
    Hidden,
}

impl Default for LayoutStyle {
    fn default() -> Self {
        Self {
            display: Display::Block,
            position: Position::Static,
            box_sizing: BoxSizing::ContentBox,
            width: Dimension::Auto,
            height: Dimension::Auto,
            min_width: Dimension::Length(Pt::ZERO),
            min_height: Dimension::Length(Pt::ZERO),
            max_width: Dimension::Auto,
            max_height: Dimension::Auto,
            margin_top: Dimension::Length(Pt::ZERO),
            margin_right: Dimension::Length(Pt::ZERO),
            margin_bottom: Dimension::Length(Pt::ZERO),
            margin_left: Dimension::Length(Pt::ZERO),
            padding_top: LengthPercentage::ZERO,
            padding_right: LengthPercentage::ZERO,
            padding_bottom: LengthPercentage::ZERO,
            padding_left: LengthPercentage::ZERO,
            inset_top: Dimension::Auto,
            inset_right: Dimension::Auto,
            inset_bottom: Dimension::Auto,
            inset_left: Dimension::Auto,
            overflow: Overflow::Visible,
            column_count: 1,
            column_gap: Pt::ZERO,
            column_rule: None,
            aspect_ratio: None,
            visibility: Visibility::Visible,
            float: Float::None,
            clear: Clear::None,
            z_index: 0,
        }
    }
}

/// Display mode for a node's children layout.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Display {
    /// Block-level layout: children are stacked vertically.
    #[default]
    Block,
    /// Flexbox layout.
    Flex,
    /// CSS Grid layout.
    Grid,
    /// Inline-level element (text run within a block context).
    Inline,
    /// Node and its subtree are not rendered.
    None,
}

/// Positioning scheme.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Position {
    /// Normal flow.
    #[default]
    Static,
    /// Offset relative to normal flow position.
    Relative,
    /// Positioned relative to containing block (page or nearest positioned ancestor).
    Absolute,
}

/// Box sizing model.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum BoxSizing {
    /// Width/height apply to content box; padding and border are added outside.
    #[default]
    ContentBox,
    /// Width/height include padding and border.
    BorderBox,
}

/// Overflow behavior.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Overflow {
    /// Content may overflow the box (default for PDF — no scrolling).
    #[default]
    Visible,
    /// Content is clipped to the box boundary.
    Hidden,
}

/// Float positioning.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Float {
    /// Normal flow (not floated).
    #[default]
    None,
    /// Float to the left edge of the container. Subsequent content wraps
    /// around the right side.
    Left,
    /// Float to the right edge of the container. Subsequent content wraps
    /// around the left side.
    Right,
}

/// Clear behavior: move below preceding floats.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum Clear {
    /// No clearing.
    #[default]
    None,
    /// Clear past left floats.
    Left,
    /// Clear past right floats.
    Right,
    /// Clear past all floats.
    Both,
}