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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
|
//! Layouting.
mod background;
mod fixed;
mod node;
mod pad;
mod par;
mod spacing;
mod stack;
mod text;
use crate::color::Color;
use crate::env::{Env, ResourceId};
use crate::geom::*;
use crate::shaping::Shaped;
pub use background::*;
pub use fixed::*;
pub use node::*;
pub use pad::*;
pub use par::*;
pub use spacing::*;
pub use stack::*;
pub use text::*;
/// Layout a tree into a collection of frames.
pub fn layout(env: &mut Env, tree: &Tree) -> Vec<Frame> {
tree.layout(&mut LayoutContext { env })
}
/// A tree of layout nodes.
#[derive(Debug, Clone, PartialEq)]
pub struct Tree {
/// Runs of pages with the same properties.
pub runs: Vec<NodePages>,
}
impl Tree {
/// Layout the tree into a collection of frames.
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<Frame> {
self.runs.iter().flat_map(|run| run.layout(ctx)).collect()
}
}
/// A run of pages that all have the same properties.
#[derive(Debug, Clone, PartialEq)]
pub struct NodePages {
/// The size of each page.
pub size: Size,
/// The layout node that produces the actual pages (typically a
/// [`NodeStack`]).
pub child: Node,
}
impl NodePages {
/// Layout the page run.
pub fn layout(&self, ctx: &mut LayoutContext) -> Vec<Frame> {
let areas = Areas::repeat(self.size, Spec::uniform(Expand::Fill));
let layouted = self.child.layout(ctx, &areas);
layouted.into_frames()
}
}
/// Layout a node.
pub trait Layout {
/// Layout the node into the given areas.
fn layout(&self, ctx: &mut LayoutContext, areas: &Areas) -> Layouted;
}
/// The context for layouting.
#[derive(Debug)]
pub struct LayoutContext<'a> {
/// The environment from which fonts are gathered.
pub env: &'a mut Env,
}
/// A collection of areas to layout into.
#[derive(Debug, Clone, PartialEq)]
pub struct Areas {
/// The remaining size of the current area.
pub current: Size,
/// The full size the current area once had (used for relative sizing).
pub full: Size,
/// A stack of followup areas (the next area is the last element).
pub backlog: Vec<Size>,
/// The final area that is repeated when the backlog is empty.
pub last: Option<Size>,
/// Whether the frames resulting from layouting into this areas should be
/// shrunk to fit their content or expanded to fill the area.
pub expand: Spec<Expand>,
}
impl Areas {
/// Create a new length-1 sequence of areas with just one `area`.
pub fn once(size: Size, expand: Spec<Expand>) -> Self {
Self {
current: size,
full: size,
backlog: vec![],
last: None,
expand,
}
}
/// Create a new sequence of areas that repeats `area` indefinitely.
pub fn repeat(size: Size, expand: Spec<Expand>) -> Self {
Self {
current: size,
full: size,
backlog: vec![],
last: Some(size),
expand,
}
}
/// 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 = size;
self.full = 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.is_nan() || size.is_nan() || self.current == size
})
}
}
/// Whether to expand or shrink a node along an axis.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Expand {
/// Fit the content.
Fit,
/// Fill the available space.
Fill,
}
impl Expand {
/// Resolve the expansion to either the `fit` or `fill` length.
///
/// Prefers `fit` if `fill` is infinite.
pub fn resolve(self, fit: Length, fill: Length) -> Length {
match self {
Self::Fill if fill.is_finite() => fill,
_ => fit,
}
}
}
/// The result of layouting 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.
Frame(Frame, ChildAlign),
/// Multiple layouts.
Frames(Vec<Frame>, ChildAlign),
}
impl Layouted {
/// Return a reference to all frames contained in this variant (zero, one or
/// arbitrarily many).
pub fn frames(&self) -> &[Frame] {
match self {
Self::Spacing(_) => &[],
Self::Frame(frame, _) => std::slice::from_ref(frame),
Self::Frames(frames, _) => frames,
}
}
/// Return a mutable reference to all frames contained in this variant.
pub fn frames_mut(&mut self) -> &mut [Frame] {
match self {
Self::Spacing(_) => &mut [],
Self::Frame(frame, _) => std::slice::from_mut(frame),
Self::Frames(frames, _) => frames,
}
}
/// Return all frames contained in this varian.
pub fn into_frames(self) -> Vec<Frame> {
match self {
Self::Spacing(_) => vec![],
Self::Frame(frame, _) => vec![frame],
Self::Frames(frames, _) => frames,
}
}
}
/// A finished layout with elements at fixed positions.
#[derive(Debug, Clone, PartialEq)]
pub struct Frame {
/// The size of the frame.
pub size: Size,
/// The elements composing this layout.
pub elements: Vec<(Point, Element)>,
}
impl Frame {
/// Create a new, empty frame.
pub fn new(size: Size) -> Self {
Self { size, elements: vec![] }
}
/// Add an element at a position.
pub fn push(&mut self, pos: Point, element: Element) {
self.elements.push((pos, element));
}
/// Add all elements of another frame, placing them relative to the given
/// position.
pub fn push_frame(&mut self, pos: Point, subframe: Self) {
for (subpos, element) in subframe.elements {
self.push(pos + subpos, element);
}
}
}
/// The building block frames are composed of.
#[derive(Debug, Clone, PartialEq)]
pub enum Element {
/// Shaped text.
Text(Shaped),
/// An image.
Image(Image),
/// Some shape that could hold another frame.
Geometry(Geometry),
}
/// A shape with some kind of fill.
#[derive(Debug, Clone, PartialEq)]
pub struct Geometry {
/// The shape to draw.
pub shape: Shape,
/// How the shape looks on the inside.
//
// TODO: This could be made into a Vec<Fill> or something such that
// the user can compose multiple fills with alpha values less
// than one to achieve cool effects.
pub fill: Fill,
}
/// Some shape.
#[derive(Debug, Clone, PartialEq)]
pub enum Shape {
/// A rectangle.
Rect(Size),
}
/// The kind of graphic fill to be applied to a [`Shape`].
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Fill {
/// The fill is a color.
Color(Color),
/// The fill is an image.
Image(Image),
}
/// An image element.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Image {
/// The image resource.
pub res: ResourceId,
/// The size of the image in the document.
pub size: Size,
}
|