Skip to main content

azul_core/
paged.rs

1//! Paged media layout primitives.
2//!
3//! Provides the [`FragmentationContext`] that the layout solver threads through to
4//! distinguish continuous (screen) from paged (print) media.
5//!
6//! For continuous media (screens), content flows into a single infinitely tall
7//! container. For paged media (print), content is laid out on a continuous canvas
8//! and afterwards sliced into fixed-size pages by the display-list slicer
9//! (`paginate_display_list_with_slicer_and_breaks` in `azul_layout::solver3::display_list`).
10//! This lets the layout engine make break decisions while respecting CSS properties
11//! like `break-before`, `break-after`, and `break-inside`.
12//!
13//! Page *decoration* (headers, footers, margin boxes, counters) lives in
14//! `azul_layout::solver3::pagination`.
15
16use crate::geom::LogicalSize;
17
18/// Selects how content is fragmented during layout.
19///
20/// This is the core abstraction for fragmentation support:
21/// - Screen rendering: [`Continuous`](Self::Continuous) — a single infinite container.
22/// - Print rendering: [`Paged`](Self::Paged) — a series of fixed-size page containers.
23#[derive(Debug, Clone, Copy)]
24pub enum FragmentationContext {
25    /// Continuous media (screen): a single, infinitely tall container.
26    ///
27    /// Used for normal screen rendering where content can scroll indefinitely;
28    /// breaks are never forced.
29    Continuous {
30        /// Width of the viewport.
31        width: f32,
32    },
33
34    /// Paged media (print): fixed-size pages.
35    ///
36    /// Used for PDF generation and print preview. Content flows from one page to
37    /// the next when a page is full.
38    Paged {
39        /// Size of each page.
40        page_size: LogicalSize,
41    },
42}
43
44impl FragmentationContext {
45    /// Create a continuous fragmentation context for screen rendering.
46    #[must_use]
47    pub const fn new_continuous(width: f32) -> Self {
48        Self::Continuous { width }
49    }
50
51    /// Create a paged fragmentation context for print rendering.
52    #[must_use]
53    pub const fn new_paged(page_size: LogicalSize) -> Self {
54        Self::Paged { page_size }
55    }
56
57    /// Get the page content height (page height for paged media).
58    ///
59    /// For continuous media, returns `f32::MAX`.
60    #[must_use]
61    pub const fn page_content_height(&self) -> f32 {
62        match self {
63            Self::Continuous { .. } => f32::MAX,
64            Self::Paged { page_size, .. } => page_size.height,
65        }
66    }
67
68    /// Check if this is paged media.
69    #[must_use]
70    pub const fn is_paged(&self) -> bool {
71        matches!(self, Self::Paged { .. })
72    }
73}
74
75/// Page margins in points.
76///
77/// Canonical paged-media margin type (formerly defined in the now-removed
78/// `crate::fragmentation` module). Re-exported from the crate root as
79/// `azul_layout::PageMargins`.
80#[derive(Debug, Clone, Copy, Default, PartialEq)]
81#[repr(C)] // crosses the C API in `PageSetup` (9g-ii-f-i)
82pub struct PageMargins {
83    pub top: f32,
84    pub right: f32,
85    pub bottom: f32,
86    pub left: f32,
87}
88
89impl PageMargins {
90    #[must_use]
91    pub const fn new(top: f32, right: f32, bottom: f32, left: f32) -> Self {
92        Self {
93            top,
94            right,
95            bottom,
96            left,
97        }
98    }
99
100    #[must_use]
101    pub const fn uniform(margin: f32) -> Self {
102        Self {
103            top: margin,
104            right: margin,
105            bottom: margin,
106            left: margin,
107        }
108    }
109
110    #[must_use]
111    pub fn horizontal(&self) -> f32 {
112        self.left + self.right
113    }
114
115    #[must_use]
116    pub fn vertical(&self) -> f32 {
117        self.top + self.bottom
118    }
119}
120
121#[cfg(test)]
122#[path = "paged_test.rs"]
123mod paged_test;