1use crate::{
2 AbsoluteLength, App, Bounds, DefiniteLength, Display, Edges, GridTemplate, InlineContent,
3 LayoutDirection, Length, Pixels, Point, Position, ResolvedDirection, SharedString, Size, Style,
4 UnicodeBidi, VerticalAlign, Window, size,
5 util::{
6 ceil_to_device_pixel, round_half_toward_zero, round_stroke_to_device_pixel,
7 round_to_device_pixel,
8 },
9};
10use std::{
11 any::Any,
12 cell::{Cell, OnceCell, RefCell},
13 fmt::Debug,
14 ops::Range,
15 rc::Rc,
16 sync::Arc,
17};
18use taffy::{
19 BlockContext, Cache, CacheTree, Layout, LayoutBlockContainer, LayoutFlexboxContainer,
20 LayoutGridContainer, LayoutInput, LayoutOutput, LayoutPartialTree, RunMode,
21 TraversePartialTree, compute_block_layout, compute_cached_layout, compute_flexbox_layout,
22 compute_grid_layout, compute_hidden_layout, compute_leaf_layout, compute_root_layout,
23 geometry::{Point as TaffyPoint, Rect as TaffyRect, Size as TaffySize},
24 prelude::{max_content, min_content},
25 style::AvailableSpace as TaffyAvailableSpace,
26 tree::NodeId,
27};
28
29#[cfg(feature = "stacker")]
30type StackSafe<T> = stacksafe::StackSafe<T>;
31#[cfg(not(feature = "stacker"))]
32type StackSafe<T> = T;
33
34type MeasureFn =
35 dyn FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>;
36type NodeMeasureFn = StackSafe<Box<MeasureFn>>;
37
38pub(crate) trait MeasureKey: Any {
42 fn same(&self, previous: &dyn MeasureKey) -> bool;
44
45 fn inherit(&self, _previous: &dyn MeasureKey) -> bool {
48 false
49 }
50
51 fn as_any(&self) -> &dyn Any;
52}
53
54#[derive(Clone)]
55pub(crate) struct LayoutDirectionHandle(Rc<Cell<ResolvedDirection>>);
56
57impl LayoutDirectionHandle {
58 pub(crate) fn get(&self) -> ResolvedDirection {
59 self.0.get()
60 }
61}
62
63struct DirectionMetadata {
64 authored: LayoutDirection,
65 unicode_bidi: UnicodeBidi,
66 source_direction: Option<ResolvedDirection>,
67 auto_direction_hint: Option<ResolvedDirection>,
68 logical_children: Option<Vec<LayoutId>>,
69 resolved: ResolvedDirection,
70 handle: OnceCell<Rc<Cell<ResolvedDirection>>>,
72}
73
74enum NodeKind {
75 Plain,
76 Measured(NodeMeasureFn),
77 Proxy {
80 island: IslandId,
81 style: Option<Box<taffy::Style>>,
82 },
83}
84
85struct Node {
86 style: taffy::Style,
87 children: Vec<NodeId>,
88 parent: Option<LayoutId>,
89 cache: Cache,
90 layout: Layout,
91 kind: NodeKind,
92 vertical_align: VerticalAlign,
93 display: Display,
94 position: Position,
95 direction: DirectionMetadata,
96 inline_content: Option<Arc<InlineContent>>,
97 inline_fragments: Option<Arc<[Bounds<Pixels>]>>,
98 placed: Option<(Point<f32>, Bounds<Pixels>)>,
100 bounds: Option<(u64, Point<f32>, Bounds<Pixels>)>,
102 inherited: bool,
105 measure_key: Option<Box<dyn MeasureKey>>,
107 last_measure: Option<(Size<Option<Pixels>>, Size<AvailableSpace>)>,
109 measured: bool,
111}
112
113pub(crate) type IslandId = u32;
115
116const WINDOW_ISLAND: IslandId = 0;
118
119#[derive(Default)]
120struct Island {
121 nodes: Vec<Node>,
122 previous: Vec<Node>,
124 changed: bool,
126 root: Option<LayoutId>,
127 anchor: Option<LayoutId>,
129 resolved_with: Option<ResolvedDirection>,
131}
132
133pub(crate) struct LayoutIsland {
136 id: IslandId,
137 released: Rc<RefCell<Vec<IslandId>>>,
138}
139
140impl LayoutIsland {
141 pub(crate) fn id(&self) -> IslandId {
142 self.id
143 }
144}
145
146impl Drop for LayoutIsland {
147 fn drop(&mut self) {
148 self.released.borrow_mut().push(self.id);
149 }
150}
151
152pub struct TaffyLayoutEngine {
160 islands: Vec<Island>,
161 free_islands: Vec<IslandId>,
162 released: Rc<RefCell<Vec<IslandId>>>,
163 current: Vec<IslandId>,
164 computed_available_spaces: Vec<(LayoutId, Size<AvailableSpace>)>,
165 bounds_epoch: u64,
166 rendered: Vec<IslandId>,
168 replays: Vec<LayoutId>,
171}
172
173impl TaffyLayoutEngine {
174 pub fn new() -> Self {
176 TaffyLayoutEngine {
177 islands: vec![Island::default()],
178 free_islands: Vec::new(),
179 released: Rc::default(),
180 current: vec![WINDOW_ISLAND],
181 computed_available_spaces: Vec::new(),
182 bounds_epoch: 0,
183 rendered: Vec::new(),
184 replays: Vec::new(),
185 }
186 }
187
188 pub fn clear(&mut self) {
192 self.islands[WINDOW_ISLAND as usize] = Island::default();
193 for id in self.released.borrow_mut().drain(..) {
194 self.islands[id as usize] = Island::default();
195 self.free_islands.push(id);
196 }
197 debug_assert_eq!(self.current, [WINDOW_ISLAND]);
198 for island in self.rendered.drain(..) {
199 self.islands[island as usize].changed = false;
200 }
201 self.replays.clear();
202 self.computed_available_spaces.clear();
203 self.bounds_epoch += 1;
204 }
205
206 pub(crate) fn create_island(&mut self) -> LayoutIsland {
208 let id = self.free_islands.pop().unwrap_or_else(|| {
209 self.islands.push(Island::default());
210 (self.islands.len() - 1) as IslandId
211 });
212 LayoutIsland {
213 id,
214 released: self.released.clone(),
215 }
216 }
217
218 pub(crate) fn begin_island(&mut self, island: IslandId) {
221 let island_state = &mut self.islands[island as usize];
222 std::mem::swap(&mut island_state.previous, &mut island_state.nodes);
224 island_state.nodes.clear();
225 island_state.root = None;
226 island_state.resolved_with = None;
227 island_state.changed = true;
228 self.rendered.push(island);
229 self.current.push(island);
230 }
231
232 pub(crate) fn end_island(&mut self) {
233 if let Some(island) = self.current.pop() {
234 self.islands[island as usize].previous.clear();
235 }
236 }
237
238 pub(crate) fn set_island_root(&mut self, island: IslandId, root: LayoutId) {
239 debug_assert_eq!(root.island(), island);
240 let inherited = self.node(root).inherited;
241 let island = &mut self.islands[island as usize];
242 island.root = Some(root);
243 island.changed = !inherited;
244 }
245
246 pub(crate) fn request_island(&mut self, island: IslandId) -> LayoutId {
248 let id = self.push_node(
249 taffy::Style::default(),
250 &[],
251 NodeKind::Proxy {
252 island,
253 style: None,
254 },
255 None,
256 &Style::default(),
257 );
258 self.islands[island as usize].anchor = Some(id);
259 id
260 }
261
262 pub(crate) fn anchor_island(&mut self, island: IslandId, anchor: LayoutId) {
264 self.islands[island as usize].anchor = Some(anchor);
265 }
266
267 fn root_style(&self, island: IslandId) -> Option<&taffy::Style> {
268 let root = self.islands[island as usize].root?;
269 Some(&self.node(root).style)
270 }
271
272 fn current_island(&self) -> IslandId {
273 *self.current.last().unwrap()
274 }
275
276 fn node(&self, id: LayoutId) -> &Node {
277 &self.islands[id.island() as usize].nodes[id.index()]
278 }
279
280 fn node_mut(&mut self, id: LayoutId) -> &mut Node {
281 &mut self.islands[id.island() as usize].nodes[id.index()]
282 }
283
284 fn push_node(
285 &mut self,
286 style: taffy::Style,
287 children: &[LayoutId],
288 kind: NodeKind,
289 measure_key: Option<Box<dyn MeasureKey>>,
290 source: &Style,
291 ) -> LayoutId {
292 let island = self.current_island();
293 let index = self.islands[island as usize].nodes.len();
294 let id = LayoutId::new(island, index);
295 for child in children {
296 self.node_mut(*child).parent = Some(id);
297 }
298 self.islands[island as usize].nodes.push(Node {
299 style,
300 children: children.iter().map(|child| NodeId::from(child.0)).collect(),
301 parent: None,
302 cache: Cache::new(),
303 layout: Layout::new(),
304 kind,
305 vertical_align: source.vertical_align,
306 display: source.display,
307 position: source.position,
308 direction: DirectionMetadata {
309 authored: source.direction,
310 unicode_bidi: source.effective_unicode_bidi(),
311 source_direction: None,
312 auto_direction_hint: None,
313 logical_children: None,
314 resolved: ResolvedDirection::LeftToRight,
315 handle: OnceCell::new(),
316 },
317 inline_content: None,
318 inline_fragments: None,
319 placed: None,
320 bounds: None,
321 inherited: false,
322 measure_key,
323 last_measure: None,
324 measured: false,
325 });
326 if let Some(previous) = self.islands[island as usize].previous.get(index)
327 && self.can_inherit(self.node(id), previous)
328 {
329 let island = &mut self.islands[id.island() as usize];
330 let (node, previous) = (&mut island.nodes[index], &mut island.previous[index]);
331 node.inherited = true;
332 std::mem::swap(&mut node.cache, &mut previous.cache);
333 node.layout = previous.layout;
334 node.style.direction = previous.style.direction;
335 node.direction.resolved = previous.direction.resolved;
336 node.last_measure = previous.last_measure;
337 let measured = match (&node.measure_key, &previous.measure_key) {
338 (Some(key), Some(previous_key)) => key.inherit(previous_key.as_ref()),
339 _ => false,
340 };
341 if matches!(node.kind, NodeKind::Measured(_)) && !measured {
342 self.replays.push(id);
343 }
344 }
345 id
346 }
347
348 fn can_inherit(&self, node: &Node, previous: &Node) -> bool {
351 let same_kind = match (&node.kind, &previous.kind) {
352 (NodeKind::Plain, NodeKind::Plain) => true,
353 (NodeKind::Measured(_), NodeKind::Measured(_)) => {
354 match (&node.measure_key, &previous.measure_key) {
355 (Some(key), Some(previous_key)) => key.same(previous_key.as_ref()),
356 _ => false,
357 }
358 }
359 (
360 NodeKind::Proxy { island, .. },
361 NodeKind::Proxy {
362 island: previous_island,
363 ..
364 },
365 ) => island == previous_island && !self.islands[*island as usize].changed,
366 _ => false,
367 };
368 let same = same_kind
369 && node.children == previous.children
370 && node
371 .children
372 .iter()
373 .all(|child| self.node(LayoutId(u64::from(*child))).inherited)
374 && node.vertical_align == previous.vertical_align
375 && node.display == previous.display
376 && node.position == previous.position
377 && node.direction.authored == previous.direction.authored
378 && node.direction.unicode_bidi == previous.direction.unicode_bidi;
379 same && if node.style.direction == previous.style.direction {
381 node.style == previous.style
382 } else {
383 taffy::Style {
384 direction: previous.style.direction,
385 ..node.style.clone()
386 } == previous.style
387 }
388 }
389
390 pub fn request_layout(
395 &mut self,
396 style: Style,
397 rem_size: Pixels,
398 scale_factor: f32,
399 children: &[LayoutId],
400 ) -> LayoutId {
401 let taffy_style = style.to_taffy(rem_size, scale_factor);
402 self.push_node(taffy_style, children, NodeKind::Plain, None, &style)
403 }
404
405 pub fn request_measured_layout(
412 &mut self,
413 style: Style,
414 rem_size: Pixels,
415 scale_factor: f32,
416 measure: impl FnMut(
417 Size<Option<Pixels>>,
418 Size<AvailableSpace>,
419 &mut Window,
420 &mut App,
421 ) -> Size<Pixels>
422 + 'static,
423 ) -> LayoutId {
424 self.request_keyed_measured_layout(style, rem_size, scale_factor, None, measure)
425 }
426
427 pub(crate) fn request_keyed_measured_layout(
430 &mut self,
431 style: Style,
432 rem_size: Pixels,
433 scale_factor: f32,
434 key: Option<Box<dyn MeasureKey>>,
435 measure: impl FnMut(
436 Size<Option<Pixels>>,
437 Size<AvailableSpace>,
438 &mut Window,
439 &mut App,
440 ) -> Size<Pixels>
441 + 'static,
442 ) -> LayoutId {
443 let taffy_style = style.to_taffy(rem_size, scale_factor);
444 let measure = Box::new(measure) as Box<MeasureFn>;
445 #[cfg(feature = "stacker")]
446 let measure = StackSafe::new(measure);
447 self.push_node(taffy_style, &[], NodeKind::Measured(measure), key, &style)
448 }
449
450 pub(crate) fn set_logical_children(&mut self, node_id: LayoutId, children: &[LayoutId]) {
451 let node = self.node_mut(node_id);
452 let same = node.children.len() == children.len()
453 && node
454 .children
455 .iter()
456 .zip(children)
457 .all(|(actual, logical)| u64::from(*actual) == logical.0);
458 node.direction.logical_children = (!same).then(|| children.to_vec());
459 }
460
461 pub(crate) fn set_direction_text(&mut self, node_id: LayoutId, text: SharedString) {
462 self.node_mut(node_id).direction.source_direction =
463 ResolvedDirection::from_first_strong(&text);
464 }
465
466 pub(crate) fn set_auto_direction_hint(
467 &mut self,
468 node_id: LayoutId,
469 direction: Option<ResolvedDirection>,
470 ) {
471 self.node_mut(node_id).direction.auto_direction_hint = direction;
472 }
473
474 pub(crate) fn island_direction_contribution(
475 &self,
476 island: IslandId,
477 ) -> Option<ResolvedDirection> {
478 self.auto_direction_contribution(self.islands[island as usize].root?)
479 }
480
481 pub(crate) fn auto_direction_contribution(
482 &self,
483 node_id: LayoutId,
484 ) -> Option<ResolvedDirection> {
485 let node_id = self.through_proxy(node_id)?;
486 (self.node(node_id).direction.authored == LayoutDirection::Inherit)
487 .then(|| self.auto_direction(node_id))
488 .flatten()
489 }
490
491 pub(crate) fn direction_handle(&self, node_id: LayoutId) -> LayoutDirectionHandle {
492 let direction = &self.node(node_id).direction;
493 LayoutDirectionHandle(
494 direction
495 .handle
496 .get_or_init(|| Rc::new(Cell::new(direction.resolved)))
497 .clone(),
498 )
499 }
500
501 pub(crate) fn directionality(&self, node_id: LayoutId) -> (ResolvedDirection, UnicodeBidi) {
502 let direction = &self.node(node_id).direction;
503 (direction.resolved, direction.unicode_bidi)
504 }
505
506 fn through_proxy(&self, node_id: LayoutId) -> Option<LayoutId> {
508 match &self.node(node_id).kind {
509 NodeKind::Proxy { island, .. } => self.islands[*island as usize].root,
510 _ => Some(node_id),
511 }
512 }
513
514 fn children_of(&self, node_id: LayoutId) -> impl Iterator<Item = LayoutId> + '_ {
515 let node = self.node(node_id);
516 let logical = node.direction.logical_children.as_deref();
517 let actual = logical
518 .is_none()
519 .then(|| node.children.iter().map(|id| LayoutId(u64::from(*id))))
520 .into_iter()
521 .flatten();
522 logical.into_iter().flatten().copied().chain(actual)
523 }
524
525 fn auto_direction(&self, node_id: LayoutId) -> Option<ResolvedDirection> {
526 let direction = &self.node(node_id).direction;
527 if let Some(direction) = direction.source_direction.or(direction.auto_direction_hint) {
528 return Some(direction);
529 }
530 self.children_of(node_id)
531 .find_map(|child| self.auto_direction_contribution(child))
532 }
533
534 fn resolve_directions(
535 &mut self,
536 root_id: LayoutId,
537 inherited: ResolvedDirection,
538 ) -> Vec<LayoutId> {
539 let mut changed = Vec::new();
540 self.resolve_direction_subtree(root_id, inherited, &mut changed);
541 changed
542 }
543
544 fn resolve_direction_subtree(
545 &mut self,
546 node_id: LayoutId,
547 inherited: ResolvedDirection,
548 changed: &mut Vec<LayoutId>,
549 ) {
550 if let NodeKind::Proxy { island, .. } = self.node(node_id).kind {
551 let island = &mut self.islands[island as usize];
552 if island.resolved_with == Some(inherited) {
553 return;
554 }
555 island.resolved_with = Some(inherited);
556 if let Some(root) = island.root {
557 self.resolve_direction_subtree(root, inherited, changed);
558 }
559 return;
560 }
561
562 let resolved = match self.node(node_id).direction.authored {
563 LayoutDirection::Inherit => inherited,
564 LayoutDirection::LeftToRight => ResolvedDirection::LeftToRight,
565 LayoutDirection::RightToLeft => ResolvedDirection::RightToLeft,
566 LayoutDirection::Auto => self
567 .auto_direction(node_id)
568 .unwrap_or(ResolvedDirection::LeftToRight),
569 };
570 let taffy_direction = match resolved {
571 ResolvedDirection::LeftToRight => taffy::style::Direction::Ltr,
572 ResolvedDirection::RightToLeft => taffy::style::Direction::Rtl,
573 };
574 let node = self.node_mut(node_id);
575 if node.direction.resolved != resolved {
576 changed.push(node_id);
577 node.direction.resolved = resolved;
578 if let Some(handle) = node.direction.handle.get() {
579 handle.set(resolved);
580 }
581 }
582 if node.style.direction != taffy_direction {
583 node.style.direction = taffy_direction;
584 self.mark_dirty(node_id);
585 }
586
587 let children: smallvec::SmallVec<[LayoutId; 8]> = self.children_of(node_id).collect();
588 for child_id in children {
589 self.resolve_direction_subtree(child_id, resolved, changed);
590 }
591 }
592
593 fn mark_dirty(&mut self, mut node_id: LayoutId) {
595 loop {
596 let node = self.node_mut(node_id);
597 node.cache.clear();
598 match node.parent {
599 Some(parent) => node_id = parent,
600 None => match self.anchor_of_root(node_id) {
601 Some(anchor) => node_id = anchor,
602 None => return,
603 },
604 }
605 }
606 }
607
608 fn anchor_of_root(&self, node_id: LayoutId) -> Option<LayoutId> {
609 let island = &self.islands[node_id.island() as usize];
610 (island.root == Some(node_id))
611 .then_some(island.anchor)
612 .flatten()
613 }
614
615 pub(crate) fn vertical_align(&self, node_id: LayoutId) -> VerticalAlign {
616 self.node(node_id).vertical_align
617 }
618
619 pub(crate) fn inherited(&self, node_id: LayoutId) -> bool {
621 self.node(node_id).inherited
622 }
623
624 pub(crate) fn display_and_position(&self, node_id: LayoutId) -> (Display, Position) {
625 let node = self.node(node_id);
626 (node.display, node.position)
627 }
628
629 pub(crate) fn inline_content(&self, node_id: LayoutId) -> Option<Arc<InlineContent>> {
630 self.node(node_id).inline_content.clone()
631 }
632
633 pub(crate) fn set_inline_content(&mut self, node_id: LayoutId, content: InlineContent) {
634 self.node_mut(node_id).inline_content = Some(Arc::new(content));
635 }
636
637 pub(crate) fn inline_fragments(&self, node_id: LayoutId) -> Option<Arc<[Bounds<Pixels>]>> {
638 self.node(node_id).inline_fragments.clone()
639 }
640
641 pub(crate) fn set_inline_fragments(
642 &mut self,
643 node_id: LayoutId,
644 fragments: Arc<[Bounds<Pixels>]>,
645 ) {
646 self.node_mut(node_id).inline_fragments = Some(fragments);
647 }
648
649 pub(crate) fn place_inline(&mut self, node_id: LayoutId, bounds: Bounds<Pixels>, scale: f32) {
651 self.bounds_epoch += 1;
652 self.node_mut(node_id).placed = Some((
653 bounds.origin.map(|position| f32::from(position) * scale),
654 bounds,
655 ));
656 }
657
658 pub fn stretch_auto_size_to_fill(
665 &mut self,
666 id: LayoutId,
667 size: Size<Pixels>,
668 scale_factor: f32,
669 ) {
670 let style = match &self.node(id).kind {
671 NodeKind::Proxy { island, .. } => self.root_style(*island),
672 _ => Some(&self.node(id).style),
673 };
674 let Some(style) = style else { return };
675 let stretch_width = style.size.width.is_auto();
676 let stretch_height = style.size.height.is_auto();
677 if !stretch_width && !stretch_height {
678 return;
679 }
680 let mut style = style.clone();
681 if stretch_width {
682 style.size.width =
683 taffy::style::Dimension::length(round_to_device_pixel(size.width.0, scale_factor));
684 }
685 if stretch_height {
686 style.size.height =
687 taffy::style::Dimension::length(round_to_device_pixel(size.height.0, scale_factor));
688 }
689 let node = self.node_mut(id);
690 match &mut node.kind {
691 NodeKind::Proxy {
692 style: stretched, ..
693 } => *stretched = Some(Box::new(style)),
694 _ => node.style = style,
695 }
696 node.cache.clear();
697 }
698
699 #[cfg_attr(feature = "stacker", stacksafe::stacksafe)]
705 pub fn compute_layout(
706 &mut self,
707 id: LayoutId,
708 available_space: Size<AvailableSpace>,
709 inherited_direction: ResolvedDirection,
710 window: &mut Window,
711 cx: &mut App,
712 ) {
713 let changed_ids = self.resolve_directions(id, inherited_direction);
714 for changed_id in changed_ids {
715 if changed_id == id {
716 continue;
717 }
718 let Some(&(_, available_space)) = self
719 .computed_available_spaces
720 .iter()
721 .find(|(computed, _)| *computed == changed_id)
722 else {
723 continue;
724 };
725 self.compute_resolved_layout(changed_id, available_space, None, window, cx);
726 }
727
728 match self
729 .computed_available_spaces
730 .iter_mut()
731 .find(|(computed, _)| *computed == id)
732 {
733 Some(entry) => entry.1 = available_space,
734 None => self.computed_available_spaces.push((id, available_space)),
735 }
736 self.compute_resolved_layout(id, available_space, None, window, cx);
737 }
738
739 pub(crate) fn layout_island(
741 &mut self,
742 island: IslandId,
743 size: Size<Pixels>,
744 inherited_direction: ResolvedDirection,
745 window: &mut Window,
746 cx: &mut App,
747 ) {
748 let Some(root) = self.islands[island as usize].root else {
749 return;
750 };
751 self.islands[island as usize].resolved_with = None;
752 self.resolve_directions(root, inherited_direction);
753 let available_space = size.map(AvailableSpace::Definite);
754 self.compute_resolved_layout(root, available_space, Some(size), window, cx);
755 }
756
757 fn compute_resolved_layout(
758 &mut self,
759 id: LayoutId,
760 available_space: Size<AvailableSpace>,
761 known_size: Option<Size<Pixels>>,
762 window: &mut Window,
763 cx: &mut App,
764 ) {
765 let scale_factor = window.scale_factor();
766 let to_device = |space: AvailableSpace| match space {
767 AvailableSpace::Definite(pixels) => AvailableSpace::Definite(pixels * scale_factor),
768 other => other,
769 };
770 let available_space: TaffySize<TaffyAvailableSpace> = size(
771 to_device(available_space.width),
772 to_device(available_space.height),
773 )
774 .into();
775 self.bounds_epoch += 1;
776
777 let mut tree = LayoutTree {
778 islands: &mut self.islands,
779 window,
780 cx,
781 scale_factor,
782 };
783 match known_size {
784 None => compute_root_layout(&mut tree, id.into(), available_space),
785 Some(known) => {
786 let known = TaffySize {
787 width: Some(known.width.0 * scale_factor),
788 height: Some(known.height.0 * scale_factor),
789 };
790 let output = tree.compute_child_layout(
791 id.into(),
792 LayoutInput {
793 known_dimensions: known,
794 known_dimensions_are_definite: TaffySize {
795 width: true,
796 height: true,
797 },
798 parent_size: known,
799 available_space,
800 run_mode: RunMode::PerformLayout,
801 sizing_mode: taffy::SizingMode::InherentSize,
802 axis: taffy::RequestedAxis::Both,
803 vertical_margins_are_collapsible: taffy::Line::FALSE,
804 },
805 );
806 let node = tree.node_mut(id.into());
807 node.layout.size = output.size;
808 node.layout.location = TaffyPoint::ZERO;
809 }
810 }
811 tree.replay_measurements(&mut self.replays);
812 }
813
814 pub fn layout_bounds(&mut self, id: LayoutId, scale_factor: f32) -> Bounds<Pixels> {
894 self.absolute_layout(id, scale_factor).1
895 }
896
897 fn absolute_layout(&mut self, id: LayoutId, scale_factor: f32) -> (Point<f32>, Bounds<Pixels>) {
898 let node = self.node(id);
899 if let Some(placed) = node.placed {
900 return placed;
901 }
902 if let Some((epoch, origin, bounds)) = node.bounds
903 && epoch == self.bounds_epoch
904 {
905 return (origin, bounds);
906 }
907 let location = Point::from(node.layout.location);
908 let layout_size = node.layout.size;
909 let parent = node.parent.or_else(|| self.anchor_of_root(id));
910 let origin = match parent {
911 Some(parent) => self.absolute_layout(parent, scale_factor).0 + location,
912 None => location,
913 };
914 let far = origin + Point::from(Size::from(layout_size));
915 let snapped = Bounds::from_corners(
916 origin.map(round_half_toward_zero),
917 far.map(round_half_toward_zero),
918 );
919 let bounds = (snapped / scale_factor).map(Pixels);
920 let epoch = self.bounds_epoch;
921 self.node_mut(id).bounds = Some((epoch, origin, bounds));
922 (origin, bounds)
923 }
924
925 pub(crate) fn parent_relative_layout_bounds(
931 &mut self,
932 node_id: LayoutId,
933 scale_factor: f32,
934 ) -> Bounds<Pixels> {
935 let node = self.node(node_id);
936 if node.inline_fragments.is_some() {
937 return self.layout_bounds(node_id, scale_factor);
938 }
939 let Some(parent_id) = node.parent else {
940 return self.layout_bounds(node_id, scale_factor);
941 };
942 let local_origin = Point::from(node.layout.location).map(round_half_toward_zero);
943 let local_size = Size::from(node.layout.size).map(round_half_toward_zero);
944 let parent_bounds = self.layout_bounds(parent_id, scale_factor);
945 Bounds::new(
946 parent_bounds.origin + (local_origin / scale_factor).map(Pixels),
947 (local_size / scale_factor).map(Pixels),
948 )
949 }
950}
951
952struct LayoutTree<'a> {
954 islands: &'a mut [Island],
955 window: &'a mut Window,
956 cx: &'a mut App,
957 scale_factor: f32,
958}
959
960impl LayoutTree<'_> {
961 fn node(&self, id: NodeId) -> &Node {
962 let id = LayoutId(u64::from(id));
963 &self.islands[id.island() as usize].nodes[id.index()]
964 }
965
966 fn node_mut(&mut self, id: NodeId) -> &mut Node {
967 let id = LayoutId(u64::from(id));
968 &mut self.islands[id.island() as usize].nodes[id.index()]
969 }
970
971 fn style(&self, id: NodeId) -> &taffy::Style {
972 match &self.node(id).kind {
973 NodeKind::Proxy {
974 style: Some(style), ..
975 } => style,
976 NodeKind::Proxy { island, .. } => match self.islands[*island as usize].root {
977 Some(root) => &self.node(root.into()).style,
978 None => &self.node(id).style,
979 },
980 _ => &self.node(id).style,
981 }
982 }
983
984 fn compute_node(
985 &mut self,
986 node_id: NodeId,
987 inputs: LayoutInput,
988 block_ctx: Option<&mut BlockContext<'_>>,
989 ) -> LayoutOutput {
990 if inputs.run_mode == RunMode::PerformHiddenLayout {
991 return compute_hidden_layout(self, node_id);
992 }
993 if let NodeKind::Proxy { island, style } = &self.node(node_id).kind {
994 let Some(root) = self.islands[*island as usize].root else {
995 return LayoutOutput::HIDDEN;
996 };
997 let mut inputs = inputs;
999 if let Some(style) = style {
1000 let size = TaffySize {
1001 width: style.size.width.into_option(),
1002 height: style.size.height.into_option(),
1003 };
1004 inputs.known_dimensions = inputs.known_dimensions.or(size);
1005 }
1006 return self.compute_node(root.into(), inputs, block_ctx);
1007 }
1008 compute_cached_layout(self, node_id, inputs, |tree, node_id, inputs| {
1009 let node = tree.node(node_id);
1010 match (node.style.display, !node.children.is_empty()) {
1011 (taffy::Display::None, _) => compute_hidden_layout(tree, node_id),
1012 (taffy::Display::Block, true) => {
1013 compute_block_layout(tree, node_id, inputs, block_ctx)
1014 }
1015 (taffy::Display::FlowRoot, true) => {
1016 compute_block_layout(tree, node_id, inputs, None)
1017 }
1018 (taffy::Display::Flex, true) => compute_flexbox_layout(tree, node_id, inputs),
1019 (taffy::Display::Grid, true) => compute_grid_layout(tree, node_id, inputs),
1020 (_, false) => tree.compute_leaf(node_id, inputs),
1021 }
1022 })
1023 }
1024
1025 fn compute_leaf(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
1026 let scale_factor = self.scale_factor;
1027 let id = LayoutId(u64::from(node_id));
1028 let Node {
1029 style,
1030 kind,
1031 direction,
1032 last_measure,
1033 measured,
1034 ..
1035 } = &mut self.islands[id.island() as usize].nodes[id.index()];
1036 let NodeKind::Measured(measure) = kind else {
1037 return compute_leaf_layout(inputs, style, |_, _| 0.0, |_, _| TaffySize::ZERO);
1038 };
1039 let unicode_bidi = direction.unicode_bidi;
1040 let window = &mut *self.window;
1041 let cx = &mut *self.cx;
1042 compute_leaf_layout(
1043 inputs,
1044 style,
1045 |_, _| 0.0,
1046 |known, available| {
1047 let known = Size {
1048 width: known.width.map(|e| Pixels(e / scale_factor)),
1049 height: known.height.map(|e| Pixels(e / scale_factor)),
1050 };
1051 let from_device = |space: AvailableSpace| match space {
1052 AvailableSpace::Definite(pixels) => {
1053 AvailableSpace::Definite(Pixels(pixels.0 / scale_factor))
1054 }
1055 other => other,
1056 };
1057 let available: Size<AvailableSpace> = available.into();
1058 let available = size(from_device(available.width), from_device(available.height));
1059 *last_measure = Some((known, available));
1060 *measured = true;
1061 let size = call_measure(
1062 measure,
1063 style.direction,
1064 unicode_bidi,
1065 known,
1066 available,
1067 window,
1068 cx,
1069 );
1070 snap_measured_size_to_device_pixels(size, scale_factor).into()
1071 },
1072 )
1073 }
1074}
1075
1076fn call_measure(
1078 measure: &mut NodeMeasureFn,
1079 direction: taffy::style::Direction,
1080 unicode_bidi: UnicodeBidi,
1081 known: Size<Option<Pixels>>,
1082 available: Size<AvailableSpace>,
1083 window: &mut Window,
1084 cx: &mut App,
1085) -> Size<Pixels> {
1086 let direction = match direction {
1087 taffy::style::Direction::Ltr => ResolvedDirection::LeftToRight,
1088 taffy::style::Direction::Rtl => ResolvedDirection::RightToLeft,
1089 };
1090 let previous_direction = std::mem::replace(&mut window.measurement_direction, direction);
1091 let previous_unicode_bidi =
1092 std::mem::replace(&mut window.measurement_unicode_bidi, unicode_bidi);
1093 let size = measure(known, available, window, cx);
1094 window.measurement_direction = previous_direction;
1095 window.measurement_unicode_bidi = previous_unicode_bidi;
1096 size
1097}
1098
1099impl LayoutTree<'_> {
1100 fn replay_measurements(&mut self, replays: &mut Vec<LayoutId>) {
1103 for id in replays.drain(..) {
1104 let Some(Node {
1105 style,
1106 kind: NodeKind::Measured(measure),
1107 direction,
1108 last_measure: Some((known, available)),
1109 measured,
1110 inherited: true,
1111 ..
1112 }) = self.islands[id.island() as usize].nodes.get_mut(id.index())
1113 else {
1114 continue;
1115 };
1116 if *measured {
1117 continue;
1118 }
1119 *measured = true;
1120 call_measure(
1121 measure,
1122 style.direction,
1123 direction.unicode_bidi,
1124 *known,
1125 *available,
1126 self.window,
1127 self.cx,
1128 );
1129 }
1130 }
1131}
1132
1133impl TraversePartialTree for LayoutTree<'_> {
1134 type ChildIter<'a>
1135 = std::iter::Copied<std::slice::Iter<'a, NodeId>>
1136 where
1137 Self: 'a;
1138
1139 fn child_ids(&self, parent: NodeId) -> Self::ChildIter<'_> {
1140 self.node(parent).children.iter().copied()
1141 }
1142
1143 fn child_count(&self, parent: NodeId) -> usize {
1144 self.node(parent).children.len()
1145 }
1146
1147 fn get_child_id(&self, parent: NodeId, index: usize) -> NodeId {
1148 self.node(parent).children[index]
1149 }
1150}
1151
1152impl LayoutPartialTree for LayoutTree<'_> {
1153 type CoreContainerStyle<'a>
1154 = &'a taffy::Style
1155 where
1156 Self: 'a;
1157
1158 type CustomIdent = String;
1159
1160 fn get_core_container_style(&self, node_id: NodeId) -> Self::CoreContainerStyle<'_> {
1161 self.style(node_id)
1162 }
1163
1164 fn set_unrounded_layout(&mut self, node_id: NodeId, layout: &Layout) {
1165 self.node_mut(node_id).layout = *layout;
1166 if let NodeKind::Proxy { island, .. } = self.node(node_id).kind
1167 && let Some(root) = self.islands[island as usize].root
1168 {
1169 self.node_mut(root.into()).layout = Layout {
1170 location: TaffyPoint::ZERO,
1171 ..*layout
1172 };
1173 }
1174 }
1175
1176 fn resolve_calc_value(&self, _val: *const (), _basis: f32) -> f32 {
1177 0.0
1178 }
1179
1180 fn compute_child_layout(&mut self, node_id: NodeId, inputs: LayoutInput) -> LayoutOutput {
1181 self.compute_node(node_id, inputs, None)
1182 }
1183}
1184
1185impl CacheTree for LayoutTree<'_> {
1186 fn cache_get(&mut self, node_id: NodeId, input: &LayoutInput) -> Option<LayoutOutput> {
1187 self.node_mut(node_id).cache.get(input)
1188 }
1189
1190 fn cache_store(&mut self, node_id: NodeId, input: &LayoutInput, output: LayoutOutput) {
1191 self.node_mut(node_id).cache.store(input, output)
1192 }
1193
1194 fn cache_clear(&mut self, node_id: NodeId) {
1195 self.node_mut(node_id).cache.clear();
1196 }
1197}
1198
1199impl LayoutBlockContainer for LayoutTree<'_> {
1200 type BlockContainerStyle<'a>
1201 = &'a taffy::Style
1202 where
1203 Self: 'a;
1204 type BlockItemStyle<'a>
1205 = &'a taffy::Style
1206 where
1207 Self: 'a;
1208
1209 fn get_block_container_style(&self, node_id: NodeId) -> Self::BlockContainerStyle<'_> {
1210 self.style(node_id)
1211 }
1212
1213 fn get_block_child_style(&self, child_node_id: NodeId) -> Self::BlockItemStyle<'_> {
1214 self.style(child_node_id)
1215 }
1216
1217 fn compute_block_child_layout(
1218 &mut self,
1219 node_id: NodeId,
1220 inputs: LayoutInput,
1221 block_ctx: Option<&mut BlockContext<'_>>,
1222 ) -> LayoutOutput {
1223 self.compute_node(node_id, inputs, block_ctx)
1224 }
1225}
1226
1227impl LayoutFlexboxContainer for LayoutTree<'_> {
1228 type FlexboxContainerStyle<'a>
1229 = &'a taffy::Style
1230 where
1231 Self: 'a;
1232 type FlexboxItemStyle<'a>
1233 = &'a taffy::Style
1234 where
1235 Self: 'a;
1236
1237 fn get_flexbox_container_style(&self, node_id: NodeId) -> Self::FlexboxContainerStyle<'_> {
1238 self.style(node_id)
1239 }
1240
1241 fn get_flexbox_child_style(&self, child_node_id: NodeId) -> Self::FlexboxItemStyle<'_> {
1242 self.style(child_node_id)
1243 }
1244}
1245
1246impl LayoutGridContainer for LayoutTree<'_> {
1247 type GridContainerStyle<'a>
1248 = &'a taffy::Style
1249 where
1250 Self: 'a;
1251 type GridItemStyle<'a>
1252 = &'a taffy::Style
1253 where
1254 Self: 'a;
1255
1256 fn get_grid_container_style(&self, node_id: NodeId) -> Self::GridContainerStyle<'_> {
1257 self.style(node_id)
1258 }
1259
1260 fn get_grid_child_style(&self, child_node_id: NodeId) -> Self::GridItemStyle<'_> {
1261 self.style(child_node_id)
1262 }
1263}
1264
1265#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
1271pub struct LayoutId(u64);
1272
1273impl LayoutId {
1274 fn new(island: IslandId, index: usize) -> Self {
1275 Self((u64::from(island) << 32) | index as u64)
1276 }
1277
1278 pub(crate) fn island(self) -> IslandId {
1279 (self.0 >> 32) as IslandId
1280 }
1281
1282 fn index(self) -> usize {
1283 self.0 as u32 as usize
1284 }
1285}
1286
1287impl From<LayoutId> for NodeId {
1288 fn from(layout_id: LayoutId) -> NodeId {
1289 NodeId::from(layout_id.0)
1290 }
1291}
1292
1293fn snap_measured_size_to_device_pixels(size: Size<Pixels>, scale_factor: f32) -> Size<f32> {
1294 size.map(|d| ceil_to_device_pixel(d.0.max(0.0), scale_factor))
1295}
1296
1297fn border_widths_to_taffy(
1298 widths: &Edges<AbsoluteLength>,
1299 rem_size: Pixels,
1300 scale_factor: f32,
1301) -> TaffyRect<taffy::style::LengthPercentage> {
1302 let snap = |w: &AbsoluteLength| {
1303 taffy::style::LengthPercentage::length(round_stroke_to_device_pixel(
1304 w.to_pixels(rem_size).0,
1305 scale_factor,
1306 ))
1307 };
1308 TaffyRect {
1309 top: snap(&widths.top),
1310 right: snap(&widths.right),
1311 bottom: snap(&widths.bottom),
1312 left: snap(&widths.left),
1313 }
1314}
1315
1316fn padding_to_taffy(
1318 padding: &Edges<DefiniteLength>,
1319 rem_size: Pixels,
1320 scale_factor: f32,
1321 proportional_horizontal: bool,
1322 proportional_vertical: bool,
1323) -> TaffyRect<taffy::style::LengthPercentage> {
1324 fn snap_absolute_pair(
1326 first: AbsoluteLength,
1327 second: AbsoluteLength,
1328 rem_size: Pixels,
1329 scale_factor: f32,
1330 ) -> (f32, f32) {
1331 let first = first.to_pixels(rem_size).0;
1332 let second = second.to_pixels(rem_size).0;
1333 let total = first + second;
1334
1335 if first < 0.0 || second < 0.0 || total == 0.0 {
1336 return (
1337 round_to_device_pixel(first, scale_factor),
1338 round_to_device_pixel(second, scale_factor),
1339 );
1340 }
1341
1342 let snapped_total = round_to_device_pixel(total, scale_factor);
1343 let snapped_first = snapped_total * (first / total);
1344
1345 (snapped_first, snapped_total - snapped_first)
1346 }
1347
1348 fn convert_pair(
1350 first: &DefiniteLength,
1351 second: &DefiniteLength,
1352 rem_size: Pixels,
1353 scale_factor: f32,
1354 proportional: bool,
1355 ) -> (
1356 taffy::style::LengthPercentage,
1357 taffy::style::LengthPercentage,
1358 ) {
1359 if proportional
1360 && let (DefiniteLength::Absolute(first), DefiniteLength::Absolute(second)) =
1361 (*first, *second)
1362 {
1363 let (first, second) = snap_absolute_pair(first, second, rem_size, scale_factor);
1364
1365 (
1366 taffy::style::LengthPercentage::length(first),
1367 taffy::style::LengthPercentage::length(second),
1368 )
1369 } else {
1370 (
1371 first.to_taffy(rem_size, scale_factor),
1372 second.to_taffy(rem_size, scale_factor),
1373 )
1374 }
1375 }
1376
1377 let (left, right) = convert_pair(
1378 &padding.left,
1379 &padding.right,
1380 rem_size,
1381 scale_factor,
1382 proportional_horizontal,
1383 );
1384 let (top, bottom) = convert_pair(
1385 &padding.top,
1386 &padding.bottom,
1387 rem_size,
1388 scale_factor,
1389 proportional_vertical,
1390 );
1391
1392 TaffyRect {
1393 top,
1394 right,
1395 bottom,
1396 left,
1397 }
1398}
1399
1400trait ToTaffy<Output> {
1401 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> Output;
1402}
1403
1404impl ToTaffy<taffy::style::Style> for Style {
1405 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::Style {
1406 use taffy::style_helpers::{fr, length, minmax, repeat};
1407
1408 fn to_grid_line(
1409 placement: &Range<crate::GridPlacement>,
1410 ) -> taffy::Line<taffy::GridPlacement> {
1411 taffy::Line {
1412 start: placement.start.into(),
1413 end: placement.end.into(),
1414 }
1415 }
1416
1417 fn to_grid_repeat<T: taffy::style::CheapCloneStr>(
1418 unit: &Option<GridTemplate>,
1419 ) -> Vec<taffy::GridTemplateComponent<T>> {
1420 unit.map(|template| {
1421 match template.min_size {
1422 crate::GridTemplateMinSize::Zero => {
1424 vec![repeat(
1425 template.repeat,
1426 vec![minmax(length(0.0_f32), fr(1.0_f32))],
1427 )]
1428 }
1429 crate::GridTemplateMinSize::MinContent => {
1431 vec![repeat(
1432 template.repeat,
1433 vec![minmax(min_content(), fr(1.0_f32))],
1434 )]
1435 }
1436 crate::GridTemplateMinSize::MaxContent => {
1438 vec![repeat(
1439 template.repeat,
1440 vec![minmax(length(0.0_f32), max_content())],
1441 )]
1442 }
1443 }
1444 })
1445 .unwrap_or_default()
1446 }
1447
1448 taffy::style::Style {
1449 display: self.display.into(),
1450 direction: taffy::style::Direction::Ltr,
1451 overflow: self.overflow.into(),
1452 scrollbar_width: self.scrollbar_width.to_taffy(rem_size, scale_factor),
1453 position: self.position.into(),
1454 inset: self.inset.to_taffy(rem_size, scale_factor),
1455 size: self.size.to_taffy(rem_size, scale_factor),
1456 min_size: self.min_size.to_taffy(rem_size, scale_factor),
1457 max_size: self.max_size.to_taffy(rem_size, scale_factor),
1458 aspect_ratio: self.aspect_ratio,
1459 margin: self.margin.to_taffy(rem_size, scale_factor),
1460 padding: padding_to_taffy(
1461 &self.padding,
1462 rem_size,
1463 scale_factor,
1464 self.size.width == Length::Auto,
1465 self.size.height == Length::Auto,
1466 ),
1467 border: border_widths_to_taffy(&self.border_widths, rem_size, scale_factor),
1468 align_items: self.align_items.map(|x| x.into()),
1469 align_self: self.align_self.map(|x| x.into()),
1470 align_content: self.align_content.map(|x| x.into()),
1471 justify_content: self.justify_content.map(|x| x.into()),
1472 gap: self.gap.to_taffy(rem_size, scale_factor),
1473 flex_direction: self.flex_direction.into(),
1474 flex_wrap: self.flex_wrap.into(),
1475 flex_basis: self.flex_basis.to_taffy(rem_size, scale_factor),
1476 flex_grow: self.flex_grow,
1477 flex_shrink: self.flex_shrink,
1478 grid_template_rows: to_grid_repeat(&self.grid_rows),
1479 grid_template_columns: to_grid_repeat(&self.grid_cols),
1480 grid_row: self
1481 .grid_location
1482 .as_ref()
1483 .map(|location| to_grid_line(&location.row))
1484 .unwrap_or_default(),
1485 grid_column: self
1486 .grid_location
1487 .as_ref()
1488 .map(|location| to_grid_line(&location.column))
1489 .unwrap_or_default(),
1490 ..Default::default()
1491 }
1492 }
1493}
1494
1495impl ToTaffy<f32> for AbsoluteLength {
1496 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> f32 {
1497 round_to_device_pixel(self.to_pixels(rem_size).0, scale_factor)
1498 }
1499}
1500
1501impl ToTaffy<taffy::style::LengthPercentageAuto> for Length {
1502 fn to_taffy(
1503 &self,
1504 rem_size: Pixels,
1505 scale_factor: f32,
1506 ) -> taffy::prelude::LengthPercentageAuto {
1507 match self {
1508 Length::Definite(length) => length.to_taffy(rem_size, scale_factor),
1509 Length::Auto => taffy::prelude::LengthPercentageAuto::auto(),
1510 }
1511 }
1512}
1513
1514impl ToTaffy<taffy::style::Dimension> for Length {
1515 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::prelude::Dimension {
1516 match self {
1517 Length::Definite(length) => length.to_taffy(rem_size, scale_factor),
1518 Length::Auto => taffy::prelude::Dimension::auto(),
1519 }
1520 }
1521}
1522
1523impl ToTaffy<taffy::style::LengthPercentage> for DefiniteLength {
1524 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentage {
1525 match self {
1526 DefiniteLength::Absolute(length) => length.to_taffy(rem_size, scale_factor),
1527 DefiniteLength::Relative(relative) => {
1528 taffy::style::LengthPercentage::percent(relative.0)
1529 }
1530 }
1531 }
1532}
1533
1534impl ToTaffy<taffy::style::LengthPercentageAuto> for DefiniteLength {
1535 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentageAuto {
1536 match self {
1537 DefiniteLength::Absolute(length) => length.to_taffy(rem_size, scale_factor),
1538 DefiniteLength::Relative(relative) => {
1539 taffy::style::LengthPercentageAuto::percent(relative.0)
1540 }
1541 }
1542 }
1543}
1544
1545impl ToTaffy<taffy::style::Dimension> for DefiniteLength {
1546 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::Dimension {
1547 match self {
1548 DefiniteLength::Absolute(length) => length.to_taffy(rem_size, scale_factor),
1549 DefiniteLength::Relative(relative) => taffy::style::Dimension::percent(relative.0),
1550 }
1551 }
1552}
1553
1554impl ToTaffy<taffy::style::LengthPercentage> for AbsoluteLength {
1555 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentage {
1556 taffy::style::LengthPercentage::length(self.to_taffy(rem_size, scale_factor))
1557 }
1558}
1559
1560impl ToTaffy<taffy::style::LengthPercentageAuto> for AbsoluteLength {
1561 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::LengthPercentageAuto {
1562 taffy::style::LengthPercentageAuto::length(self.to_taffy(rem_size, scale_factor))
1563 }
1564}
1565
1566impl ToTaffy<taffy::style::Dimension> for AbsoluteLength {
1567 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> taffy::style::Dimension {
1568 taffy::style::Dimension::length(self.to_taffy(rem_size, scale_factor))
1569 }
1570}
1571
1572impl<T, T2> From<TaffyPoint<T>> for Point<T2>
1573where
1574 T: Into<T2>,
1575 T2: Clone + Debug + Default + PartialEq,
1576{
1577 fn from(point: TaffyPoint<T>) -> Point<T2> {
1578 Point {
1579 x: point.x.into(),
1580 y: point.y.into(),
1581 }
1582 }
1583}
1584
1585impl<T, T2> From<Point<T>> for TaffyPoint<T2>
1586where
1587 T: Into<T2> + Clone + Debug + Default + PartialEq,
1588{
1589 fn from(val: Point<T>) -> Self {
1590 TaffyPoint {
1591 x: val.x.into(),
1592 y: val.y.into(),
1593 }
1594 }
1595}
1596
1597impl<T, U> ToTaffy<TaffySize<U>> for Size<T>
1598where
1599 T: ToTaffy<U> + Clone + Debug + Default + PartialEq,
1600{
1601 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> TaffySize<U> {
1602 TaffySize {
1603 width: self.width.to_taffy(rem_size, scale_factor),
1604 height: self.height.to_taffy(rem_size, scale_factor),
1605 }
1606 }
1607}
1608
1609impl<T, U> ToTaffy<TaffyRect<U>> for Edges<T>
1610where
1611 T: ToTaffy<U> + Clone + Debug + Default + PartialEq,
1612{
1613 fn to_taffy(&self, rem_size: Pixels, scale_factor: f32) -> TaffyRect<U> {
1614 TaffyRect {
1615 top: self.top.to_taffy(rem_size, scale_factor),
1616 right: self.right.to_taffy(rem_size, scale_factor),
1617 bottom: self.bottom.to_taffy(rem_size, scale_factor),
1618 left: self.left.to_taffy(rem_size, scale_factor),
1619 }
1620 }
1621}
1622
1623impl<T, U> From<TaffySize<T>> for Size<U>
1624where
1625 T: Into<U>,
1626 U: Clone + Debug + Default + PartialEq,
1627{
1628 fn from(taffy_size: TaffySize<T>) -> Self {
1629 Size {
1630 width: taffy_size.width.into(),
1631 height: taffy_size.height.into(),
1632 }
1633 }
1634}
1635
1636impl<T, U> From<Size<T>> for TaffySize<U>
1637where
1638 T: Into<U> + Clone + Debug + Default + PartialEq,
1639{
1640 fn from(size: Size<T>) -> Self {
1641 TaffySize {
1642 width: size.width.into(),
1643 height: size.height.into(),
1644 }
1645 }
1646}
1647
1648#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
1654pub enum AvailableSpace {
1655 Definite(Pixels),
1657 #[default]
1659 MinContent,
1660 MaxContent,
1662}
1663
1664impl AvailableSpace {
1665 pub const fn min_size() -> Size<Self> {
1678 Size {
1679 width: Self::MinContent,
1680 height: Self::MinContent,
1681 }
1682 }
1683}
1684
1685impl From<AvailableSpace> for TaffyAvailableSpace {
1686 fn from(space: AvailableSpace) -> TaffyAvailableSpace {
1687 match space {
1688 AvailableSpace::Definite(Pixels(value)) => TaffyAvailableSpace::Definite(value),
1689 AvailableSpace::MinContent => TaffyAvailableSpace::MinContent,
1690 AvailableSpace::MaxContent => TaffyAvailableSpace::MaxContent,
1691 }
1692 }
1693}
1694
1695impl From<TaffyAvailableSpace> for AvailableSpace {
1696 fn from(space: TaffyAvailableSpace) -> AvailableSpace {
1697 match space {
1698 TaffyAvailableSpace::Definite(value) => AvailableSpace::Definite(Pixels(value)),
1699 TaffyAvailableSpace::MinContent => AvailableSpace::MinContent,
1700 TaffyAvailableSpace::MaxContent => AvailableSpace::MaxContent,
1701 }
1702 }
1703}
1704
1705impl From<Pixels> for AvailableSpace {
1706 fn from(pixels: Pixels) -> Self {
1707 AvailableSpace::Definite(pixels)
1708 }
1709}
1710
1711impl From<Size<Pixels>> for Size<AvailableSpace> {
1712 fn from(size: Size<Pixels>) -> Self {
1713 Size {
1714 width: AvailableSpace::Definite(size.width),
1715 height: AvailableSpace::Definite(size.height),
1716 }
1717 }
1718}
1719
1720#[cfg(test)]
1721mod tests {
1722 use super::*;
1723 use crate::px;
1724
1725 fn direction_style(direction: LayoutDirection) -> Style {
1726 Style {
1727 direction,
1728 ..Default::default()
1729 }
1730 }
1731
1732 #[test]
1733 fn direction_defaults_to_ltr_and_inherits_through_overrides() {
1734 let mut engine = TaffyLayoutEngine::new();
1735 let inherited_grandchild = engine.request_layout(
1736 direction_style(LayoutDirection::Inherit),
1737 px(16.0),
1738 1.0,
1739 &[],
1740 );
1741 let rtl_child = engine.request_layout(
1742 direction_style(LayoutDirection::RightToLeft),
1743 px(16.0),
1744 1.0,
1745 &[inherited_grandchild],
1746 );
1747 let root = engine.request_layout(
1748 direction_style(LayoutDirection::Inherit),
1749 px(16.0),
1750 1.0,
1751 &[rtl_child],
1752 );
1753
1754 let _ = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1755
1756 assert_eq!(
1757 engine.direction_handle(root).get(),
1758 ResolvedDirection::LeftToRight
1759 );
1760 assert_eq!(
1761 engine.direction_handle(rtl_child).get(),
1762 ResolvedDirection::RightToLeft
1763 );
1764 assert_eq!(
1765 engine.node(rtl_child).style.direction,
1766 taffy::style::Direction::Rtl
1767 );
1768 assert_eq!(
1769 engine.direction_handle(inherited_grandchild).get(),
1770 ResolvedDirection::RightToLeft
1771 );
1772 }
1773
1774 #[test]
1775 fn auto_direction_uses_first_eligible_strong_descendant() {
1776 let mut engine = TaffyLayoutEngine::new();
1777 let neutral = engine.request_layout(
1778 direction_style(LayoutDirection::Inherit),
1779 px(16.0),
1780 1.0,
1781 &[],
1782 );
1783 engine.set_direction_text(neutral, "123 …".into());
1784 let arabic = engine.request_layout(
1785 direction_style(LayoutDirection::Inherit),
1786 px(16.0),
1787 1.0,
1788 &[],
1789 );
1790 engine.set_direction_text(arabic, "مرحبا".into());
1791 let root = engine.request_layout(
1792 direction_style(LayoutDirection::Auto),
1793 px(16.0),
1794 1.0,
1795 &[neutral, arabic],
1796 );
1797
1798 let _ = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1799
1800 assert_eq!(
1801 engine.direction_handle(root).get(),
1802 ResolvedDirection::RightToLeft
1803 );
1804 assert_eq!(
1805 engine.direction_handle(neutral).get(),
1806 ResolvedDirection::RightToLeft
1807 );
1808 }
1809
1810 #[test]
1811 fn auto_direction_excludes_directional_subtrees_and_falls_back_to_ltr() {
1812 let mut engine = TaffyLayoutEngine::new();
1813 let explicit_child = engine.request_layout(
1814 direction_style(LayoutDirection::RightToLeft),
1815 px(16.0),
1816 1.0,
1817 &[],
1818 );
1819 engine.set_direction_text(explicit_child, "مرحبا".into());
1820 let root = engine.request_layout(
1821 direction_style(LayoutDirection::Auto),
1822 px(16.0),
1823 1.0,
1824 &[explicit_child],
1825 );
1826
1827 let _ = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1828
1829 assert_eq!(
1830 engine.direction_handle(root).get(),
1831 ResolvedDirection::LeftToRight
1832 );
1833 assert_eq!(
1834 engine.direction_handle(explicit_child).get(),
1835 ResolvedDirection::RightToLeft
1836 );
1837 }
1838
1839 #[test]
1840 fn auto_direction_updates_when_source_text_changes() {
1841 let mut engine = TaffyLayoutEngine::new();
1842 let text = engine.request_layout(
1843 direction_style(LayoutDirection::Inherit),
1844 px(16.0),
1845 1.0,
1846 &[],
1847 );
1848 let root = engine.request_layout(
1849 direction_style(LayoutDirection::Auto),
1850 px(16.0),
1851 1.0,
1852 &[text],
1853 );
1854 engine.set_direction_text(text, "English".into());
1855 let _ = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1856 assert_eq!(
1857 engine.direction_handle(root).get(),
1858 ResolvedDirection::LeftToRight
1859 );
1860
1861 engine.set_direction_text(text, "مرحبا".into());
1862 let changed = engine.resolve_directions(root, ResolvedDirection::LeftToRight);
1863 assert!(changed.contains(&root));
1864 assert_eq!(
1865 engine.direction_handle(root).get(),
1866 ResolvedDirection::RightToLeft
1867 );
1868 }
1869
1870 #[test]
1871 fn auto_sized_axes_snap_padding_proportionally() {
1872 use taffy::style::LengthPercentage;
1873
1874 let mut style = Style {
1875 padding: Edges {
1876 top: Pixels(6.5).into(),
1877 right: Pixels(5.0).into(),
1878 bottom: Pixels(6.5).into(),
1879 left: Pixels(2.5).into(),
1880 },
1881 ..Default::default()
1882 };
1883
1884 let padding = style.to_taffy(Pixels(16.0), 1.0).padding;
1885 let expected_left = 7.0 * (2.5 / 7.5);
1886 assert_eq!(padding.left, LengthPercentage::length(expected_left));
1887 assert_eq!(padding.right, LengthPercentage::length(7.0 - expected_left));
1888 assert_eq!(padding.top, LengthPercentage::length(6.5));
1889 assert_eq!(padding.bottom, LengthPercentage::length(6.5));
1890
1891 style.size.width = Length::Definite(Pixels(100.0).into());
1892 let padding = style.to_taffy(Pixels(16.0), 1.0).padding;
1893 assert_eq!(padding.left, LengthPercentage::length(2.0));
1894 assert_eq!(padding.right, LengthPercentage::length(5.0));
1895 assert_eq!(padding.top, LengthPercentage::length(6.5));
1896 assert_eq!(padding.bottom, LengthPercentage::length(6.5));
1897
1898 style.size.width = Length::Auto;
1899 style.padding.top = Pixels(6.75).into();
1900 style.padding.bottom = Pixels(6.75).into();
1901 let padding = style.to_taffy(Pixels(16.0), 2.0).padding;
1902 assert_eq!(padding.top, LengthPercentage::length(13.5));
1903 assert_eq!(padding.bottom, LengthPercentage::length(13.5));
1904 }
1905
1906 #[test]
1907 fn border_widths_to_taffy_use_stroke_snapping() {
1908 let border_widths = Edges {
1909 top: Pixels(0.0).into(),
1910 right: Pixels(0.4).into(),
1911 bottom: Pixels(0.5).into(),
1912 left: Pixels(1.6).into(),
1913 };
1914 let taffy_border = border_widths_to_taffy(&border_widths, Pixels(16.0), 1.0);
1915
1916 assert_eq!(
1917 taffy_border.top,
1918 taffy::style::LengthPercentage::length(0.0)
1919 );
1920 assert_eq!(
1921 taffy_border.right,
1922 taffy::style::LengthPercentage::length(1.0)
1923 );
1924 assert_eq!(
1925 taffy_border.bottom,
1926 taffy::style::LengthPercentage::length(1.0)
1927 );
1928 assert_eq!(
1929 taffy_border.left,
1930 taffy::style::LengthPercentage::length(2.0)
1931 );
1932 }
1933
1934 struct Measured {
1935 key: u32,
1936 calls: Rc<Cell<usize>>,
1937 }
1938
1939 impl MeasureKey for u32 {
1940 fn same(&self, previous: &dyn MeasureKey) -> bool {
1941 previous.as_any().downcast_ref::<u32>() == Some(self)
1942 }
1943
1944 fn as_any(&self) -> &dyn Any {
1945 self
1946 }
1947 }
1948
1949 impl crate::IntoElement for Measured {
1950 type Element = Self;
1951
1952 fn into_element(self) -> Self {
1953 self
1954 }
1955 }
1956
1957 impl crate::Element for Measured {
1958 type RequestLayoutState = ();
1959 type PrepaintState = ();
1960
1961 fn id(&self) -> Option<crate::ElementId> {
1962 None
1963 }
1964
1965 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
1966 None
1967 }
1968
1969 fn request_layout(
1970 &mut self,
1971 _: Option<&crate::GlobalElementId>,
1972 _: Option<&crate::InspectorElementId>,
1973 window: &mut Window,
1974 _: &mut App,
1975 ) -> (LayoutId, ()) {
1976 let calls = self.calls.clone();
1977 let layout_id = window.request_keyed_measured_layout(
1978 Style::default(),
1979 self.key,
1980 move |_, _, _, _| {
1981 calls.set(calls.get() + 1);
1982 crate::size(px(10.), px(10.))
1983 },
1984 );
1985 (layout_id, ())
1986 }
1987
1988 fn prepaint(
1989 &mut self,
1990 _: Option<&crate::GlobalElementId>,
1991 _: Option<&crate::InspectorElementId>,
1992 _: crate::Bounds<Pixels>,
1993 _: &mut (),
1994 _: &mut Window,
1995 _: &mut App,
1996 ) {
1997 }
1998
1999 fn paint(
2000 &mut self,
2001 _: Option<&crate::GlobalElementId>,
2002 _: Option<&crate::InspectorElementId>,
2003 _: crate::Bounds<Pixels>,
2004 _: &mut (),
2005 _: &mut (),
2006 _: &mut Window,
2007 _: &mut App,
2008 ) {
2009 }
2010 }
2011
2012 struct Row {
2013 keys: Vec<u32>,
2014 calls: Rc<Cell<usize>>,
2015 }
2016
2017 impl crate::Render for Row {
2018 fn render(
2019 &mut self,
2020 _: &mut Window,
2021 _: &mut crate::Context<Self>,
2022 ) -> impl crate::IntoElement {
2023 use crate::{ParentElement as _, Styled as _};
2024 crate::div()
2025 .flex()
2026 .flex_wrap()
2027 .w(px(25.))
2028 .children(self.keys.iter().map(|key| Measured {
2029 key: *key,
2030 calls: self.calls.clone(),
2031 }))
2032 }
2033 }
2034
2035 #[crate::test]
2036 fn unchanged_nodes_keep_their_layout_when_their_view_renders_again(
2037 cx: &mut crate::TestAppContext,
2038 ) {
2039 let calls = Rc::new(Cell::new(0));
2040 let window = cx.add_window({
2041 let calls = calls.clone();
2042 move |_, _| Row {
2043 keys: vec![1, 2, 3],
2044 calls,
2045 }
2046 });
2047 let measured_first = calls.get();
2048 assert!(measured_first >= 3);
2049
2050 calls.set(0);
2052 window.update(cx, |_, _, cx| cx.notify()).unwrap();
2053 cx.run_until_parked();
2054 assert_eq!(calls.get(), 3);
2055
2056 calls.set(0);
2058 window
2059 .update(cx, |row, _, cx| {
2060 row.keys[1] = 20;
2061 cx.notify();
2062 })
2063 .unwrap();
2064 cx.run_until_parked();
2065 assert!(
2066 calls.get() > 3,
2067 "the changed node is measured again: {}",
2068 calls.get()
2069 );
2070 }
2071}