1use crate::resolve::{self, Align, ImageFiles, Layout, Node, Scene, Size as DSize};
5use crate::tree::{Order, OrderKey};
6
7use super::*;
8
9mod run;
10pub(super) use run::*;
11impl Renderer {
12 pub fn layout(&mut self, scene: &Scene) -> Vec<Frame> {
15 self.register(&scene.fonts);
16 let mut l = Laid::build(self, scene);
17 l.settle_top(self, &l.hugs.clone());
18 l.frames(self, &scene.root).into_values().collect()
19 }
20
21 pub(super) fn compute(
22 &mut self,
23 runs: &mut Runs,
24 tree: &mut TaffyTree<Option<Leaf>>,
25 root: NodeId,
26 available: Size<AvailableSpace>,
27 ) {
28 tree.compute_layout_with_measure(root, available, |input, _id, ctx, style| {
29 let known = input.known_dimensions;
30 let fixed = |d: Dimension| (!d.is_auto()).then(|| d.value());
31 let known = Size {
32 width: known.width.or(fixed(style.size.width)),
33 height: known.height.or(fixed(style.size.height)),
34 };
35 let size = match ctx {
36 Some(Some(Leaf::Intrinsic(w, h))) => {
37 let (w, h) = (*w, *h);
39 match (known.width, known.height) {
40 (Some(kw), None) => Size {
41 width: kw,
42 height: kw * h / w,
43 },
44 (None, Some(kh)) => Size {
45 width: kh * w / h,
46 height: kh,
47 },
48 (kw, kh) => Size {
49 width: kw.unwrap_or(w),
50 height: kh.unwrap_or(h),
51 },
52 }
53 }
54 Some(Some(Leaf::Run(id))) => {
55 let [t, r, b, l] = runs.get(*id).padding;
59 let own = Size {
60 width: fixed(style.size.width).map(|v| v.max(l + r)),
61 height: fixed(style.size.height).map(|v| v.max(t + b)),
62 };
63 let known = Size {
64 width: input.known_dimensions.width.or(own.width),
65 height: input.known_dimensions.height.or(own.height),
66 };
67 return taffy::LayoutOutput::from_outer_size(self.measure_run(
68 runs,
69 *id,
70 known,
71 input.available_space,
72 ));
73 }
74 Some(Some(Leaf::Text(text, wraps))) => {
75 let width = known.width.or(match input.available_space.width {
76 AvailableSpace::Definite(w) if *wraps => Some(w),
77 _ => None,
78 });
79 let layout = self.text_layout(text, width);
80 Size {
81 width: known.width.unwrap_or(layout.width().ceil()),
82 height: known.height.unwrap_or(layout.height()),
83 }
84 }
85 _ => Size {
86 width: known.width.unwrap_or(0.0),
87 height: known.height.unwrap_or(0.0),
88 },
89 };
90 taffy::LayoutOutput::from_outer_size(size)
91 })
92 .expect("layout");
93 }
94}
95
96impl Renderer {
97 pub(super) fn settle_in(
100 &mut self,
101 runs: &mut Runs,
102 tree: &mut TaffyTree<Option<Leaf>>,
103 root: NodeId,
104 available: Size<AvailableSpace>,
105 hugs: &[(NodeId, bool, bool)],
106 ) {
107 for _ in 0..=hugs.len() {
108 self.compute(runs, tree, root, available);
109 let mut changed = false;
110 for &(id, w, h) in hugs {
111 let (mut ew, mut eh) = (0.0f32, 0.0f32);
112 for child in tree.children(id).expect("children") {
113 let l = tree.unrounded_layout(child);
114 ew = ew.max(l.location.x + l.size.width);
115 eh = eh.max(l.location.y + l.size.height);
116 }
117 let mut style = tree.style(id).expect("style").clone();
118 let mut ch = false;
119 let mut set = |d: &mut Dimension, v: f32| {
120 if *d != Dimension::length(v) {
121 *d = Dimension::length(v);
122 ch = true;
123 }
124 };
125 if w {
126 set(&mut style.size.width, ew);
127 }
128 if h {
129 set(&mut style.size.height, eh);
130 }
131 if ch {
132 tree.set_style(id, style).expect("style");
133 changed = true;
134 }
135 }
136 if !changed {
137 break;
138 }
139 }
140 }
141}
142
143pub(super) fn find_node<'a>(root: &'a Node, order: &[OrderKey]) -> &'a Node {
144 let mut at = root;
145 for k in order {
146 at = at.children.get(k).expect("a node there");
147 }
148 at
149}
150
151pub(super) fn remove_subtree(tree: &mut TaffyTree<Option<Leaf>>, id: NodeId) {
153 for child in tree.children(id).unwrap_or_default() {
154 remove_subtree(tree, child);
155 }
156 let _ = tree.remove(id);
157}
158
159pub(super) enum Leaf {
162 Text(Box<resolve::TextStyle>, bool),
164 Intrinsic(f32, f32),
165 Run(u32),
167}
168
169pub(super) struct Laid {
172 pub(super) top: TaffyTree<Option<Leaf>>,
173 pub(super) root: NodeId,
174 pub(super) runs: Runs,
175 pub(super) nodes: BTreeMap<Order, (Owner, NodeId)>,
177 pub(super) run_of: BTreeMap<Order, u32>,
179 pub(super) hugs: Vec<(NodeId, bool, bool)>,
182}
183
184use std::collections::BTreeMap;
185
186impl Laid {
187 pub(super) fn build(_r: &mut Renderer, scene: &Scene) -> Laid {
189 let mut top = TaffyTree::new();
190 top.disable_rounding();
193 let mut l = Laid {
194 top: TaffyTree::new(),
195 root: NodeId::from(0u64),
196 runs: Runs::default(),
197 nodes: BTreeMap::new(),
198 run_of: BTreeMap::new(),
199 hugs: Vec::new(),
200 };
201 let mut hugs = Vec::new();
202 let root = l.build_node(
203 &mut top,
204 Owner::Top,
205 None,
206 &scene.root,
207 None,
208 &mut hugs,
209 &scene.images,
210 Vec::new(),
211 );
212 l.top = top;
213 l.root = root;
214 l.hugs = hugs;
215 l
216 }
217
218 pub(super) fn tree(&self, owner: Owner) -> &TaffyTree<Option<Leaf>> {
219 match owner {
220 Owner::Top => &self.top,
221 Owner::Run(id) => &self.runs.get(id).tree,
222 }
223 }
224
225 pub(super) fn tree_mut(&mut self, owner: Owner) -> &mut TaffyTree<Option<Leaf>> {
226 match owner {
227 Owner::Top => &mut self.top,
228 Owner::Run(id) => &mut self.runs.get_mut(id).tree,
229 }
230 }
231
232 #[allow(clippy::too_many_arguments)]
236 pub(super) fn build_node(
237 &mut self,
238 tree: &mut TaffyTree<Option<Leaf>>,
239 owner: Owner,
240 inside: Option<OrderKey>,
241 node: &Node,
242 parent: Option<&Node>,
243 hugs: &mut Vec<(NodeId, bool, bool)>,
244 images: &ImageFiles,
245 order: Order,
246 ) -> NodeId {
247 let style = style_of(node, parent);
248 if let Some(leaf) = leaf_of(node, images) {
249 let id = tree.new_leaf_with_context(style, Some(leaf)).expect("leaf");
250 self.nodes.insert(order, (owner, id));
251 return id;
252 }
253 if is_run(node) {
254 let rid = self.runs.reserve();
255 let leaf = tree
258 .new_leaf_with_context(style, Some(Leaf::Run(rid)))
259 .expect("leaf");
260 let mut run = RunLayout::new(node, order.clone(), owner, leaf, inside);
261 for (k, c) in node.children.entries() {
262 self.add_child(&mut run, rid, k, c, node, images, &order);
263 }
264 self.runs.put(rid, run);
265 self.run_of.insert(order.clone(), rid);
266 self.nodes.insert(order, (owner, leaf));
267 return leaf;
268 }
269 let children: Vec<NodeId> = node
270 .children
271 .entries()
272 .map(|(k, c)| {
273 let mut o = order.clone();
274 o.push(k.clone());
275 self.build_node(tree, owner, inside.clone(), c, Some(node), hugs, images, o)
276 })
277 .collect();
278 let id = tree.new_with_children(style, &children).expect("node");
279 if let Some((w, h)) = hugs_of(node, parent) {
280 hugs.push((id, w, h));
281 }
282 self.nodes.insert(order, (owner, id));
283 id
284 }
285
286 #[allow(clippy::too_many_arguments)]
289 pub(super) fn add_child(
290 &mut self,
291 run: &mut RunLayout,
292 rid: u32,
293 k: &OrderKey,
294 child: &Node,
295 node: &Node,
296 images: &ImageFiles,
297 order: &Order,
298 ) {
299 let mut o = order.clone();
300 o.push(k.clone());
301 let mut hugs = Vec::new();
302 let mut tree = std::mem::replace(&mut run.tree, TaffyTree::new());
303 let id = self.build_node(
304 &mut tree,
305 Owner::Run(rid),
306 Some(k.clone()),
307 child,
308 Some(node),
309 &mut hugs,
310 images,
311 o,
312 );
313 run.tree = tree;
314 let across = if run.row { child.height } else { child.width };
315 run.add(k.clone(), id, across == DSize::Fill, hugs);
316 }
317
318 pub(super) fn settle_top(&mut self, r: &mut Renderer, hugs: &[(NodeId, bool, bool)]) {
321 let root = self.root;
322 r.settle_in(&mut self.runs, &mut self.top, root, Size::MAX_CONTENT, hugs);
323 }
324
325 pub(super) fn run_places(
328 &self,
329 rid: u32,
330 size: Size<f32>,
331 ) -> Option<(&RunLayout, &Asked, f32)> {
332 let run = self.runs.get(rid);
333 let (pa0, pa1) = run.padding_along();
334 let (pc0, pc1) = run.padding_across();
335 let (along, across) = if run.row {
336 (size.width, size.height)
337 } else {
338 (size.height, size.width)
339 };
340 let line = (across - pc0 - pc1).max(0.0);
341 let asked = run.placed(line)?;
342 let free = along - pa0 - pa1 - RunLayout::length(asked, run.gap) as f32;
343 Some((run, asked, pa0 + run.lead(free)))
344 }
345
346 pub(super) fn frames(&mut self, r: &mut Renderer, root: &Node) -> BTreeMap<Order, Frame> {
348 let mut out = BTreeMap::new();
349 let top = self.root;
350 self.frames_of(
351 r,
352 root,
353 Vec::new(),
354 Owner::Top,
355 top,
356 Place::default(),
357 true,
358 &mut out,
359 );
360 out
361 }
362
363 #[allow(clippy::too_many_arguments)]
364 fn frames_of(
365 &mut self,
366 r: &mut Renderer,
367 node: &Node,
368 order: Order,
369 owner: Owner,
370 id: NodeId,
371 parent: Place,
372 root: bool,
373 out: &mut BTreeMap<Order, Frame>,
374 ) {
375 let tree = self.tree(owner);
376 let (frame, place) = placed(tree, id, parent, root);
377 out.insert(order.clone(), frame);
378 if let Some(&rid) = self.run_of.get(&order) {
379 let size = tree.unrounded_layout(id).size;
380 let mut before = 0.0f64;
381 for (k, c) in node.children.entries() {
382 let Some((run, asked, lead)) = self.run_places(rid, size) else {
383 return;
384 };
385 let line = asked.line;
386 let Some(s) = asked.sizes.get(k).copied() else {
387 continue;
388 };
389 let (pc0, _) = run.padding_across();
390 let stretch = run.children[k].stretch;
391 let across = pc0 + run.across(line, &s, stretch);
392 let item = child_place(place, run.row, lead as f64 + before, across as f64);
393 let (gap, node_id) = (run.gap, run.children[k].node);
394 r.relay(&mut self.runs, rid, k, line);
395 let mut o = order.clone();
396 o.push(k.clone());
397 self.frames_of(r, c, o, Owner::Run(rid), node_id, item, false, out);
398 before += s.along as f64 + gap as f64;
399 }
400 return;
401 }
402 let kids = tree.children(id).unwrap_or_default();
403 for ((k, c), &child) in node.children.entries().zip(&kids) {
404 let mut o = order.clone();
405 o.push(k.clone());
406 self.frames_of(r, c, o, owner, child, place, false, out);
407 }
408 }
409}
410
411pub(super) fn child_place(run: Place, row: bool, along: f64, across: f64) -> Place {
416 let (along, across) = (along as f32, across as f32);
419 let (dx, dy) = if row {
420 (along, across)
421 } else {
422 (across, along)
423 };
424 let raw = (run.raw.0 + dx, run.raw.1 + dy);
425 let at = (
426 run.at.0 + snap(raw.0) - snap(run.raw.0),
427 run.at.1 + snap(raw.1) - snap(run.raw.1),
428 );
429 Place { at, raw }
430}
431
432#[cfg(test)]
436pub(super) fn build_plain(
437 tree: &mut TaffyTree<Option<Leaf>>,
438 node: &Node,
439 parent: Option<&Node>,
440 hugs: &mut Vec<(NodeId, bool, bool)>,
441 images: &ImageFiles,
442) -> NodeId {
443 let style = style_of(node, parent);
444 if let Some(leaf) = leaf_of(node, images) {
445 return tree.new_leaf_with_context(style, Some(leaf)).expect("leaf");
446 }
447 let children: Vec<NodeId> = node
448 .children
449 .iter()
450 .map(|c| build_plain(tree, c, Some(node), hugs, images))
451 .collect();
452 let id = tree.new_with_children(style, &children).expect("node");
453 if let Some((w, h)) = hugs_of(node, parent) {
454 hugs.push((id, w, h));
455 }
456 id
457}
458
459pub(super) fn hugs_of(node: &Node, parent: Option<&Node>) -> Option<(bool, bool)> {
462 if leafy(node) {
463 return None;
464 }
465 let hugs_by = |s: DSize| s == DSize::Hug || (parent.is_none() && s == DSize::Fill);
467 let (w, h) = (hugs_by(node.width), hugs_by(node.height));
468 (node.layout == Layout::None && !node.children.is_empty() && (w || h)).then_some((w, h))
469}
470
471pub(super) fn leafy(node: &Node) -> bool {
473 node.text.is_some() || node.vector.is_some() || node.image.is_some()
474}
475
476pub(super) fn leaf_of(node: &Node, images: &ImageFiles) -> Option<Leaf> {
478 if let Some(text) = &node.text {
479 let wraps = !matches!(node.width, DSize::Hug);
480 return Some(Leaf::Text(Box::new(text.clone()), wraps));
481 }
482 let intrinsic = match (&node.vector, &node.image) {
483 (Some(v), _) => Some((v.view_box[2], v.view_box[3])),
484 (_, Some(i)) => images.get(&i.id).map(|f| (f.width as f32, f.height as f32)),
485 _ => None,
486 };
487 intrinsic.map(|(w, h)| Leaf::Intrinsic(w, h))
488}
489
490pub(super) fn style_of(node: &Node, parent: Option<&Node>) -> Style {
492 let mut style = Style::default();
493 let dir = parent.map(|p| p.layout);
494 let dim = |s: DSize| match s {
495 DSize::Px(v) => Dimension::length(v),
496 _ => Dimension::auto(),
497 };
498 style.size = Size {
499 width: dim(node.width),
500 height: dim(node.height),
501 };
502 let (main, cross) = match dir {
503 Some(Layout::Row) => (node.width, node.height),
504 Some(Layout::Column) => (node.height, node.width),
505 _ => (DSize::Hug, DSize::Hug),
506 };
507 if main == DSize::Fill {
508 style.flex_grow = 1.0;
509 style.flex_basis = Dimension::length(0.0);
510 }
511 if cross == DSize::Fill {
512 style.align_self = Some(AlignSelf::STRETCH);
513 }
514 style.position = Position::Relative;
518 if dir == Some(Layout::None) {
519 style.position = Position::Absolute;
520 style.inset = taffy::Rect {
521 left: LengthPercentageAuto::length(node.x),
522 top: LengthPercentageAuto::length(node.y),
523 right: LengthPercentageAuto::auto(),
524 bottom: LengthPercentageAuto::auto(),
525 };
526 }
527 style.flex_shrink = 0.0;
528 match node.layout {
529 Layout::Row => style.flex_direction = FlexDirection::Row,
530 Layout::Column => style.flex_direction = FlexDirection::Column,
531 Layout::None => {}
532 }
533 style.gap = Size {
534 width: LengthPercentage::length(node.gap),
535 height: LengthPercentage::length(node.gap),
536 };
537 let [t, r, b, l] = node.padding;
538 style.padding = taffy::Rect {
539 top: LengthPercentage::length(t),
540 right: LengthPercentage::length(r),
541 bottom: LengthPercentage::length(b),
542 left: LengthPercentage::length(l),
543 };
544 style.align_items = match node.align {
545 Align::Center => AlignItems::CENTER,
546 Align::End => AlignItems::FLEX_END,
547 _ => AlignItems::FLEX_START,
548 };
549 style.justify_content = match node.justify {
550 Align::Center => JustifyContent::CENTER,
551 Align::End => JustifyContent::FLEX_END,
552 Align::SpaceBetween => JustifyContent::SPACE_BETWEEN,
553 Align::Start => JustifyContent::FLEX_START,
554 };
555 style
556}
557
558#[cfg(test)]
559mod tests;
560
561pub(super) fn snap(v: f32) -> f32 {
563 (v + 0.5).floor()
564}
565
566#[derive(Clone, Copy, Debug, Default)]
572pub(super) struct Place {
573 pub(super) at: (f32, f32),
574 pub(super) raw: (f32, f32),
575}
576
577pub(super) fn placed(
583 tree: &TaffyTree<Option<Leaf>>,
584 id: NodeId,
585 parent: Place,
586 _root: bool,
587) -> (Frame, Place) {
588 let l = tree.unrounded_layout(id);
589 let base = parent.raw;
590 let (x, y) = (base.0 + l.location.x, base.1 + l.location.y);
591 let frame = Frame {
592 x: parent.at.0 + snap(x) - snap(base.0),
593 y: parent.at.1 + snap(y) - snap(base.1),
594 width: snap(x + l.size.width) - snap(x),
595 height: snap(y + l.size.height) - snap(y),
596 };
597 let place = Place {
598 at: (frame.x, frame.y),
599 raw: (x, y),
600 };
601 (frame, place)
602}