1use float_pigment_css::length_num::*;
2use float_pigment_css::typing::TextAlign;
3use float_pigment_css::{
4 num_traits::Zero,
5 typing::{
6 AlignContent, AlignItems, AlignSelf, BoxSizing, Direction, Display, FlexDirection,
7 FlexWrap, JustifyContent, Position, WritingMode,
8 },
9};
10use float_pigment_layout::{
11 DefLength, Edge, EdgeOption, InlineMeasure, InlineUnit, LayoutNode, LayoutStyle,
12 LayoutTreeNode, LayoutTreeVisitor, MeasureResult, OptionNum, OptionSize, Point, Size, Vector,
13};
14
15use crate::{convert_node_ref_to_ptr, Length};
16use crate::{
17 env::Env,
18 node::{ChildOperation, Node},
19 Len, MeasureMode, NodeType,
20};
21
22fn is_specified(x: Len) -> bool {
23 x != Len::MAX
24}
25
26impl LayoutTreeNode for Node {
27 type Length = Len;
28 type LengthCustom = i32;
29 type TreeVisitor = Node;
30 type Style = Node;
31 type InlineUnit = LayoutInlineUnit;
32 type InlineMeasure = LayoutInlineMeasure;
33 type Env = Env;
34
35 #[inline]
36 fn layout_node(&self) -> &LayoutNode<Self> {
37 &self.layout_node
38 }
39
40 #[inline]
41 fn tree_visitor(&self) -> &Self::TreeVisitor {
42 self
43 }
44
45 #[inline]
46 fn style(&self) -> &Self::Style {
47 self
48 }
49
50 #[inline]
51 fn resolve_custom_length(
52 &self,
53 custom: &Self::LengthCustom,
54 owner: Self::Length,
55 ) -> Self::Length {
56 if let Some(func) = self.resolve_calc() {
57 return func(*custom, owner);
58 };
59 Len::zero()
60 }
61
62 #[inline]
63 fn should_measure(&self, _env: &mut Self::Env) -> bool {
64 self.has_measure_func()
65 }
66
67 #[inline]
68 fn measure_block_size(
69 &self,
70 _env: &mut Self::Env,
71 req_size: OptionSize<Self::Length>,
72 min: Size<Self::Length>,
73 max: Size<Self::Length>,
74 max_content: OptionSize<Self::Length>,
75 _update_position: bool,
76 ) -> MeasureResult<Self::Length> {
77 let width = req_size.width.val();
78 let height = req_size.height.val();
79 let mut size = Size::new(Len::zero(), Len::zero());
80 let mut skip_measure = false;
81 if let (Some(width), Some(height)) = (width, height) {
82 if self.style().width() != DefLength::Auto
83 && self.style().height() != DefLength::Auto
84 && is_specified(width)
85 && is_specified(height)
86 {
87 size = Size::new(width, height);
88 skip_measure = true
89 }
90 } else if let Some(ratio) = self.style().aspect_ratio() {
91 if let Some(height) = height {
92 if is_specified(height) {
93 size = Size::new(height.mul_f32(ratio), height);
94 skip_measure = true;
95 }
96 } else if let Some(width) = width {
97 if is_specified(width) {
98 size = Size::new(width, width.div_f32(ratio));
99 skip_measure = true;
100 }
101 }
102 }
103 if !skip_measure {
104 if let Some(func) = unsafe { self.measure_func() } {
105 let mut width_measure_mode = MeasureMode::AtMost;
106 let mut height_measure_mode = MeasureMode::AtMost;
107 let (min_width, max_width) = if let Some(req_size_width) = req_size.width.val() {
108 let min_width = req_size_width;
109 let max_width = req_size_width;
110 width_measure_mode = MeasureMode::Exactly;
111 (min_width, max_width)
112 } else {
113 let min_width = if !is_specified(min.width) {
114 Len::zero()
115 } else {
116 min.width
117 };
118 let max_width = max.width;
119 (min_width, max_width)
120 };
121 let (min_height, max_height) = if let Some(req_size_height) = req_size.height.val()
122 {
123 let min_height = req_size_height;
124 let max_height = req_size_height;
125 height_measure_mode = MeasureMode::Exactly;
126 (min_height, max_height)
127 } else {
128 let min_height = if !is_specified(min.height) {
129 Len::zero()
130 } else {
131 min.height
132 };
133 let max_height = max.height;
134 (min_height, max_height)
135 };
136 let mut size_from_cache = false;
137 if self.node_type() == NodeType::Text {
138 if let Some(cache) = unsafe { self.measure_cache() }.as_mut() {
139 if let Some(size_cache) = cache.get(&(
140 OptionSize::new(
141 OptionNum::some(min_width).to_hashable(),
142 OptionNum::some(min_height).to_hashable(),
143 ),
144 OptionSize::new(
145 OptionNum::some(max_width).to_hashable(),
146 OptionNum::some(max_height).to_hashable(),
147 ),
148 OptionSize::new(
149 max_content.width.to_hashable(),
150 max_content.height.to_hashable(),
151 ),
152 )) {
153 size = *size_cache;
154 size_from_cache = true;
155 }
156 }
157 }
158 if !size_from_cache {
159 let measure_size = func(
160 convert_node_ref_to_ptr(self),
161 max_width,
162 width_measure_mode,
163 max_height,
164 height_measure_mode,
165 min_width,
166 min_height,
167 max_content.width.unwrap_or(max_width),
168 max_content.height.unwrap_or(max_height),
169 );
170 let width = if is_specified(measure_size.width) {
171 measure_size.width
172 } else {
173 Len::zero()
174 };
175 let height = if is_specified(measure_size.height) {
176 measure_size.height
177 } else {
178 Len::zero()
179 };
180 let measure_size = Size::new(width, height);
181 size = Size::new(
182 measure_size.width.clamp(min.width, max.width),
183 measure_size.height.clamp(min.height, max.height),
184 );
185 if self.node_type() == NodeType::Text {
186 if let Some(cache) = unsafe { self.measure_cache() }.as_mut() {
187 cache.put(
188 (
189 OptionSize::new(
190 OptionNum::some(min_width),
191 OptionNum::some(min_height),
192 ),
193 OptionSize::new(
194 OptionNum::some(max_width),
195 OptionNum::some(max_height),
196 ),
197 OptionSize::new(
198 max_content.width.to_hashable(),
199 max_content.height.to_hashable(),
200 ),
201 ),
202 size,
203 );
204 }
205 }
206 }
207 };
208 }
209 let mut baseline = size.to_vector();
210 let mut baseline_from_cache = false;
211 if self.node_type() == NodeType::Text {
212 if let Some(cache) = unsafe { self.baseline_cache() }.as_mut() {
213 if let Some(baseline_cache) = cache.get(&Size::new(size.width, size.height)) {
214 baseline_from_cache = true;
215 baseline = Vector::new(Len::zero(), *baseline_cache);
216 }
217 }
218 }
219 if !baseline_from_cache {
220 if let Some(func) = unsafe { self.baseline_func() } {
221 let ret = func(convert_node_ref_to_ptr(self), size.width, size.height);
222 baseline = Vector::new(Len::zero(), ret);
223 if let Some(cache) = unsafe { self.baseline_cache() }.as_mut() {
224 cache.put(Size::new(size.width, size.height), ret);
225 }
226 }
227 }
228 MeasureResult {
229 size,
230 first_baseline_ascent: baseline,
231 last_baseline_ascent: baseline,
232 }
233 }
234
235 #[inline]
236 fn measure_inline_unit(
237 &self,
238 env: &mut Self::Env,
239 req_size: OptionSize<Self::Length>,
240 min: Size<Self::Length>,
241 max: Size<Self::Length>,
242 max_content: OptionSize<Self::Length>,
243 ) -> Self::InlineUnit {
244 let measure_res = self.measure_block_size(env, req_size, min, max, max_content, false);
245 let size = measure_res.size;
246 LayoutInlineUnit {
247 offset: Point::zero(),
248 size,
249 first_baseline_ascent: Vector::new(
250 measure_res.first_baseline_ascent.x,
251 measure_res.first_baseline_ascent.y,
252 ),
253 last_baseline_ascent: Vector::new(
254 measure_res.last_baseline_ascent.x,
255 measure_res.last_baseline_ascent.y,
256 ),
257 is_inline_block: false,
258 }
259 }
260}
261
262impl LayoutTreeVisitor<Node> for Node {
263 #[inline]
264 fn parent(&self) -> Option<&Node> {
265 unsafe { Node::parent(self) }
266 }
267
268 #[inline]
269 fn for_each_child<'a, 'b: 'a, F>(&'b self, f: F)
270 where
271 F: FnMut(&'a Node, usize),
272 Node: 'a,
273 {
274 unsafe { self.for_each_child_node(f) }
275 }
276
277 #[inline]
278 fn children_len(&self) -> usize {
279 Node::children_len(self)
280 }
281
282 #[inline]
283 fn child_at(&self, index: usize) -> Option<&Node> {
284 unsafe { self.get_child_at(index) }
285 }
286}
287#[derive(Debug, Clone)]
288pub struct LayoutInlineUnit {
289 offset: Point<Len>,
290 size: Size<Len>,
291 first_baseline_ascent: Vector<Len>,
292 last_baseline_ascent: Vector<Len>,
293 is_inline_block: bool,
294}
295
296impl LayoutInlineUnit {
297 fn to_tuple(&self) -> (Point<Len>, MeasureResult<Len>) {
298 (
299 self.offset,
300 MeasureResult {
301 size: self.size,
302 first_baseline_ascent: self.first_baseline_ascent,
303 last_baseline_ascent: self.last_baseline_ascent,
304 },
305 )
306 }
307 fn adjust_inline_size(&mut self, padding_border: Edge<Len>) {
308 if self.is_inline_block {
309 return;
310 }
311 self.size.height += padding_border.vertical();
312 self.size.width += padding_border.horizontal();
313 self.first_baseline_ascent.y += padding_border.top;
314 self.last_baseline_ascent.y += padding_border.top;
315 }
316}
317
318impl InlineUnit<Node> for LayoutInlineUnit {
319 type Env = Env;
320 fn inline_block(_env: &mut Env, _node: &Node, size: Size<Len>, baseline_ascent: Len) -> Self {
321 Self {
322 offset: Point::zero(),
323 size,
324 first_baseline_ascent: Vector::new(Len::zero(), baseline_ascent),
325 last_baseline_ascent: Vector::new(Len::zero(), baseline_ascent),
326 is_inline_block: true,
327 }
328 }
329}
330
331#[derive(Debug, Clone)]
332struct Line {
333 inline_units: Vec<LayoutInlineUnit>,
334 total_inline_size: Len,
335 total_block_size: Len,
336 block_start: Len,
337 inline_offset: Len,
338 first_baseline_ascent: Vector<Len>,
339 }
341
342impl Default for Line {
343 fn default() -> Self {
344 Self {
345 inline_units: vec![],
346 total_inline_size: Len::zero(),
347 total_block_size: Len::zero(),
348 block_start: Len::zero(),
349 inline_offset: Len::zero(),
350 first_baseline_ascent: Vector::default(),
351 }
353 }
354}
355
356impl Line {
357 fn is_empty(&self) -> bool {
358 self.inline_units.is_empty()
359 }
360
361 fn collect_inline_unit(&mut self, mut inline_unit: LayoutInlineUnit, margin: EdgeOption<Len>) {
362 inline_unit.offset.x += self.total_inline_size + margin.left.or_zero();
363 inline_unit.offset.y += self.block_start + margin.top.or_zero();
364 self.total_inline_size += inline_unit.size.width + margin.horizontal();
365 self.total_block_size = self
366 .total_block_size
367 .max(inline_unit.size.height + margin.vertical());
368 self.first_baseline_ascent = self
369 .first_baseline_ascent
370 .max(inline_unit.first_baseline_ascent);
371 self.inline_units.push(inline_unit);
372 }
373
374 fn adjust_inline_offset(&mut self) {
375 self.inline_units.iter_mut().for_each(|inline_unit| {
376 inline_unit.offset.x += self.inline_offset;
377 })
378 }
379
380 fn adjust_block_offset(&mut self) {
381 self.inline_units.iter_mut().for_each(|inline_unit| {
383 let max_baseline = self.first_baseline_ascent.y;
384 let self_baseline = inline_unit.first_baseline_ascent.y;
385 inline_unit.offset.y += max_baseline - self_baseline;
386 })
387 }
388
389 fn set_inline_offset(&mut self, inline_offset: Len) {
390 self.inline_offset = inline_offset
391 }
392}
393
394pub struct LayoutInlineMeasure {}
395impl InlineMeasure<Node> for LayoutInlineMeasure {
396 type InlineUnit = LayoutInlineUnit;
397 type Env = Env;
398
399 fn block_size(
400 _env: &mut Env,
401 block_node: &Node,
402 inline_nodes: Vec<(LayoutInlineUnit, EdgeOption<Len>, Edge<Len>)>,
403 req_size: OptionSize<Len>,
404 _max_content_with_max_size: OptionSize<Len>,
405 _update_position: bool,
406 ) -> (Size<Len>, Vec<(Point<Len>, MeasureResult<Len>)>) {
407 let suggested_width = req_size.width;
408 let suggested_height = req_size.height;
409 if inline_nodes.is_empty() {
410 return (
411 Size::new(
412 suggested_width.unwrap_or(Len::zero()),
413 suggested_height.unwrap_or(Len::zero()),
414 ),
415 Vec::with_capacity(0),
416 );
417 }
418 let mut lines: Vec<Line> = vec![];
419 let mut prev_line_block_start = Len::zero();
420 let mut current_line = Line::default();
421 if let Some(suggested_width) = suggested_width.val() {
422 inline_nodes
423 .into_iter()
424 .for_each(|(mut inline_unit, margin, padding_border)| {
425 inline_unit.adjust_inline_size(padding_border);
426 if (current_line.total_inline_size
427 + inline_unit.size.width
428 + margin.horizontal()
429 > suggested_width)
430 && !current_line.is_empty()
431 {
432 prev_line_block_start += current_line.total_block_size;
433 lines.push(current_line.clone());
434 current_line = Line::default();
435 current_line.block_start = prev_line_block_start;
436 }
437 current_line.collect_inline_unit(inline_unit, margin);
438 });
439 } else {
440 inline_nodes
441 .into_iter()
442 .for_each(|(mut inline_unit, margin, padding_border)| {
443 inline_unit.adjust_inline_size(padding_border);
444 current_line.collect_inline_unit(inline_unit, margin);
445 });
446 }
447 if !current_line.is_empty() {
448 lines.push(current_line.clone());
449 }
450 let (mut block_width, mut block_height) = (Len::zero(), Len::zero());
451 lines.iter_mut().for_each(|line| {
452 block_width = block_width.max(line.total_inline_size);
453 block_height += line.total_block_size;
454 line.adjust_block_offset();
455 });
456 let block_size = Size::new(
457 suggested_width.unwrap_or(block_width),
458 suggested_height.unwrap_or(block_height),
459 );
460 if let Some(suggested_width) = suggested_width.val() {
461 if suggested_width > block_width {
462 let text_align = block_node.style().text_align();
463 match text_align {
464 TextAlign::Start | TextAlign::Left => {}
465 TextAlign::End | TextAlign::Right => lines.iter_mut().for_each(|line| {
466 let inline_offset = suggested_width - line.total_inline_size;
467 line.set_inline_offset(inline_offset);
468 line.adjust_inline_offset()
469 }),
470 TextAlign::Center => lines.iter_mut().for_each(|line| {
471 let inline_offset = (suggested_width - line.total_inline_size).div_f32(2.);
472 line.set_inline_offset(inline_offset);
473 line.adjust_inline_offset()
474 }),
475 TextAlign::Justify => {}
476 TextAlign::JustifyAll => {}
477 TextAlign::MatchParent => {}
478 }
479 }
480 }
481 let detailed_position = lines
482 .into_iter()
483 .flat_map(|line| {
484 line.inline_units
485 .into_iter()
486 .map(|inline_unit| inline_unit.to_tuple())
487 })
488 .collect();
489 (block_size, detailed_position)
490 }
491}
492
493impl LayoutStyle<Len> for Node {
494 #[inline]
495 fn display(&self) -> Display {
496 self.style_manager().display()
497 }
498
499 #[inline]
500 fn position(&self) -> Position {
501 self.style_manager().position()
502 }
503
504 #[inline]
505 fn box_sizing(&self) -> BoxSizing {
506 self.style_manager().box_sizing()
507 }
508
509 #[inline]
510 fn direction(&self) -> Direction {
511 self.style_manager().direction()
512 }
513
514 #[inline]
515 fn writing_mode(&self) -> WritingMode {
516 self.style_manager().writing_mode()
517 }
518
519 #[inline]
520 fn flex_direction(&self) -> FlexDirection {
521 self.style_manager().flex_direction()
522 }
523
524 #[inline]
525 fn flex_wrap(&self) -> FlexWrap {
526 self.style_manager().flex_wrap()
527 }
528
529 #[inline]
530 fn flex_grow(&self) -> f32 {
531 self.style_manager().flex_grow()
532 }
533
534 #[inline]
535 fn flex_shrink(&self) -> f32 {
536 self.style_manager().flex_shrink()
537 }
538
539 #[inline]
540 fn align_items(&self) -> AlignItems {
541 self.style_manager().align_items()
542 }
543
544 #[inline]
545 fn align_self(&self) -> AlignSelf {
546 self.style_manager().align_self()
547 }
548
549 #[inline]
550 fn align_content(&self) -> AlignContent {
551 self.style_manager().align_content()
552 }
553
554 #[inline]
555 fn justify_content(&self) -> JustifyContent {
556 self.style_manager().justify_content()
557 }
558
559 #[inline]
560 fn left(&self) -> Length {
561 self.style_manager().left()
562 }
563
564 #[inline]
565 fn right(&self) -> Length {
566 self.style_manager().right()
567 }
568
569 #[inline]
570 fn top(&self) -> Length {
571 self.style_manager().top()
572 }
573
574 #[inline]
575 fn bottom(&self) -> Length {
576 self.style_manager().bottom()
577 }
578
579 #[inline]
580 fn border_left(&self) -> Length {
581 self.style_manager().border_left()
582 }
583
584 #[inline]
585 fn border_right(&self) -> Length {
586 self.style_manager().border_right()
587 }
588
589 #[inline]
590 fn border_top(&self) -> Length {
591 self.style_manager().border_top()
592 }
593
594 #[inline]
595 fn border_bottom(&self) -> Length {
596 self.style_manager().border_bottom()
597 }
598
599 #[inline]
600 fn margin_left(&self) -> Length {
601 self.style_manager().margin_left()
602 }
603
604 #[inline]
605 fn margin_right(&self) -> Length {
606 self.style_manager().margin_right()
607 }
608
609 #[inline]
610 fn margin_top(&self) -> Length {
611 self.style_manager().margin_top()
612 }
613
614 #[inline]
615 fn margin_bottom(&self) -> Length {
616 self.style_manager().margin_bottom()
617 }
618
619 #[inline]
620 fn padding_left(&self) -> Length {
621 self.style_manager().padding_left()
622 }
623
624 #[inline]
625 fn padding_right(&self) -> Length {
626 self.style_manager().padding_right()
627 }
628
629 #[inline]
630 fn padding_top(&self) -> Length {
631 self.style_manager().padding_top()
632 }
633
634 #[inline]
635 fn padding_bottom(&self) -> Length {
636 self.style_manager().padding_bottom()
637 }
638
639 #[inline]
640 fn flex_basis(&self) -> Length {
641 self.style_manager().flex_basis()
642 }
643
644 #[inline]
645 fn width(&self) -> Length {
646 self.style_manager().width()
647 }
648
649 #[inline]
650 fn height(&self) -> Length {
651 self.style_manager().height()
652 }
653
654 #[inline]
655 fn min_width(&self) -> Length {
656 self.style_manager().min_width()
657 }
658
659 #[inline]
660 fn min_height(&self) -> Length {
661 self.style_manager().min_height()
662 }
663
664 #[inline]
665 fn max_width(&self) -> Length {
666 self.style_manager().max_width()
667 }
668
669 #[inline]
670 fn max_height(&self) -> Length {
671 self.style_manager().max_height()
672 }
673
674 #[inline]
675 fn aspect_ratio(&self) -> Option<f32> {
676 self.style_manager().aspect_ratio()
677 }
678
679 #[inline]
680 fn order(&self) -> i32 {
681 self.style_manager().order()
682 }
683
684 #[inline]
685 fn text_align(&self) -> TextAlign {
686 self.style_manager().text_align()
687 }
688
689 #[inline]
690 fn row_gap(&self) -> Length {
691 self.style_manager().row_gap()
692 }
693
694 #[inline]
695 fn column_gap(&self) -> Length {
696 self.style_manager().column_gap()
697 }
698}