1use std::cell::RefCell;
4use std::rc::{Rc, Weak};
5use std::sync::Arc;
6
7use crate::cache::TaitankLayoutCache;
8use crate::config::{TaitankConfig, TaitankConfigRef};
9use crate::flex::*;
10use crate::flexline::FlexLine;
11use crate::style::TaitankStyle;
12use crate::util::*;
13
14pub type TaitankNodeRef = Rc<RefCell<TaitankNode>>;
15pub type WeakTaitankNodeRef = Weak<RefCell<TaitankNode>>;
16
17pub type TaitankMeasureFunction =
18 Box<dyn Fn(TaitankNodeRef, f32, MeasureMode, f32, MeasureMode, Option<*mut ()>) -> TaitankSize>;
19pub type TaitankDirtiedFunction = Box<dyn Fn(TaitankNodeRef)>;
20
21pub struct TaitankNode {
22 pub style: TaitankStyle,
23 pub layout_result: TaitankLayout,
24
25 pub context: Option<*mut ()>,
26 pub children: Vec<TaitankNodeRef>,
27 pub parent: Option<WeakTaitankNodeRef>,
28
29 pub measure: Option<TaitankMeasureFunction>,
30
31 pub is_frozen: bool,
32 pub is_dirty: bool,
33 pub has_new_layout: bool,
34 pub dirtied_function: Option<TaitankDirtiedFunction>,
35
36 pub layout_cache: TaitankLayoutCache,
37 pub in_initial_state: bool,
38 pub config: Option<TaitankConfigRef>,
39}
40
41impl TaitankNode {
42 pub fn new() -> TaitankNodeRef {
43 Self::new_with_config(Arc::new(TaitankConfig::default()))
44 }
45
46 pub fn new_with_config(config: TaitankConfigRef) -> TaitankNodeRef {
47 let mut node = Self {
48 style: TaitankStyle::new(),
49 layout_result: TaitankLayout::default(),
50 context: None,
51 children: Vec::new(),
52 parent: None,
53 measure: None,
54 is_frozen: false,
55 is_dirty: false,
56 has_new_layout: false,
57 dirtied_function: None,
58 layout_cache: TaitankLayoutCache::new(),
59 in_initial_state: true,
60 config: Some(config),
61 };
62 node.init_layout_result();
63 Rc::new(RefCell::new(node))
64 }
65
66 pub fn init_layout_result(&mut self) {
67 self.layout_result = TaitankLayout::default();
68 self.layout_cache.clear_cache();
69 self.in_initial_state = true;
70 }
71
72 pub fn reset(&mut self) -> bool {
73 if !self.children.is_empty() || self.parent.is_some() {
74 return false;
75 }
76 self.children.clear();
77 self.children.shrink_to_fit();
78 self.init_layout_result();
79 self.in_initial_state = true;
80 true
81 }
82
83 pub fn print_node(&self, indent: u32) {
84 let indent_str = " ".repeat(indent as usize);
85 let width = if self.layout_result.dim[0].is_nan() {
86 "NAN".to_string()
87 } else {
88 format!("{:.0}", self.layout_result.dim[0].round())
89 };
90 let height = if self.layout_result.dim[1].is_nan() {
91 "NAN".to_string()
92 } else {
93 format!("{:.0}", self.layout_result.dim[1].round())
94 };
95 let left = if self.layout_result.position[0].is_nan() {
96 "NAN".to_string()
97 } else {
98 format!("{:.0}", self.layout_result.position[0].round())
99 };
100 let top = if self.layout_result.position[1].is_nan() {
101 "NAN".to_string()
102 } else {
103 format!("{:.0}", self.layout_result.position[1].round())
104 };
105
106 let style_str = format!("flex-direction:{:?};", self.style.flex_direction);
108
109 println!(
110 "{}<div layout=\"width:{}; height:{}; left:{}; top:{}\" style=\"{}\">",
111 indent_str, width, height, left, top, style_str
112 );
113
114 for child in &self.children {
115 child.borrow().print_node(indent + 4);
116 }
117
118 println!("{}</div>", indent_str);
119 }
120
121 pub fn set_parent(&mut self, parent: Option<WeakTaitankNodeRef>) {
122 self.parent = parent;
123 }
124
125 pub fn get_parent(&self) -> Option<TaitankNodeRef> {
126 self.parent.as_ref().and_then(|p| p.upgrade())
127 }
128
129 pub fn add_child(&mut self, child: TaitankNodeRef) {
130 self.children.push(child.clone());
133 self.mark_as_dirty();
136 }
137
138 pub fn insert_child(&mut self, child: TaitankNodeRef, index: usize) -> bool {
139 if index > self.children.len() {
140 return false;
141 }
142 self.children.insert(index, child);
143 self.mark_as_dirty();
144 true
145 }
146
147 pub fn get_child(&self, index: usize) -> Option<TaitankNodeRef> {
148 self.children.get(index).cloned()
149 }
150
151 pub fn remove_child(&mut self, child: &TaitankNodeRef) -> bool {
152 if let Some(pos) = self.children.iter().position(|c| Rc::ptr_eq(c, child)) {
153 self.children.remove(pos);
154 child.borrow_mut().set_parent(None);
155 child.borrow_mut().reset_layout_recursive(false);
156 self.mark_as_dirty();
157 true
158 } else {
159 false
160 }
161 }
162
163 pub fn child_count(&self) -> usize {
164 self.children.len()
165 }
166
167 pub fn set_display_type(&mut self, display_type: DisplayType) {
168 if self.style.display_type == display_type {
169 return;
170 }
171 self.style.display_type = display_type;
172 self.is_dirty = false;
173 self.mark_as_dirty();
174 }
175
176 pub fn set_has_new_layout(&mut self, has_new_layout: bool) {
177 self.has_new_layout = has_new_layout;
178 }
179
180 pub fn get_has_new_layout(&self) -> bool {
181 self.has_new_layout
182 }
183
184 pub fn mark_as_dirty(&mut self) {
185 if !self.is_dirty {
186 self.set_dirty(true);
187 if let Some(parent) = self.get_parent() {
188 parent.borrow_mut().mark_as_dirty();
189 }
190 }
191 }
192
193 pub fn set_dirty(&mut self, dirty: bool) {
194 if self.is_dirty == dirty {
195 return;
196 }
197 self.is_dirty = dirty;
198 if self.is_dirty {
199 self.layout_result.direction = TaitankDirection::Inherit;
200 self.is_frozen = false;
201 self.layout_cache.clear_cache();
202 if let Some(ref dirtied_fn) = self.dirtied_function {
203 let self_ref = Rc::new(RefCell::new(TaitankNode {
204 style: self.style.clone(),
205 layout_result: self.layout_result.clone(),
206 context: self.context,
207 children: Vec::new(),
208 parent: None,
209 measure: None,
210 is_frozen: self.is_frozen,
211 is_dirty: self.is_dirty,
212 has_new_layout: self.has_new_layout,
213 dirtied_function: None,
214 layout_cache: TaitankLayoutCache::new(),
215 in_initial_state: self.in_initial_state,
216 config: self.config.clone(),
217 }));
218 dirtied_fn(self_ref);
219 }
220 }
221 }
222
223 pub fn set_dirtied_function(&mut self, dirtied_function: Option<TaitankDirtiedFunction>) {
224 self.dirtied_function = dirtied_function;
225 }
226
227 pub fn set_context(&mut self, context: Option<*mut ()>) {
228 self.context = context;
229 }
230
231 pub fn get_context(&self) -> Option<*mut ()> {
232 self.context
233 }
234
235 pub fn get_start_border(&self, axis: FlexDirection) -> f32 {
236 self.style.get_start_border(axis)
237 }
238
239 pub fn get_end_border(&self, axis: FlexDirection) -> f32 {
240 self.style.get_end_border(axis)
241 }
242
243 pub fn get_start_padding_and_border(&self, axis: FlexDirection) -> f32 {
244 self.style.get_start_padding(axis) + self.style.get_start_border(axis)
245 }
246
247 pub fn get_end_padding_and_border(&self, axis: FlexDirection) -> f32 {
248 self.style.get_end_padding(axis) + self.style.get_end_border(axis)
249 }
250
251 pub fn get_padding_and_border(&self, axis: FlexDirection) -> f32 {
252 self.get_start_padding_and_border(axis) + self.get_end_padding_and_border(axis)
253 }
254
255 pub fn get_margin(&self, axis: FlexDirection) -> f32 {
256 self.style.get_margin(axis)
257 }
258
259 pub fn get_start_margin(&self, axis: FlexDirection) -> f32 {
260 self.style.get_start_margin(axis)
261 }
262
263 pub fn get_end_margin(&self, axis: FlexDirection) -> f32 {
264 self.style.get_end_margin(axis)
265 }
266
267 pub fn is_auto_start_margin(&self, axis: FlexDirection) -> bool {
268 self.style.is_auto_start_margin(axis)
269 }
270
271 pub fn is_auto_end_margin(&self, axis: FlexDirection) -> bool {
272 self.style.is_auto_end_margin(axis)
273 }
274
275 pub fn set_layout_start_margin(&mut self, axis: FlexDirection, value: f32) {
276 let idx = K_AXIS_START[axis as usize] as usize;
277 if !is_defined(self.layout_result.margin[idx])
278 || !float_is_equal(self.layout_result.margin[idx], value)
279 {
280 self.layout_result.margin[idx] = value;
281 }
282 }
283
284 pub fn set_layout_end_margin(&mut self, axis: FlexDirection, value: f32) {
285 let idx = K_AXIS_END[axis as usize] as usize;
286 if !is_defined(self.layout_result.margin[idx])
287 || !float_is_equal(self.layout_result.margin[idx], value)
288 {
289 self.layout_result.margin[idx] = value;
290 }
291 }
292
293 pub fn get_layout_margin(&self, axis: FlexDirection) -> f32 {
294 self.get_layout_start_margin(axis) + self.get_layout_end_margin(axis)
295 }
296
297 pub fn get_layout_start_margin(&self, axis: FlexDirection) -> f32 {
298 let idx = K_AXIS_START[axis as usize] as usize;
299 if is_defined(self.layout_result.margin[idx]) {
300 self.layout_result.margin[idx]
301 } else {
302 0.0
303 }
304 }
305
306 pub fn get_layout_end_margin(&self, axis: FlexDirection) -> f32 {
307 let idx = K_AXIS_END[axis as usize] as usize;
308 if is_defined(self.layout_result.margin[idx]) {
309 self.layout_result.margin[idx]
310 } else {
311 0.0
312 }
313 }
314
315 pub fn resolve_relative_position(&self, axis: FlexDirection, for_axis_start: bool) -> f32 {
316 if for_axis_start {
317 self.style.get_start_position(axis)
318 } else {
319 self.style.get_end_position(axis)
320 }
321 }
322
323 pub fn set_layout_start_position(
324 &mut self,
325 axis: FlexDirection,
326 value: f32,
327 add_relative_position: bool,
328 ) {
329 let relative_pos = if add_relative_position {
330 self.resolve_relative_position(axis, true)
331 } else {
332 0.0
333 };
334 let final_value = if is_defined(relative_pos) {
335 value + relative_pos
336 } else {
337 value
338 };
339 let idx = K_AXIS_START[axis as usize] as usize;
340
341 if !float_is_equal(self.layout_result.cached_position[idx], final_value) {
342 self.layout_result.cached_position[idx] = final_value;
343 self.set_has_new_layout(true);
344 }
345 self.layout_result.position[idx] = final_value;
346 }
347
348 pub fn set_layout_end_position(
349 &mut self,
350 axis: FlexDirection,
351 value: f32,
352 add_relative_position: bool,
353 ) {
354 let relative_pos = if add_relative_position {
355 self.resolve_relative_position(axis, false)
356 } else {
357 0.0
358 };
359 let final_value = if is_defined(relative_pos) {
360 value + relative_pos
361 } else {
362 value
363 };
364 let idx = K_AXIS_END[axis as usize] as usize;
365
366 if !float_is_equal(self.layout_result.cached_position[idx], final_value) {
367 self.layout_result.cached_position[idx] = final_value;
368 self.set_has_new_layout(true);
369 }
370 self.layout_result.position[idx] = final_value;
371 }
372
373 pub fn get_layout_start_position(&self, axis: FlexDirection) -> f32 {
374 self.layout_result.position[K_AXIS_START[axis as usize] as usize]
375 }
376
377 pub fn get_layout_end_position(&self, axis: FlexDirection) -> f32 {
378 self.layout_result.position[K_AXIS_END[axis as usize] as usize]
379 }
380
381 pub fn resolve_main_axis(&self) -> FlexDirection {
382 let main_axis = self.style.flex_direction;
383 let direction = self.get_layout_direction();
384 if direction == TaitankDirection::Rtl {
385 match main_axis {
386 FlexDirection::Row => FlexDirection::RowReverse,
387 FlexDirection::RowReverse => FlexDirection::Row,
388 _ => main_axis,
389 }
390 } else {
391 main_axis
392 }
393 }
394
395 pub fn resolve_cross_axis(&self) -> FlexDirection {
396 let main_axis = self.style.flex_direction;
397 let direction = self.get_layout_direction();
398 let cross_axis = if is_row_direction(main_axis) {
399 if self.style.flex_wrap == FlexWrapMode::WrapReverse {
400 FlexDirection::ColumnReverse
401 } else {
402 FlexDirection::Column
403 }
404 } else if self.style.flex_wrap == FlexWrapMode::WrapReverse {
405 FlexDirection::RowReverse
406 } else {
407 FlexDirection::Row
408 };
409
410 if is_row_direction(cross_axis) && direction == TaitankDirection::Rtl {
411 match cross_axis {
412 FlexDirection::Row => FlexDirection::RowReverse,
413 FlexDirection::RowReverse => FlexDirection::Row,
414 _ => cross_axis,
415 }
416 } else {
417 cross_axis
418 }
419 }
420
421 pub fn get_node_align(&self, item: &TaitankNodeRef) -> FlexAlign {
422 let item_borrow = item.borrow();
423 if item_borrow.style.align_self == FlexAlign::Auto {
424 self.style.align_items
425 } else {
426 item_borrow.style.align_self
427 }
428 }
429
430 pub fn get_bound_axis(&self, axis: FlexDirection, value: f32) -> f32 {
431 let min = self.style.min_dim[K_AXIS_DIM[axis as usize] as usize];
432 let max = self.style.max_dim[K_AXIS_DIM[axis as usize] as usize];
433 let mut bound_value = value;
434 if is_defined(max) && max >= 0.0 && bound_value > max {
435 bound_value = max;
436 }
437 if is_defined(min) && min >= 0.0 && bound_value < min {
438 bound_value = min;
439 }
440 bound_value
441 }
442
443 pub fn set_config(&mut self, config: Option<TaitankConfigRef>) {
444 self.config = config;
445 }
446
447 pub fn get_config(&self) -> Option<TaitankConfigRef> {
448 self.config.clone()
449 }
450
451 pub fn get_main_axis_dimension(&self) -> f32 {
452 let main_axis = self.style.flex_direction;
453 if !self.is_layout_dimension_defined(main_axis) {
454 return VALUE_UNDEFINED;
455 }
456 self.get_layout_dimension(main_axis)
457 }
458
459 pub fn get_layout_dimension(&self, axis: FlexDirection) -> f32 {
460 if !self.is_layout_dimension_defined(axis) {
461 return VALUE_UNDEFINED;
462 }
463 self.layout_result.dim[K_AXIS_DIM[axis as usize] as usize]
464 }
465
466 pub fn is_layout_dimension_defined(&self, axis: FlexDirection) -> bool {
467 is_defined(self.layout_result.dim[K_AXIS_DIM[axis as usize] as usize])
468 }
469
470 pub fn set_layout_dimension(&mut self, axis: FlexDirection, value: f32) {
471 self.layout_result.dim[K_AXIS_DIM[axis as usize] as usize] = value;
472 }
473
474 pub fn set_layout_direction(&mut self, direction: TaitankDirection) {
475 self.layout_result.direction = direction;
476 }
477
478 pub fn get_layout_direction(&self) -> TaitankDirection {
479 self.layout_result.direction
480 }
481
482 pub fn reset_layout_recursive(&mut self, is_display_none: bool) {
483 if is_display_none {
484 self.layout_result = TaitankLayout::default();
485 } else {
486 for i in 0..4 {
487 self.layout_result.position[i] = 0.0;
488 self.layout_result.cached_position[i] = 0.0;
489 }
490 }
491 self.has_new_layout = false;
492 for child in self.children.iter() {
493 child.borrow_mut().reset_layout_recursive(is_display_none);
494 }
495 }
496
497 pub fn resolve_direction(&self, parent_direction: TaitankDirection) -> TaitankDirection {
498 if self.style.direction == TaitankDirection::Inherit {
499 if parent_direction != TaitankDirection::Inherit {
500 parent_direction
501 } else {
502 TaitankDirection::Ltr
503 }
504 } else {
505 self.style.direction
506 }
507 }
508
509 pub fn resolve_style_values(&mut self) {
510 let main_axis = self.resolve_main_axis();
511 let cross_axis = self.resolve_cross_axis();
512
513 self.set_layout_start_margin(main_axis, self.style.get_start_margin(main_axis));
514 self.set_layout_end_margin(main_axis, self.style.get_end_margin(main_axis));
515 self.set_layout_start_margin(cross_axis, self.style.get_start_margin(cross_axis));
516 self.set_layout_end_margin(cross_axis, self.style.get_end_margin(cross_axis));
517
518 self.layout_result.padding[K_AXIS_START[main_axis as usize] as usize] =
519 self.style.get_start_padding(main_axis);
520 self.layout_result.padding[K_AXIS_END[main_axis as usize] as usize] =
521 self.style.get_end_padding(main_axis);
522 self.layout_result.padding[K_AXIS_START[cross_axis as usize] as usize] =
523 self.style.get_start_padding(cross_axis);
524 self.layout_result.padding[K_AXIS_END[cross_axis as usize] as usize] =
525 self.style.get_end_padding(cross_axis);
526
527 self.layout_result.border[K_AXIS_START[main_axis as usize] as usize] =
528 self.style.get_start_border(main_axis);
529 self.layout_result.border[K_AXIS_END[main_axis as usize] as usize] =
530 self.style.get_end_border(main_axis);
531 self.layout_result.border[K_AXIS_START[cross_axis as usize] as usize] =
532 self.style.get_start_border(cross_axis);
533 self.layout_result.border[K_AXIS_END[cross_axis as usize] as usize] =
534 self.style.get_end_border(cross_axis);
535 }
536
537 pub fn cache_layout_or_measure_result(
538 &mut self,
539 available_size: TaitankSize,
540 measure_mode: TaitankSizeMode,
541 layout_action: FlexLayoutAction,
542 ) {
543 let result_size = TaitankSize::new(
544 self.layout_result.dim[Dimension::Width as usize],
545 self.layout_result.dim[Dimension::Height as usize],
546 );
547 self.layout_cache
548 .cache_result(available_size, result_size, measure_mode, layout_action);
549 if layout_action == FlexLayoutAction::Layout {
550 self.set_dirty(false);
551 self.set_has_new_layout(true);
552 self.in_initial_state = false;
553 }
554 }
555
556 pub fn layout_single_node(
557 &mut self,
558 available_width: f32,
559 width_measure_mode: MeasureMode,
560 available_height: f32,
561 height_measure_mode: MeasureMode,
562 layout_action: FlexLayoutAction,
563 layout_context: Option<*mut ()>,
564 ) {
565 if width_measure_mode == MeasureMode::Exactly && height_measure_mode == MeasureMode::Exactly
566 {
567 self.layout_result.dim[Dimension::Width as usize] =
568 available_width + self.get_padding_and_border(FlexDirection::Row);
569 self.layout_result.dim[Dimension::Height as usize] =
570 available_height + self.get_padding_and_border(FlexDirection::Column);
571 } else {
572 let mut dim = TaitankSize::new(0.0, 0.0);
573 let mut need_measure = true;
574
575 if let Some(parent) = self.get_parent() {
576 let parent_borrow = parent.borrow();
577 if self.style.flex_grow > 0.0
578 && self.style.flex_shrink > 0.0
579 && parent_borrow.child_count() == 1
580 && !parent_borrow.style.is_dimension_auto(FlexDirection::Row)
581 && !parent_borrow.style.is_dimension_auto(FlexDirection::Column)
582 {
583 need_measure = false;
584 }
585 }
586
587 if !need_measure {
588 dim.width = available_width;
589 dim.height = available_height;
590 } else if let Some(ref measure_fn) = self.measure {
591 let self_ref = Rc::new(RefCell::new(TaitankNode {
592 style: self.style.clone(),
593 layout_result: self.layout_result.clone(),
594 context: self.context,
595 children: Vec::new(),
596 parent: None,
597 measure: None,
598 is_frozen: self.is_frozen,
599 is_dirty: self.is_dirty,
600 has_new_layout: self.has_new_layout,
601 dirtied_function: None,
602 layout_cache: TaitankLayoutCache::new(),
603 in_initial_state: self.in_initial_state,
604 config: self.config.clone(),
605 }));
606 dim = measure_fn(
607 self_ref,
608 available_width,
609 width_measure_mode,
610 available_height,
611 height_measure_mode,
612 layout_context,
613 );
614 }
615
616 self.layout_result.dim[Dimension::Width as usize] = self.get_bound_axis(
617 FlexDirection::Row,
618 if width_measure_mode == MeasureMode::Exactly {
619 available_width + self.get_padding_and_border(FlexDirection::Row)
620 } else {
621 dim.width + self.get_padding_and_border(FlexDirection::Row)
622 },
623 );
624
625 self.layout_result.dim[Dimension::Height as usize] = self.get_bound_axis(
626 FlexDirection::Column,
627 if height_measure_mode == MeasureMode::Exactly {
628 available_height + self.get_padding_and_border(FlexDirection::Column)
629 } else {
630 dim.height + self.get_padding_and_border(FlexDirection::Column)
631 },
632 );
633 }
634
635 let available_size = TaitankSize::new(available_width, available_height);
636 let measure_mode = TaitankSizeMode {
637 width_measure_mode,
638 height_measure_mode,
639 };
640 self.cache_layout_or_measure_result(available_size, measure_mode, layout_action);
641 }
642
643 pub fn layout(
648 &mut self,
649 parent_width: f32,
650 parent_height: f32,
651 config: TaitankConfigRef,
652 parent_direction: TaitankDirection,
653 layout_context: Option<*mut ()>,
654 ) {
655 self.layout_impl(
659 parent_width,
660 parent_height,
661 parent_direction,
662 FlexLayoutAction::Layout,
663 layout_context,
664 );
665
666 let main_axis = self.resolve_main_axis();
667 let cross_axis = self.resolve_cross_axis();
668 self.set_layout_start_position(main_axis, self.get_start_margin(main_axis), true);
669 self.set_layout_end_position(main_axis, self.get_end_margin(main_axis), true);
670 self.set_layout_start_position(cross_axis, self.get_start_margin(cross_axis), true);
671 self.set_layout_end_position(cross_axis, self.get_end_margin(cross_axis), true);
672
673 let scale_factor = config.get_scale_factor();
674 self.convert_layout_result(0.0, 0.0, scale_factor);
675 }
676
677 pub fn layout_impl(
678 &mut self,
679 parent_width: f32,
680 parent_height: f32,
681 parent_direction: TaitankDirection,
682 layout_action: FlexLayoutAction,
683 layout_context: Option<*mut ()>,
684 ) {
685 let direction = self.resolve_direction(parent_direction);
689 if self.get_layout_direction() != direction {
690 self.set_layout_direction(direction);
691 self.layout_cache.clear_cache();
692 self.resolve_style_values();
693 }
694
695 let main_axis = self.style.flex_direction;
696 let perform_layout = layout_action == FlexLayoutAction::Layout;
697
698 let adjusted_parent_width = if is_defined(parent_width) {
700 let width = parent_width - self.get_margin(FlexDirection::Row);
701 if width >= 0.0 {
702 width
703 } else {
704 0.0
705 }
706 } else {
707 VALUE_UNDEFINED
708 };
709
710 let adjusted_parent_height = if is_defined(parent_height) {
711 let height = parent_height - self.get_margin(FlexDirection::Column);
712 if height >= 0.0 {
713 height
714 } else {
715 0.0
716 }
717 } else {
718 VALUE_UNDEFINED
719 };
720
721 let node_width = if is_defined(self.style.dim[Dimension::Width as usize]) {
723 self.get_bound_axis(
724 FlexDirection::Row,
725 self.style.dim[Dimension::Width as usize],
726 )
727 } else {
728 VALUE_UNDEFINED
729 };
730
731 let node_height = if is_defined(self.style.dim[Dimension::Height as usize]) {
732 self.get_bound_axis(
733 FlexDirection::Column,
734 self.style.dim[Dimension::Height as usize],
735 )
736 } else {
737 VALUE_UNDEFINED
738 };
739
740 if layout_action == FlexLayoutAction::MeasureWidth && is_defined(node_width) {
742 self.layout_result.dim[Dimension::Width as usize] = node_width;
743 return;
744 }
745 if layout_action == FlexLayoutAction::MeasureHeight && is_defined(node_height) {
746 self.layout_result.dim[Dimension::Height as usize] = node_height;
747 return;
748 }
749
750 let mut available_width = VALUE_UNDEFINED;
752 if is_defined(node_width) {
753 available_width = node_width - self.get_padding_and_border(FlexDirection::Row);
754 } else if is_defined(adjusted_parent_width) {
755 available_width =
756 adjusted_parent_width - self.get_padding_and_border(FlexDirection::Row);
757 }
758
759 let mut available_height = VALUE_UNDEFINED;
760 if is_defined(node_height) {
761 available_height = node_height - self.get_padding_and_border(FlexDirection::Column);
762 } else if is_defined(adjusted_parent_height) {
763 available_height =
764 adjusted_parent_height - self.get_padding_and_border(FlexDirection::Column);
765 }
766
767 if is_defined(self.style.max_dim[Dimension::Width as usize]) {
769 if float_is_equal(
770 self.style.max_dim[Dimension::Width as usize],
771 self.style.min_dim[Dimension::Width as usize],
772 ) {
773 self.style.dim[Dimension::Width as usize] =
774 self.style.min_dim[Dimension::Width as usize];
775 }
776 let max_dim_width = self.style.max_dim[Dimension::Width as usize]
777 - self.get_padding_and_border(FlexDirection::Row);
778 if max_dim_width >= 0.0 && max_dim_width < nan_as_inf(available_width) {
779 available_width = max_dim_width;
780 }
781 }
782
783 if is_defined(self.style.max_dim[Dimension::Height as usize]) {
784 if float_is_equal(
785 self.style.max_dim[Dimension::Height as usize],
786 self.style.min_dim[Dimension::Height as usize],
787 ) {
788 self.style.dim[Dimension::Height as usize] =
789 self.style.min_dim[Dimension::Height as usize];
790 }
791 let max_dim_height = self.style.max_dim[Dimension::Height as usize]
792 - self.get_padding_and_border(FlexDirection::Column);
793 if max_dim_height >= 0.0 && max_dim_height < nan_as_inf(available_height) {
794 available_height = max_dim_height;
795 }
796 }
797
798 available_width = if available_width < 0.0 {
800 0.0
801 } else {
802 available_width
803 };
804 available_height = if available_height < 0.0 {
805 0.0
806 } else {
807 available_height
808 };
809
810 let mut width_measure_mode = MeasureMode::Undefined;
812 if is_defined(self.style.dim[Dimension::Width as usize]) {
813 width_measure_mode = MeasureMode::Exactly;
814 } else if is_defined(available_width) {
815 if let Some(parent) = self.get_parent() {
816 let parent_borrow = parent.borrow();
817 if parent_borrow.style.is_overflow_scroll()
818 && is_row_direction(parent_borrow.style.flex_direction)
819 {
820 width_measure_mode = MeasureMode::Undefined;
821 available_width = VALUE_AUTO;
822 } else {
823 width_measure_mode = MeasureMode::AtMost;
824 }
825 } else {
826 width_measure_mode = MeasureMode::AtMost;
827 }
828 }
829
830 let mut height_measure_mode = MeasureMode::Undefined;
831 if is_defined(self.style.dim[Dimension::Height as usize]) {
832 height_measure_mode = MeasureMode::Exactly;
833 } else if is_defined(available_height) {
834 if let Some(parent) = self.get_parent() {
835 let parent_borrow = parent.borrow();
836 if parent_borrow.style.is_overflow_scroll()
837 && is_column_direction(parent_borrow.style.flex_direction)
838 {
839 height_measure_mode = MeasureMode::Undefined;
840 available_height = VALUE_AUTO;
841 } else {
842 height_measure_mode = MeasureMode::AtMost;
843 }
844 } else {
845 height_measure_mode = MeasureMode::AtMost;
846 }
847 }
848
849 let available_size = TaitankSize::new(available_width, available_height);
850 let measure_mode = TaitankSizeMode {
851 width_measure_mode,
852 height_measure_mode,
853 };
854
855 if let Some(cache_result) = self.layout_cache.get_cached_measure_result(
857 available_size,
858 measure_mode,
859 layout_action,
860 self.measure.is_some(),
861 ) {
862 match layout_action {
863 FlexLayoutAction::MeasureWidth => {
864 self.layout_result.dim[Dimension::Width as usize] =
865 cache_result.result_size.width;
866 }
867 FlexLayoutAction::MeasureHeight => {
868 self.layout_result.dim[Dimension::Height as usize] =
869 cache_result.result_size.height;
870 }
871 FlexLayoutAction::Layout => {
872 if cache_result.layout_action != FlexLayoutAction::Layout
874 && self.measure.is_some()
875 {
876 self.layout_result.dim[Dimension::Width as usize] =
877 cache_result.result_size.width;
878 self.layout_result.dim[Dimension::Height as usize] =
879 cache_result.result_size.height;
880 self.cache_layout_or_measure_result(
881 available_size,
882 measure_mode,
883 layout_action,
884 );
885 }
886 self.set_dirty(false);
887 }
888 }
889 return;
890 }
891
892 if layout_action == FlexLayoutAction::Layout {
894 self.layout_result.had_overflow = false;
895 }
896
897 if self.children.is_empty() {
899 self.layout_single_node(
900 available_width,
901 width_measure_mode,
902 available_height,
903 height_measure_mode,
904 layout_action,
905 layout_context,
906 );
907 return;
908 }
909
910 self.calculate_items_flex_basis(available_size, layout_context);
912
913 let mut flex_lines = Vec::new();
915 let sum_hypothetical_main_size_overflow =
916 self.collect_flex_lines(&mut flex_lines, available_size);
917
918 let mut max_sum_items_main_size = 0.0;
920 for line in flex_lines.iter() {
921 if line.sum_hypothetical_main_size > max_sum_items_main_size {
922 max_sum_items_main_size = line.sum_hypothetical_main_size;
923 }
924 }
925
926 let container_inner_main_size;
928 if is_defined(self.style.dim[K_AXIS_DIM[main_axis as usize] as usize]) {
929 container_inner_main_size = self.style.dim[K_AXIS_DIM[main_axis as usize] as usize]
930 - self.get_padding_and_border(main_axis);
931 } else if sum_hypothetical_main_size_overflow {
932 let main_inner_size = if K_AXIS_DIM[main_axis as usize] == Dimension::Width {
933 available_size.width
934 } else {
935 available_size.height
936 };
937
938 if max_sum_items_main_size > main_inner_size && !self.style.is_overflow_scroll() {
939 let self_rc = Rc::new(RefCell::new(TaitankNode {
941 style: self.style.clone(),
942 layout_result: self.layout_result.clone(),
943 context: self.context,
944 children: Vec::new(),
945 parent: None,
946 measure: None,
947 is_frozen: self.is_frozen,
948 is_dirty: self.is_dirty,
949 has_new_layout: self.has_new_layout,
950 dirtied_function: None,
951 layout_cache: TaitankLayoutCache::new(),
952 in_initial_state: self.in_initial_state,
953 config: self.config.clone(),
954 }));
955
956 if let Some(parent) = self.get_parent() {
957 let parent_borrow = parent.borrow();
958 let node_align = parent_borrow.get_node_align(&self_rc);
959 let parent_cross_axis = parent_borrow.resolve_cross_axis();
960 if node_align == FlexAlign::Stretch
961 && K_AXIS_DIM[main_axis as usize] == K_AXIS_DIM[parent_cross_axis as usize]
962 && self.style.position_type != PositionType::Absolute
963 {
964 container_inner_main_size = main_inner_size;
965 } else {
966 container_inner_main_size = max_sum_items_main_size;
967 }
968 } else {
969 container_inner_main_size = max_sum_items_main_size;
970 }
971 } else {
972 container_inner_main_size = main_inner_size;
973 }
974 } else {
975 container_inner_main_size = max_sum_items_main_size;
976 }
977 self.layout_result.dim[K_AXIS_DIM[main_axis as usize] as usize] = self.get_bound_axis(
978 main_axis,
979 container_inner_main_size + self.get_padding_and_border(main_axis),
980 );
981
982 if (layout_action == FlexLayoutAction::MeasureWidth && is_row_direction(main_axis))
984 || (layout_action == FlexLayoutAction::MeasureHeight && is_column_direction(main_axis))
985 {
986 self.cache_layout_or_measure_result(available_size, measure_mode, layout_action);
987 return;
988 }
989
990 self.determine_items_main_axis_size(&mut flex_lines, layout_action);
992
993 let sum_lines_cross_size = self.determine_cross_axis_size(
995 &mut flex_lines,
996 available_size,
997 layout_action,
998 layout_context,
999 );
1000
1001 if !perform_layout {
1003 let cross_axis = self.resolve_cross_axis();
1005 let cross_dim_size =
1006 if is_defined(self.style.dim[K_AXIS_DIM[cross_axis as usize] as usize]) {
1007 self.style.dim[K_AXIS_DIM[cross_axis as usize] as usize]
1008 } else {
1009 sum_lines_cross_size + self.get_padding_and_border(cross_axis)
1010 };
1011 self.layout_result.dim[K_AXIS_DIM[cross_axis as usize] as usize] =
1012 self.get_bound_axis(cross_axis, cross_dim_size);
1013 self.cache_layout_or_measure_result(available_size, measure_mode, layout_action);
1014 return;
1015 }
1016
1017 self.main_axis_alignment(&mut flex_lines);
1019
1020 self.cross_axis_alignment(&mut flex_lines);
1022
1023 self.cache_layout_or_measure_result(available_size, measure_mode, layout_action);
1025
1026 self.layout_fixed_items(measure_mode, layout_context);
1028 }
1029
1030 pub fn calculate_items_flex_basis(
1031 &mut self,
1032 available_size: TaitankSize,
1033 layout_context: Option<*mut ()>,
1034 ) {
1035 let main_axis = self.style.flex_direction;
1036 for child in self.children.iter() {
1037 let mut child_borrow = child.borrow_mut();
1038 if child_borrow.style.display_type == DisplayType::None {
1039 child_borrow.reset_layout_recursive(true);
1040 continue;
1041 }
1042 if child_borrow.style.position_type == PositionType::Absolute {
1043 continue;
1044 }
1045
1046 if is_defined(child_borrow.style.get_flex_basis())
1048 && is_defined(self.style.dim[K_AXIS_DIM[main_axis as usize] as usize])
1049 {
1050 child_borrow.layout_result.flex_base_size = child_borrow.style.get_flex_basis();
1051 } else if is_defined(child_borrow.style.dim[K_AXIS_DIM[main_axis as usize] as usize]) {
1052 child_borrow.layout_result.flex_base_size =
1053 child_borrow.style.dim[K_AXIS_DIM[main_axis as usize] as usize];
1054 } else {
1055 let old_main_dim = child_borrow.style.get_dimension_by_axis(main_axis);
1056 let flex_basis = child_borrow.style.flex_basis;
1057 child_borrow
1058 .style
1059 .set_dimension_by_axis(main_axis, flex_basis);
1060 child_borrow.layout_impl(
1061 available_size.width,
1062 available_size.height,
1063 self.get_layout_direction(),
1064 if is_row_direction(main_axis) {
1065 FlexLayoutAction::MeasureWidth
1066 } else {
1067 FlexLayoutAction::MeasureHeight
1068 },
1069 layout_context,
1070 );
1071 child_borrow
1072 .style
1073 .set_dimension_by_axis(main_axis, old_main_dim);
1074 child_borrow.layout_result.flex_base_size = if is_defined(
1075 child_borrow.layout_result.dim[K_AXIS_DIM[main_axis as usize] as usize],
1076 ) {
1077 child_borrow.layout_result.dim[K_AXIS_DIM[main_axis as usize] as usize]
1078 } else {
1079 0.0
1080 };
1081 }
1082
1083 child_borrow.layout_result.hypothetical_main_axis_size =
1084 child_borrow.get_bound_axis(main_axis, child_borrow.layout_result.flex_base_size);
1085 child_borrow
1086 .layout_result
1087 .hypothetical_main_axis_margin_boxsize =
1088 child_borrow.layout_result.hypothetical_main_axis_size
1089 + child_borrow.get_margin(main_axis);
1090 }
1091 }
1092
1093 pub fn collect_flex_lines(
1094 &mut self,
1095 flex_lines: &mut Vec<FlexLine>,
1096 available_size: TaitankSize,
1097 ) -> bool {
1098 let mut sum_hypothetical_main_size_overflow = false;
1099 let available_width = if K_AXIS_DIM[self.style.flex_direction as usize] == Dimension::Width
1100 {
1101 if is_undefined(available_size.width) {
1102 f32::INFINITY
1103 } else {
1104 available_size.width
1105 }
1106 } else if is_undefined(available_size.height) {
1107 f32::INFINITY
1108 } else {
1109 available_size.height
1110 };
1111
1112 let mut line: Option<FlexLine> = None;
1113 let items_size = self.children.len();
1114 let mut i = 0;
1115
1116 while i < items_size {
1117 let child = &self.children[i];
1118 let child_borrow = child.borrow();
1119 if child_borrow.style.position_type == PositionType::Absolute
1120 || child_borrow.style.display_type == DisplayType::None
1121 {
1122 if i == items_size - 1 {
1123 if let Some(l) = line {
1124 flex_lines.push(l);
1125 }
1126 break;
1127 }
1128 i += 1;
1129 continue;
1130 }
1131
1132 if line.is_none() {
1133 line = Some(FlexLine::new(Rc::new(RefCell::new(TaitankNode {
1134 style: self.style.clone(),
1135 layout_result: self.layout_result.clone(),
1136 context: self.context,
1137 children: Vec::new(),
1138 parent: None,
1139 measure: None,
1140 is_frozen: self.is_frozen,
1141 is_dirty: self.is_dirty,
1142 has_new_layout: self.has_new_layout,
1143 dirtied_function: None,
1144 layout_cache: TaitankLayoutCache::new(),
1145 in_initial_state: self.in_initial_state,
1146 config: self.config.clone(),
1147 }))));
1148 }
1149
1150 let sum_size = line.as_ref().unwrap().sum_hypothetical_main_size
1151 + child_borrow
1152 .layout_result
1153 .hypothetical_main_axis_margin_boxsize;
1154 let left_space = available_width - sum_size;
1155 if left_space < 0.0 {
1156 sum_hypothetical_main_size_overflow = true;
1157 }
1158
1159 if self.style.flex_wrap == FlexWrapMode::NoWrap {
1160 line.as_mut().unwrap().add_item(child.clone());
1161 if i == items_size - 1 {
1162 flex_lines.push(line.take().unwrap());
1163 break;
1164 }
1165 i += 1;
1166 } else if left_space >= 0.0 || line.as_ref().unwrap().is_empty() {
1167 line.as_mut().unwrap().add_item(child.clone());
1168 if i == items_size - 1 {
1169 flex_lines.push(line.take().unwrap());
1170 }
1171 i += 1;
1172 } else {
1173 flex_lines.push(line.take().unwrap());
1174 }
1175 }
1176
1177 sum_hypothetical_main_size_overflow
1178 }
1179
1180 pub fn determine_items_main_axis_size(
1181 &mut self,
1182 flex_lines: &mut [FlexLine],
1183 layout_action: FlexLayoutAction,
1184 ) {
1185 for line in flex_lines.iter_mut() {
1186 line.container_main_inner_size = self.get_layout_dimension(self.style.flex_direction)
1187 - self.get_padding_and_border(self.style.flex_direction);
1188 line.freeze_inflexible_items(layout_action);
1189 loop {
1190 if line.resolve_flexible_lengths() {
1191 break;
1192 }
1193 }
1194 }
1195 }
1196
1197 pub fn determine_cross_axis_size(
1198 &mut self,
1199 flex_lines: &mut [FlexLine],
1200 available_size: TaitankSize,
1201 layout_action: FlexLayoutAction,
1202 layout_context: Option<*mut ()>,
1203 ) -> f32 {
1204 let main_axis = self.style.flex_direction;
1205 let cross_axis = self.resolve_cross_axis();
1206 let mut sum_lines_cross_size = 0.0;
1207
1208 let lines_count = flex_lines.len();
1209 let is_single_line = lines_count == 1;
1210 let cross_dim_defined =
1211 is_defined(self.style.dim[K_AXIS_DIM[cross_axis as usize] as usize]);
1212
1213 for line in flex_lines.iter_mut() {
1215 let mut max_item_cross_size = 0.0;
1216
1217 for item in line.items.iter() {
1218 let node_align = {
1221 let item_borrow = item.borrow();
1222 if item_borrow.style.align_self == FlexAlign::Auto {
1223 self.style.align_items
1224 } else {
1225 item_borrow.style.align_self
1226 }
1227 };
1228
1229 let item_borrow = item.borrow_mut();
1230
1231 let mut current_layout_action = layout_action;
1233
1234 let should_delay_stretch = node_align == FlexAlign::Stretch
1235 && item_borrow.style.is_dimension_auto(cross_axis)
1236 && !item_borrow.style.is_auto_margin(cross_axis)
1237 && layout_action == FlexLayoutAction::Layout;
1238
1239 let old_main_dim = item_borrow.style.get_dimension_by_axis(main_axis);
1241 let layout_dim_main = item_borrow.get_layout_dimension(main_axis);
1242 drop(item_borrow);
1243
1244 if should_delay_stretch {
1245 current_layout_action = if K_AXIS_DIM[cross_axis as usize] == Dimension::Width {
1247 FlexLayoutAction::MeasureWidth
1248 } else {
1249 FlexLayoutAction::MeasureHeight
1250 };
1251 }
1252
1253 let mut item_borrow_mut = item.borrow_mut();
1254 item_borrow_mut
1255 .style
1256 .set_dimension_by_axis(main_axis, layout_dim_main);
1257 item_borrow_mut.layout_impl(
1258 available_size.width,
1259 available_size.height,
1260 self.get_layout_direction(),
1261 current_layout_action,
1262 layout_context,
1263 );
1264 item_borrow_mut
1265 .style
1266 .set_dimension_by_axis(main_axis, old_main_dim);
1267
1268 self.layout_result.had_overflow =
1270 self.layout_result.had_overflow || item_borrow_mut.layout_result.had_overflow;
1271
1272 let item_out_cross_size = item_borrow_mut.get_layout_dimension(cross_axis)
1274 + item_borrow_mut.get_margin(cross_axis);
1275 if item_out_cross_size > max_item_cross_size {
1276 max_item_cross_size = item_out_cross_size;
1277 }
1278 }
1279
1280 max_item_cross_size = self.get_bound_axis(cross_axis, max_item_cross_size);
1282 line.line_cross_size = max_item_cross_size;
1283 sum_lines_cross_size += max_item_cross_size;
1284
1285 if is_single_line && cross_dim_defined {
1287 let inner_cross_size = self.get_bound_axis(
1288 cross_axis,
1289 self.style.dim[K_AXIS_DIM[cross_axis as usize] as usize],
1290 ) - self.get_padding_and_border(cross_axis);
1291 line.line_cross_size = inner_cross_size;
1292 sum_lines_cross_size = inner_cross_size;
1293 }
1294 }
1295
1296 if is_defined(self.style.dim[K_AXIS_DIM[cross_axis as usize] as usize])
1298 && self.style.align_content == FlexAlign::Stretch
1299 {
1300 let inner_cross_size = self.get_bound_axis(
1301 cross_axis,
1302 self.style.dim[K_AXIS_DIM[cross_axis as usize] as usize],
1303 ) - self.get_padding_and_border(cross_axis);
1304 if sum_lines_cross_size < inner_cross_size {
1305 let extra_space_per_line =
1306 (inner_cross_size - sum_lines_cross_size) / flex_lines.len() as f32;
1307 for line in flex_lines.iter_mut() {
1308 line.line_cross_size += extra_space_per_line;
1309 }
1310 sum_lines_cross_size = inner_cross_size;
1311 }
1312 }
1313
1314 for line in flex_lines.iter_mut() {
1316 for item in line.items.iter() {
1317 let node_align = {
1319 let item_borrow = item.borrow();
1320 if item_borrow.style.align_self == FlexAlign::Auto {
1321 self.style.align_items
1322 } else {
1323 item_borrow.style.align_self
1324 }
1325 };
1326
1327 let item_borrow = item.borrow_mut();
1328
1329 let should_stretch = node_align == FlexAlign::Stretch
1330 && item_borrow.style.is_dimension_auto(cross_axis)
1331 && !item_borrow.style.is_auto_margin(cross_axis);
1332
1333 if should_stretch {
1334 let line_cross_size = line.line_cross_size;
1336 let margin_cross = item_borrow.get_margin(cross_axis);
1337 let old_main_dim = item_borrow.style.get_dimension_by_axis(main_axis);
1338 let old_cross_dim = item_borrow.style.get_dimension_by_axis(cross_axis);
1339 let layout_dim_main = item_borrow.get_layout_dimension(main_axis);
1340 let layout_dim_cross = item_borrow.get_layout_dimension(cross_axis);
1341 drop(item_borrow);
1342
1343 let mut item_borrow_mut = item.borrow_mut();
1344 item_borrow_mut.layout_result.dim[K_AXIS_DIM[cross_axis as usize] as usize] =
1345 item_borrow_mut.get_bound_axis(cross_axis, line_cross_size - margin_cross);
1346
1347 item_borrow_mut
1349 .style
1350 .set_dimension_by_axis(main_axis, layout_dim_main);
1351 item_borrow_mut
1352 .style
1353 .set_dimension_by_axis(cross_axis, layout_dim_cross);
1354 item_borrow_mut.layout_impl(
1355 available_size.width,
1356 available_size.height,
1357 self.get_layout_direction(),
1358 layout_action,
1359 layout_context,
1360 );
1361 item_borrow_mut
1362 .style
1363 .set_dimension_by_axis(main_axis, old_main_dim);
1364 item_borrow_mut
1365 .style
1366 .set_dimension_by_axis(cross_axis, old_cross_dim);
1367 }
1368 }
1369 }
1370
1371 sum_lines_cross_size
1372 }
1373
1374 pub fn main_axis_alignment(&mut self, flex_lines: &mut [FlexLine]) {
1375 for line in flex_lines.iter_mut() {
1376 line.align_items();
1377 }
1378 }
1379
1380 pub fn cross_axis_alignment(&mut self, flex_lines: &mut [FlexLine]) {
1381 let cross_axis = self.resolve_cross_axis();
1382 let mut sum_lines_cross_size = 0.0;
1383 let lines_count = flex_lines.len();
1384
1385 for line in flex_lines.iter_mut() {
1387 sum_lines_cross_size += line.line_cross_size;
1388
1389 for item in line.items.iter() {
1390 let node_align = {
1392 let item_borrow = item.borrow();
1393 if item_borrow.style.align_self == FlexAlign::Auto {
1394 self.style.align_items
1395 } else {
1396 item_borrow.style.align_self
1397 }
1398 };
1399
1400 let mut item_borrow = item.borrow_mut();
1401
1402 let remaining_free_space = line.line_cross_size
1404 - item_borrow.layout_result.dim[K_AXIS_DIM[cross_axis as usize] as usize]
1405 - item_borrow.get_margin(cross_axis);
1406
1407 if remaining_free_space > 0.0 {
1408 if item_borrow.is_auto_start_margin(cross_axis)
1410 && item_borrow.is_auto_end_margin(cross_axis)
1411 {
1412 item_borrow.set_layout_start_margin(cross_axis, remaining_free_space / 2.0);
1413 item_borrow.set_layout_end_margin(cross_axis, remaining_free_space / 2.0);
1414 } else if item_borrow.is_auto_start_margin(cross_axis) {
1415 item_borrow.set_layout_start_margin(cross_axis, remaining_free_space);
1416 } else if item_borrow.is_auto_end_margin(cross_axis) {
1417 item_borrow.set_layout_end_margin(cross_axis, remaining_free_space);
1418 } else {
1419 let start_margin = item_borrow.style.get_start_margin(cross_axis);
1421 let end_margin = item_borrow.style.get_end_margin(cross_axis);
1422 item_borrow.set_layout_start_margin(cross_axis, start_margin);
1423 item_borrow.set_layout_end_margin(cross_axis, end_margin);
1424 }
1425 } else {
1426 let start_margin = item_borrow.style.get_start_margin(cross_axis);
1428 let end_margin = item_borrow.style.get_end_margin(cross_axis);
1429 item_borrow.set_layout_start_margin(cross_axis, start_margin);
1430 item_borrow.set_layout_end_margin(cross_axis, end_margin);
1431 }
1432
1433 let remaining_free_space_for_align = line.line_cross_size
1435 - item_borrow.layout_result.dim[K_AXIS_DIM[cross_axis as usize] as usize]
1436 - item_borrow.get_layout_margin(cross_axis);
1437
1438 if node_align == FlexAlign::Stretch
1440 && item_borrow.style.is_dimension_auto(cross_axis)
1441 && !item_borrow.style.is_auto_margin(cross_axis)
1442 && item_borrow.layout_result.dim[K_AXIS_DIM[cross_axis as usize] as usize]
1443 == 0.0
1444 {
1445 let target = line.line_cross_size - item_borrow.get_margin(cross_axis);
1446 item_borrow.layout_result.dim[K_AXIS_DIM[cross_axis as usize] as usize] =
1447 item_borrow.get_bound_axis(cross_axis, target);
1448 }
1449
1450 let mut offset = item_borrow.get_layout_start_margin(cross_axis);
1451
1452 match node_align {
1453 FlexAlign::Start => {
1454 }
1456 FlexAlign::Center => {
1457 offset += remaining_free_space_for_align / 2.0;
1458 }
1459 FlexAlign::End => {
1460 offset += remaining_free_space_for_align;
1461 }
1462 _ => {}
1466 }
1467
1468 item_borrow.set_layout_start_position(cross_axis, offset, false);
1470 }
1471 }
1472
1473 let cross_dim_size = if is_defined(self.style.dim[K_AXIS_DIM[cross_axis as usize] as usize])
1475 {
1476 self.style.dim[K_AXIS_DIM[cross_axis as usize] as usize]
1477 } else {
1478 sum_lines_cross_size + self.get_padding_and_border(cross_axis)
1479 };
1480 self.layout_result.dim[K_AXIS_DIM[cross_axis as usize] as usize] =
1481 self.get_bound_axis(cross_axis, cross_dim_size);
1482
1483 let inner_cross_size = self.layout_result.dim[K_AXIS_DIM[cross_axis as usize] as usize]
1485 - self.get_padding_and_border(cross_axis);
1486 let remaining_free_space = inner_cross_size - sum_lines_cross_size;
1487 let mut offset = self.get_start_padding_and_border(cross_axis);
1488 let mut space = 0.0;
1489
1490 match self.style.align_content {
1491 FlexAlign::Start => {
1492 }
1494 FlexAlign::Center => {
1495 offset += remaining_free_space / 2.0;
1496 }
1497 FlexAlign::End => {
1498 offset += remaining_free_space;
1499 }
1500 FlexAlign::SpaceBetween => {
1501 if lines_count > 1 {
1502 space = remaining_free_space / (lines_count - 1) as f32;
1503 }
1504 }
1505 FlexAlign::SpaceAround => {
1506 space = remaining_free_space / lines_count as f32;
1507 offset += space / 2.0;
1508 }
1509 FlexAlign::SpaceEvenly => {
1510 space = remaining_free_space / (lines_count + 1) as f32;
1511 offset += space;
1512 }
1513 _ => {}
1514 }
1515
1516 let mut current_offset = offset;
1518 for line in flex_lines.iter_mut() {
1519 for item in line.items.iter_mut() {
1520 let mut item_borrow = item.borrow_mut();
1521 let current_cross_pos = item_borrow.get_layout_start_position(cross_axis);
1522 item_borrow.set_layout_start_position(
1523 cross_axis,
1524 current_cross_pos + current_offset,
1525 false,
1526 );
1527 let container_dim = self.get_layout_dimension(cross_axis);
1528 let item_dim = item_borrow.get_layout_dimension(cross_axis);
1529 let item_start_pos = item_borrow.get_layout_start_position(cross_axis);
1530 item_borrow.set_layout_end_position(
1531 cross_axis,
1532 container_dim - item_dim - item_start_pos,
1533 false,
1534 );
1535 }
1536 current_offset += line.line_cross_size + space;
1537 }
1538 }
1539
1540 pub fn layout_fixed_items(
1541 &mut self,
1542 _measure_mode: TaitankSizeMode,
1543 layout_context: Option<*mut ()>,
1544 ) {
1545 let main_axis = self.resolve_main_axis();
1546 let cross_axis = self.resolve_cross_axis();
1547
1548 let mut absolute_items: Vec<(TaitankNodeRef, f32, f32)> = Vec::new();
1550
1551 for item in self.children.iter() {
1552 let item_borrow = item.borrow();
1553 if item_borrow.style.display_type == DisplayType::None {
1555 drop(item_borrow);
1556 let mut item_borrow_mut = item.borrow_mut();
1557 item_borrow_mut.reset_layout_recursive(true);
1558 continue;
1559 }
1560 if item_borrow.style.position_type != PositionType::Absolute {
1561 continue;
1562 }
1563
1564 let item_old_style_dim_main_axis = item_borrow.style.get_dimension_by_axis(main_axis);
1565 let item_old_style_dim_cross_axis = item_borrow.style.get_dimension_by_axis(cross_axis);
1566 drop(item_borrow);
1567
1568 absolute_items.push((
1569 item.clone(),
1570 item_old_style_dim_main_axis,
1571 item_old_style_dim_cross_axis,
1572 ));
1573 }
1574
1575 for (item, item_old_style_dim_main_axis, item_old_style_dim_cross_axis) in absolute_items {
1577 let parent_width = self.get_layout_dimension(FlexDirection::Row)
1578 - self.get_padding_and_border(FlexDirection::Row);
1579 let parent_height = self.get_layout_dimension(FlexDirection::Column)
1580 - self.get_padding_and_border(FlexDirection::Column);
1581
1582 let mut item_borrow_mut = item.borrow_mut();
1583
1584 if is_undefined(item_old_style_dim_main_axis)
1586 && is_defined(item_borrow_mut.style.get_start_position(main_axis))
1587 && is_defined(item_borrow_mut.style.get_end_position(main_axis))
1588 {
1589 let container_dim = self.get_layout_dimension(main_axis);
1590 let start_border = self.style.get_start_border(main_axis);
1591 let end_border = self.style.get_end_border(main_axis);
1592 let start_pos = item_borrow_mut.style.get_start_position(main_axis);
1593 let end_pos = item_borrow_mut.style.get_end_position(main_axis);
1594 let margin = item_borrow_mut.get_margin(main_axis);
1595 item_borrow_mut.style.set_dimension_by_axis(
1596 main_axis,
1597 container_dim - start_border - end_border - start_pos - end_pos - margin,
1598 );
1599 }
1600
1601 if is_undefined(item_old_style_dim_cross_axis)
1603 && is_defined(item_borrow_mut.style.get_start_position(cross_axis))
1604 && is_defined(item_borrow_mut.style.get_end_position(cross_axis))
1605 {
1606 let container_dim = self.get_layout_dimension(cross_axis);
1607 let start_border = self.style.get_start_border(cross_axis);
1608 let end_border = self.style.get_end_border(cross_axis);
1609 let start_pos = item_borrow_mut.style.get_start_position(cross_axis);
1610 let end_pos = item_borrow_mut.style.get_end_position(cross_axis);
1611 let margin = item_borrow_mut.get_margin(cross_axis);
1612 item_borrow_mut.style.set_dimension_by_axis(
1613 cross_axis,
1614 container_dim - start_border - end_border - start_pos - end_pos - margin,
1615 );
1616 }
1617
1618 item_borrow_mut.layout_impl(
1620 parent_width,
1621 parent_height,
1622 self.get_layout_direction(),
1623 FlexLayoutAction::Layout,
1624 layout_context,
1625 );
1626
1627 item_borrow_mut
1629 .style
1630 .set_dimension_by_axis(main_axis, item_old_style_dim_main_axis);
1631 item_borrow_mut
1632 .style
1633 .set_dimension_by_axis(cross_axis, item_old_style_dim_cross_axis);
1634 drop(item_borrow_mut);
1635
1636 self.calculate_fixed_item_position(&item, main_axis);
1639 self.calculate_fixed_item_position(&item, cross_axis);
1641 }
1642 }
1643
1644 pub fn calculate_fixed_item_position(&mut self, item: &TaitankNodeRef, axis: FlexDirection) {
1645 let item_borrow = item.borrow();
1646
1647 if is_defined(item_borrow.style.get_start_position(axis)) {
1648 let start_pos = item_borrow.style.get_start_position(axis);
1649 let start_border = self.get_start_border(axis);
1650 let start_margin = item_borrow.get_layout_start_margin(axis);
1651 drop(item_borrow);
1652
1653 let mut item_borrow_mut = item.borrow_mut();
1654 item_borrow_mut.set_layout_start_position(
1655 axis,
1656 start_border + start_margin + start_pos,
1657 false,
1658 );
1659 let container_dim = self.get_layout_dimension(axis);
1660 let item_dim = item_borrow_mut.get_layout_dimension(axis);
1661 let item_start_pos = item_borrow_mut.get_layout_start_position(axis);
1662 item_borrow_mut.set_layout_end_position(
1663 axis,
1664 container_dim - item_dim - item_start_pos,
1665 false,
1666 );
1667 } else if is_defined(item_borrow.style.get_end_position(axis)) {
1668 let end_pos = item_borrow.style.get_end_position(axis);
1669 let end_border = self.get_end_border(axis);
1670 let end_margin = item_borrow.get_layout_end_margin(axis);
1671 drop(item_borrow);
1672
1673 let mut item_borrow_mut = item.borrow_mut();
1674 item_borrow_mut.set_layout_end_position(axis, end_border + end_margin + end_pos, false);
1675 let container_dim = self.get_layout_dimension(axis);
1676 let item_dim = item_borrow_mut.get_layout_dimension(axis);
1677 let item_end_pos = item_borrow_mut.get_layout_end_position(axis);
1678 item_borrow_mut.set_layout_start_position(
1679 axis,
1680 container_dim - item_dim - item_end_pos,
1681 false,
1682 );
1683 } else {
1684 let remaining_free_space = self.get_layout_dimension(axis)
1686 - self.get_padding_and_border(axis)
1687 - item_borrow.get_layout_dimension(axis);
1688 let mut offset = self.get_start_padding_and_border(axis);
1689
1690 let align_mode = if axis == self.resolve_main_axis() {
1691 self.style.justify_content
1692 } else {
1693 let item_borrow = item.borrow();
1694 if item_borrow.style.align_self == FlexAlign::Auto {
1695 self.style.align_items
1696 } else {
1697 item_borrow.style.align_self
1698 }
1699 };
1700
1701 drop(item_borrow);
1702 let mut item_borrow_mut = item.borrow_mut();
1703
1704 match align_mode {
1705 FlexAlign::Start => {
1706 }
1708 FlexAlign::Center => {
1709 offset += remaining_free_space / 2.0;
1710 }
1711 FlexAlign::End => {
1712 offset += remaining_free_space;
1713 }
1714 _ => {}
1715 }
1716
1717 let start_margin = item_borrow_mut.get_layout_start_margin(axis);
1718 item_borrow_mut.set_layout_start_position(
1719 axis,
1720 self.get_start_padding_and_border(axis) + start_margin + offset,
1721 false,
1722 );
1723 let container_dim = self.get_layout_dimension(axis);
1724 let item_dim = item_borrow_mut.get_layout_dimension(axis);
1725 let item_start_pos = item_borrow_mut.get_layout_start_position(axis);
1726 item_borrow_mut.set_layout_end_position(
1727 axis,
1728 container_dim - item_dim - item_start_pos,
1729 false,
1730 );
1731 }
1732 }
1733
1734 pub fn convert_layout_result(&mut self, abs_left: f32, abs_top: f32, scale_factor: f32) {
1735 use crate::util::{double_is_equal, fmod, round_value_to_pixel_grid};
1736
1737 let left = self.layout_result.position[CSSDirection::Left as usize];
1743 let top = self.layout_result.position[CSSDirection::Top as usize];
1744 let width = self.layout_result.dim[Dimension::Width as usize];
1745 let height = self.layout_result.dim[Dimension::Height as usize];
1746
1747 let mut abs_left_new = abs_left + left;
1748 let mut abs_top_new = abs_top + top;
1749 let is_text_node = self.style.node_type == NodeType::Text || self.measure.is_some();
1750
1751 self.layout_result.position[CSSDirection::Left as usize] =
1753 round_value_to_pixel_grid(left as f64, scale_factor as f64, false, is_text_node) as f32;
1754 self.layout_result.position[CSSDirection::Top as usize] =
1755 round_value_to_pixel_grid(top as f64, scale_factor as f64, false, is_text_node) as f32;
1756
1757 let width_scaled = width * scale_factor;
1759 let height_scaled = height * scale_factor;
1760 let has_fractional_width = !double_is_equal(fmod(width_scaled, 1.0) as f64, 0.0)
1761 && !double_is_equal(fmod(width_scaled, 1.0) as f64, 1.0);
1762 let has_fractional_height = !double_is_equal(fmod(height_scaled, 1.0) as f64, 0.0)
1763 && !double_is_equal(fmod(height_scaled, 1.0) as f64, 1.0);
1764
1765 let abs_right = abs_left_new + width;
1766 let abs_bottom = abs_top_new + height;
1767
1768 let rounded_right = round_value_to_pixel_grid(
1770 abs_right as f64,
1771 scale_factor as f64,
1772 is_text_node && has_fractional_width,
1773 is_text_node && !has_fractional_width,
1774 ) as f32;
1775 let rounded_left = round_value_to_pixel_grid(
1776 abs_left_new as f64,
1777 scale_factor as f64,
1778 false,
1779 is_text_node,
1780 ) as f32;
1781 self.layout_result.dim[Dimension::Width as usize] = rounded_right - rounded_left;
1782
1783 let rounded_bottom = round_value_to_pixel_grid(
1785 abs_bottom as f64,
1786 scale_factor as f64,
1787 is_text_node && has_fractional_height,
1788 is_text_node && !has_fractional_height,
1789 ) as f32;
1790 let rounded_top =
1791 round_value_to_pixel_grid(abs_top_new as f64, scale_factor as f64, false, is_text_node)
1792 as f32;
1793 self.layout_result.dim[Dimension::Height as usize] = rounded_bottom - rounded_top;
1794
1795 abs_left_new = rounded_left;
1797 abs_top_new = rounded_top;
1798 for child in self.children.iter() {
1799 child
1800 .borrow_mut()
1801 .convert_layout_result(abs_left_new, abs_top_new, scale_factor);
1802 }
1803 }
1804}