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