1use crate::parser::{Parse, ParserContext};
8use crate::values::generics::box_::PositionProperty;
9use crate::values::generics::Optional;
10use crate::values::DashedIdent;
11use crate::Zero;
12use cssparser::Parser;
13use std::fmt::Write;
14use style_traits::ParseError;
15use style_traits::StyleParseErrorKind;
16use style_traits::ToCss;
17use style_traits::{CssWriter, SpecifiedValueInfo};
18
19#[allow(missing_docs)]
21#[derive(
22 Animate,
23 Clone,
24 ComputeSquaredDistance,
25 Copy,
26 Debug,
27 MallocSizeOf,
28 PartialEq,
29 SpecifiedValueInfo,
30 ToAnimatedValue,
31 ToAnimatedZero,
32 ToComputedValue,
33 ToCss,
34 ToResolvedValue,
35 ToShmem,
36 ToTyped,
37)]
38#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
39#[repr(C, u8)]
40pub enum GenericLengthPercentageOrAuto<LengthPercent> {
41 LengthPercentage(LengthPercent),
42 Auto,
43}
44
45pub use self::GenericLengthPercentageOrAuto as LengthPercentageOrAuto;
46
47impl<LengthPercentage> LengthPercentageOrAuto<LengthPercentage> {
48 #[inline]
50 pub fn auto() -> Self {
51 LengthPercentageOrAuto::Auto
52 }
53
54 #[inline]
56 pub fn is_auto(&self) -> bool {
57 matches!(*self, LengthPercentageOrAuto::Auto)
58 }
59
60 pub fn parse_with<'i, 't>(
62 context: &ParserContext,
63 input: &mut Parser<'i, 't>,
64 parser: impl FnOnce(
65 &ParserContext,
66 &mut Parser<'i, 't>,
67 ) -> Result<LengthPercentage, ParseError<'i>>,
68 ) -> Result<Self, ParseError<'i>> {
69 if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
70 return Ok(LengthPercentageOrAuto::Auto);
71 }
72
73 Ok(LengthPercentageOrAuto::LengthPercentage(parser(
74 context, input,
75 )?))
76 }
77}
78
79impl<LengthPercentage> LengthPercentageOrAuto<LengthPercentage>
80where
81 LengthPercentage: Clone,
82{
83 #[inline]
85 pub fn auto_is(&self, f: impl FnOnce() -> LengthPercentage) -> LengthPercentage {
86 match self {
87 LengthPercentageOrAuto::LengthPercentage(length) => length.clone(),
88 LengthPercentageOrAuto::Auto => f(),
89 }
90 }
91
92 #[inline]
94 pub fn non_auto(&self) -> Option<LengthPercentage> {
95 match self {
96 LengthPercentageOrAuto::LengthPercentage(length) => Some(length.clone()),
97 LengthPercentageOrAuto::Auto => None,
98 }
99 }
100
101 pub fn map<T>(&self, f: impl FnOnce(LengthPercentage) -> T) -> LengthPercentageOrAuto<T> {
103 match self {
104 LengthPercentageOrAuto::LengthPercentage(l) => {
105 LengthPercentageOrAuto::LengthPercentage(f(l.clone()))
106 },
107 LengthPercentageOrAuto::Auto => LengthPercentageOrAuto::Auto,
108 }
109 }
110}
111
112impl<LengthPercentage: Zero> Zero for LengthPercentageOrAuto<LengthPercentage> {
113 fn zero() -> Self {
114 LengthPercentageOrAuto::LengthPercentage(Zero::zero())
115 }
116
117 fn is_zero(&self) -> bool {
118 match *self {
119 LengthPercentageOrAuto::LengthPercentage(ref l) => l.is_zero(),
120 LengthPercentageOrAuto::Auto => false,
121 }
122 }
123}
124
125impl<LengthPercentage: Parse> Parse for LengthPercentageOrAuto<LengthPercentage> {
126 fn parse<'i, 't>(
127 context: &ParserContext,
128 input: &mut Parser<'i, 't>,
129 ) -> Result<Self, ParseError<'i>> {
130 Self::parse_with(context, input, LengthPercentage::parse)
131 }
132}
133
134#[allow(missing_docs)]
141#[derive(
142 Animate,
143 ComputeSquaredDistance,
144 Clone,
145 Debug,
146 MallocSizeOf,
147 PartialEq,
148 ToAnimatedValue,
149 ToAnimatedZero,
150 ToComputedValue,
151 ToCss,
152 ToResolvedValue,
153 ToShmem,
154 ToTyped,
155)]
156#[repr(C, u8)]
157pub enum GenericSize<LengthPercent> {
158 LengthPercentage(LengthPercent),
159 Auto,
160 #[animation(error)]
161 MaxContent,
162 #[animation(error)]
163 MinContent,
164 #[animation(error)]
165 FitContent,
166 #[cfg(feature = "gecko")]
167 #[animation(error)]
168 MozAvailable,
169 #[animation(error)]
170 WebkitFillAvailable,
171 #[animation(error)]
172 Stretch,
173 #[animation(error)]
174 #[css(function = "fit-content")]
175 FitContentFunction(LengthPercent),
176 AnchorSizeFunction(Box<GenericAnchorSizeFunction<Self>>),
177 AnchorContainingCalcFunction(LengthPercent),
178}
179
180impl<LengthPercent> SpecifiedValueInfo for GenericSize<LengthPercent>
181where
182 LengthPercent: SpecifiedValueInfo,
183{
184 fn collect_completion_keywords(f: style_traits::KeywordsCollectFn) {
185 LengthPercent::collect_completion_keywords(f);
186 f(&["auto", "stretch", "fit-content", "max-content", "min-content"]);
187 if cfg!(feature = "gecko") {
188 f(&["-moz-available"]);
189 }
190 if static_prefs::pref!("layout.css.webkit-fill-available.enabled") {
191 f(&["-webkit-fill-available"]);
192 }
193 if static_prefs::pref!("layout.css.anchor-positioning.enabled") {
194 f(&["anchor-size"]);
195 }
196 }
197}
198
199pub use self::GenericSize as Size;
200
201impl<LengthPercentage> Size<LengthPercentage> {
202 #[inline]
204 pub fn auto() -> Self {
205 Size::Auto
206 }
207
208 #[inline]
210 pub fn is_auto(&self) -> bool {
211 matches!(*self, Size::Auto)
212 }
213}
214
215#[allow(missing_docs)]
217#[derive(
218 Animate,
219 Clone,
220 ComputeSquaredDistance,
221 Debug,
222 MallocSizeOf,
223 PartialEq,
224 ToAnimatedValue,
225 ToAnimatedZero,
226 ToComputedValue,
227 ToCss,
228 ToResolvedValue,
229 ToShmem,
230 ToTyped,
231)]
232#[repr(C, u8)]
233pub enum GenericMaxSize<LengthPercent> {
234 LengthPercentage(LengthPercent),
235 None,
236 #[animation(error)]
237 MaxContent,
238 #[animation(error)]
239 MinContent,
240 #[animation(error)]
241 FitContent,
242 #[cfg(feature = "gecko")]
243 #[animation(error)]
244 MozAvailable,
245 #[animation(error)]
246 WebkitFillAvailable,
247 #[animation(error)]
248 Stretch,
249 #[animation(error)]
250 #[css(function = "fit-content")]
251 FitContentFunction(LengthPercent),
252 AnchorSizeFunction(Box<GenericAnchorSizeFunction<Self>>),
253 AnchorContainingCalcFunction(LengthPercent),
254}
255
256impl<LP> SpecifiedValueInfo for GenericMaxSize<LP>
257where
258 LP: SpecifiedValueInfo,
259{
260 fn collect_completion_keywords(f: style_traits::KeywordsCollectFn) {
261 LP::collect_completion_keywords(f);
262 f(&["none", "stretch", "fit-content", "max-content", "min-content"]);
263 if cfg!(feature = "gecko") {
264 f(&["-moz-available"]);
265 }
266 if static_prefs::pref!("layout.css.webkit-fill-available.enabled") {
267 f(&["-webkit-fill-available"]);
268 }
269 if static_prefs::pref!("layout.css.anchor-positioning.enabled") {
270 f(&["anchor-size"]);
271 }
272 }
273}
274
275pub use self::GenericMaxSize as MaxSize;
276
277impl<LengthPercentage> MaxSize<LengthPercentage> {
278 #[inline]
280 pub fn none() -> Self {
281 MaxSize::None
282 }
283}
284
285#[derive(
287 Animate,
288 Clone,
289 ComputeSquaredDistance,
290 Copy,
291 Debug,
292 MallocSizeOf,
293 Parse,
294 PartialEq,
295 SpecifiedValueInfo,
296 ToAnimatedValue,
297 ToAnimatedZero,
298 ToComputedValue,
299 ToCss,
300 ToResolvedValue,
301 ToShmem,
302 ToTyped,
303)]
304#[repr(C, u8)]
305pub enum GenericLengthOrNumber<L, N> {
306 Number(N),
311 Length(L),
313}
314
315pub use self::GenericLengthOrNumber as LengthOrNumber;
316
317impl<L, N: Zero> Zero for LengthOrNumber<L, N> {
318 fn zero() -> Self {
319 LengthOrNumber::Number(Zero::zero())
320 }
321
322 fn is_zero(&self) -> bool {
323 match *self {
324 LengthOrNumber::Number(ref n) => n.is_zero(),
325 LengthOrNumber::Length(..) => false,
326 }
327 }
328}
329
330#[derive(
332 Animate,
333 Clone,
334 ComputeSquaredDistance,
335 Copy,
336 Debug,
337 MallocSizeOf,
338 Parse,
339 PartialEq,
340 SpecifiedValueInfo,
341 ToAnimatedValue,
342 ToAnimatedZero,
343 ToComputedValue,
344 ToCss,
345 ToResolvedValue,
346 ToShmem,
347 ToTyped,
348)]
349#[repr(C, u8)]
350#[allow(missing_docs)]
351pub enum GenericLengthPercentageOrNormal<LengthPercent> {
352 LengthPercentage(LengthPercent),
353 Normal,
354}
355
356pub use self::GenericLengthPercentageOrNormal as LengthPercentageOrNormal;
357
358impl<LengthPercent> LengthPercentageOrNormal<LengthPercent> {
359 #[inline]
361 pub fn normal() -> Self {
362 LengthPercentageOrNormal::Normal
363 }
364}
365
366#[derive(
371 Animate,
372 Clone,
373 ComputeSquaredDistance,
374 Debug,
375 MallocSizeOf,
376 PartialEq,
377 SpecifiedValueInfo,
378 ToShmem,
379 ToAnimatedValue,
380 ToAnimatedZero,
381 ToComputedValue,
382 ToResolvedValue,
383 Serialize,
384 Deserialize,
385)]
386#[repr(C)]
387pub struct GenericAnchorSizeFunction<Fallback> {
388 #[animation(constant)]
391 pub target_element: DashedIdent,
392 pub size: AnchorSizeKeyword,
395 pub fallback: Optional<Fallback>,
397}
398
399impl<Fallback> ToCss for GenericAnchorSizeFunction<Fallback>
400where
401 Fallback: ToCss,
402{
403 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> std::fmt::Result
404 where
405 W: Write,
406 {
407 dest.write_str("anchor-size(")?;
408 let mut previous_entry_printed = false;
409 if !self.target_element.is_empty() {
410 previous_entry_printed = true;
411 self.target_element.to_css(dest)?;
412 }
413 if self.size != AnchorSizeKeyword::None {
414 if previous_entry_printed {
415 dest.write_str(" ")?;
416 }
417 previous_entry_printed = true;
418 self.size.to_css(dest)?;
419 }
420 if let Some(f) = self.fallback.as_ref() {
421 if previous_entry_printed {
422 dest.write_str(", ")?;
423 }
424 f.to_css(dest)?;
425 }
426 dest.write_str(")")
427 }
428}
429
430impl<Fallback> Parse for GenericAnchorSizeFunction<Fallback>
431where
432 Fallback: Parse,
433{
434 fn parse<'i, 't>(
435 context: &ParserContext,
436 input: &mut Parser<'i, 't>,
437 ) -> Result<Self, ParseError<'i>> {
438 if !static_prefs::pref!("layout.css.anchor-positioning.enabled") {
439 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
440 }
441 input.expect_function_matching("anchor-size")?;
442 Self::parse_inner(context, input, |i| Fallback::parse(context, i))
443 }
444}
445impl<Fallback> GenericAnchorSizeFunction<Fallback> {
446 pub fn valid_for(&self, position_property: PositionProperty) -> bool {
448 position_property.is_absolutely_positioned()
449 }
450}
451
452pub enum AnchorResolutionResult<'a, LengthPercentage> {
454 Resolved(LengthPercentage),
456 Fallback(&'a LengthPercentage),
458 Invalid,
460}
461
462impl<'a, LengthPercentage> AnchorResolutionResult<'a, LengthPercentage> {
463 pub fn new_anchor_invalid(fallback: Option<&'a LengthPercentage>) -> Self {
465 if let Some(fb) = fallback {
466 return Self::Fallback(fb);
467 }
468 Self::Invalid
469 }
470}
471
472impl<LengthPercentage> GenericAnchorSizeFunction<LengthPercentage> {
473 pub fn parse_inner<'i, 't, F>(
475 context: &ParserContext,
476 input: &mut Parser<'i, 't>,
477 f: F,
478 ) -> Result<Self, ParseError<'i>>
479 where
480 F: FnOnce(&mut Parser<'i, '_>) -> Result<LengthPercentage, ParseError<'i>>,
481 {
482 input.parse_nested_block(|i| {
483 let mut target_element = i
484 .try_parse(|i| DashedIdent::parse(context, i))
485 .unwrap_or(DashedIdent::empty());
486 let size = i
487 .try_parse(AnchorSizeKeyword::parse)
488 .unwrap_or(AnchorSizeKeyword::None);
489 if target_element.is_empty() {
490 target_element = i
491 .try_parse(|i| DashedIdent::parse(context, i))
492 .unwrap_or(DashedIdent::empty());
493 }
494 let previous_parsed = !target_element.is_empty() || size != AnchorSizeKeyword::None;
495 let fallback = i
496 .try_parse(|i| {
497 if previous_parsed {
498 i.expect_comma()?;
499 }
500 f(i)
501 })
502 .ok();
503 Ok(GenericAnchorSizeFunction {
504 target_element,
505 size: size.into(),
506 fallback: fallback.into(),
507 })
508 })
509 }
510}
511
512#[derive(
514 Animate,
515 Clone,
516 ComputeSquaredDistance,
517 Copy,
518 Debug,
519 MallocSizeOf,
520 PartialEq,
521 Parse,
522 SpecifiedValueInfo,
523 ToCss,
524 ToShmem,
525 ToAnimatedValue,
526 ToAnimatedZero,
527 ToComputedValue,
528 ToResolvedValue,
529 Serialize,
530 Deserialize,
531)]
532#[repr(u8)]
533pub enum AnchorSizeKeyword {
534 #[css(skip)]
536 None,
537 Width,
539 Height,
541 Block,
543 Inline,
545 SelfBlock,
547 SelfInline,
549}
550
551#[derive(
554 Animate,
555 Clone,
556 ComputeSquaredDistance,
557 Debug,
558 MallocSizeOf,
559 PartialEq,
560 ToCss,
561 ToShmem,
562 ToAnimatedValue,
563 ToAnimatedZero,
564 ToComputedValue,
565 ToResolvedValue,
566 ToTyped,
567)]
568#[repr(C)]
569pub enum GenericMargin<LP> {
570 LengthPercentage(LP),
572 Auto,
574 AnchorSizeFunction(Box<GenericAnchorSizeFunction<Self>>),
578 AnchorContainingCalcFunction(LP),
581}
582
583#[cfg(feature = "servo")]
584impl<LP> GenericMargin<LP> {
585 #[inline]
587 pub fn is_auto(&self) -> bool {
588 matches!(self, Self::Auto)
589 }
590}
591
592#[cfg(feature = "servo")]
593impl GenericMargin<crate::values::computed::LengthPercentage> {
594 #[inline]
596 pub fn is_definitely_zero(&self) -> bool {
597 match self {
598 Self::LengthPercentage(lp) => lp.is_definitely_zero(),
599 _ => false,
600 }
601 }
602}
603
604impl<LP> SpecifiedValueInfo for GenericMargin<LP>
605where
606 LP: SpecifiedValueInfo,
607{
608 fn collect_completion_keywords(f: style_traits::KeywordsCollectFn) {
609 LP::collect_completion_keywords(f);
610 f(&["auto"]);
611 if static_prefs::pref!("layout.css.anchor-positioning.enabled") {
612 f(&["anchor-size"]);
613 }
614 }
615}
616
617impl<LP> Zero for GenericMargin<LP>
618where
619 LP: Zero,
620{
621 fn is_zero(&self) -> bool {
622 match self {
623 Self::LengthPercentage(l) => l.is_zero(),
624 Self::Auto | Self::AnchorSizeFunction(_) | Self::AnchorContainingCalcFunction(_) => {
625 false
626 },
627 }
628 }
629
630 fn zero() -> Self {
631 Self::LengthPercentage(LP::zero())
632 }
633}