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, Default)]
178pub enum DefLength<L: LengthNum, T: PartialEq + Clone = i32> {
179 #[default]
181 Undefined,
182
183 Auto,
185
186 Points(L),
188
189 Percent(f32),
191
192 Custom(T),
196}
197
198impl<L: LengthNum, T: PartialEq + Display + Clone> Display for DefLength<L, T> {
199 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200 match self {
201 Self::Undefined => write!(f, "Undefined"),
202 Self::Auto => write!(f, "Auto"),
203 Self::Points(x) => write!(f, "Points({})", L::to_f32(*x)),
204 Self::Percent(x) => write!(f, "Percent({})", *x),
205 Self::Custom(x) => write!(f, "Custom({})", *x),
206 }
207 }
208}
209
210impl<L: LengthNum, T: PartialEq + Clone> DefLength<L, T> {
211 pub(crate) fn resolve<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
212 &self,
213 parent: OptionNum<L>,
214 node: &N,
215 ) -> OptionNum<L> {
216 match self {
217 Self::Undefined => OptionNum::none(),
218 Self::Auto => OptionNum::none(),
219 Self::Points(x) => OptionNum::some(*x),
220 Self::Percent(x) => parent * *x,
221 Self::Custom(x) => {
222 OptionNum::some(node.resolve_custom_length(x, parent.unwrap_or(L::zero())))
223 }
224 }
225 }
226
227 pub(crate) fn resolve_with_auto<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
228 &self,
229 parent: OptionNum<L>,
230 node: &N,
231 ) -> OptionNum<L> {
232 match self {
233 Self::Undefined => OptionNum::some(L::zero()),
234 Self::Auto => OptionNum::none(),
235 Self::Points(x) => OptionNum::some(*x),
236 Self::Percent(x) => parent * *x,
237 Self::Custom(x) => {
238 OptionNum::some(node.resolve_custom_length(x, parent.unwrap_or(L::zero())))
239 }
240 }
241 }
242
243 pub(crate) fn resolve_num<N: LayoutTreeNode<Length = L, LengthCustom = T>>(
244 &self,
245 parent: L,
246 node: &N,
247 ) -> OptionNum<L> {
248 match self {
249 Self::Undefined => OptionNum::none(),
250 Self::Auto => OptionNum::none(),
251 Self::Points(x) => OptionNum::some(*x),
252 Self::Percent(x) => OptionNum::some(parent.mul_f32(*x)),
253 Self::Custom(x) => OptionNum::some(node.resolve_custom_length(x, parent)),
254 }
255 }
256}
257
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
260pub struct OptionNum<L>(Option<L>);
261
262impl<L: LengthNum> OptionNum<L> {
263 pub fn to_hashable(&self) -> OptionNum<L::Hashable> {
265 match self.0 {
266 None => OptionNum(None),
267 Some(x) => OptionNum(Some(x.to_hashable())),
268 }
269 }
270
271 #[inline]
273 pub fn none() -> Self {
274 Self(None)
275 }
276
277 #[inline]
279 pub fn some(v: L) -> Self {
280 Self(Some(v))
281 }
282
283 #[inline]
285 pub fn zero() -> Self {
286 Self(Some(L::zero()))
287 }
288
289 #[inline]
291 pub fn is_none(&self) -> bool {
292 self.0.is_none()
293 }
294
295 #[inline]
297 pub fn is_some(&self) -> bool {
298 self.0.is_some()
299 }
300
301 #[inline]
303 pub fn val(&self) -> Option<L> {
304 self.0
305 }
306
307 #[inline]
309 pub fn unwrap_or(self, rhs: L) -> L {
310 self.0.unwrap_or(rhs)
311 }
312
313 #[inline]
315 pub fn unwrap_or_else(self, f: impl FnOnce() -> L) -> L {
316 self.0.unwrap_or_else(f)
317 }
318
319 #[inline]
321 pub fn or(self, rhs: Self) -> Self {
322 Self(self.0.or(rhs.0))
323 }
324
325 #[inline]
327 pub fn or_zero(self) -> L {
328 self.0.unwrap_or_else(L::zero)
329 }
330
331 #[inline]
333 pub fn map(self, f: impl FnOnce(L) -> L) -> Self {
334 Self(self.0.map(f))
335 }
336}
337
338impl<L: LengthNum> From<Option<L>> for OptionNum<L> {
339 fn from(value: Option<L>) -> Self {
340 Self(value)
341 }
342}
343
344impl<L: LengthNum> core::ops::Add<L> for OptionNum<L> {
345 type Output = Self;
346
347 fn add(self, rhs: L) -> Self {
348 self.map(|x| x + rhs)
349 }
350}
351
352impl<L: LengthNum> core::ops::Sub<L> for OptionNum<L> {
353 type Output = Self;
354
355 fn sub(self, rhs: L) -> Self {
356 self.map(|x| x - rhs)
357 }
358}
359
360impl<L: LengthNum> core::ops::Mul<f32> for OptionNum<L> {
361 type Output = Self;
362
363 fn mul(self, rhs: f32) -> Self {
364 self.map(|x| x.mul_f32(rhs))
365 }
366}
367
368impl<L: LengthNum> core::ops::Mul<i32> for OptionNum<L> {
369 type Output = Self;
370
371 fn mul(self, rhs: i32) -> Self {
372 self.map(|x| x.mul_i32(rhs))
373 }
374}
375
376impl<L: LengthNum> core::ops::Add<Self> for OptionNum<L> {
377 type Output = Self;
378
379 fn add(self, rhs: Self) -> Self {
380 match rhs.val() {
381 Some(x) => self + x,
382 None => self,
383 }
384 }
385}
386
387impl<L: LengthNum> core::ops::Sub<Self> for OptionNum<L> {
388 type Output = Self;
389
390 fn sub(self, rhs: Self) -> Self {
391 match rhs.val() {
392 Some(x) => self - x,
393 None => self,
394 }
395 }
396}
397
398pub(crate) trait MinMax {
399 fn min(self, rhs: Self) -> Self;
400 fn max(self, rhs: Self) -> Self;
401}
402
403impl<L: LengthNum> MinMax for L {
404 fn min(self, rhs: Self) -> Self {
405 if self < rhs {
406 self
407 } else {
408 rhs
409 }
410 }
411
412 fn max(self, rhs: Self) -> Self {
413 if self > rhs {
414 self
415 } else {
416 rhs
417 }
418 }
419}
420
421pub(crate) trait MaybeMinMax<In, Out> {
422 fn maybe_min(self, rhs: In) -> Out;
423 fn maybe_max(self, rhs: In) -> Out;
424}
425
426impl<L: LengthNum> MaybeMinMax<OptionNum<L>, L> for L {
427 fn maybe_min(self, rhs: OptionNum<L>) -> L {
428 match rhs.val() {
429 None => self,
430 Some(x) => self.min(x),
431 }
432 }
433
434 fn maybe_max(self, rhs: OptionNum<L>) -> L {
435 match rhs.val() {
436 None => self,
437 Some(x) => self.max(x),
438 }
439 }
440}
441
442impl<L: LengthNum> MaybeMinMax<Self, Self> for OptionNum<L> {
443 fn maybe_min(self, rhs: Self) -> Self {
444 match self.val() {
445 None => OptionNum::none(),
446 Some(x) => match rhs.val() {
447 None => self,
448 Some(y) => OptionNum::some(x.min(y)),
449 },
450 }
451 }
452
453 fn maybe_max(self, rhs: Self) -> Self {
454 match self.val() {
455 None => OptionNum::none(),
456 Some(x) => match rhs.val() {
457 None => self,
458 Some(y) => OptionNum::some(x.max(y)),
459 },
460 }
461 }
462}
463
464impl<L: LengthNum> MaybeMinMax<L, Self> for OptionNum<L> {
465 fn maybe_min(self, rhs: L) -> OptionNum<L> {
466 match self.val() {
467 None => OptionNum::none(),
468 Some(x) => OptionNum::some(x.min(rhs)),
469 }
470 }
471
472 fn maybe_max(self, rhs: L) -> OptionNum<L> {
473 match self.val() {
474 None => OptionNum::none(),
475 Some(x) => OptionNum::some(x.max(rhs)),
476 }
477 }
478}
479
480impl<L: LengthNum> MaybeMinMax<OptionSize<L>, Size<L>> for Size<L> {
481 fn maybe_min(self, rhs: OptionSize<L>) -> Size<L> {
482 let width = match rhs.width.val() {
483 None => self.width,
484 Some(x) => self.width.min(x),
485 };
486 let height = match rhs.height.val() {
487 None => self.height,
488 Some(x) => self.height.min(x),
489 };
490 Size::new(width, height)
491 }
492
493 fn maybe_max(self, rhs: OptionSize<L>) -> Size<L> {
494 let width = match rhs.width.val() {
495 None => self.width,
496 Some(x) => self.width.max(x),
497 };
498 let height = match rhs.height.val() {
499 None => self.height,
500 Some(x) => self.height.max(x),
501 };
502 Size::new(width, height)
503 }
504}
505
506#[allow(missing_docs)]
508#[derive(Debug, Clone, Copy, PartialEq)]
509pub struct Edge<L: LengthNum> {
510 pub left: L,
511 pub right: L,
512 pub top: L,
513 pub bottom: L,
514}
515
516impl<L: LengthNum> Edge<L> {
517 #[inline(always)]
519 pub fn zero() -> Self {
520 Self {
521 left: L::zero(),
522 right: L::zero(),
523 top: L::zero(),
524 bottom: L::zero(),
525 }
526 }
527
528 #[inline(always)]
530 pub fn horizontal(&self) -> L {
531 self.left + self.right
532 }
533
534 #[inline(always)]
536 pub fn vertical(&self) -> L {
537 self.top + self.bottom
538 }
539
540 #[inline(always)]
541 pub(crate) fn main_axis_sum(&self, dir: AxisDirection) -> L {
542 match dir {
543 AxisDirection::Vertical => self.vertical(),
544 AxisDirection::Horizontal => self.horizontal(),
545 }
546 }
547
548 #[inline(always)]
549 pub(crate) fn cross_axis_sum(&self, dir: AxisDirection) -> L {
550 match dir {
551 AxisDirection::Vertical => self.horizontal(),
552 AxisDirection::Horizontal => self.vertical(),
553 }
554 }
555
556 #[inline(always)]
557 pub(crate) fn main_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> L {
558 match (dir, rev) {
559 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left,
560 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right,
561 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top,
562 (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom,
563 }
564 }
565
566 #[allow(unused)]
567 #[inline(always)]
568 pub(crate) fn main_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> L {
569 match (dir, rev) {
570 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right,
571 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left,
572 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom,
573 (AxisDirection::Vertical, AxisReverse::Reversed) => self.top,
574 }
575 }
576
577 #[inline(always)]
578 pub(crate) fn cross_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> L {
579 match (dir, rev) {
580 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top,
581 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom,
582 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left,
583 (AxisDirection::Vertical, AxisReverse::Reversed) => self.right,
584 }
585 }
586
587 #[allow(unused)]
588 #[inline(always)]
589 pub(crate) fn cross_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> L {
590 match (dir, rev) {
591 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom,
592 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top,
593 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right,
594 (AxisDirection::Vertical, AxisReverse::Reversed) => self.left,
595 }
596 }
597}
598
599impl<L: LengthNum> core::ops::Add<Edge<L>> for Edge<L> {
600 type Output = Self;
601
602 fn add(self, rhs: Edge<L>) -> Self {
603 Self {
604 left: self.left + rhs.left,
605 right: self.right + rhs.right,
606 top: self.top + rhs.top,
607 bottom: self.bottom + rhs.bottom,
608 }
609 }
610}
611
612impl<L: LengthNum> core::ops::Sub<Edge<L>> for Edge<L> {
613 type Output = Self;
614 fn sub(self, rhs: Edge<L>) -> Self {
615 Self {
616 left: self.left - rhs.left,
617 right: self.right - rhs.right,
618 top: self.top - rhs.top,
619 bottom: self.bottom - rhs.bottom,
620 }
621 }
622}
623
624#[allow(missing_docs)]
626#[derive(Debug, Clone, Copy, PartialEq)]
627pub struct EdgeOption<L: LengthNum> {
628 pub left: OptionNum<L>,
629 pub right: OptionNum<L>,
630 pub top: OptionNum<L>,
631 pub bottom: OptionNum<L>,
632}
633
634impl<L: LengthNum> EdgeOption<L> {
635 #[inline(always)]
637 pub fn or_zero(&self) -> Edge<L> {
638 Edge {
639 left: self.left.or_zero(),
640 right: self.right.or_zero(),
641 top: self.top.or_zero(),
642 bottom: self.bottom.or_zero(),
643 }
644 }
645
646 #[inline(always)]
648 pub fn horizontal(&self) -> L {
649 self.left.or_zero() + self.right.or_zero()
650 }
651
652 #[inline(always)]
654 pub fn vertical(&self) -> L {
655 self.top.or_zero() + self.bottom.or_zero()
656 }
657
658 pub(crate) fn is_left_right_either_none(&self) -> bool {
659 self.left.is_none() || self.right.is_none()
660 }
661
662 pub(crate) fn is_top_bottom_either_none(&self) -> bool {
663 self.top.is_none() || self.bottom.is_none()
664 }
665
666 #[inline(always)]
667 pub(crate) fn main_axis_sum(&self, dir: AxisDirection) -> L {
668 match dir {
669 AxisDirection::Horizontal => self.horizontal(),
670 AxisDirection::Vertical => self.vertical(),
671 }
672 }
673
674 #[inline(always)]
675 pub(crate) fn cross_axis_sum(&self, dir: AxisDirection) -> L {
676 match dir {
677 AxisDirection::Horizontal => self.vertical(),
678 AxisDirection::Vertical => self.horizontal(),
679 }
680 }
681
682 #[inline(always)]
683 pub(crate) fn main_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
684 match (dir, rev) {
685 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left,
686 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right,
687 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top,
688 (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom,
689 }
690 }
691
692 #[inline(always)]
693 pub(crate) fn set_main_axis_start(
694 &mut self,
695 dir: AxisDirection,
696 rev: AxisReverse,
697 value: OptionNum<L>,
698 ) {
699 match (dir, rev) {
700 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.left = value,
701 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.right = value,
702 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.top = value,
703 (AxisDirection::Vertical, AxisReverse::Reversed) => self.bottom = value,
704 }
705 }
706
707 #[inline(always)]
708 pub(crate) fn main_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
709 match (dir, rev) {
710 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right,
711 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left,
712 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom,
713 (AxisDirection::Vertical, AxisReverse::Reversed) => self.top,
714 }
715 }
716
717 #[inline(always)]
718 pub(crate) fn set_main_axis_end(
719 &mut self,
720 dir: AxisDirection,
721 rev: AxisReverse,
722 value: OptionNum<L>,
723 ) {
724 match (dir, rev) {
725 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.right = value,
726 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.left = value,
727 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.bottom = value,
728 (AxisDirection::Vertical, AxisReverse::Reversed) => self.top = value,
729 }
730 }
731
732 #[inline(always)]
733 pub(crate) fn cross_axis_start(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
734 match (dir, rev) {
735 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top,
736 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom,
737 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left,
738 (AxisDirection::Vertical, AxisReverse::Reversed) => self.right,
739 }
740 }
741
742 #[inline(always)]
743 pub(crate) fn set_cross_axis_start(
744 &mut self,
745 dir: AxisDirection,
746 rev: AxisReverse,
747 value: OptionNum<L>,
748 ) {
749 match (dir, rev) {
750 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.top = value,
751 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.bottom = value,
752 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.left = value,
753 (AxisDirection::Vertical, AxisReverse::Reversed) => self.right = value,
754 }
755 }
756
757 #[inline(always)]
758 pub(crate) fn cross_axis_end(&self, dir: AxisDirection, rev: AxisReverse) -> OptionNum<L> {
759 match (dir, rev) {
760 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom,
761 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top,
762 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right,
763 (AxisDirection::Vertical, AxisReverse::Reversed) => self.left,
764 }
765 }
766
767 #[inline(always)]
768 pub(crate) fn set_cross_axis_end(
769 &mut self,
770 dir: AxisDirection,
771 rev: AxisReverse,
772 value: OptionNum<L>,
773 ) {
774 match (dir, rev) {
775 (AxisDirection::Horizontal, AxisReverse::NotReversed) => self.bottom = value,
776 (AxisDirection::Horizontal, AxisReverse::Reversed) => self.top = value,
777 (AxisDirection::Vertical, AxisReverse::NotReversed) => self.right = value,
778 (AxisDirection::Vertical, AxisReverse::Reversed) => self.left = value,
779 }
780 }
781}
782
783#[derive(Debug, Clone, Copy, PartialEq)]
784pub(crate) enum AxisDirection {
785 Horizontal,
786 Vertical,
787}
788
789#[derive(Debug, Clone, Copy, PartialEq, Hash)]
790pub(crate) enum AxisReverse {
791 NotReversed,
792 Reversed,
793}
794
795#[derive(Debug, Clone, Copy, PartialEq)]
796pub(crate) struct AxisInfo {
797 pub(crate) dir: AxisDirection,
798 pub(crate) main_dir_rev: AxisReverse,
799 pub(crate) cross_dir_rev: AxisReverse,
800}
801
802impl AxisInfo {
803 pub(crate) fn from_writing_mode(writing_mode: WritingMode) -> Self {
804 let (dir, main_dir_rev, cross_dir_rev) = match writing_mode {
805 WritingMode::HorizontalTb => (
806 AxisDirection::Vertical,
807 AxisReverse::NotReversed,
808 AxisReverse::NotReversed,
809 ),
810 WritingMode::VerticalLr => (
811 AxisDirection::Horizontal,
812 AxisReverse::NotReversed,
813 AxisReverse::NotReversed,
814 ),
815 WritingMode::VerticalRl => (
816 AxisDirection::Horizontal,
817 AxisReverse::Reversed,
818 AxisReverse::NotReversed,
819 ),
820 };
821 Self {
822 dir,
823 main_dir_rev,
824 cross_dir_rev,
825 }
826 }
827
828 pub(crate) fn from_writing_mode_and_direction(
830 writing_mode: WritingMode,
831 direction: Direction,
832 ) -> Self {
833 let rtl_reverse = if matches!(direction, Direction::RTL) {
834 AxisReverse::Reversed
835 } else {
836 AxisReverse::NotReversed
837 };
838 let (dir, main_dir_rev, cross_dir_rev) = match writing_mode {
839 WritingMode::HorizontalTb => (
841 AxisDirection::Vertical,
842 AxisReverse::NotReversed,
843 rtl_reverse,
844 ),
845 WritingMode::VerticalLr => (
847 AxisDirection::Horizontal,
848 AxisReverse::NotReversed,
849 rtl_reverse,
850 ),
851 WritingMode::VerticalRl => (
853 AxisDirection::Horizontal,
854 AxisReverse::Reversed,
855 rtl_reverse,
856 ),
857 };
858 Self {
859 dir,
860 main_dir_rev,
861 cross_dir_rev,
862 }
863 }
864}
865#[derive(Debug, Clone, Copy, PartialEq)]
866pub(crate) struct MinMaxSize<L: LengthNum> {
867 pub(crate) min_width: OptionNum<L>,
868 pub(crate) max_width: OptionNum<L>,
869 pub(crate) min_height: OptionNum<L>,
870 pub(crate) max_height: OptionNum<L>,
871}
872
873#[derive(Debug, Clone, Copy, PartialEq)]
874pub(crate) struct MinMaxLimit<L: LengthNum> {
875 pub(crate) min_width: L,
876 pub(crate) max_width: OptionNum<L>,
877 pub(crate) min_height: L,
878 pub(crate) max_height: OptionNum<L>,
879}
880
881impl<L: LengthNum> MinMaxLimit<L> {
882 pub(crate) fn normalized_size(&self, v: OptionSize<L>) -> Normalized<OptionSize<L>> {
883 Normalized(OptionSize::new(
884 v.width
885 .map(|x| x.maybe_min(self.max_width).max(self.min_width)),
886 v.height
887 .map(|x| x.maybe_min(self.max_height).max(self.min_height)),
888 ))
889 }
890
891 pub(crate) fn normalized_size_keep_main(
896 &self,
897 v: OptionSize<L>,
898 dir: AxisDirection,
899 ) -> Normalized<OptionSize<L>> {
900 match dir {
901 AxisDirection::Horizontal => Normalized(OptionSize::new(
902 v.width,
903 v.height
904 .map(|x| x.maybe_min(self.max_height).max(self.min_height)),
905 )),
906 AxisDirection::Vertical => Normalized(OptionSize::new(
907 v.width
908 .map(|x| x.maybe_min(self.max_width).max(self.min_width)),
909 v.height,
910 )),
911 }
912 }
913
914 pub(crate) fn width(&self, x: L) -> L {
915 x.maybe_min(self.max_width).max(self.min_width)
916 }
917
918 pub(crate) fn height(&self, x: L) -> L {
919 x.maybe_min(self.max_height).max(self.min_height)
920 }
921
922 pub(crate) fn maybe(&self) -> MinMaxLimitMaybe<'_, L> {
923 MinMaxLimitMaybe(self)
924 }
925
926 #[inline(always)]
927 pub(crate) fn main_size(&self, x: L, dir: AxisDirection) -> L {
928 match dir {
929 AxisDirection::Horizontal => self.width(x),
930 AxisDirection::Vertical => self.height(x),
931 }
932 }
933
934 #[inline(always)]
935 pub(crate) fn cross_size(&self, x: L, dir: AxisDirection) -> L {
936 match dir {
937 AxisDirection::Horizontal => self.height(x),
938 AxisDirection::Vertical => self.width(x),
939 }
940 }
941
942 #[inline(always)]
943 pub(crate) fn min_main_size(&self, dir: AxisDirection) -> L {
944 match dir {
945 AxisDirection::Horizontal => self.min_width,
946 AxisDirection::Vertical => self.min_height,
947 }
948 }
949
950 #[inline(always)]
951 #[allow(unused)]
952 pub(crate) fn max_main_size(&self, dir: AxisDirection) -> OptionNum<L> {
953 match dir {
954 AxisDirection::Horizontal => self.max_width,
955 AxisDirection::Vertical => self.max_height,
956 }
957 }
958
959 #[inline(always)]
960 #[allow(unused)]
961 pub(crate) fn min_cross_size(&self, dir: AxisDirection) -> L {
962 match dir {
963 AxisDirection::Horizontal => self.min_height,
964 AxisDirection::Vertical => self.min_width,
965 }
966 }
967
968 #[inline(always)]
969 #[allow(unused)]
970 pub(crate) fn max_cross_size(&self, dir: AxisDirection) -> OptionNum<L> {
971 match dir {
972 AxisDirection::Horizontal => self.max_height,
973 AxisDirection::Vertical => self.max_width,
974 }
975 }
976
977 #[inline(always)]
978 #[allow(unused)]
979 pub(crate) fn set_min_cross_size(&mut self, x: L, dir: AxisDirection) {
980 match dir {
981 AxisDirection::Horizontal => self.min_height = x,
982 AxisDirection::Vertical => self.min_width = x,
983 }
984 }
985
986 #[inline(always)]
987 #[allow(unused)]
988 pub(crate) fn set_max_cross_size(&mut self, x: OptionNum<L>, dir: AxisDirection) {
989 match dir {
990 AxisDirection::Horizontal => self.max_height = x,
991 AxisDirection::Vertical => self.max_width = x,
992 }
993 }
994
995 #[inline(always)]
996 #[allow(unused)]
997 pub(crate) fn set_min_main_size(&mut self, x: L, dir: AxisDirection) {
998 match dir {
999 AxisDirection::Horizontal => self.min_width = x,
1000 AxisDirection::Vertical => self.min_height = x,
1001 }
1002 }
1003
1004 #[inline(always)]
1005 #[allow(unused)]
1006 pub(crate) fn set_max_main_size(&mut self, x: OptionNum<L>, dir: AxisDirection) {
1007 match dir {
1008 AxisDirection::Horizontal => self.max_width = x,
1009 AxisDirection::Vertical => self.max_height = x,
1010 }
1011 }
1012}
1013
1014pub(crate) struct MinMaxLimitMaybe<'a, L: LengthNum>(&'a MinMaxLimit<L>);
1015
1016impl<'a, L: LengthNum> MinMaxLimitMaybe<'a, L> {
1017 pub(crate) fn width(&self, v: OptionNum<L>) -> OptionNum<L> {
1018 v.map(|x| x.maybe_min(self.0.max_width).max(self.0.min_width))
1019 }
1020
1021 pub(crate) fn height(&self, v: OptionNum<L>) -> OptionNum<L> {
1022 v.map(|x| x.maybe_min(self.0.max_height).max(self.0.min_height))
1023 }
1024
1025 #[inline(always)]
1026 #[allow(unused)]
1027 pub(crate) fn main_size(&self, dir: AxisDirection, v: OptionNum<L>) -> OptionNum<L> {
1028 match dir {
1029 AxisDirection::Horizontal => self.width(v),
1030 AxisDirection::Vertical => self.height(v),
1031 }
1032 }
1033
1034 #[inline(always)]
1035 pub(crate) fn cross_size(&self, dir: AxisDirection, v: OptionNum<L>) -> OptionNum<L> {
1036 match dir {
1037 AxisDirection::Horizontal => self.height(v),
1038 AxisDirection::Vertical => self.width(v),
1039 }
1040 }
1041}
1042
1043#[derive(Debug, Clone, Copy, PartialEq, Hash)]
1044pub(crate) struct Normalized<T>(pub(crate) T);
1045
1046impl<T> Deref for Normalized<T> {
1047 type Target = T;
1048
1049 fn deref(&self) -> &Self::Target {
1050 &self.0
1051 }
1052}
1053
1054#[inline(always)]
1055pub(crate) fn size_to_option<L: LengthNum>(size: Size<L>) -> OptionSize<L> {
1056 OptionSize::new(OptionNum::some(size.width), OptionNum::some(size.height))
1057}
1058
1059#[allow(missing_docs)]
1060#[derive(Debug, Clone, PartialEq, Default)]
1061pub enum LayoutGridTemplate<L: LengthNum, T: PartialEq + Clone = i32> {
1062 #[default]
1063 None,
1064 TrackList(Vec<LayoutTrackListItem<L, T>>),
1065}
1066
1067#[allow(missing_docs)]
1068#[derive(Debug, Clone, PartialEq)]
1069pub enum LayoutTrackListItem<L: LengthNum, T: PartialEq + Clone = i32> {
1070 LineNames(Vec<String>),
1071 TrackSize(LayoutTrackSize<L, T>),
1072}
1073
1074impl<L: LengthNum, T: PartialEq + Clone> LayoutTrackListItem<L, T> {
1075 pub fn is_intrinsic(&self) -> bool {
1078 matches!(
1079 self,
1080 LayoutTrackListItem::TrackSize(
1081 LayoutTrackSize::Length(DefLength::Auto)
1082 | LayoutTrackSize::MinContent
1083 | LayoutTrackSize::MaxContent
1084 )
1085 )
1086 }
1087}
1088
1089#[allow(missing_docs)]
1090#[derive(Debug, Clone, PartialEq)]
1091pub enum LayoutTrackSize<L: LengthNum, T: PartialEq + Clone = i32> {
1092 MinContent,
1093 MaxContent,
1094 Fr(f32),
1095 Length(DefLength<L, T>),
1096}
1097
1098#[allow(missing_docs)]
1104#[derive(Debug, Clone, PartialEq)]
1105pub struct LayoutGridAuto<L: LengthNum, T: PartialEq + Clone = i32>(pub Vec<LayoutTrackSize<L, T>>);
1106
1107impl<L: LengthNum, T: PartialEq + Clone> Default for LayoutGridAuto<L, T> {
1108 fn default() -> Self {
1109 Self(vec![LayoutTrackSize::Length(DefLength::Auto)])
1111 }
1112}
1113
1114impl<L: LengthNum, T: PartialEq + Clone> LayoutGridAuto<L, T> {
1115 pub fn get(&self, index: usize) -> LayoutTrackSize<L, T> {
1118 if self.0.is_empty() {
1119 LayoutTrackSize::Length(DefLength::Auto)
1120 } else {
1121 self.0[index % self.0.len()].clone()
1122 }
1123 }
1124
1125 pub fn len(&self) -> usize {
1127 self.0.len()
1128 }
1129
1130 pub fn is_empty(&self) -> bool {
1132 self.0.is_empty()
1133 }
1134}
1135
1136#[cfg(test)]
1137mod test {
1138
1139 use crate::{AxisDirection, Normalized, OptionSize, Size, SizeGetter, SizeSetter};
1140
1141 #[test]
1142 fn option_size_get_main_size() {
1143 let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1144 let size = os.main_size(AxisDirection::Horizontal);
1145 assert_eq!(size.val(), Some(10.));
1147 let size = os.main_size(AxisDirection::Vertical);
1148 assert_eq!(size.val(), Some(20.));
1149 }
1150
1151 #[test]
1152 fn option_size_get_cross_size() {
1153 let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1154 let size = os.cross_size(AxisDirection::Horizontal);
1155 assert_eq!(size.val(), Some(20.));
1156 let size = os.cross_size(AxisDirection::Vertical);
1157 assert_eq!(size.val(), Some(10.));
1158 }
1159
1160 #[test]
1161 fn normalized_option_size_get_size() {
1162 let os = OptionSize::new(crate::OptionNum::some(10.), crate::OptionNum::some(20.));
1163 let normalized = Normalized(os);
1164 let size = normalized.main_size(AxisDirection::Horizontal);
1165 assert_eq!(size.val(), Some(10.));
1166 let size = normalized.main_size(AxisDirection::Vertical);
1167 assert_eq!(size.val(), Some(20.));
1168 }
1169
1170 #[test]
1171 fn size_get_size() {
1172 let s = Size::new(10.0_f32, 20.0_f32);
1173 let size = s.main_size(AxisDirection::Horizontal);
1174 assert_eq!(size, 10.);
1175 let size = s.main_size(AxisDirection::Vertical);
1176 assert_eq!(size, 20.);
1177 }
1178
1179 #[test]
1180 fn size_set_size() {
1181 let mut s = Size::new(10.0_f32, 20.0_f32);
1182 s.set_main_size(AxisDirection::Horizontal, 20.);
1183 assert_eq!(s.main_size(AxisDirection::Horizontal), 20.);
1184 s.set_cross_size(AxisDirection::Horizontal, 30.);
1185 assert_eq!(s.cross_size(AxisDirection::Horizontal), 30.);
1186 }
1187}