1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
//! Layouting of documents.
mod fixed;
mod node;
mod pad;
mod par;
mod spacing;
mod stack;
mod text;
use image::RgbaImage;
use crate::font::SharedFontLoader;
use crate::geom::*;
use crate::shaping::Shaped;
pub use fixed::*;
pub use node::*;
pub use pad::*;
pub use par::*;
pub use spacing::*;
pub use stack::*;
pub use text::*;
/// Layout a document and return the produced layouts.
pub fn layout(document: &Document, loader: SharedFontLoader) -> Vec<BoxLayout> {
let mut ctx = LayoutContext { loader };
document.layout(&mut ctx)
}
/// The context for layouting.
#[derive(Debug, Clone)]
pub struct LayoutContext {
/// The font loader to query fonts from when typesetting text.
pub loader: SharedFontLoader,
}
/// Layout a node.
pub trait Layout {
/// Layout the node into the given areas.
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted;
}
/// A sequence of areas to layout into.
#[derive(Debug, Clone, PartialEq)]
pub struct Areas {
/// The current area.
pub current: Area,
/// The backlog of followup areas.
///
/// _Note_: This works stack-like and not queue-like!
pub backlog: Vec<Size>,
/// The last area that is repeated when the backlog is empty.
pub last: Option<Size>,
}
impl Areas {
/// Create a new length-1 sequence of areas with just one `area`.
pub fn once(size: Size) -> Self {
Self {
current: Area::new(size),
backlog: vec![],
last: None,
}
}
/// Create a new sequence of areas that repeats `area` indefinitely.
pub fn repeat(size: Size) -> Self {
Self {
current: Area::new(size),
backlog: vec![],
last: Some(size),
}
}
/// Advance to the next area if there is any.
pub fn next(&mut self) {
if let Some(size) = self.backlog.pop().or(self.last) {
self.current = Area::new(size);
}
}
/// Whether `current` is a fully sized (untouched) copy of the last area.
///
/// If this is false calling `next()` will have no effect.
pub fn in_full_last(&self) -> bool {
self.backlog.is_empty() && self.last.map_or(true, |size| self.current.rem == size)
}
}
/// The area into which content can be laid out.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Area {
/// The remaining size of this area.
pub rem: Size,
/// The full size this area once had (used for relative sizing).
pub full: Size,
}
impl Area {
/// Create a new area.
pub fn new(size: Size) -> Self {
Self { rem: size, full: size }
}
}
/// How to determine a container's size along an axis.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Expansion {
/// Fit the content.
Fit,
/// Fill the available space.
Fill,
}
impl Expansion {
/// Returns `Fill` if the condition is true and `Fit` otherwise.
pub fn fill_if(condition: bool) -> Self {
if condition { Self::Fill } else { Self::Fit }
}
}
/// The result of [layouting](Layout::layout) a node.
#[derive(Debug, Clone, PartialEq)]
pub enum Layouted {
/// Spacing that should be added to the parent.
Spacing(Length),
/// A layout that should be added to and aligned in the parent.
Layout(BoxLayout, BoxAlign),
/// Multiple layouts.
Layouts(Vec<BoxLayout>, BoxAlign),
}
impl Layouted {
/// Return all layouts contained in this variant (zero, one or arbitrarily
/// many).
pub fn into_layouts(self) -> Vec<BoxLayout> {
match self {
Self::Spacing(_) => vec![],
Self::Layout(layout, _) => vec![layout],
Self::Layouts(layouts, _) => layouts,
}
}
}
/// A finished box with content at fixed positions.
#[derive(Debug, Clone, PartialEq)]
pub struct BoxLayout {
/// The size of the box.
pub size: Size,
/// The elements composing this layout.
pub elements: Vec<(Point, LayoutElement)>,
}
impl BoxLayout {
/// Create a new empty collection.
pub fn new(size: Size) -> Self {
Self { size, elements: vec![] }
}
/// Add an element at a position.
pub fn push(&mut self, pos: Point, element: LayoutElement) {
self.elements.push((pos, element));
}
/// Add all elements of another collection, placing them relative to the
/// given position.
pub fn push_layout(&mut self, pos: Point, more: Self) {
for (subpos, element) in more.elements {
self.push(pos + subpos, element);
}
}
}
/// A layout element, the basic building block layouts are composed of.
#[derive(Debug, Clone, PartialEq)]
pub enum LayoutElement {
/// Shaped text.
Text(Shaped),
/// An image.
Image(ImageElement),
}
/// An image.
#[derive(Debug, Clone, PartialEq)]
pub struct ImageElement {
/// The image.
pub buf: RgbaImage,
/// The document size of the image.
pub size: Size,
}
/// The top-level layout node.
#[derive(Debug, Clone, PartialEq)]
pub struct Document {
/// The runs of pages with same properties.
pub runs: Vec<Pages>,
}
impl Document {
/// Layout the document.
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<BoxLayout> {
self.runs.iter().flat_map(|run| run.layout(ctx)).collect()
}
}
/// A variable-length run of pages that all have the same properties.
#[derive(Debug, Clone, PartialEq)]
pub struct Pages {
/// The size of each page.
pub size: Size,
/// The layout node that produces the actual pages (typically a [`Stack`]).
pub child: LayoutNode,
}
impl Pages {
/// Layout the page run.
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<BoxLayout> {
let areas = Areas::repeat(self.size);
let layouted = self.child.layout(ctx, &areas);
layouted.into_layouts()
}
}
|