1use malloc_size_of_derive::MallocSizeOf;
8use style::properties::longhands::flex_direction::computed_value::T as FlexDirection;
9
10use crate::geom::{LogicalRect, LogicalSides, LogicalVec2};
11
12#[derive(Clone, Copy, Debug, Default)]
13pub(super) struct FlexRelativeVec2<T> {
14 pub main: T,
15 pub cross: T,
16}
17
18#[derive(Clone, Copy, Debug)]
19pub(super) struct FlexRelativeSides<T> {
20 pub cross_start: T,
21 pub main_start: T,
22 pub cross_end: T,
23 pub main_end: T,
24}
25
26pub(super) struct FlexRelativeRect<T> {
27 pub start_corner: FlexRelativeVec2<T>,
28 pub size: FlexRelativeVec2<T>,
29}
30
31impl<T> std::ops::Add for FlexRelativeVec2<T>
32where
33 T: std::ops::Add,
34{
35 type Output = FlexRelativeVec2<T::Output>;
36 fn add(self, rhs: Self) -> Self::Output {
37 FlexRelativeVec2 {
38 main: self.main + rhs.main,
39 cross: self.cross + rhs.cross,
40 }
41 }
42}
43
44impl<T> std::ops::Sub for FlexRelativeVec2<T>
45where
46 T: std::ops::Sub,
47{
48 type Output = FlexRelativeVec2<T::Output>;
49 fn sub(self, rhs: Self) -> Self::Output {
50 FlexRelativeVec2 {
51 main: self.main - rhs.main,
52 cross: self.cross - rhs.cross,
53 }
54 }
55}
56
57impl<T> FlexRelativeSides<T> {
58 pub fn sum_by_axis(self) -> FlexRelativeVec2<T::Output>
59 where
60 T: std::ops::Add,
61 {
62 FlexRelativeVec2 {
63 main: self.main_start + self.main_end,
64 cross: self.cross_start + self.cross_end,
65 }
66 }
67
68 pub fn cross_sum(self) -> T::Output
69 where
70 T: std::ops::Add,
71 {
72 self.cross_start + self.cross_end
73 }
74}
75
76#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
79pub(super) enum FlexAxis {
80 Row,
83 Column,
85}
86
87#[derive(Clone, Copy, Debug, MallocSizeOf)]
90pub(super) enum MainStartCrossStart {
91 InlineStartBlockStart,
92 InlineStartBlockEnd,
93 BlockStartInlineStart,
94 BlockStartInlineEnd,
95 InlineEndBlockStart,
96 InlineEndBlockEnd,
97 BlockEndInlineStart,
98 BlockEndInlineEnd,
99}
100
101impl FlexAxis {
102 pub fn from(flex_direction: FlexDirection) -> Self {
103 match flex_direction {
104 FlexDirection::Row | FlexDirection::RowReverse => FlexAxis::Row,
105 FlexDirection::Column | FlexDirection::ColumnReverse => FlexAxis::Column,
106 }
107 }
108
109 pub fn vec2_to_flex_relative<T>(self, flow_relative: LogicalVec2<T>) -> FlexRelativeVec2<T> {
110 let LogicalVec2 { inline, block } = flow_relative;
111 match self {
112 FlexAxis::Row => FlexRelativeVec2 {
113 main: inline,
114 cross: block,
115 },
116 FlexAxis::Column => FlexRelativeVec2 {
117 main: block,
118 cross: inline,
119 },
120 }
121 }
122
123 pub fn vec2_to_flow_relative<T>(self, flex_relative: FlexRelativeVec2<T>) -> LogicalVec2<T> {
124 let FlexRelativeVec2 { main, cross } = flex_relative;
125 match self {
126 FlexAxis::Row => LogicalVec2 {
127 inline: main,
128 block: cross,
129 },
130 FlexAxis::Column => LogicalVec2 {
131 block: main,
132 inline: cross,
133 },
134 }
135 }
136}
137
138macro_rules! sides_mapping_methods {
139 (
140 $(
141 $variant: path => {
142 $( $flex_relative_side: ident <=> $flow_relative_side: ident, )+
143 },
144 )+
145 ) => {
146 pub fn sides_to_flex_relative<T>(self, flow_relative: LogicalSides<T>) -> FlexRelativeSides<T> {
147 match self {
148 $(
149 $variant => FlexRelativeSides {
150 $( $flex_relative_side: flow_relative.$flow_relative_side, )+
151 },
152 )+
153 }
154 }
155
156 pub fn sides_to_flow_relative<T>(self, flex_relative: FlexRelativeSides<T>) -> LogicalSides<T> {
157 match self {
158 $(
159 $variant => LogicalSides {
160 $( $flow_relative_side: flex_relative.$flex_relative_side, )+
161 },
162 )+
163 }
164 }
165 }
166}
167
168impl MainStartCrossStart {
169 pub fn from(flex_direction: FlexDirection, flex_wrap_reverse: bool) -> Self {
170 match (flex_direction, flex_wrap_reverse) {
171 (FlexDirection::Row, true) => MainStartCrossStart::InlineStartBlockEnd,
177 (FlexDirection::Row, false) => MainStartCrossStart::InlineStartBlockStart,
178 (FlexDirection::Column, true) => MainStartCrossStart::BlockStartInlineEnd,
179 (FlexDirection::Column, false) => MainStartCrossStart::BlockStartInlineStart,
180 (FlexDirection::RowReverse, true) => MainStartCrossStart::InlineEndBlockEnd,
181 (FlexDirection::RowReverse, false) => MainStartCrossStart::InlineEndBlockStart,
182 (FlexDirection::ColumnReverse, true) => MainStartCrossStart::BlockEndInlineEnd,
183 (FlexDirection::ColumnReverse, false) => MainStartCrossStart::BlockEndInlineStart,
184 }
185 }
186
187 sides_mapping_methods! {
188 MainStartCrossStart::InlineStartBlockStart => {
189 main_start <=> inline_start,
190 cross_start <=> block_start,
191 main_end <=> inline_end,
192 cross_end <=> block_end,
193 },
194 MainStartCrossStart::InlineStartBlockEnd => {
195 main_start <=> inline_start,
196 cross_start <=> block_end,
197 main_end <=> inline_end,
198 cross_end <=> block_start,
199 },
200 MainStartCrossStart::BlockStartInlineStart => {
201 main_start <=> block_start,
202 cross_start <=> inline_start,
203 main_end <=> block_end,
204 cross_end <=> inline_end,
205 },
206 MainStartCrossStart::BlockStartInlineEnd => {
207 main_start <=> block_start,
208 cross_start <=> inline_end,
209 main_end <=> block_end,
210 cross_end <=> inline_start,
211 },
212 MainStartCrossStart::InlineEndBlockStart => {
213 main_start <=> inline_end,
214 cross_start <=> block_start,
215 main_end <=> inline_start,
216 cross_end <=> block_end,
217 },
218 MainStartCrossStart::InlineEndBlockEnd => {
219 main_start <=> inline_end,
220 cross_start <=> block_end,
221 main_end <=> inline_start,
222 cross_end <=> block_start,
223 },
224 MainStartCrossStart::BlockEndInlineStart => {
225 main_start <=> block_end,
226 cross_start <=> inline_start,
227 main_end <=> block_start,
228 cross_end <=> inline_end,
229 },
230 MainStartCrossStart::BlockEndInlineEnd => {
231 main_start <=> block_end,
232 cross_start <=> inline_end,
233 main_end <=> block_start,
234 cross_end <=> inline_start,
235 },
236 }
237}
238
239pub(super) fn rect_to_flow_relative<T>(
242 flex_axis: FlexAxis,
243 main_start_cross_start_sides_are: MainStartCrossStart,
244 base_rect_size: FlexRelativeVec2<T>,
245 rect: FlexRelativeRect<T>,
246) -> LogicalRect<T>
247where
248 T: Copy + std::ops::Add<Output = T> + std::ops::Sub<Output = T>,
249{
250 let end_corner_position = rect.start_corner + rect.size;
253 let end_corner_offsets = base_rect_size - end_corner_position;
254 let start_corner_position = rect.start_corner;
256 let start_corner_offsets = start_corner_position;
257
258 let flow_relative_offsets =
260 main_start_cross_start_sides_are.sides_to_flow_relative(FlexRelativeSides {
261 main_start: start_corner_offsets.main,
262 cross_start: start_corner_offsets.cross,
263 main_end: end_corner_offsets.main,
264 cross_end: end_corner_offsets.cross,
265 });
266 let flow_relative_base_rect_size = flex_axis.vec2_to_flow_relative(base_rect_size);
267
268 let start_corner = LogicalVec2 {
270 inline: flow_relative_offsets.inline_start,
271 block: flow_relative_offsets.block_start,
272 };
273 let end_corner_position = LogicalVec2 {
274 inline: flow_relative_base_rect_size.inline - flow_relative_offsets.inline_end,
275 block: flow_relative_base_rect_size.block - flow_relative_offsets.block_end,
276 };
277 let size = end_corner_position - start_corner;
278 LogicalRect { start_corner, size }
279}