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 }
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 }
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 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}