1use std::fmt::Write;
9
10use style_traits::CssWriter;
11use style_traits::SpecifiedValueInfo;
12use style_traits::ToCss;
13
14use crate::logical_geometry::PhysicalSide;
15use crate::values::animated::ToAnimatedZero;
16use crate::values::computed::position::TryTacticAdjustment;
17use crate::values::generics::box_::PositionProperty;
18use crate::values::generics::length::GenericAnchorSizeFunction;
19use crate::values::generics::ratio::Ratio;
20use crate::values::generics::Optional;
21use crate::values::DashedIdent;
22
23#[derive(
25 Animate,
26 Clone,
27 ComputeSquaredDistance,
28 Copy,
29 Debug,
30 Deserialize,
31 MallocSizeOf,
32 PartialEq,
33 Serialize,
34 SpecifiedValueInfo,
35 ToAnimatedValue,
36 ToAnimatedZero,
37 ToComputedValue,
38 ToResolvedValue,
39 ToShmem,
40 ToTyped,
41)]
42#[repr(C)]
43pub struct GenericPosition<H, V> {
44 pub horizontal: H,
46 pub vertical: V,
48}
49
50impl<H, V> PositionComponent for Position<H, V>
51where
52 H: PositionComponent,
53 V: PositionComponent,
54{
55 #[inline]
56 fn is_center(&self) -> bool {
57 self.horizontal.is_center() && self.vertical.is_center()
58 }
59}
60
61pub use self::GenericPosition as Position;
62
63impl<H, V> Position<H, V> {
64 pub fn new(horizontal: H, vertical: V) -> Self {
66 Self {
67 horizontal,
68 vertical,
69 }
70 }
71}
72
73pub trait PositionComponent {
75 fn is_center(&self) -> bool;
78}
79
80#[derive(
84 Animate,
85 Clone,
86 ComputeSquaredDistance,
87 Copy,
88 Debug,
89 Deserialize,
90 MallocSizeOf,
91 Parse,
92 PartialEq,
93 Serialize,
94 SpecifiedValueInfo,
95 ToAnimatedZero,
96 ToAnimatedValue,
97 ToComputedValue,
98 ToCss,
99 ToResolvedValue,
100 ToShmem,
101 ToTyped,
102)]
103#[repr(C, u8)]
104pub enum GenericPositionOrAuto<Pos> {
105 Position(Pos),
107 Auto,
109}
110
111pub use self::GenericPositionOrAuto as PositionOrAuto;
112
113impl<Pos> PositionOrAuto<Pos> {
114 #[inline]
116 pub fn auto() -> Self {
117 PositionOrAuto::Auto
118 }
119
120 #[inline]
122 pub fn is_auto(&self) -> bool {
123 matches!(self, PositionOrAuto::Auto)
124 }
125}
126
127#[derive(
129 Animate,
130 Clone,
131 ComputeSquaredDistance,
132 Copy,
133 Debug,
134 MallocSizeOf,
135 PartialEq,
136 Parse,
137 SpecifiedValueInfo,
138 ToAnimatedValue,
139 ToAnimatedZero,
140 ToComputedValue,
141 ToCss,
142 ToResolvedValue,
143 ToShmem,
144 ToTyped,
145)]
146#[repr(C, u8)]
147pub enum GenericZIndex<I> {
148 Integer(I),
150 Auto,
152}
153
154pub use self::GenericZIndex as ZIndex;
155
156impl<Integer> ZIndex<Integer> {
157 #[inline]
159 pub fn auto() -> Self {
160 ZIndex::Auto
161 }
162
163 #[inline]
165 pub fn is_auto(self) -> bool {
166 matches!(self, ZIndex::Auto)
167 }
168
169 #[inline]
171 pub fn integer_or(self, auto: Integer) -> Integer {
172 match self {
173 ZIndex::Integer(n) => n,
174 ZIndex::Auto => auto,
175 }
176 }
177}
178
179#[derive(
181 Animate,
182 Clone,
183 ComputeSquaredDistance,
184 Copy,
185 Debug,
186 MallocSizeOf,
187 PartialEq,
188 SpecifiedValueInfo,
189 ToAnimatedValue,
190 ToComputedValue,
191 ToCss,
192 ToResolvedValue,
193 ToShmem,
194)]
195#[repr(C, u8)]
196pub enum PreferredRatio<N> {
197 #[css(skip)]
199 None,
200 Ratio(
202 #[animation(field_bound)]
203 #[css(field_bound)]
204 #[distance(field_bound)]
205 Ratio<N>,
206 ),
207}
208
209#[derive(
211 Animate,
212 Clone,
213 ComputeSquaredDistance,
214 Copy,
215 Debug,
216 MallocSizeOf,
217 PartialEq,
218 SpecifiedValueInfo,
219 ToAnimatedValue,
220 ToComputedValue,
221 ToCss,
222 ToResolvedValue,
223 ToShmem,
224 ToTyped,
225)]
226#[repr(C)]
227pub struct GenericAspectRatio<N> {
228 #[animation(constant)]
230 #[css(represents_keyword)]
231 pub auto: bool,
232 #[animation(field_bound)]
234 #[css(field_bound)]
235 #[distance(field_bound)]
236 pub ratio: PreferredRatio<N>,
237}
238
239pub use self::GenericAspectRatio as AspectRatio;
240
241impl<N> AspectRatio<N> {
242 #[inline]
244 pub fn auto() -> Self {
245 AspectRatio {
246 auto: true,
247 ratio: PreferredRatio::None,
248 }
249 }
250}
251
252impl<N> ToAnimatedZero for AspectRatio<N> {
253 #[inline]
254 fn to_animated_zero(&self) -> Result<Self, ()> {
255 Err(())
256 }
257}
258
259#[derive(
268 Animate,
269 Clone,
270 ComputeSquaredDistance,
271 Debug,
272 MallocSizeOf,
273 PartialEq,
274 ToCss,
275 ToShmem,
276 ToAnimatedValue,
277 ToAnimatedZero,
278 ToComputedValue,
279 ToResolvedValue,
280 ToTyped,
281)]
282#[repr(C)]
283pub enum GenericInset<P, LP> {
284 LengthPercentage(LP),
286 Auto,
288 AnchorFunction(Box<GenericAnchorFunction<P, Self>>),
292 AnchorSizeFunction(Box<GenericAnchorSizeFunction<Self>>),
296 AnchorContainingCalcFunction(LP),
299}
300
301impl<P, LP> SpecifiedValueInfo for GenericInset<P, LP>
302where
303 LP: SpecifiedValueInfo,
304{
305 fn collect_completion_keywords(f: style_traits::KeywordsCollectFn) {
306 LP::collect_completion_keywords(f);
307 f(&["auto"]);
308 if static_prefs::pref!("layout.css.anchor-positioning.enabled") {
309 f(&["anchor", "anchor-size"]);
310 }
311 }
312}
313
314impl<P, LP> GenericInset<P, LP> {
315 #[inline]
317 pub fn auto() -> Self {
318 Self::Auto
319 }
320
321 #[inline]
323 #[cfg(feature = "servo")]
324 pub fn is_auto(&self) -> bool {
325 matches!(self, Self::Auto)
326 }
327}
328
329pub use self::GenericInset as Inset;
330
331#[derive(
336 Animate,
337 Clone,
338 ComputeSquaredDistance,
339 Debug,
340 MallocSizeOf,
341 PartialEq,
342 SpecifiedValueInfo,
343 ToShmem,
344 ToAnimatedValue,
345 ToAnimatedZero,
346 ToComputedValue,
347 ToResolvedValue,
348 Serialize,
349 Deserialize,
350)]
351#[repr(C)]
352pub struct GenericAnchorFunction<Percentage, Fallback> {
353 #[animation(constant)]
356 pub target_element: DashedIdent,
357 pub side: GenericAnchorSide<Percentage>,
360 pub fallback: Optional<Fallback>,
362}
363
364impl<Percentage, Fallback> ToCss for GenericAnchorFunction<Percentage, Fallback>
365where
366 Percentage: ToCss,
367 Fallback: ToCss,
368{
369 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> std::fmt::Result
370 where
371 W: Write,
372 {
373 dest.write_str("anchor(")?;
374 if !self.target_element.is_empty() {
375 self.target_element.to_css(dest)?;
376 dest.write_str(" ")?;
377 }
378 self.side.to_css(dest)?;
379 if let Some(f) = self.fallback.as_ref() {
380 dest.write_str(", ")?;
382 f.to_css(dest)?;
383 }
384 dest.write_str(")")
385 }
386}
387
388impl<Percentage, Fallback> GenericAnchorFunction<Percentage, Fallback> {
389 pub fn valid_for(&self, side: PhysicalSide, position_property: PositionProperty) -> bool {
391 position_property.is_absolutely_positioned() && self.side.valid_for(side)
392 }
393}
394
395#[derive(
397 Animate,
398 Clone,
399 ComputeSquaredDistance,
400 Copy,
401 Debug,
402 MallocSizeOf,
403 PartialEq,
404 SpecifiedValueInfo,
405 ToCss,
406 ToShmem,
407 Parse,
408 ToAnimatedValue,
409 ToAnimatedZero,
410 ToComputedValue,
411 ToResolvedValue,
412 Serialize,
413 Deserialize,
414)]
415#[repr(u8)]
416pub enum AnchorSideKeyword {
417 Inside,
419 Outside,
421 Top,
423 Left,
425 Right,
427 Bottom,
429 Start,
433 End,
435 SelfStart,
437 SelfEnd,
439 Center,
441}
442
443impl AnchorSideKeyword {
444 fn from_physical_side(side: PhysicalSide) -> Self {
445 match side {
446 PhysicalSide::Top => Self::Top,
447 PhysicalSide::Right => Self::Right,
448 PhysicalSide::Bottom => Self::Bottom,
449 PhysicalSide::Left => Self::Left,
450 }
451 }
452
453 fn physical_side(self) -> Option<PhysicalSide> {
454 Some(match self {
455 Self::Top => PhysicalSide::Top,
456 Self::Right => PhysicalSide::Right,
457 Self::Bottom => PhysicalSide::Bottom,
458 Self::Left => PhysicalSide::Left,
459 _ => return None,
460 })
461 }
462}
463
464impl TryTacticAdjustment for AnchorSideKeyword {
465 fn try_tactic_adjustment(&mut self, old_side: PhysicalSide, new_side: PhysicalSide) {
466 if !old_side.parallel_to(new_side) {
467 let Some(s) = self.physical_side() else {
468 return;
469 };
470 *self = Self::from_physical_side(if s == new_side {
471 old_side
472 } else if s == old_side {
473 new_side
474 } else if s == new_side.opposite_side() {
475 old_side.opposite_side()
476 } else {
477 debug_assert_eq!(s, old_side.opposite_side());
478 new_side.opposite_side()
479 });
480 return;
481 }
482
483 *self = match self {
484 Self::Center | Self::Inside | Self::Outside => *self,
485 Self::SelfStart => Self::SelfEnd,
486 Self::SelfEnd => Self::SelfStart,
487 Self::Start => Self::End,
488 Self::End => Self::Start,
489 Self::Top => Self::Bottom,
490 Self::Bottom => Self::Top,
491 Self::Left => Self::Right,
492 Self::Right => Self::Left,
493 }
494 }
495}
496
497impl AnchorSideKeyword {
498 fn valid_for(&self, side: PhysicalSide) -> bool {
499 match self {
500 Self::Left | Self::Right => matches!(side, PhysicalSide::Left | PhysicalSide::Right),
501 Self::Top | Self::Bottom => matches!(side, PhysicalSide::Top | PhysicalSide::Bottom),
502 Self::Inside
503 | Self::Outside
504 | Self::Start
505 | Self::End
506 | Self::SelfStart
507 | Self::SelfEnd
508 | Self::Center => true,
509 }
510 }
511}
512
513#[derive(
515 Animate,
516 Clone,
517 ComputeSquaredDistance,
518 Copy,
519 Debug,
520 MallocSizeOf,
521 PartialEq,
522 Parse,
523 SpecifiedValueInfo,
524 ToCss,
525 ToShmem,
526 ToAnimatedValue,
527 ToAnimatedZero,
528 ToComputedValue,
529 ToResolvedValue,
530 Serialize,
531 Deserialize,
532)]
533#[repr(C)]
534pub enum GenericAnchorSide<P> {
535 Keyword(AnchorSideKeyword),
537 Percentage(P),
539}
540
541impl<P> GenericAnchorSide<P> {
542 pub fn valid_for(&self, side: PhysicalSide) -> bool {
544 match self {
545 Self::Keyword(k) => k.valid_for(side),
546 Self::Percentage(_) => true,
547 }
548 }
549}