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
69#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
72pub(super) enum FlexAxis {
73 Row,
76 Column,
78}
79
80#[derive(Clone, Copy, Debug, MallocSizeOf)]
83pub(super) enum MainStartCrossStart {
84 InlineStartBlockStart,
85 InlineStartBlockEnd,
86 BlockStartInlineStart,
87 BlockStartInlineEnd,
88 InlineEndBlockStart,
89 InlineEndBlockEnd,
90 BlockEndInlineStart,
91 BlockEndInlineEnd,
92}
93
94impl FlexAxis {
95 pub fn from(flex_direction: FlexDirection) -> Self {
96 match flex_direction {
97 FlexDirection::Row | FlexDirection::RowReverse => FlexAxis::Row,
98 FlexDirection::Column | FlexDirection::ColumnReverse => FlexAxis::Column,
99 }
100 }
101
102 pub fn vec2_to_flex_relative<T>(self, flow_relative: LogicalVec2<T>) -> FlexRelativeVec2<T> {
103 let LogicalVec2 { inline, block } = flow_relative;
104 match self {
105 FlexAxis::Row => FlexRelativeVec2 {
106 main: inline,
107 cross: block,
108 },
109 FlexAxis::Column => FlexRelativeVec2 {
110 main: block,
111 cross: inline,
112 },
113 }
114 }
115
116 pub fn vec2_to_flow_relative<T>(self, flex_relative: FlexRelativeVec2<T>) -> LogicalVec2<T> {
117 let FlexRelativeVec2 { main, cross } = flex_relative;
118 match self {
119 FlexAxis::Row => LogicalVec2 {
120 inline: main,
121 block: cross,
122 },
123 FlexAxis::Column => LogicalVec2 {
124 block: main,
125 inline: cross,
126 },
127 }
128 }
129}
130
131macro_rules! sides_mapping_methods {
132 (
133 $(
134 $variant: path => {
135 $( $flex_relative_side: ident <=> $flow_relative_side: ident, )+
136 },
137 )+
138 ) => {
139 pub fn sides_to_flex_relative<T>(self, flow_relative: LogicalSides<T>) -> FlexRelativeSides<T> {
140 match self {
141 $(
142 $variant => FlexRelativeSides {
143 $( $flex_relative_side: flow_relative.$flow_relative_side, )+
144 },
145 )+
146 }
147 }
148
149 pub fn sides_to_flow_relative<T>(self, flex_relative: FlexRelativeSides<T>) -> LogicalSides<T> {
150 match self {
151 $(
152 $variant => LogicalSides {
153 $( $flow_relative_side: flex_relative.$flex_relative_side, )+
154 },
155 )+
156 }
157 }
158 }
159}
160
161impl MainStartCrossStart {
162 pub fn from(flex_direction: FlexDirection, flex_wrap_reverse: bool) -> Self {
163 match (flex_direction, flex_wrap_reverse) {
164 (FlexDirection::Row, true) => MainStartCrossStart::InlineStartBlockEnd,
170 (FlexDirection::Row, false) => MainStartCrossStart::InlineStartBlockStart,
171 (FlexDirection::Column, true) => MainStartCrossStart::BlockStartInlineEnd,
172 (FlexDirection::Column, false) => MainStartCrossStart::BlockStartInlineStart,
173 (FlexDirection::RowReverse, true) => MainStartCrossStart::InlineEndBlockEnd,
174 (FlexDirection::RowReverse, false) => MainStartCrossStart::InlineEndBlockStart,
175 (FlexDirection::ColumnReverse, true) => MainStartCrossStart::BlockEndInlineEnd,
176 (FlexDirection::ColumnReverse, false) => MainStartCrossStart::BlockEndInlineStart,
177 }
178 }
179
180 sides_mapping_methods! {
181 MainStartCrossStart::InlineStartBlockStart => {
182 main_start <=> inline_start,
183 cross_start <=> block_start,
184 main_end <=> inline_end,
185 cross_end <=> block_end,
186 },
187 MainStartCrossStart::InlineStartBlockEnd => {
188 main_start <=> inline_start,
189 cross_start <=> block_end,
190 main_end <=> inline_end,
191 cross_end <=> block_start,
192 },
193 MainStartCrossStart::BlockStartInlineStart => {
194 main_start <=> block_start,
195 cross_start <=> inline_start,
196 main_end <=> block_end,
197 cross_end <=> inline_end,
198 },
199 MainStartCrossStart::BlockStartInlineEnd => {
200 main_start <=> block_start,
201 cross_start <=> inline_end,
202 main_end <=> block_end,
203 cross_end <=> inline_start,
204 },
205 MainStartCrossStart::InlineEndBlockStart => {
206 main_start <=> inline_end,
207 cross_start <=> block_start,
208 main_end <=> inline_start,
209 cross_end <=> block_end,
210 },
211 MainStartCrossStart::InlineEndBlockEnd => {
212 main_start <=> inline_end,
213 cross_start <=> block_end,
214 main_end <=> inline_start,
215 cross_end <=> block_start,
216 },
217 MainStartCrossStart::BlockEndInlineStart => {
218 main_start <=> block_end,
219 cross_start <=> inline_start,
220 main_end <=> block_start,
221 cross_end <=> inline_end,
222 },
223 MainStartCrossStart::BlockEndInlineEnd => {
224 main_start <=> block_end,
225 cross_start <=> inline_end,
226 main_end <=> block_start,
227 cross_end <=> inline_start,
228 },
229 }
230}
231
232pub(super) fn rect_to_flow_relative<T>(
235 flex_axis: FlexAxis,
236 main_start_cross_start_sides_are: MainStartCrossStart,
237 base_rect_size: FlexRelativeVec2<T>,
238 rect: FlexRelativeRect<T>,
239) -> LogicalRect<T>
240where
241 T: Copy + std::ops::Add<Output = T> + std::ops::Sub<Output = T>,
242{
243 let end_corner_position = rect.start_corner + rect.size;
246 let end_corner_offsets = base_rect_size - end_corner_position;
247 let start_corner_position = rect.start_corner;
249 let start_corner_offsets = start_corner_position;
250
251 let flow_relative_offsets =
253 main_start_cross_start_sides_are.sides_to_flow_relative(FlexRelativeSides {
254 main_start: start_corner_offsets.main,
255 cross_start: start_corner_offsets.cross,
256 main_end: end_corner_offsets.main,
257 cross_end: end_corner_offsets.cross,
258 });
259 let flow_relative_base_rect_size = flex_axis.vec2_to_flow_relative(base_rect_size);
260
261 let start_corner = LogicalVec2 {
263 inline: flow_relative_offsets.inline_start,
264 block: flow_relative_offsets.block_start,
265 };
266 let end_corner_position = LogicalVec2 {
267 inline: flow_relative_base_rect_size.inline - flow_relative_offsets.inline_end,
268 block: flow_relative_base_rect_size.block - flow_relative_offsets.block_end,
269 };
270 let size = end_corner_position - start_corner;
271 LogicalRect { start_corner, size }
272}