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, EdgeOption, InlineMeasure, InlineUnit, InlineUnitMetadata, 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    ) -> MeasureResult<Self::Length> {
244        self.measure_block_size(env, req_size, min, max, max_content, false)
245    }
246}
247
248impl LayoutTreeVisitor<Node> for Node {
249    #[inline]
250    fn parent(&self) -> Option<&Node> {
251        unsafe { Node::parent(self) }
252    }
253
254    #[inline]
255    fn for_each_child<'a, 'b: 'a, F>(&'b self, f: F)
256    where
257        F: FnMut(&'a Node, usize),
258        Node: 'a,
259    {
260        unsafe { self.for_each_child_node(f) }
261    }
262
263    #[inline]
264    fn children_len(&self) -> usize {
265        Node::children_len(self)
266    }
267
268    #[inline]
269    fn child_at(&self, index: usize) -> Option<&Node> {
270        unsafe { self.get_child_at(index) }
271    }
272}
273#[derive(Debug, Clone)]
274pub struct LayoutInlineUnit {
275    offset: Point<Len>,
276    size: Size<Len>,
277    first_baseline_ascent: Vector<Len>,
278    last_baseline_ascent: Vector<Len>,
279}
280
281impl LayoutInlineUnit {
282    fn to_tuple(&self) -> (Point<Len>, MeasureResult<Len>) {
283        (
284            self.offset,
285            MeasureResult {
286                size: self.size,
287                first_baseline_ascent: self.first_baseline_ascent,
288                last_baseline_ascent: self.last_baseline_ascent,
289            },
290        )
291    }
292}
293
294impl InlineUnit<Node> for LayoutInlineUnit {
295    type Env = Env;
296    fn new(_env: &mut Env, _node: &Node, res: MeasureResult<Len>) -> Self {
297        Self {
298            offset: Point::zero(),
299            size: res.size,
300            first_baseline_ascent: res.first_baseline_ascent,
301            last_baseline_ascent: res.last_baseline_ascent,
302        }
303    }
304}
305
306#[derive(Debug, Clone)]
307struct Line {
308    inline_units: Vec<LayoutInlineUnit>,
309    total_inline_size: Len,
310    total_block_size: Len,
311    block_start: Len,
312    inline_offset: Len,
313    first_baseline_ascent: Vector<Len>,
314    // text_align: TextAlign,
315}
316
317impl Default for Line {
318    fn default() -> Self {
319        Self {
320            inline_units: vec![],
321            total_inline_size: Len::zero(),
322            total_block_size: Len::zero(),
323            block_start: Len::zero(),
324            inline_offset: Len::zero(),
325            first_baseline_ascent: Vector::default(),
326            // text_align: TextAlign::Start,
327        }
328    }
329}
330
331impl Line {
332    fn is_empty(&self) -> bool {
333        self.inline_units.is_empty()
334    }
335
336    fn collect_inline_unit(&mut self, mut inline_unit: LayoutInlineUnit, margin: EdgeOption<Len>) {
337        inline_unit.offset.x += self.total_inline_size + margin.left.or_zero();
338        inline_unit.offset.y += self.block_start + margin.top.or_zero();
339        self.total_inline_size += inline_unit.size.width + margin.horizontal();
340        self.total_block_size = self
341            .total_block_size
342            .max(inline_unit.size.height + margin.vertical());
343        self.first_baseline_ascent = self
344            .first_baseline_ascent
345            .max(inline_unit.first_baseline_ascent);
346        self.inline_units.push(inline_unit);
347    }
348
349    fn adjust_inline_offset(&mut self) {
350        self.inline_units.iter_mut().for_each(|inline_unit| {
351            inline_unit.offset.x += self.inline_offset;
352        })
353    }
354
355    fn adjust_block_offset(&mut self) {
356        // TODO affected by vertical-align
357        self.inline_units.iter_mut().for_each(|inline_unit| {
358            let max_baseline = self.first_baseline_ascent.y;
359            let self_baseline = inline_unit.first_baseline_ascent.y;
360            inline_unit.offset.y += max_baseline - self_baseline;
361        })
362    }
363
364    fn set_inline_offset(&mut self, inline_offset: Len) {
365        self.inline_offset = inline_offset
366    }
367}
368
369pub struct LayoutInlineMeasure {}
370impl InlineMeasure<Node> for LayoutInlineMeasure {
371    type InlineUnit = LayoutInlineUnit;
372    type Env = Env;
373
374    fn block_size(
375        _env: &mut Env,
376        block_node: &Node,
377        inline_nodes: Vec<InlineUnitMetadata<Node>>,
378        req_size: OptionSize<Len>,
379        _max_content_with_max_size: OptionSize<Len>,
380        _update_position: bool,
381    ) -> (Size<Len>, Vec<(Point<Len>, MeasureResult<Len>)>) {
382        let suggested_width = req_size.width;
383        let suggested_height = req_size.height;
384        if inline_nodes.is_empty() {
385            return (
386                Size::new(
387                    suggested_width.unwrap_or(Len::zero()),
388                    suggested_height.unwrap_or(Len::zero()),
389                ),
390                Vec::with_capacity(0),
391            );
392        }
393        let mut lines: Vec<Line> = vec![];
394        let mut prev_line_block_start = Len::zero();
395        let mut current_line = Line::default();
396        if let Some(suggested_width) = suggested_width.val() {
397            inline_nodes
398                .into_iter()
399                .for_each(|InlineUnitMetadata { unit, margin }| {
400                    if (current_line.total_inline_size + unit.size.width + margin.horizontal()
401                        > suggested_width)
402                        && !current_line.is_empty()
403                    {
404                        prev_line_block_start += current_line.total_block_size;
405                        lines.push(current_line.clone());
406                        current_line = Line::default();
407                        current_line.block_start = prev_line_block_start;
408                    }
409                    current_line.collect_inline_unit(unit, margin);
410                });
411        } else {
412            inline_nodes
413                .into_iter()
414                .for_each(|InlineUnitMetadata { unit, margin }| {
415                    current_line.collect_inline_unit(unit, margin);
416                });
417        }
418        if !current_line.is_empty() {
419            lines.push(current_line.clone());
420        }
421        let (mut block_width, mut block_height) = (Len::zero(), Len::zero());
422        lines.iter_mut().for_each(|line| {
423            block_width = block_width.max(line.total_inline_size);
424            block_height += line.total_block_size;
425            line.adjust_block_offset();
426        });
427        let block_size = Size::new(
428            suggested_width.unwrap_or(block_width),
429            suggested_height.unwrap_or(block_height),
430        );
431        if let Some(suggested_width) = suggested_width.val() {
432            if suggested_width > block_width {
433                let text_align = block_node.style().text_align();
434                match text_align {
435                    TextAlign::Start | TextAlign::Left => {}
436                    TextAlign::End | TextAlign::Right => lines.iter_mut().for_each(|line| {
437                        let inline_offset = suggested_width - line.total_inline_size;
438                        line.set_inline_offset(inline_offset);
439                        line.adjust_inline_offset()
440                    }),
441                    TextAlign::Center => lines.iter_mut().for_each(|line| {
442                        let inline_offset = (suggested_width - line.total_inline_size).div_f32(2.);
443                        line.set_inline_offset(inline_offset);
444                        line.adjust_inline_offset()
445                    }),
446                    TextAlign::Justify => {}
447                    TextAlign::JustifyAll => {}
448                    TextAlign::MatchParent => {}
449                }
450            }
451        }
452        let detailed_position = lines
453            .into_iter()
454            .flat_map(|line| {
455                line.inline_units
456                    .into_iter()
457                    .map(|inline_unit| inline_unit.to_tuple())
458            })
459            .collect();
460        (block_size, detailed_position)
461    }
462}
463
464impl LayoutStyle<Len> for Node {
465    #[inline]
466    fn display(&self) -> Display {
467        self.style_manager().display()
468    }
469
470    #[inline]
471    fn position(&self) -> Position {
472        self.style_manager().position()
473    }
474
475    #[inline]
476    fn box_sizing(&self) -> BoxSizing {
477        self.style_manager().box_sizing()
478    }
479
480    #[inline]
481    fn direction(&self) -> Direction {
482        self.style_manager().direction()
483    }
484
485    #[inline]
486    fn writing_mode(&self) -> WritingMode {
487        self.style_manager().writing_mode()
488    }
489
490    #[inline]
491    fn flex_direction(&self) -> FlexDirection {
492        self.style_manager().flex_direction()
493    }
494
495    #[inline]
496    fn flex_wrap(&self) -> FlexWrap {
497        self.style_manager().flex_wrap()
498    }
499
500    #[inline]
501    fn flex_grow(&self) -> f32 {
502        self.style_manager().flex_grow()
503    }
504
505    #[inline]
506    fn flex_shrink(&self) -> f32 {
507        self.style_manager().flex_shrink()
508    }
509
510    #[inline]
511    fn align_items(&self) -> AlignItems {
512        self.style_manager().align_items()
513    }
514
515    #[inline]
516    fn align_self(&self) -> AlignSelf {
517        self.style_manager().align_self()
518    }
519
520    #[inline]
521    fn align_content(&self) -> AlignContent {
522        self.style_manager().align_content()
523    }
524
525    #[inline]
526    fn justify_content(&self) -> JustifyContent {
527        self.style_manager().justify_content()
528    }
529
530    #[inline]
531    fn left(&self) -> Length {
532        self.style_manager().left()
533    }
534
535    #[inline]
536    fn right(&self) -> Length {
537        self.style_manager().right()
538    }
539
540    #[inline]
541    fn top(&self) -> Length {
542        self.style_manager().top()
543    }
544
545    #[inline]
546    fn bottom(&self) -> Length {
547        self.style_manager().bottom()
548    }
549
550    #[inline]
551    fn border_left(&self) -> Length {
552        self.style_manager().border_left()
553    }
554
555    #[inline]
556    fn border_right(&self) -> Length {
557        self.style_manager().border_right()
558    }
559
560    #[inline]
561    fn border_top(&self) -> Length {
562        self.style_manager().border_top()
563    }
564
565    #[inline]
566    fn border_bottom(&self) -> Length {
567        self.style_manager().border_bottom()
568    }
569
570    #[inline]
571    fn margin_left(&self) -> Length {
572        self.style_manager().margin_left()
573    }
574
575    #[inline]
576    fn margin_right(&self) -> Length {
577        self.style_manager().margin_right()
578    }
579
580    #[inline]
581    fn margin_top(&self) -> Length {
582        self.style_manager().margin_top()
583    }
584
585    #[inline]
586    fn margin_bottom(&self) -> Length {
587        self.style_manager().margin_bottom()
588    }
589
590    #[inline]
591    fn padding_left(&self) -> Length {
592        self.style_manager().padding_left()
593    }
594
595    #[inline]
596    fn padding_right(&self) -> Length {
597        self.style_manager().padding_right()
598    }
599
600    #[inline]
601    fn padding_top(&self) -> Length {
602        self.style_manager().padding_top()
603    }
604
605    #[inline]
606    fn padding_bottom(&self) -> Length {
607        self.style_manager().padding_bottom()
608    }
609
610    #[inline]
611    fn flex_basis(&self) -> Length {
612        self.style_manager().flex_basis()
613    }
614
615    #[inline]
616    fn width(&self) -> Length {
617        self.style_manager().width()
618    }
619
620    #[inline]
621    fn height(&self) -> Length {
622        self.style_manager().height()
623    }
624
625    #[inline]
626    fn min_width(&self) -> Length {
627        self.style_manager().min_width()
628    }
629
630    #[inline]
631    fn min_height(&self) -> Length {
632        self.style_manager().min_height()
633    }
634
635    #[inline]
636    fn max_width(&self) -> Length {
637        self.style_manager().max_width()
638    }
639
640    #[inline]
641    fn max_height(&self) -> Length {
642        self.style_manager().max_height()
643    }
644
645    #[inline]
646    fn aspect_ratio(&self) -> Option<f32> {
647        self.style_manager().aspect_ratio()
648    }
649
650    #[inline]
651    fn order(&self) -> i32 {
652        self.style_manager().order()
653    }
654
655    #[inline]
656    fn text_align(&self) -> TextAlign {
657        self.style_manager().text_align()
658    }
659
660    #[inline]
661    fn row_gap(&self) -> Length {
662        self.style_manager().row_gap()
663    }
664
665    #[inline]
666    fn column_gap(&self) -> Length {
667        self.style_manager().column_gap()
668    }
669}