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