float_pigment_forest/layout/
layout_impl.rs

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    // text_align: TextAlign,
340}
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            // text_align: TextAlign::Start,
352        }
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        // TODO affected by vertical-align
382        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}