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;