1use core::{fmt::Display, ops::Deref};
2
3use alloc::{string::String, vec::Vec};
4use euclid::UnknownUnit;
5use float_pigment_css::typing::{Direction, WritingMode};
6
7use crate::LayoutTreeNode;
8pub(crate) use float_pigment_css::length_num::{length_sum, LengthNum};
9
10pub type Rect<L> = euclid::Rect<L, UnknownUnit>;
12
13pub type Size<L> = euclid::Size2D<L, UnknownUnit>;
15
16pub type OptionSize<L> = euclid::Size2D<OptionNum<L>, UnknownUnit>;
18
19pub type Vector<L> = euclid::Vector2D<L, euclid::UnknownUnit>;
21
22pub type Point<L> = euclid::Point2D<L, euclid::UnknownUnit>;
24
25pub(crate) trait PointGetter<T> {
26 fn main_axis(&self, dir: AxisDirection) -> T;
27 fn cross_axis(&self, dir: AxisDirection) -> T;
28}
29
30impl<L: LengthNum> PointGetter<L> for Point<L> {
31 fn main_axis(&self, dir: AxisDirection) -> L {
32 match dir {
33 AxisDirection::Horizontal => self.x,
34 AxisDirection::Vertical => self.y,
35 }
36 }
37 fn cross_axis(&self, dir: AxisDirection) -> L {
38 match dir {
39 AxisDirection::Horizontal => self.y,
40 AxisDirection::Vertical => self.x,
41 }
42 }
43}
44
45pub(crate) trait SizeGetter<T: Copy> {
46 fn main_size(&self, dir: AxisDirection) -> T;
47 fn cross_size(&self, dir: AxisDirection) -> T;
48}
49
50pub(crate) trait SizeSetter<T> {
51 fn set_main_size(&mut self, dir: AxisDirection, value: T);
52 fn set_cross_size(&mut self, dir: AxisDirection, value: T);
53}
54
55impl<T: Copy> SizeGetter<T> for euclid::Size2D<T, UnknownUnit> {
56 #[inline]
57 fn main_size(&self, dir: AxisDirection) -> T {
58 match dir {
59 AxisDirection::Horizontal => self.width,
60 AxisDirection::Vertical => self.height,
61 }
62 }
63
64 #[inline]
65 fn cross_size(&self, dir: AxisDirection) -> T {
66 match dir {
67 AxisDirection::Horizontal => self.height,
68 AxisDirection::Vertical => self.width,
69 }
70 }
71}
72
73impl<T> SizeSetter<T> for euclid::Size2D<T, UnknownUnit> {
74 #[inline]
75 fn set_main_size(&mut self, dir: AxisDirection, value: T) {
76 match dir {
77 AxisDirection::Horizontal => self.width = value,
78 AxisDirection::Vertical => self.height = value,
79 }
80 }
81
82 #[inline]
83 fn set_cross_size(&mut self, dir: AxisDirection, value: T) {
84 match dir {
85 AxisDirection::Horizontal => self.height = value,
86 AxisDirection::Vertical => self.width = value,
87 }
88 }
89}
90
91pub(crate) trait SizeProxy<T> {
92 fn new_with_dir(dir: AxisDirection, main_size: T, cross_size: T) -> Self;
93}
94
95impl<T> SizeProxy<T> for euclid::Size2D<T, UnknownUnit> {
96 #[inline(always)]
97 fn new_with_dir(dir: AxisDirection, main_size: T, cross_size: T) -> Self {
98 let (width, height) = match dir {
99 AxisDirection::Horizontal => (main_size, cross_size),
100 AxisDirection::Vertical => (cross_size, main_size),
101 };
102 Self::new(width, height)
103 }
104}
105
106pub(crate) trait OrZero<L: LengthNum>: Sized {
107 fn or_zero(&self) -> Size<L>;
108}
109
110impl<L: LengthNum> OrZero<L> for OptionSize<L> {
111 #[inline(always)]
112 fn or_zero(&self) -> Size<L> {
113 Size::new(self.width.or_zero(), self.height.or_zero())
114 }
115}
116
117pub(crate) trait VectorGetter<T> {
118 #[allow(unused)]
119 fn main_axis(&self, dir: AxisDirection) -> T;
120 fn cross_axis(&self, dir: AxisDirection) -> T;
121}
122
123impl<L: LengthNum> VectorGetter<L> for Vector<L> {
124 #[inline]
125 fn main_axis(&self, dir: AxisDirection) -> L {
126 match dir {
127 AxisDirection::Horizontal => self.x,
128 AxisDirection::Vertical => self.y,
129 }
130 }
131 #[inline]
132 fn cross_axis(&self, dir: AxisDirection) -> L {
133 match dir {
134 AxisDirection::Horizontal => self.y,
135 AxisDirection::Vertical => self.x,
136 }
137 }
138}
139
140pub(crate) trait VectorSetter<T> {
141 fn set_main_axis(&mut self, dir: AxisDirection, value: T);
142 fn set_cross_axis(&mut self, dir: AxisDirection, value: T);
143}
144
145impl<L: LengthNum> VectorSetter<L> for Vector<L> {
146 #[inline(always)]
147 fn set_main_axis(&mut self, dir: AxisDirection, value: L) {
148 match dir {
149 AxisDirection::Horizontal => self.x = value,
150 AxisDirection::Vertical => self.y = value,
151 }
152 }
153 #[inline(always)]
154 fn set_cross_axis(&mut self, dir: AxisDirection, value: L) {
155 match dir {
156 AxisDirection::Horizontal => self.y = value,
157 AxisDirection::Vertical => self.x = value,
158 }
159 }
160}
161
162pub(crate) trait VectorProxy<T> {
163 fn new_with_dir(dir: AxisDirection, main_axis: T, cross_axis: T) -> Self;
164}
165
166impl<L: LengthNum> VectorProxy<L> for Vector<L> {
167 fn new_with_dir(dir: AxisDirection, main_axis: L, cross_axis: L) -> Self {
168 let (x, y) = match dir {
169 AxisDirection::Horizontal => (main_axis, cross_axis),
170 AxisDirection::Vertical => (cross_axis, main_axis),
171 };
172 Self::new(x, y)
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq)]
178pub enum DefLength<L: LengthNum, T: PartialEq + Clone = i32> {
179 Undefined,
181
182 Auto,
184
185 Points(L),
187
188 Percent(f32),
190
191 Custom(T),
195}
196
197impl<L: LengthNum, T: PartialEq + Display + Clone> Display for DefLength<L, T> {
198 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
199 match self {
200 Self::Undefined => write!(f, "Undefined"),
201 Self::Auto => write!(f, "Auto"),
202 Self::Points(x) => write!(f, "Points({})", L::to_f32(*x)),
203 Self::Percent(x) => write!(f, "Percent({})", *x),
204 Self::Custom(x) => write!(f, "Custom({})", *x),
205 }
206 }
207}
208
209impl<L: LengthNum, T: PartialEq + Clone> Default for DefLength<L, T> {
210 fn default() -> Self {
211 Self::Undefined
212 }
213}
214
215impl<L: LengthNum, T: PartialEq + Clone> DefLength<L, T> {
216 pub(crate) fn resolve<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
217 &self,
218 parent: OptionNum<L>,
219 node: &N,
220 ) -> OptionNum<L> {
221 match self {
222 Self::Undefined => OptionNum::none(),
223 Self::Auto => OptionNum::none(),
224 Self::Points(x) => OptionNum::some(*x),
225 Self::Percent(x) => parent * *x,
226 Self::Custom(x) => {
227 OptionNum::some(node.resolve_custom_length(x, parent.unwrap_or(L::zero())))
228 }
229 }
230 }
231
232 pub(crate) fn resolve_with_auto<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
233 &self,
234 parent: OptionNum<L>,
235 node: &N,
236 ) -> OptionNum<L> {
237 match self {
238 Self::Undefined => OptionNum::some(L::zero()),
239 Self::Auto => OptionNum::none(),
240 Self::Points(x) => OptionNum::some(*x),
241 Self::Percent(x) => parent * *x,
242 Self::Custom(x) => {
243 OptionNum::some(node.resolve_custom_length(x, parent.unwrap_or(L::zero())))
244 }
245 }
246 }
247
248 pub(crate) fn resolve_num<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
249 &self,
250 parent: L,
251 node: &N,
252 ) -> OptionNum<L> {
253 match self {
254 Self::Undefined => OptionNum::none(),
255 Self::Auto => OptionNum::none(),
256 Self::Points(x) => OptionNum::some(*x),
257 Self::Percent(x) => OptionNum::some(parent.mul_f32(*x)),
258 Self::Custom(x) => OptionNum::some(node.resolve_custom_length(x, parent)),
259 }
260 }
261}
262
263#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
265pub struct OptionNum<L>(Option<L>);
266
267impl<L: LengthNum> OptionNum<L> {
268 pub fn to_hashable(&self) -> OptionNum<L::Hashable> {
270 match self.0 {
271 None => OptionNum(None),
272 Some(x) => OptionNum(Some(x.to_hashable())),
273 }
274 }
275
276 #[inline]
278 pub fn none() -> Self {
279 Self(None)
280 }
281
282 #[inline]
284 pub fn some(v: L) -> Self {
285 Self(Some(v))
286 }
287
288 #[inline]
290 pub fn zero() -> Self {
291 Self(Some(L::zero()))
292 }
293
294 #[inline]
296 pub fn is_none(&self) -> bool {
297 self.0.is_none()
298 }
299
300 #[inline]
302 pub fn is_some(&self) -> bool {
303 self.0.is_some()
304 }
305
306 #[inline]
308 pub fn val(&self) -> Option<L> {
309 self.0
310 }
311
312 #[inline]
314 pub fn unwrap_or(self, rhs: L) -> L {
315 self.0.unwrap_or(rhs)
316 }
317
318 #[inline]
320 pub fn unwrap_or_else(self, f: impl FnOnce() -> L) -> L {
321 self.0.unwrap_or_else(f)
322 }
323
324 #[inline]
326 pub fn or(self, rhs: Self) -> Self {
327 Self(self.0.or(rhs.0))
328 }
329
330 #[inline]
332 pub fn or_zero(self) -> L {
333 self.0.unwrap_or_else(L::zero)
334 }
335
336 #[inline]
338 pub fn map(self, f: impl FnOnce(L) -> L) -> Self {
339 Self(self.0.map(f))
340 }
341}
342
343impl<L: LengthNum> From<Option<L>> for OptionNum<L> {
344 fn from(value: Option<L>) -> Self {
345 Self(value)
346 }
347}
348
349impl<L: LengthNum> core::ops::Add<L> for OptionNum<L> {
350 type Output = Self;
351
352 fn add(self, rhs: L) -> Self {
353 self.map(|x| x + rhs)
354 }
355}
356
357impl<L: LengthNum> core::ops::Sub<L> for OptionNum<L> {
358 type Output = Self;
359
360 fn sub(self, rhs: L) -> Self {
361 self.map(|x| x - rhs)
362 }
363}
364
365impl<L: LengthNum> core::ops::Mul<f32> for OptionNum<L> {
366 type Output = Self;
367
368 fn mul(self, rhs: f32) -> Self {
369 self.map(|x| x.mul_f32(rhs))
370 }
371}
372
373impl<L: LengthNum> core::ops::Mul<i32> for OptionNum<L> {
374 type Output = Self;
375
376 fn mul(self, rhs: i32) -> Self {
377 self.map(|x| x.mul_i32(rhs))
378 }
379}
380
381impl<L: LengthNum> core::ops::Add<Self> for OptionNum<L> {
382 type Output = Self;
383
384 fn add(self, rhs: Self) -> Self {
385 match rhs.val() {
386 Some(x) => self + x,
387 None => self,
388 }
389 }
390}
391
392impl<L: LengthNum> core::ops::Sub<Self> for OptionNum<L> {
393 type Output = Self;
394
395 fn sub(self, rhs: Self) -> Self {
396 match rhs.val() {
397 Some(x) => self - x,
398 None => self,
399 }
400 }
401}
402
403pub(crate) trait MinMax {
404 fn min(self, rhs: Self) -> Self;
405 fn max(self, rhs: Self) -> Self;
406}
407
408impl<L: LengthNum> MinMax for L {
409 fn min(self, rhs: Self) -> Self {
410 if self < rhs {
411 self
412 } else {
413 rhs
414 }
415 }
416
417 fn max(self, rhs: Self) -> Self {
418 if self > rhs {
419 self
420 } else {
421 rhs
422 }
423 }
424}
425
426pub(crate) trait MaybeMinMax<In, Out> {
427 fn maybe_min(self, rhs: In) -> Out;
428 fn maybe_max(self, rhs: In) -> Out;
429}
430
431impl<L: LengthNum> MaybeMinMax<OptionNum<L>, L> for L {
432 fn maybe_min(self, rhs: OptionNum<L>) -> L {
433 match rhs.val() {
434 None => self,
435 Some(x) => self.min(x),
436 }
437 }
438
439 fn maybe_max(self, rhs: OptionNum<L>) -> L {
440 match rhs.val() {
441 None => self,
442 Some(x) => self.max(x),
443 }
444 }
445}
446
447impl<L: LengthNum> MaybeMinMax<Self, Self> for OptionNum<L> {
448 fn maybe_min(self, rhs: Self) -> Self {
449 match self.val() {
450 None => OptionNum::none(),
451 Some(x) => match rhs.val() {
452 None => self,
453 Some(y) => OptionNum::some(x.min(y)),
454 },
455 }
456 }
457
458 fn maybe_max(self, rhs: Self) -> Self {
459 match self.val() {
460 None => OptionNum::none(),
461 Some(x) => match rhs.val() {
462 None => self,
463 Some(y) => OptionNum::some(x.max(y)),
464 },
465 }
466 }
467}
468
469impl<L: LengthNum> MaybeMinMax<L, Self> for OptionNum<L> {
470 fn maybe_min(self, rhs: L) -> OptionNum<L> {
471 match self.val() {
472 None => OptionNum::none(),
473 Some(x) => OptionNum::some(x.min(rhs)),
474 }
475 }
476
477 fn maybe_max(self, rhs: L) -> OptionNum<L> {
478 match self.val() {
479 None => OptionNum::none(),
480 Some(x) => OptionNum::some(x.max(rhs)),
481 }
482 }
483}
484
485impl<L: LengthNum> MaybeMinMax<OptionSize<L>, Size<L>> for Size<L> {
486 fn maybe_min(self, rhs: OptionSize<L>) -> Size<L> {
487 let width = match rhs.width.val() {
488 None => self.width,
489 Some(x) => self.width.min(x),
490 };
491 let height = match rhs.height.val() {
492 None => self.height,
493 Some(x) => self.height.min(x),
494 };
495 Size::new(width, height)
496 }
497
498 fn maybe_max(self, rhs: OptionSize<L>) -> Size<L> {
499 let width = match rhs.width.val() {
500 None => self.width,
501 Some(x) => self.width.max(x),
502 };
503 let height = match rhs.height.val() {
504 None => self.height,
505 Some(x) => self.height.max(x),
506 };
507 Size::new(width, height)
508 }
509}
510
511#[allow(missing_docs)]
513#[derive(Debug, Clone, Copy, PartialEq)]
514pub struct Edge<L: LengthNum> {
515 pub left: L,
516 pub right: L,
517 pub top: L,
518 pub bottom: L,
519}
520
521impl<L: LengthNum> Edge<L> {
522 #[inline(always)]
524 pub fn zero() -> Self {
525 Self {
526 left: L::zero(),
527 right: L::zero(),
528 top: L::zero(),
529 bottom: L::zero(),
530 }
531 }
532
533 #[inline(always)]
535 pub fn horizontal(&self) -> L {
536 self.left + self.right
537 }
538
539 #[inline(always)]
541 pub fn vertical(&self) -> L {
542 self.top + self.bottom
543 }
544
545 #[inline(always)]
546 pub(crate) fn main_axis_sum(&self, dir: AxisDirection) -> L {
547 match dir {
548 AxisDirection::Vertical => self.vertical(),
549 AxisDirection::Horizontal => self.horizontal(),
550 }
551 }
552
553 #[inline(always)]
554 pub(crate) fn cross_axis_sum(&self, dir: AxisDirection) -> L {
555 match dir {
556 AxisDirection::Vertical => self.horizontal(),
557 AxisDirection::Horizontal => self.vertical(),
558 }
559 }
560
561 #[inline(always)]
562 pub(crate) fn main_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> L {
563 match (dir, rev) {
564 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left,
565 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right,
566 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top,
567 (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom,
568 }
569 }
570
571 #[allow(unused)]
572 #[inline(always)]
573 pub(crate) fn main_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> L {
574 match (dir, rev) {
575 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right,
576 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left,
577 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom,
578 (AxisDirection::Vertical, AxisReverse::Reversed) => self.top,
579 }
580 }
581
582 #[inline(always)]
583 pub(crate) fn cross_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> L {
584 match (dir, rev) {
585 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top,
586 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom,
587 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left,
588 (AxisDirection::Vertical, AxisReverse::Reversed) => self.right,
589 }
590 }
591
592 #[allow(unused)]
593 #[inline(always)]
594 pub(crate) fn cross_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> L {
595 match (dir, rev) {
596 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom,
597 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top,
598 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right,
599 (AxisDirection::Vertical, AxisReverse::Reversed) => self.left,
600 }
601 }
602}
603
604impl<L: LengthNum> core::ops::Add<Edge<L>> for Edge<L> {
605 type Output = Self;
606
607 fn add(self, rhs: Edge<L>) -> Self {
608 Self {
609 left: self.left + rhs.left,
610 right: self.right + rhs.right,
611 top: self.top + rhs.top,
612 bottom: self.bottom + rhs.bottom,
613 }
614 }
615}
616
617impl<L: LengthNum> core::ops::Sub<Edge<L>> for Edge<L> {
618 type Output = Self;
619 fn sub(self, rhs: Edge<L>) -> Self {
620 Self {
621 left: self.left - rhs.left,
622 right: self.right - rhs.right,
623 top: self.top - rhs.top,
624 bottom: self.bottom - rhs.bottom,
625 }
626 }
627}
628
629#[allow(missing_docs)]
631#[derive(Debug, Clone, Copy, PartialEq)]
632pub struct EdgeOption<L: LengthNum> {
633 pub left: OptionNum<L>,
634 pub right: OptionNum<L>,
635 pub top: OptionNum<L>,
636 pub bottom: OptionNum<L>,
637}
638
639impl<L: LengthNum> EdgeOption<L> {
640 #[inline(always)]
642 pub fn or_zero(&self) -> Edge<L> {
643 Edge {
644 left: self.left.or_zero(),
645 right: self.right.or_zero(),
646 top: self.top.or_zero(),
647 bottom: self.bottom.or_zero(),
648 }
649 }
650
651 #[inline(always)]
653 pub fn horizontal(&self) -> L {
654 self.left.or_zero() + self.right.or_zero()
655 }
656
657 #[inline(always)]
659 pub fn vertical(&self) -> L {
660 self.top.or_zero() + self.bottom.or_zero()
661 }
662
663 pub(crate) fn is_left_right_either_none(&self) -> bool {
664 self.left.is_none() || self.right.is_none()
665 }
666
667 pub(crate) fn is_top_bottom_either_none(&self) -> bool {
668 self.top.is_none() || self.bottom.is_none()
669 }
670
671 #[inline(always)]
672 pub(crate) fn main_axis_sum(&self, dir: AxisDirection) -> L {
673 match dir {
674 AxisDirection::Horizontal => self.horizontal(),
675 AxisDirection::Vertical => self.vertical(),
676 }
677 }
678
679 #[inline(always)]
680 pub(crate) fn cross_axis_sum(&self, dir: AxisDirection) -> L {
681 match dir {
682 AxisDirection::Horizontal => self.vertical(),
683 AxisDirection::Vertical => self.horizontal(),
684 }
685 }
686
687 #[inline(always)]
688 pub(crate) fn main_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
689 match (dir, rev) {
690 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left,
691 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right,
692 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top,
693 (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom,
694 }
695 }
696
697 #[inline(always)]
698 pub(crate) fn set_main_axis_start(
699 &mut self,
700 dir: AxisDirection,
701 rev: AxisReverse,
702 value: OptionNum<L>,
703 ) {
704 match (dir, rev) {
705 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left = value,
706 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right = value,
707 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top = value,
708 (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom = value,
709 }
710 }
711
712 #[inline(always)]
713 pub(crate) fn main_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
714 match (dir, rev) {
715 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right,
716 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left,
717 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom,
718 (AxisDirection::Vertical, AxisReverse::Reversed) => self.top,
719 }
720 }
721
722 #[inline(always)]
723 pub(crate) fn set_main_axis_end(
724 &mut self,
725 dir: AxisDirection,
726 rev: AxisReverse,
727 value: OptionNum<L>,
728 ) {
729 match (dir, rev) {
730 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right = value,
731 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left = value,
732 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom = value,
733 (AxisDirection::Vertical, AxisReverse::Reversed) => self.top = value,
734 }
735 }
736
737 #[inline(always)]
738 pub(crate) fn cross_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
739 match (dir, rev) {
740 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top,
741 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom,
742 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left,
743 (AxisDirection::Vertical, AxisReverse::Reversed) => self.right,
744 }
745 }
746
747 #[inline(always)]
748 pub(crate) fn set_cross_axis_start(
749 &mut self,
750 dir: AxisDirection,
751 rev: AxisReverse,
752 value: OptionNum<L>,
753 ) {
754 match (dir, rev) {
755 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top = value,
756 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom = value,
757 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left = value,
758 (AxisDirection::Vertical, AxisReverse::Reversed) => self.right = value,
759 }
760 }
761
762 #[inline(always)]
763 pub(crate) fn cross_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
764 match (dir, rev) {
765 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom,
766 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top,
767 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right,
768 (AxisDirection::Vertical, AxisReverse::Reversed) => self.left,
769 }
770 }
771
772 #[inline(always)]
773 pub(crate) fn set_cross_axis_end(
774 &mut self,
775 dir: AxisDirection,
776 rev: AxisReverse,
777 value: OptionNum<L>,
778 ) {
779 match (dir, rev) {
780 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom = value,
781 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top = value,
782 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right = value,
783 (AxisDirection::Vertical, AxisReverse::Reversed) => self.left = value,
784 }
785 }
786}
787
788#[derive(Debug, Clone, Copy, PartialEq)]
789pub(crate) enum AxisDirection {
790 Horizontal,
791 Vertical,
792}
793
794#[derive(Debug, Clone, Copy, PartialEq, Hash)]
795pub(crate) enum AxisReverse {
796 NotReversed,
797 Reversed,
798}
799
800#[derive(Debug, Clone, Copy, PartialEq)]
801pub(crate) struct AxisInfo {
802 pub(crate) dir: AxisDirection,
803 pub(crate) main_dir_rev: AxisReverse,
804 pub(crate) cross_dir_rev: AxisReverse,
805}
806
807impl AxisInfo {
808 pub(crate) fn from_writing_mode(writing_mode: WritingMode) -> Self {
809 let (dir, main_dir_rev, cross_dir_rev) = match writing_mode {
810 WritingMode::HorizontalTb => (
811 AxisDirection::Vertical,
812 AxisReverse::NotReversed,
813 AxisReverse::NotReversed,
814 ),
815 WritingMode::VerticalLr => (
816 AxisDirection::Horizontal,
817 AxisReverse::NotReversed,
818 AxisReverse::NotReversed,
819 ),
820 WritingMode::VerticalRl => (
821 AxisDirection::Horizontal,
822 AxisReverse::Reversed,
823 AxisReverse::NotReversed,
824 ),
825 };
826 Self {
827 dir,
828 main_dir_rev,
829 cross_dir_rev,
830 }
831 }
832
833 pub(crate) fn from_writing_mode_and_direction(
836 writing_mode: WritingMode,
837 direction: Direction,
838 ) -> Self {
839 let rtl_reverse = if matches!(direction, Direction::RTL) {
840 AxisReverse::Reversed
841 } else {
842 AxisReverse::NotReversed
843 };
844 let (dir, main_dir_rev, cross_dir_rev) = match writing_mode {
845 WritingMode::HorizontalTb => (
847 AxisDirection::Vertical,
848 AxisReverse::NotReversed,
849 rtl_reverse,
850 ),
851 WritingMode::VerticalLr => (
853 AxisDirection::Horizontal,
854 AxisReverse::NotReversed,
855 rtl_reverse,
856 ),
857 WritingMode::VerticalRl => (
859 AxisDirection::Horizontal,
860 AxisReverse::Reversed,
861 rtl_reverse,
862 ),
863 };
864 Self {
865 dir,
866 main_dir_rev,
867 cross_dir_rev,
868 }
869 }
870}
871#[derive(Debug, Clone, Copy, PartialEq)]
872pub(crate) struct MinMaxSize<L: LengthNum> {
873 pub(crate) min_width: OptionNum<L>,
874 pub(crate) max_width: OptionNum<L>,
875 pub(crate) min_height: OptionNum<L>,
876 pub(crate) max_height: OptionNum<L>,
877}
878
879#[derive(Debug, Clone, Copy, PartialEq)]
880pub(crate) struct MinMaxLimit<L: LengthNum> {
881 pub(crate) min_width: L,
882 pub(crate) max_width: OptionNum<L>,
883 pub(crate) min_height: L,
884 pub(crate) max_height: OptionNum<L>,
885}
886
887impl<L: LengthNum> MinMaxLimit<L> {
888 pub(crate) fn normalized_size(&self, v: OptionSize<L>) -> Normalized<OptionSize<L>> {
889 Normalized(OptionSize::new(
890 v.width
891 .map(|x| x.maybe_min(self.max_width).max(self.min_width)),
892 v.height
893 .map(|x| x.maybe_min(self.max_height).max(self.min_height)),
894 ))
895 }
896
897 pub(crate) fn width(&self, x: L) -> L {
898 x.maybe_min(self.max_width).max(self.min_width)
899 }
900
901 pub(crate) fn height(&self, x: L) -> L {
902 x.maybe_min(self.max_height).max(self.min_height)
903 }
904
905 pub(crate) fn maybe(&self) -> MinMaxLimitMaybe<'_, L> {
906 MinMaxLimitMaybe(self)
907 }
908
909 #[inline(always)]
910 pub(crate) fn main_size(&self, x: L, dir: AxisDirection) -> L {
911 match dir {
912 AxisDirection::Horizontal => self.width(x),
913 AxisDirection::Vertical => self.height(x),
914 }
915 }
916
917 #[inline(always)]
918 pub(crate) fn cross_size(&self, x: L, dir: AxisDirection) -> L {
919 match dir {
920 AxisDirection::Horizontal => self.height(x),
921 AxisDirection::Vertical => self.width(x),
922 }
923 }
924
925 #[inline(always)]
926 pub(crate) fn min_main_size(&self, dir: AxisDirection) -> L {
927 match dir {
928 AxisDirection::Horizontal => self.min_width,
929 AxisDirection::Vertical => self.min_height,
930 }
931 }
932
933 #[inline(always)]
934 #[allow(unused)]
935 pub(crate) fn max_main_size(&self, dir: AxisDirection) -> OptionNum<L> {
936 match dir {
937 AxisDirection::Horizontal => self.max_width,
938 AxisDirection::Vertical => self.max_height,
939 }
940 }
941
942 #[inline(always)]
943 #[allow(unused)]
944 pub(crate) fn min_cross_size(&self, dir: AxisDirection) -> L {
945 match dir {
946 AxisDirection::Horizontal => self.min_height,
947 AxisDirection::Vertical => self.min_width,
948 }
949 }
950
951 #[inline(always)]
952 #[allow(unused)]
953 pub(crate) fn max_cross_size(&self, dir: AxisDirection) -> OptionNum<L> {
954 match dir {
955 AxisDirection::Horizontal => self.max_height,
956 AxisDirection::Vertical => self.max_width,
957 }
958 }
959
960 #[inline(always)]
961 #[allow(unused)]
962 pub(crate) fn set_min_cross_size(&mut self, x: L, dir: AxisDirection) {
963 match dir {
964 AxisDirection::Horizontal => self.min_height = x,
965 AxisDirection::Vertical => self.min_width = x,
966 }
967 }
968
969 #[inline(always)]
970 #[allow(unused)]
971 pub(crate) fn set_max_cross_size(&mut self, x: OptionNum<L>, dir: AxisDirection) {
972 match dir {
973 AxisDirection::Horizontal => self.max_height = x,
974 AxisDirection::Vertical => self.max_width = x,
975 }
976 }
977
978 #[inline(always)]
979 #[allow(unused)]
980 pub(crate) fn set_min_main_size(&mut self, x: L, dir: AxisDirection) {
981 match dir {
982 AxisDirection::Horizontal => self.min_width = x,
983 AxisDirection::Vertical => self.min_height = x,
984 }
985 }
986
987 #[inline(always)]
988 #[allow(unused)]
989 pub(crate) fn set_max_main_size(&mut self, x: OptionNum<L>, dir: AxisDirection) {
990 match dir {
991 AxisDirection::Horizontal => self.max_width = x,
992 AxisDirection::Vertical => self.max_height = x,
993 }
994 }
995}
996
997pub(crate) struct MinMaxLimitMaybe<'a, L: LengthNum>(&'a MinMaxLimit<L>);
998
999impl<'a, L: LengthNum> MinMaxLimitMaybe<'a, L> {
1000 pub(crate) fn width(&self, v: OptionNum<L>) -> OptionNum<L> {
1001 v.map(|x| x.maybe_min(self.0.max_width).max(self.0.min_width))
1002 }
1003
1004 pub(crate) fn height(&self, v: OptionNum<L>) -> OptionNum<L> {
1005 v.map(|x| x.maybe_min(self.0.max_height).max(self.0.min_height))
1006 }
1007
1008 #[inline(always)]
1009 #[allow(unused)]
1010 pub(crate) fn main_size(&self, dir: AxisDirection, v: OptionNum<L>) -> OptionNum<L> {
1011 match dir {
1012 AxisDirection::Horizontal => self.width(v),
1013 AxisDirection::Vertical => self.height(v),
1014 }
1015 }
1016
1017 #[inline(always)]
1018 pub(crate) fn cross_size(&self, dir: AxisDirection, v: OptionNum<L>) -> OptionNum<L> {
1019 match dir {
1020 AxisDirection::Horizontal => self.height(v),
1021 AxisDirection::Vertical => self.width(v),
1022 }
1023 }
1024}
1025
1026#[derive(Debug, Clone, Copy, PartialEq, Hash)]
1027pub(crate) struct Normalized<T>(pub(crate) T);
1028
1029impl<T> Deref for Normalized<T> {
1030 type Target = T;
1031
1032 fn deref(&self) -> &Self::Target {
1033 &self.0
1034 }
1035}
1036
1037#[inline(always)]
1038pub(crate) fn size_to_option<L: LengthNum>(size: Size<L>) -> OptionSize<L> {
1039 OptionSize::new(OptionNum::some(size.width), OptionNum::some(size.height))
1040}
1041
1042#[allow(missing_docs)]
1043#[derive(Debug, Clone, PartialEq)]
1044pub enum LayoutGridTemplate<L: LengthNum, T: PartialEq + Clone = i32> {
1045 None,
1046 TrackList(Vec<LayoutTrackListItem<L, T>>),
1047}
1048
1049impl<L: LengthNum, T: PartialEq + Clone> Default for LayoutGridTemplate<L, T> {
1050 fn default() -> Self {
1051 Self::None
1052 }
1053}
1054
1055#[allow(missing_docs)]
1056#[derive(Debug, Clone, PartialEq)]
1057pub enum LayoutTrackListItem<L: LengthNum, T: PartialEq + Clone = i32> {
1058 LineNames(Vec<String>),
1059 TrackSize(LayoutTrackSize<L, T>),
1060}
1061
1062impl<L: LengthNum, T: PartialEq + Clone> LayoutTrackListItem<L, T> {
1063 pub fn is_intrinsic(&self) -> bool {
1066 matches!(
1067 self,
1068 LayoutTrackListItem::TrackSize(
1069 LayoutTrackSize::Length(DefLength::Auto)
1070 | LayoutTrackSize::MinContent
1071 | LayoutTrackSize::MaxContent
1072 )
1073 )
1074 }
1075}
1076
1077#[allow(missing_docs)]
1078#[derive(Debug, Clone, PartialEq)]
1079pub enum LayoutTrackSize<L: LengthNum, T: PartialEq + Clone = i32> {
1080 MinContent,
1081 MaxContent,
1082 Fr(f32),
1083 Length(DefLength<L, T>),
1084}
1085
1086#[allow(missing_docs)]
1092#[derive(Debug, Clone, PartialEq)]
1093pub struct LayoutGridAuto<L: LengthNum, T: PartialEq + Clone = i32>(pub Vec<LayoutTrackSize<L, T>>);
1094
1095impl<L: LengthNum, T: PartialEq + Clone> Default for LayoutGridAuto<L, T> {
1096 fn default() -> Self {
1097 Self(vec![LayoutTrackSize::Length(DefLength::Auto)])
1099 }
1100}
1101
1102impl<L: LengthNum, T: PartialEq + Clone> LayoutGridAuto<L, T> {
1103 pub fn get(&self, index: usize) -> LayoutTrackSize<L, T> {
1106 if self.0.is_empty() {
1107 LayoutTrackSize::Length(DefLength::Auto)
1108 } else {
1109 self.0[index % self.0.len()].clone()
1110 }
1111 }
1112
1113 pub fn len(&self) -> usize {
1115 self.0.len()
1116 }
1117
1118 pub fn is_empty(&self) -> bool {
1120 self.0.is_empty()
1121 }
1122}
1123
1124#[cfg(test)]
1125mod test {
1126
1127 use crate::{AxisDirection, Normalized, OptionSize, Size, SizeGetter, SizeSetter};
1128
1129 #[test]
1130 fn option_size_get_main_size() {
1131 let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1132 let size = os.main_size(AxisDirection::Horizontal);
1133 assert_eq!(size.val(), Some(10.));
1135 let size = os.main_size(AxisDirection::Vertical);
1136 assert_eq!(size.val(), Some(20.));
1137 }
1138
1139 #[test]
1140 fn option_size_get_cross_size() {
1141 let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1142 let size = os.cross_size(AxisDirection::Horizontal);
1143 assert_eq!(size.val(), Some(20.));
1144 let size = os.cross_size(AxisDirection::Vertical);
1145 assert_eq!(size.val(), Some(10.));
1146 }
1147
1148 #[test]
1149 fn normalized_option_size_get_size() {
1150 let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1151 let normalized = Normalized(os);
1152 let size = normalized.main_size(AxisDirection::Horizontal);
1153 assert_eq!(size.val(), Some(10.));
1154 let size = normalized.main_size(AxisDirection::Vertical);
1155 assert_eq!(size.val(), Some(20.));
1156 }
1157
1158 #[test]
1159 fn size_get_size() {
1160 let s = Size::new(10.0_f32, 20.0_f32);
1161 let size = s.main_size(AxisDirection::Horizontal);
1162 assert_eq!(size, 10.);
1163 let size = s.main_size(AxisDirection::Vertical);
1164 assert_eq!(size, 20.);
1165 }
1166
1167 #[test]
1168 fn size_set_size() {
1169 let mut s = Size::new(10.0_f32, 20.0_f32);
1170 s.set_main_size(AxisDirection::Horizontal, 20.);
1171 assert_eq!(s.main_size(AxisDirection::Horizontal), 20.);
1172 s.set_cross_size(AxisDirection::Horizontal, 30.);
1173 assert_eq!(s.cross_size(AxisDirection::Horizontal), 30.);
1174 }
1175}