1use crate::*;
2use float_pigment_css::num_traits::{bounds::Bounded, Zero};
3
4#[allow(clippy::type_complexity)]
5pub(crate) struct LayoutUnit<T: LayoutTreeNode> {
6 pub(crate) cache: LayoutComputeCache<T::Length>,
7 pub(crate) result: Rect<T::Length>,
8 pub(crate) result_padding_rect: Rect<T::Length>,
9 pub(crate) result_content_rect: Rect<T::Length>,
10 pub(crate) computed_style: ComputedStyle<T::Length>,
11 pub(crate) layout_algorithm: LayoutAlgorithm,
12}
13
14impl<T: LayoutTreeNode> LayoutUnit<T> {
15 pub(crate) fn new() -> Self {
16 Self {
17 cache: LayoutComputeCache::new(),
18 result: Rect::zero(),
19 result_padding_rect: Rect::zero(),
20 result_content_rect: Rect::zero(),
21 computed_style: ComputedStyle::default(),
22 layout_algorithm: LayoutAlgorithm::None,
23 }
24 }
25
26 pub(crate) fn mark_dirty(&mut self, node_tree_visitor: &T::TreeVisitor) -> bool {
27 if !self.mark_self_dirty() {
28 return false;
29 }
30 let mut cur = node_tree_visitor;
31 while let Some(parent) = cur.parent() {
32 parent.tree_visitor().dirty_marked();
33 if !parent.layout_node().unit().mark_self_dirty() {
34 break;
35 }
36 cur = parent.tree_visitor();
37 }
38 true
39 }
40
41 fn mark_self_dirty(&mut self) -> bool {
42 self.cache.clear()
43 }
44
45 #[inline]
46 pub(crate) fn result(&self) -> Rect<T::Length> {
47 self.result
48 }
49
50 #[inline]
51 pub(crate) fn result_padding_rect(&self) -> Rect<T::Length> {
52 self.result_padding_rect
53 }
54
55 #[inline]
56 pub(crate) fn result_content_rect(&self) -> Rect<T::Length> {
57 self.result_content_rect
58 }
59
60 #[inline]
61 pub(crate) fn compute_with_containing_size(
62 &mut self,
63 env: &mut T::Env,
64 node: &T,
65 available_size: OptionSize<T::Length>,
66 containing_size: OptionSize<T::Length>,
67 ) {
68 let (margin, border, padding_border) = self.margin_border_padding(node, containing_size);
69 let min_max_limit =
70 self.normalized_min_max_limit(node, containing_size, border, padding_border);
71 let mut css_size = self.css_border_box_size(node, containing_size, border, padding_border);
72 css_size.width = css_size.width.or({
73 match node.style().display() {
74 Display::InlineBlock | Display::InlineFlex => OptionNum::none(),
75 _ => available_size.width - margin.left - margin.right,
76 }
77 });
78 css_size.height = css_size.height.or({
79 match node.style().display() {
80 Display::InlineBlock | Display::InlineFlex => OptionNum::none(),
81 _ => available_size.height - margin.top - margin.bottom,
82 }
83 });
84 let size = min_max_limit.normalized_size(css_size);
85 let req = ComputeRequest {
86 size,
87 parent_inner_size: size,
88 max_content: size,
89 kind: ComputeRequestKind::Position,
90 parent_is_block: node.style().display() == Display::Block
91 || node.style().display() == Display::InlineBlock
92 || node.style().display() == Display::Inline,
93 sizing_mode: SizingMode::Normal,
94 };
95 let result = self.compute_internal(env, node, req);
96 self.result = Rect::new(
97 Point::new(margin.left.or_zero(), result.collapsed_margin.start.solve()),
98 result.size.0,
99 );
100
101 self.computed_style.margin.top = result.collapsed_margin.start.solve();
103 self.computed_style.margin.left = margin.left.or_zero();
104 self.computed_style.margin.right = margin.right.or_zero();
105 self.computed_style.margin.bottom = result.collapsed_margin.end.solve();
106 }
107
108 #[inline]
109 pub(crate) fn compute(&mut self, env: &mut T::Env, node: &T, size: OptionSize<T::Length>) {
110 let size = Normalized(size);
111 let req = ComputeRequest {
112 size,
113 parent_inner_size: size,
114 max_content: size,
115 kind: ComputeRequestKind::Position,
116 parent_is_block: false,
117 sizing_mode: SizingMode::Normal,
118 };
119 let result = self.compute_internal(env, node, req);
120 self.result = Rect::new(Point::zero(), result.size.0);
121 }
122
123 #[inline]
124 pub(crate) fn computed_style(&self) -> ComputedStyle<T::Length> {
125 self.computed_style
126 }
127
128 pub(crate) fn clear_display_none_result(&mut self, node: &T) {
129 self.cache.touch(node);
131 self.cache.clear_position_cache();
132 self.result = Rect::zero();
133 self.result_padding_rect = Rect::zero();
134 self.result_content_rect = Rect::zero();
135 self.layout_algorithm = LayoutAlgorithm::None;
136 node.tree_visitor().for_each_child(|child_node, _| {
137 child_node
138 .layout_node()
139 .unit()
140 .clear_display_none_result(child_node);
141 });
142 }
143
144 pub(crate) fn compute_internal(
145 &mut self,
146 env: &mut T::Env,
147 node: &T,
148 request: ComputeRequest<T::Length>,
149 ) -> ComputeResult<T::Length> {
150 let style = node.style();
151 let mut layout_algorithm = match style.display() {
152 Display::None => LayoutAlgorithm::None,
153 Display::Block | Display::InlineBlock | Display::Inline => LayoutAlgorithm::Block,
154 Display::Flex | Display::InlineFlex => LayoutAlgorithm::Flex,
155 Display::Grid | Display::InlineGrid => LayoutAlgorithm::Grid,
156 Display::FlowRoot => todo!(),
157 };
158
159 let ret = if let Some(r) = self.cache.read(node, &request) {
160 r
163 } else {
164 let (margin, border, padding_border) =
167 self.margin_border_padding(node, *request.parent_inner_size);
168 if let Some(ret) = self.compute_measure_block_if_exists(
169 env,
170 node,
171 request.clone(),
172 margin,
173 border,
174 padding_border,
175 ) {
176 layout_algorithm = LayoutAlgorithm::BlockMeasure;
177 ret
178 } else {
179 match layout_algorithm {
180 LayoutAlgorithm::None => {
181 self.clear_display_none_result(node);
182 ComputeResult {
183 size: Normalized(Size::zero()),
184 first_baseline_ascent: Vector::zero(),
185 last_baseline_ascent: Vector::zero(),
186 collapsed_margin: CollapsedBlockMargin::zero(),
187 }
188 }
189 LayoutAlgorithm::Block => algo::flow::Flow::compute(
190 self,
191 env,
192 node,
193 request.clone(),
194 margin,
195 border,
196 padding_border,
197 ),
198 LayoutAlgorithm::Flex => algo::flex_box::FlexBox::compute(
199 self,
200 env,
201 node,
202 request.clone(),
203 margin,
204 border,
205 padding_border,
206 ),
207 LayoutAlgorithm::Grid => algo::grid::GridContainer::compute(
208 self,
209 env,
210 node,
211 request.clone(),
212 margin,
213 border,
214 padding_border,
215 ),
216 _ => unreachable!(),
217 }
218 }
219 };
220
221 if request.kind == ComputeRequestKind::Position {
222 self.save_all_results(node, env, *request.parent_inner_size, layout_algorithm);
223 }
224 ret
226 }
227
228 pub(crate) fn save_all_results(
229 &mut self,
230 node: &T,
231 env: &mut T::Env,
232 parent_inner_size: OptionSize<T::Length>,
233 layout_algorithm: LayoutAlgorithm,
234 ) {
235 let (margin, border, padding_border) = self.margin_border_padding(node, parent_inner_size);
236 self.save_border_padding_result(border, padding_border);
237 self.save_computed_style(margin, border, padding_border - border);
238 self.layout_algorithm = layout_algorithm;
239 node.size_updated(env, self.result.size, &self.computed_style);
240 }
241
242 pub(crate) fn update_result_layout_algorithm(
243 &mut self,
244 f: impl FnOnce(LayoutAlgorithm) -> LayoutAlgorithm,
245 ) {
246 self.layout_algorithm = f(self.layout_algorithm);
247 }
248
249 pub(crate) fn save_computed_style(
250 &mut self,
251 margin: EdgeOption<T::Length>,
252 border: Edge<T::Length>,
253 padding: Edge<T::Length>,
254 ) {
255 self.computed_style = ComputedStyle {
256 margin: Edge {
257 left: margin.left.or_zero(),
258 right: margin.right.or_zero(),
259 top: margin.top.or_zero(),
260 bottom: margin.bottom.or_zero(),
261 },
262 border: Edge {
263 left: border.left,
264 right: border.right,
265 top: border.top,
266 bottom: border.bottom,
267 },
268 padding: Edge {
269 left: padding.left,
270 right: padding.right,
271 top: padding.top,
272 bottom: padding.bottom,
273 },
274 }
275 }
276
277 pub(crate) fn save_border_padding_result(
278 &mut self,
279 border: Edge<T::Length>,
280 padding_border: Edge<T::Length>,
281 ) {
282 self.result_padding_rect = Rect::new(
283 Point::new(border.left, border.top),
284 Size::new(
285 self.result.size.width - border.left - border.right,
286 self.result.size.height - border.top - border.bottom,
287 ),
288 );
289 self.result_content_rect = Rect::new(
290 Point::new(padding_border.left, padding_border.top),
291 Size::new(
292 self.result.size.width - padding_border.left - padding_border.right,
293 self.result.size.height - padding_border.top - padding_border.bottom,
294 ),
295 );
296 }
298
299 pub(crate) fn is_requested_size_fixed(
300 &mut self,
301 request: &ComputeRequest<T::Length>,
302 collapsed_margin: Option<CollapsedBlockMargin<T::Length>>,
303 ) -> Option<ComputeResult<T::Length>> {
304 let collapsed_margin = if let Some(x) = collapsed_margin {
305 x
306 } else if request.parent_is_block {
307 return None;
308 } else {
309 CollapsedBlockMargin::zero()
310 };
311 match request.kind {
313 ComputeRequestKind::AllSize => {
314 if let Some(width) = request.size.width.val() {
315 if let Some(height) = request.size.height.val() {
316 let size = Size::new(width, height);
317 return Some(ComputeResult {
318 size: Normalized(size),
319 first_baseline_ascent: size.to_vector(),
320 last_baseline_ascent: size.to_vector(),
321 collapsed_margin,
322 });
323 }
324 }
325 }
326 ComputeRequestKind::RowSize => {
327 if let Some(width) = request.size.width.val() {
328 let size = Size::new(width, T::Length::zero());
329 return Some(ComputeResult {
330 size: Normalized(size),
331 first_baseline_ascent: size.to_vector(),
332 last_baseline_ascent: size.to_vector(),
333 collapsed_margin,
334 });
335 }
336 }
337 ComputeRequestKind::ColSize => {
338 if let Some(height) = request.size.height.val() {
339 let size = Size::new(T::Length::zero(), height);
340 return Some(ComputeResult {
341 size: Normalized(size),
342 first_baseline_ascent: size.to_vector(),
343 last_baseline_ascent: size.to_vector(),
344 collapsed_margin,
345 });
346 }
347 }
348 _ => {}
349 }
350 None
351 }
352
353 #[allow(clippy::type_complexity)]
354 pub(crate) fn margin_border_padding(
355 &self,
356 node: &T,
357 parent_inner_size: OptionSize<T::Length>,
358 ) -> (EdgeOption<T::Length>, Edge<T::Length>, Edge<T::Length>) {
359 let style = node.style();
360 let length_ratio_base = match style.writing_mode() {
361 WritingMode::HorizontalTb => parent_inner_size.width,
362 WritingMode::VerticalLr | WritingMode::VerticalRl => parent_inner_size.height,
363 };
364 let margin = EdgeOption {
365 left: style
366 .margin_left()
367 .resolve_with_auto(length_ratio_base, node),
368 right: style
369 .margin_right()
370 .resolve_with_auto(length_ratio_base, node),
371 top: style
372 .margin_top()
373 .resolve_with_auto(length_ratio_base, node),
374 bottom: style
375 .margin_bottom()
376 .resolve_with_auto(length_ratio_base, node),
377 };
378 let border = Edge {
379 left: style
380 .border_left()
381 .resolve(length_ratio_base, node)
382 .or_zero(),
383 right: style
384 .border_right()
385 .resolve(length_ratio_base, node)
386 .or_zero(),
387 top: style
388 .border_top()
389 .resolve(length_ratio_base, node)
390 .or_zero(),
391 bottom: style
392 .border_bottom()
393 .resolve(length_ratio_base, node)
394 .or_zero(),
395 };
396 let padding = Edge {
397 left: style
398 .padding_left()
399 .resolve(length_ratio_base, node)
400 .or_zero(),
401 right: style
402 .padding_right()
403 .resolve(length_ratio_base, node)
404 .or_zero(),
405 top: style
406 .padding_top()
407 .resolve(length_ratio_base, node)
408 .or_zero(),
409 bottom: style
410 .padding_bottom()
411 .resolve(length_ratio_base, node)
412 .or_zero(),
413 };
414 let padding_border = Edge {
415 left: padding.left + border.left,
416 right: padding.right + border.right,
417 top: padding.top + border.top,
418 bottom: padding.bottom + border.bottom,
419 };
420 (margin, border, padding_border)
421 }
422
423 #[inline]
424 pub(crate) fn min_max_size_limit(
425 &self,
426 node: &T,
427 parent_inner_size: OptionSize<T::Length>,
428 size: Size<T::Length>,
429 border: Edge<T::Length>,
430 padding_border: Edge<T::Length>,
431 ) -> Normalized<Size<T::Length>> {
432 let ret = self.min_max_option_size_limit(
433 node,
434 parent_inner_size,
435 size_to_option(size),
436 border,
437 padding_border,
438 );
439 Normalized(Size::new(ret.width.or_zero(), ret.height.or_zero()))
440 }
441
442 #[inline]
443 pub(crate) fn min_max_option_size_limit(
444 &self,
445 node: &T,
446 parent_inner_size: OptionSize<T::Length>,
447 size: OptionSize<T::Length>,
448 border: Edge<T::Length>,
449 padding_border: Edge<T::Length>,
450 ) -> Normalized<OptionSize<T::Length>> {
451 let min_max_limit =
452 self.normalized_min_max_limit(node, parent_inner_size, border, padding_border);
453 min_max_limit.normalized_size(size)
454 }
455 #[inline]
456 pub(crate) fn min_max_size(
457 node: &T,
458 parent_size: OptionSize<T::Length>,
459 ) -> MinMaxSize<T::Length> {
460 let style = node.style();
461 let min_width = style.min_width().resolve(parent_size.width, node);
462 let max_width = style.max_width().resolve(parent_size.width, node);
463 let min_height = style.min_height().resolve(parent_size.height, node);
464 let max_height = style.max_height().resolve(parent_size.height, node);
465 MinMaxSize {
466 min_width,
467 max_width,
468 min_height,
469 max_height,
470 }
471 }
472
473 #[inline]
474 pub(crate) fn normalized_min_max_limit(
475 &self,
476 node: &T,
477 parent_size: OptionSize<T::Length>,
478 border: Edge<T::Length>,
479 padding_border: Edge<T::Length>,
480 ) -> MinMaxLimit<T::Length> {
481 let style = node.style();
482 let MinMaxSize {
483 min_width,
484 max_width,
485 min_height,
486 max_height,
487 } = Self::min_max_size(node, parent_size);
488 match style.box_sizing() {
489 BoxSizing::BorderBox => {
490 let min_width = padding_border.horizontal().maybe_max(min_width);
491 let min_height = padding_border.vertical().maybe_max(min_height);
492 MinMaxLimit {
493 min_width,
494 max_width,
495 min_height,
496 max_height,
497 }
498 }
499 BoxSizing::PaddingBox => {
500 let min_width = border.horizontal().maybe_max(min_width)
501 + padding_border.horizontal()
502 - border.horizontal();
503 let max_width = max_width + padding_border.horizontal() - border.horizontal();
504 let min_height = border.vertical().maybe_max(min_height)
505 + padding_border.vertical()
506 - border.vertical();
507 let max_height = max_height + padding_border.vertical() - border.vertical();
508 MinMaxLimit {
509 min_width,
510 max_width,
511 min_height,
512 max_height,
513 }
514 }
515 BoxSizing::ContentBox => {
516 let min_width =
517 T::Length::zero().maybe_max(min_width) + padding_border.horizontal();
518 let max_width = max_width + padding_border.horizontal();
519 let min_height =
520 T::Length::zero().maybe_max(min_height) + padding_border.vertical();
521 let max_height = max_height + padding_border.vertical();
522 MinMaxLimit {
523 min_width,
524 max_width,
525 min_height,
526 max_height,
527 }
528 }
529 }
530 }
531
532 #[inline]
533 pub(crate) fn css_border_box_size(
534 &self,
535 node: &T,
536 parent_inner_size: OptionSize<T::Length>,
537 border: Edge<T::Length>,
538 padding_border: Edge<T::Length>,
539 ) -> OptionSize<T::Length> {
540 let style = node.style();
541 let size = OptionSize::new(
542 style.width().resolve(parent_inner_size.width, node),
543 style.height().resolve(parent_inner_size.height, node),
544 );
545 match style.box_sizing() {
546 BoxSizing::BorderBox => size,
547 BoxSizing::PaddingBox => OptionSize::new(
548 size.width + padding_border.horizontal() - border.horizontal(),
549 size.height + padding_border.vertical() - border.vertical(),
550 ),
551 BoxSizing::ContentBox => OptionSize::new(
552 size.width + padding_border.horizontal(),
553 size.height + padding_border.vertical(),
554 ),
555 }
556 }
557
558 #[inline]
559 pub(crate) fn compute_measure_block_if_exists(
560 &mut self,
561 env: &mut T::Env,
562 node: &T,
563 request: ComputeRequest<T::Length>,
564 margin: EdgeOption<T::Length>,
565 border: Edge<T::Length>,
566 padding_border: Edge<T::Length>,
567 ) -> Option<ComputeResult<T::Length>> {
568 if node.should_measure(env) {
570 let req_size = match request.sizing_mode {
571 SizingMode::Normal => OptionSize::new(
572 request.size.width - padding_border.horizontal(),
573 request.size.height - padding_border.vertical(),
574 ),
575 SizingMode::MinContent => OptionSize::new(OptionNum::zero(), OptionNum::none()),
576 SizingMode::MaxContent => OptionSize::new(OptionNum::none(), OptionNum::none()),
577 };
578 let max_content = request.max_content;
579 let min_max_limit = self.normalized_min_max_limit(
580 node,
581 *request.parent_inner_size,
582 border,
583 padding_border,
584 );
585 let r = node.measure_block_size(
586 env,
587 req_size,
588 Size::new(
589 min_max_limit.min_width - padding_border.horizontal(),
590 min_max_limit.min_height - padding_border.vertical(),
591 ),
592 Size::new(
593 (min_max_limit.max_width - padding_border.horizontal())
594 .unwrap_or(T::Length::max_value()),
595 (min_max_limit.max_height - padding_border.vertical())
596 .unwrap_or(T::Length::max_value()),
597 ),
598 OptionSize::new(
599 max_content.width - padding_border.horizontal(),
600 max_content.height - padding_border.vertical(),
601 ),
602 request.kind == ComputeRequestKind::Position,
603 request.sizing_mode,
604 );
605 let size = Normalized(Size::new(
606 r.size.width + padding_border.horizontal(),
607 r.size.height + padding_border.vertical(),
608 ));
609 let first_baseline_ascent =
610 r.first_baseline_ascent + Vector::new(padding_border.left, padding_border.top);
611 let last_baseline_ascent =
612 r.last_baseline_ascent + Vector::new(padding_border.left, padding_border.top);
613 let axis_info = AxisInfo::from_writing_mode(node.style().writing_mode());
614 let ret = ComputeResult {
615 size,
616 first_baseline_ascent,
617 last_baseline_ascent,
618 collapsed_margin: CollapsedBlockMargin::from_margin(
619 margin
620 .or_zero()
621 .main_axis_start(axis_info.dir, axis_info.main_dir_rev),
622 margin
623 .or_zero()
624 .main_axis_end(axis_info.dir, axis_info.main_dir_rev),
625 ),
626 };
627 if request.kind == ComputeRequestKind::Position {
628 self.result = Rect::new(Point::zero(), *size);
629 self.cache.write_position(node, &request, ret);
630 } else {
631 self.cache.write_all_size(node, &request, ret);
632 }
633 Some(ret)
634 } else {
635 None
636 }
637 }
638
639 #[allow(clippy::too_many_arguments)]
640 pub(crate) fn get_measure_inline_unit_if_exists(
641 &mut self,
642 env: &mut T::Env,
643 node: &T,
644 parent_inner_size: OptionSize<T::Length>,
645 max_content: OptionSize<T::Length>,
646 border: Edge<T::Length>,
647 padding_border: Edge<T::Length>,
648 sizing_mode: SizingMode,
649 ) -> Option<T::InlineUnit> {
650 if node.should_measure(env) {
652 let css_box_size =
653 self.css_border_box_size(node, parent_inner_size, border, padding_border);
654 let req_size = match sizing_mode {
655 SizingMode::Normal => OptionSize::new(
656 css_box_size.width - padding_border.horizontal(),
657 css_box_size.height - padding_border.vertical(),
658 ),
659 SizingMode::MinContent => OptionSize::new(OptionNum::zero(), OptionNum::none()),
660 SizingMode::MaxContent => OptionSize::new(OptionNum::none(), OptionNum::none()),
661 };
662 let min_max_limit =
663 self.normalized_min_max_limit(node, parent_inner_size, border, padding_border);
664 let r = node.measure_inline_unit(
665 env,
666 req_size,
667 Size::new(
668 min_max_limit.min_width - padding_border.horizontal(),
669 min_max_limit.min_height - padding_border.vertical(),
670 ),
671 Size::new(
672 (min_max_limit.max_width - padding_border.horizontal())
673 .unwrap_or(T::Length::max_value()),
674 (min_max_limit.max_height - padding_border.vertical())
675 .unwrap_or(T::Length::max_value()),
676 ),
677 OptionSize::new(
678 max_content.width - padding_border.horizontal(),
679 max_content.height - padding_border.vertical(),
680 ),
681 sizing_mode,
682 );
683
684 let size = Size::new(
685 r.size.width + padding_border.horizontal(),
686 r.size.height + padding_border.vertical(),
687 );
688 let first_baseline_ascent =
689 r.first_baseline_ascent + Vector::new(padding_border.left, padding_border.top);
690 let last_baseline_ascent =
691 r.last_baseline_ascent + Vector::new(padding_border.left, padding_border.top);
692 let ret = T::InlineUnit::new(
693 env,
694 node,
695 MeasureResult {
696 size,
697 first_baseline_ascent,
698 last_baseline_ascent,
699 },
700 );
701 Some(ret)
702 } else {
703 None
704 }
705 }
706
707 #[inline]
708 pub(crate) fn gen_origin(
709 &mut self,
710 axis_info: AxisInfo,
711 parent_size: Size<T::Length>,
712 offset_main: T::Length,
713 offset_cross: T::Length,
714 ) -> Vector<T::Length> {
715 let (width, height, width_rev, height_rev) = match axis_info.dir {
716 AxisDirection::Horizontal => (
717 offset_main,
718 offset_cross,
719 axis_info.main_dir_rev,
720 axis_info.cross_dir_rev,
721 ),
722 AxisDirection::Vertical => (
723 offset_cross,
724 offset_main,
725 axis_info.cross_dir_rev,
726 axis_info.main_dir_rev,
727 ),
728 };
729 let width = match width_rev {
730 AxisReverse::NotReversed => width,
731 AxisReverse::Reversed => parent_size.width - width - self.result.size.width,
732 };
733 let height = match height_rev {
734 AxisReverse::NotReversed => height,
735 AxisReverse::Reversed => parent_size.height - height - self.result.size.height,
736 };
737 self.result.origin = Point::new(width, height);
738
739 self.result.origin.to_vector()
741 }
742}
743
744#[allow(missing_docs)]
745#[derive(Clone, PartialEq, Copy, Hash, Eq, Debug)]
747pub enum SizingMode {
748 Normal,
749 MinContent,
750 MaxContent,
751}
752
753#[derive(Clone, PartialEq)]
754pub(crate) struct ComputeRequest<L: LengthNum> {
755 pub(crate) size: Normalized<OptionSize<L>>, pub(crate) parent_inner_size: Normalized<OptionSize<L>>, pub(crate) max_content: Normalized<OptionSize<L>>, pub(crate) kind: ComputeRequestKind,
759 pub(crate) parent_is_block: bool,
760 pub(crate) sizing_mode: SizingMode,
761}
762
763impl<L: LengthNum> fmt::Debug for ComputeRequest<L> {
764 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
765 write!(
766 f,
767 "ComputeRequest<{:?},{:?}>({:?}x{:?}, parent {:?}x{:?}, max {:?}x{:?}, parent_is_block {:?})",
768 self.kind,
769 self.sizing_mode,
770 self.size.width,
771 self.size.height,
772 self.parent_inner_size.width,
773 self.parent_inner_size.height,
774 self.max_content.width,
775 self.max_content.height,
776 self.parent_is_block,
777 )
778 }
779}
780
781#[derive(Debug, Clone, Copy, PartialEq)]
782pub(crate) struct ComputeResult<L: LengthNum> {
783 pub(crate) size: Normalized<Size<L>>, pub(crate) first_baseline_ascent: Vector<L>, pub(crate) last_baseline_ascent: Vector<L>, pub(crate) collapsed_margin: CollapsedBlockMargin<L>, }
788
789#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
790pub(crate) enum ComputeRequestKind {
791 RowSize,
792 ColSize,
793 AllSize,
794 Position,
795}
796
797impl ComputeRequestKind {
798 pub(crate) fn shift_to_all_size(&self) -> Self {
799 match self {
800 Self::RowSize => Self::AllSize,
801 Self::ColSize => Self::AllSize,
802 Self::AllSize => Self::AllSize,
803 Self::Position => Self::Position,
804 }
805 }
806
807 pub(crate) fn shift_to_all_size_with_position(&self, with_position: bool) -> Self {
808 match self {
809 Self::RowSize => Self::AllSize,
810 Self::ColSize => Self::AllSize,
811 Self::AllSize => Self::AllSize,
812 Self::Position => {
813 if with_position {
814 Self::Position
815 } else {
816 Self::AllSize
817 }
818 }
819 }
820 }
821}
822
823#[derive(Debug, Clone, Copy, PartialEq)]
824pub(crate) struct CollapsedBlockMargin<L: LengthNum> {
825 pub(crate) collapsed_through: bool,
826 pub(crate) start: CollapsedMargin<L>,
827 pub(crate) end: CollapsedMargin<L>,
828}
829
830#[derive(Debug, Clone, Copy, PartialEq)]
831pub(crate) struct CollapsedMargin<L: LengthNum> {
832 positive: L,
833 negative: L,
834}
835
836impl<L: LengthNum> CollapsedBlockMargin<L> {
837 pub(crate) fn from_margin(margin_start: L, margin_end: L) -> Self {
838 Self {
839 collapsed_through: false,
840 start: CollapsedMargin::new(margin_start),
841 end: CollapsedMargin::new(margin_end),
842 }
843 }
844 pub(crate) fn from_collapsed_margin(
845 margin_start: CollapsedMargin<L>,
846 margin_end: CollapsedMargin<L>,
847 ) -> Self {
848 Self {
849 collapsed_through: false,
850 start: margin_start,
851 end: margin_end,
852 }
853 }
854 pub(crate) fn zero() -> Self {
855 Self {
856 collapsed_through: false,
857 start: CollapsedMargin::zero(),
858 end: CollapsedMargin::zero(),
859 }
860 }
861}
862
863impl<L: LengthNum> CollapsedMargin<L> {
864 pub(crate) fn zero() -> Self {
865 Self {
866 positive: L::zero(),
867 negative: L::zero(),
868 }
869 }
870 pub(crate) fn new(margin: L) -> Self {
871 Self {
872 positive: margin.max(L::zero()),
873 negative: margin.min(L::zero()),
874 }
875 }
876
877 pub(crate) fn adjoin(&self, other: &Self) -> Self {
878 Self {
879 positive: self.positive.max(other.positive),
880 negative: self.negative.min(other.negative),
881 }
882 }
883
884 pub(crate) fn adjoin_assign(&mut self, other: &Self) {
885 *self = self.adjoin(other);
886 }
887
888 pub(crate) fn solve(&self) -> L {
889 self.positive + self.negative
890 }
891}
892
893#[inline(always)]
894pub(crate) fn is_display_none<T: LayoutTreeNode>(style: &T::Style) -> bool {
895 style.display() == Display::None
896}