1use super::{AllowQuirks, Number, Percentage, ToComputedValue};
10use crate::computed_value_flags::ComputedValueFlags;
11use crate::derives::*;
12use crate::font_metrics::{FontMetrics, FontMetricsOrientation};
13#[cfg(feature = "gecko")]
14use crate::gecko_bindings::structs::GeckoFontMetrics;
15use crate::parser::{Parse, ParserContext};
16use crate::values::computed::{self, CSSPixelLength, Context, FontSize};
17use crate::values::generics::length as generics;
18use crate::values::generics::length::{
19 GenericAnchorSizeFunction, GenericLengthOrNumber, GenericLengthPercentageOrNormal,
20 GenericMargin, GenericMaxSize, GenericSize,
21};
22use crate::values::generics::NonNegative;
23use crate::values::specified::calc::{self, AllowAnchorPositioningFunctions, CalcNode};
24use crate::values::specified::font::QueryFontMetricsFlags;
25use crate::values::specified::NonNegativeNumber;
26use crate::values::CSSFloat;
27use crate::{Zero, ZeroNoPercent};
28use app_units::AU_PER_PX;
29use cssparser::{match_ignore_ascii_case, Parser, Token};
30use debug_unreachable::debug_unreachable;
31use std::cmp;
32use std::fmt::{self, Write};
33use style_traits::values::specified::AllowedNumericType;
34use style_traits::{
35 CssString, CssWriter, NumericValue, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss,
36 ToTyped, TypedValue,
37};
38
39pub use super::image::Image;
40pub use super::image::{EndingShape as GradientEndingShape, Gradient};
41pub use crate::values::specified::calc::CalcLengthPercentage;
42
43pub const PX_PER_IN: CSSFloat = 96.;
45pub const PX_PER_CM: CSSFloat = PX_PER_IN / 2.54;
47pub const PX_PER_MM: CSSFloat = PX_PER_IN / 25.4;
49pub const PX_PER_Q: CSSFloat = PX_PER_MM / 4.;
51pub const PX_PER_PT: CSSFloat = PX_PER_IN / 72.;
53pub const PX_PER_PC: CSSFloat = PX_PER_PT * 12.;
55
56#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
60#[repr(u8)]
61pub enum FontRelativeLength {
62 #[css(dimension)]
64 Em(CSSFloat),
65 #[css(dimension)]
67 Ex(CSSFloat),
68 #[css(dimension)]
70 Rex(CSSFloat),
71 #[css(dimension)]
73 Ch(CSSFloat),
74 #[css(dimension)]
76 Rch(CSSFloat),
77 #[css(dimension)]
79 Cap(CSSFloat),
80 #[css(dimension)]
82 Rcap(CSSFloat),
83 #[css(dimension)]
85 Ic(CSSFloat),
86 #[css(dimension)]
88 Ric(CSSFloat),
89 #[css(dimension)]
91 Rem(CSSFloat),
92 #[css(dimension)]
94 Lh(CSSFloat),
95 #[css(dimension)]
97 Rlh(CSSFloat),
98}
99
100#[derive(Clone, Copy, Debug, PartialEq)]
102pub enum FontBaseSize {
103 CurrentStyle,
105 InheritedStyle,
107}
108
109#[derive(Clone, Copy, Debug, PartialEq)]
111pub enum LineHeightBase {
112 CurrentStyle,
114 InheritedStyle,
116}
117
118impl FontBaseSize {
119 pub fn resolve(&self, context: &Context) -> computed::FontSize {
121 let style = context.style();
122 match *self {
123 Self::CurrentStyle => style.get_font().clone_font_size(),
124 Self::InheritedStyle => {
125 let zoom = style.effective_zoom_for_inheritance;
128 style.get_parent_font().clone_font_size().zoom(zoom)
129 },
130 }
131 }
132}
133
134impl FontRelativeLength {
135 pub const EM: &'static str = "em";
137 pub const EX: &'static str = "ex";
139 pub const REX: &'static str = "rex";
141 pub const CH: &'static str = "ch";
143 pub const RCH: &'static str = "rch";
145 pub const CAP: &'static str = "cap";
147 pub const RCAP: &'static str = "rcap";
149 pub const IC: &'static str = "ic";
151 pub const RIC: &'static str = "ric";
153 pub const REM: &'static str = "rem";
155 pub const LH: &'static str = "lh";
157 pub const RLH: &'static str = "rlh";
159
160 fn unitless_value(&self) -> CSSFloat {
162 match *self {
163 Self::Em(v)
164 | Self::Ex(v)
165 | Self::Rex(v)
166 | Self::Ch(v)
167 | Self::Rch(v)
168 | Self::Cap(v)
169 | Self::Rcap(v)
170 | Self::Ic(v)
171 | Self::Ric(v)
172 | Self::Rem(v)
173 | Self::Lh(v)
174 | Self::Rlh(v) => v,
175 }
176 }
177
178 fn unit(&self) -> &'static str {
180 match *self {
181 Self::Em(_) => Self::EM,
182 Self::Ex(_) => Self::EX,
183 Self::Rex(_) => Self::REX,
184 Self::Ch(_) => Self::CH,
185 Self::Rch(_) => Self::RCH,
186 Self::Cap(_) => Self::CAP,
187 Self::Rcap(_) => Self::RCAP,
188 Self::Ic(_) => Self::IC,
189 Self::Ric(_) => Self::RIC,
190 Self::Rem(_) => Self::REM,
191 Self::Lh(_) => Self::LH,
192 Self::Rlh(_) => Self::RLH,
193 }
194 }
195
196 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
197 where
198 O: Fn(f32, f32) -> f32,
199 {
200 use self::FontRelativeLength::*;
201
202 if std::mem::discriminant(self) != std::mem::discriminant(other) {
203 return Err(());
204 }
205
206 Ok(match (self, other) {
207 (&Em(one), &Em(other)) => Em(op(one, other)),
208 (&Ex(one), &Ex(other)) => Ex(op(one, other)),
209 (&Rex(one), &Rex(other)) => Rex(op(one, other)),
210 (&Ch(one), &Ch(other)) => Ch(op(one, other)),
211 (&Rch(one), &Rch(other)) => Rch(op(one, other)),
212 (&Cap(one), &Cap(other)) => Cap(op(one, other)),
213 (&Rcap(one), &Rcap(other)) => Rcap(op(one, other)),
214 (&Ic(one), &Ic(other)) => Ic(op(one, other)),
215 (&Ric(one), &Ric(other)) => Ric(op(one, other)),
216 (&Rem(one), &Rem(other)) => Rem(op(one, other)),
217 (&Lh(one), &Lh(other)) => Lh(op(one, other)),
218 (&Rlh(one), &Rlh(other)) => Rlh(op(one, other)),
219 _ => unsafe {
222 match *self {
223 Em(..) | Rem(..) | Ex(..) | Rex(..) | Ch(..) | Rch(..) | Cap(..) | Rcap(..)
224 | Ic(..) | Ric(..) | Lh(..) | Rlh(..) => {},
225 }
226 debug_unreachable!("Forgot to handle unit in try_op()")
227 },
228 })
229 }
230
231 fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
232 match self {
233 Self::Em(x) => Self::Em(op(*x)),
234 Self::Ex(x) => Self::Ex(op(*x)),
235 Self::Rex(x) => Self::Rex(op(*x)),
236 Self::Ch(x) => Self::Ch(op(*x)),
237 Self::Rch(x) => Self::Rch(op(*x)),
238 Self::Cap(x) => Self::Cap(op(*x)),
239 Self::Rcap(x) => Self::Rcap(op(*x)),
240 Self::Ic(x) => Self::Ic(op(*x)),
241 Self::Ric(x) => Self::Ric(op(*x)),
242 Self::Rem(x) => Self::Rem(op(*x)),
243 Self::Lh(x) => Self::Lh(op(*x)),
244 Self::Rlh(x) => Self::Rlh(op(*x)),
245 }
246 }
247
248 pub fn to_computed_value(
250 &self,
251 context: &Context,
252 base_size: FontBaseSize,
253 line_height_base: LineHeightBase,
254 ) -> computed::Length {
255 let (reference_size, length) =
256 self.reference_font_size_and_length(context, base_size, line_height_base);
257 (reference_size * length).finite()
258 }
259
260 #[cfg(feature = "gecko")]
262 pub fn to_computed_pixel_length_with_font_metrics(
263 &self,
264 get_font_metrics: impl Fn() -> GeckoFontMetrics,
265 ) -> Result<CSSFloat, ()> {
266 let metrics = get_font_metrics();
267 Ok(match *self {
268 Self::Em(v) => v * metrics.mComputedEmSize.px(),
269 Self::Ex(v) => v * metrics.mXSize.px(),
270 Self::Ch(v) => v * metrics.mChSize.px(),
271 Self::Cap(v) => v * metrics.mCapHeight.px(),
272 Self::Ic(v) => v * metrics.mIcWidth.px(),
273 Self::Lh(_)
276 | Self::Rlh(_)
277 | Self::Rem(_)
278 | Self::Rex(_)
279 | Self::Rch(_)
280 | Self::Rcap(_)
281 | Self::Ric(_) => return Err(()),
282 })
283 }
284
285 fn reference_font_size_and_length(
293 &self,
294 context: &Context,
295 base_size: FontBaseSize,
296 line_height_base: LineHeightBase,
297 ) -> (computed::Length, CSSFloat) {
298 fn query_font_metrics(
299 context: &Context,
300 base_size: FontBaseSize,
301 orientation: FontMetricsOrientation,
302 flags: QueryFontMetricsFlags,
303 ) -> FontMetrics {
304 context.query_font_metrics(base_size, orientation, flags)
305 }
306
307 fn ex_size(
308 context: &Context,
309 base_size: FontBaseSize,
310 reference_font_size: &FontSize,
311 ) -> computed::Length {
312 let metrics = query_font_metrics(
314 context,
315 base_size,
316 FontMetricsOrientation::Horizontal,
317 QueryFontMetricsFlags::empty(),
318 );
319 metrics.x_height_or_default(reference_font_size.used_size())
320 }
321
322 fn ch_size(
323 context: &Context,
324 base_size: FontBaseSize,
325 reference_font_size: &FontSize,
326 ) -> computed::Length {
327 let metrics = query_font_metrics(
335 context,
336 base_size,
337 FontMetricsOrientation::MatchContextPreferHorizontal,
338 QueryFontMetricsFlags::NEEDS_CH,
339 );
340 metrics.zero_advance_measure_or_default(
341 reference_font_size.used_size(),
342 context.style().writing_mode.is_upright(),
343 )
344 }
345
346 fn cap_size(context: &Context, base_size: FontBaseSize) -> computed::Length {
347 let metrics = query_font_metrics(
348 context,
349 base_size,
350 FontMetricsOrientation::Horizontal,
351 QueryFontMetricsFlags::empty(),
352 );
353 metrics.cap_height_or_default()
354 }
355
356 fn ic_size(
357 context: &Context,
358 base_size: FontBaseSize,
359 reference_font_size: &FontSize,
360 ) -> computed::Length {
361 let metrics = query_font_metrics(
362 context,
363 base_size,
364 FontMetricsOrientation::MatchContextPreferVertical,
365 QueryFontMetricsFlags::NEEDS_IC,
366 );
367 metrics.ic_width_or_default(reference_font_size.used_size())
368 }
369
370 let reference_font_size = base_size.resolve(context);
371 match *self {
372 Self::Em(length) => {
374 if context.for_non_inherited_property && base_size == FontBaseSize::CurrentStyle {
375 context
376 .rule_cache_conditions
377 .borrow_mut()
378 .set_font_size_dependency(reference_font_size.computed_size);
379 }
380
381 (reference_font_size.computed_size(), length)
382 },
383 Self::Lh(length) => {
384 let reference_size = if context.in_media_query {
390 context
391 .device()
392 .calc_line_height(
393 &context.default_style().get_font(),
394 context.style().writing_mode,
395 None,
396 )
397 .0
398 } else {
399 let line_height = context.builder.calc_line_height(
400 context.device(),
401 line_height_base,
402 context.style().writing_mode,
403 );
404 if context.for_non_inherited_property
405 && line_height_base == LineHeightBase::CurrentStyle
406 {
407 context
408 .rule_cache_conditions
409 .borrow_mut()
410 .set_line_height_dependency(line_height)
411 }
412 line_height.0
413 };
414 (reference_size, length)
415 },
416 Self::Ex(length) => (ex_size(context, base_size, &reference_font_size), length),
417 Self::Ch(length) => (ch_size(context, base_size, &reference_font_size), length),
418 Self::Cap(length) => (cap_size(context, base_size), length),
419 Self::Ic(length) => (ic_size(context, base_size, &reference_font_size), length),
420
421 Self::Rex(length) => {
423 let reference_size = if context.builder.is_root_element || context.in_media_query {
424 ex_size(context, base_size, &reference_font_size)
425 } else {
426 context
427 .device()
428 .root_font_metrics_ex()
429 .zoom(context.builder.effective_zoom)
430 };
431 (reference_size, length)
432 },
433 Self::Rch(length) => {
434 let reference_size = if context.builder.is_root_element || context.in_media_query {
435 ch_size(context, base_size, &reference_font_size)
436 } else {
437 context
438 .device()
439 .root_font_metrics_ch()
440 .zoom(context.builder.effective_zoom)
441 };
442 (reference_size, length)
443 },
444 Self::Rcap(length) => {
445 let reference_size = if context.builder.is_root_element || context.in_media_query {
446 cap_size(context, base_size)
447 } else {
448 context
449 .device()
450 .root_font_metrics_cap()
451 .zoom(context.builder.effective_zoom)
452 };
453 (reference_size, length)
454 },
455 Self::Ric(length) => {
456 let reference_size = if context.builder.is_root_element || context.in_media_query {
457 ic_size(context, base_size, &reference_font_size)
458 } else {
459 context
460 .device()
461 .root_font_metrics_ic()
462 .zoom(context.builder.effective_zoom)
463 };
464 (reference_size, length)
465 },
466 Self::Rem(length) => {
467 let reference_size = if context.builder.is_root_element || context.in_media_query {
474 reference_font_size.computed_size()
475 } else {
476 context
477 .device()
478 .root_font_size()
479 .zoom(context.builder.effective_zoom)
480 };
481 (reference_size, length)
482 },
483 Self::Rlh(length) => {
484 let reference_size = if context.builder.is_root_element {
490 context
491 .builder
492 .calc_line_height(
493 context.device(),
494 line_height_base,
495 context.style().writing_mode,
496 )
497 .0
498 } else if context.in_media_query {
499 context
500 .device()
501 .calc_line_height(
502 &context.default_style().get_font(),
503 context.style().writing_mode,
504 None,
505 )
506 .0
507 } else {
508 context.device().root_line_height()
509 };
510 let reference_size = reference_size.zoom(context.builder.effective_zoom);
511 (reference_size, length)
512 },
513 }
514 }
515}
516
517pub enum ViewportVariant {
519 UADefault,
521 Small,
523 Large,
525 Dynamic,
527}
528
529#[derive(PartialEq)]
531enum ViewportUnit {
532 Vw,
534 Vh,
536 Vmin,
538 Vmax,
540 Vb,
542 Vi,
544}
545
546#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
550#[repr(u8)]
551pub enum ViewportPercentageLength {
552 #[css(dimension)]
554 Vw(CSSFloat),
555 #[css(dimension)]
557 Svw(CSSFloat),
558 #[css(dimension)]
560 Lvw(CSSFloat),
561 #[css(dimension)]
563 Dvw(CSSFloat),
564 #[css(dimension)]
566 Vh(CSSFloat),
567 #[css(dimension)]
569 Svh(CSSFloat),
570 #[css(dimension)]
572 Lvh(CSSFloat),
573 #[css(dimension)]
575 Dvh(CSSFloat),
576 #[css(dimension)]
578 Vmin(CSSFloat),
579 #[css(dimension)]
581 Svmin(CSSFloat),
582 #[css(dimension)]
584 Lvmin(CSSFloat),
585 #[css(dimension)]
587 Dvmin(CSSFloat),
588 #[css(dimension)]
590 Vmax(CSSFloat),
591 #[css(dimension)]
593 Svmax(CSSFloat),
594 #[css(dimension)]
596 Lvmax(CSSFloat),
597 #[css(dimension)]
599 Dvmax(CSSFloat),
600 #[css(dimension)]
602 Vb(CSSFloat),
603 #[css(dimension)]
605 Svb(CSSFloat),
606 #[css(dimension)]
608 Lvb(CSSFloat),
609 #[css(dimension)]
611 Dvb(CSSFloat),
612 #[css(dimension)]
614 Vi(CSSFloat),
615 #[css(dimension)]
617 Svi(CSSFloat),
618 #[css(dimension)]
620 Lvi(CSSFloat),
621 #[css(dimension)]
623 Dvi(CSSFloat),
624}
625
626impl ViewportPercentageLength {
627 fn unitless_value(&self) -> CSSFloat {
629 self.unpack().2
630 }
631
632 fn unit(&self) -> &'static str {
634 match *self {
635 Self::Vw(_) => "vw",
636 Self::Lvw(_) => "lvw",
637 Self::Svw(_) => "svw",
638 Self::Dvw(_) => "dvw",
639 Self::Vh(_) => "vh",
640 Self::Svh(_) => "svh",
641 Self::Lvh(_) => "lvh",
642 Self::Dvh(_) => "dvh",
643 Self::Vmin(_) => "vmin",
644 Self::Svmin(_) => "svmin",
645 Self::Lvmin(_) => "lvmin",
646 Self::Dvmin(_) => "dvmin",
647 Self::Vmax(_) => "vmax",
648 Self::Svmax(_) => "svmax",
649 Self::Lvmax(_) => "lvmax",
650 Self::Dvmax(_) => "dvmax",
651 Self::Vb(_) => "vb",
652 Self::Svb(_) => "svb",
653 Self::Lvb(_) => "lvb",
654 Self::Dvb(_) => "dvb",
655 Self::Vi(_) => "vi",
656 Self::Svi(_) => "svi",
657 Self::Lvi(_) => "lvi",
658 Self::Dvi(_) => "dvi",
659 }
660 }
661
662 fn unpack(&self) -> (ViewportVariant, ViewportUnit, CSSFloat) {
663 match *self {
664 Self::Vw(v) => (ViewportVariant::UADefault, ViewportUnit::Vw, v),
665 Self::Svw(v) => (ViewportVariant::Small, ViewportUnit::Vw, v),
666 Self::Lvw(v) => (ViewportVariant::Large, ViewportUnit::Vw, v),
667 Self::Dvw(v) => (ViewportVariant::Dynamic, ViewportUnit::Vw, v),
668 Self::Vh(v) => (ViewportVariant::UADefault, ViewportUnit::Vh, v),
669 Self::Svh(v) => (ViewportVariant::Small, ViewportUnit::Vh, v),
670 Self::Lvh(v) => (ViewportVariant::Large, ViewportUnit::Vh, v),
671 Self::Dvh(v) => (ViewportVariant::Dynamic, ViewportUnit::Vh, v),
672 Self::Vmin(v) => (ViewportVariant::UADefault, ViewportUnit::Vmin, v),
673 Self::Svmin(v) => (ViewportVariant::Small, ViewportUnit::Vmin, v),
674 Self::Lvmin(v) => (ViewportVariant::Large, ViewportUnit::Vmin, v),
675 Self::Dvmin(v) => (ViewportVariant::Dynamic, ViewportUnit::Vmin, v),
676 Self::Vmax(v) => (ViewportVariant::UADefault, ViewportUnit::Vmax, v),
677 Self::Svmax(v) => (ViewportVariant::Small, ViewportUnit::Vmax, v),
678 Self::Lvmax(v) => (ViewportVariant::Large, ViewportUnit::Vmax, v),
679 Self::Dvmax(v) => (ViewportVariant::Dynamic, ViewportUnit::Vmax, v),
680 Self::Vb(v) => (ViewportVariant::UADefault, ViewportUnit::Vb, v),
681 Self::Svb(v) => (ViewportVariant::Small, ViewportUnit::Vb, v),
682 Self::Lvb(v) => (ViewportVariant::Large, ViewportUnit::Vb, v),
683 Self::Dvb(v) => (ViewportVariant::Dynamic, ViewportUnit::Vb, v),
684 Self::Vi(v) => (ViewportVariant::UADefault, ViewportUnit::Vi, v),
685 Self::Svi(v) => (ViewportVariant::Small, ViewportUnit::Vi, v),
686 Self::Lvi(v) => (ViewportVariant::Large, ViewportUnit::Vi, v),
687 Self::Dvi(v) => (ViewportVariant::Dynamic, ViewportUnit::Vi, v),
688 }
689 }
690
691 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
692 where
693 O: Fn(f32, f32) -> f32,
694 {
695 use self::ViewportPercentageLength::*;
696
697 if std::mem::discriminant(self) != std::mem::discriminant(other) {
698 return Err(());
699 }
700
701 Ok(match (self, other) {
702 (&Vw(one), &Vw(other)) => Vw(op(one, other)),
703 (&Svw(one), &Svw(other)) => Svw(op(one, other)),
704 (&Lvw(one), &Lvw(other)) => Lvw(op(one, other)),
705 (&Dvw(one), &Dvw(other)) => Dvw(op(one, other)),
706 (&Vh(one), &Vh(other)) => Vh(op(one, other)),
707 (&Svh(one), &Svh(other)) => Svh(op(one, other)),
708 (&Lvh(one), &Lvh(other)) => Lvh(op(one, other)),
709 (&Dvh(one), &Dvh(other)) => Dvh(op(one, other)),
710 (&Vmin(one), &Vmin(other)) => Vmin(op(one, other)),
711 (&Svmin(one), &Svmin(other)) => Svmin(op(one, other)),
712 (&Lvmin(one), &Lvmin(other)) => Lvmin(op(one, other)),
713 (&Dvmin(one), &Dvmin(other)) => Dvmin(op(one, other)),
714 (&Vmax(one), &Vmax(other)) => Vmax(op(one, other)),
715 (&Svmax(one), &Svmax(other)) => Svmax(op(one, other)),
716 (&Lvmax(one), &Lvmax(other)) => Lvmax(op(one, other)),
717 (&Dvmax(one), &Dvmax(other)) => Dvmax(op(one, other)),
718 (&Vb(one), &Vb(other)) => Vb(op(one, other)),
719 (&Svb(one), &Svb(other)) => Svb(op(one, other)),
720 (&Lvb(one), &Lvb(other)) => Lvb(op(one, other)),
721 (&Dvb(one), &Dvb(other)) => Dvb(op(one, other)),
722 (&Vi(one), &Vi(other)) => Vi(op(one, other)),
723 (&Svi(one), &Svi(other)) => Svi(op(one, other)),
724 (&Lvi(one), &Lvi(other)) => Lvi(op(one, other)),
725 (&Dvi(one), &Dvi(other)) => Dvi(op(one, other)),
726 _ => unsafe {
729 match *self {
730 Vw(..) | Svw(..) | Lvw(..) | Dvw(..) | Vh(..) | Svh(..) | Lvh(..) | Dvh(..)
731 | Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) | Vmax(..) | Svmax(..)
732 | Lvmax(..) | Dvmax(..) | Vb(..) | Svb(..) | Lvb(..) | Dvb(..) | Vi(..)
733 | Svi(..) | Lvi(..) | Dvi(..) => {},
734 }
735 debug_unreachable!("Forgot to handle unit in try_op()")
736 },
737 })
738 }
739
740 fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
741 match self {
742 Self::Vw(x) => Self::Vw(op(*x)),
743 Self::Svw(x) => Self::Svw(op(*x)),
744 Self::Lvw(x) => Self::Lvw(op(*x)),
745 Self::Dvw(x) => Self::Dvw(op(*x)),
746 Self::Vh(x) => Self::Vh(op(*x)),
747 Self::Svh(x) => Self::Svh(op(*x)),
748 Self::Lvh(x) => Self::Lvh(op(*x)),
749 Self::Dvh(x) => Self::Dvh(op(*x)),
750 Self::Vmin(x) => Self::Vmin(op(*x)),
751 Self::Svmin(x) => Self::Svmin(op(*x)),
752 Self::Lvmin(x) => Self::Lvmin(op(*x)),
753 Self::Dvmin(x) => Self::Dvmin(op(*x)),
754 Self::Vmax(x) => Self::Vmax(op(*x)),
755 Self::Svmax(x) => Self::Svmax(op(*x)),
756 Self::Lvmax(x) => Self::Lvmax(op(*x)),
757 Self::Dvmax(x) => Self::Dvmax(op(*x)),
758 Self::Vb(x) => Self::Vb(op(*x)),
759 Self::Svb(x) => Self::Svb(op(*x)),
760 Self::Lvb(x) => Self::Lvb(op(*x)),
761 Self::Dvb(x) => Self::Dvb(op(*x)),
762 Self::Vi(x) => Self::Vi(op(*x)),
763 Self::Svi(x) => Self::Svi(op(*x)),
764 Self::Lvi(x) => Self::Lvi(op(*x)),
765 Self::Dvi(x) => Self::Dvi(op(*x)),
766 }
767 }
768
769 pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
771 let (variant, unit, factor) = self.unpack();
772 let size = context.viewport_size_for_viewport_unit_resolution(variant);
773 let length: app_units::Au = match unit {
774 ViewportUnit::Vw => size.width,
775 ViewportUnit::Vh => size.height,
776 ViewportUnit::Vmin => cmp::min(size.width, size.height),
777 ViewportUnit::Vmax => cmp::max(size.width, size.height),
778 ViewportUnit::Vi | ViewportUnit::Vb => {
779 context
780 .rule_cache_conditions
781 .borrow_mut()
782 .set_writing_mode_dependency(context.builder.writing_mode);
783 if (unit == ViewportUnit::Vb) == context.style().writing_mode.is_vertical() {
784 size.width
785 } else {
786 size.height
787 }
788 },
789 };
790
791 let length = context.builder.effective_zoom.zoom(length.0 as f32);
793
794 let trunc_scaled =
799 ((length as f64 * factor as f64 / 100.).trunc() / AU_PER_PX as f64) as f32;
800 CSSPixelLength::new(crate::values::normalize(trunc_scaled))
801 }
802}
803
804#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
806#[repr(C)]
807pub struct CharacterWidth(pub i32);
808
809impl CharacterWidth {
810 pub fn to_computed_value(&self, reference_font_size: computed::Length) -> computed::Length {
812 let average_advance = reference_font_size * 0.5;
817 let max_advance = reference_font_size;
818 (average_advance * (self.0 as CSSFloat - 1.0) + max_advance).finite()
819 }
820}
821
822#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
824#[repr(u8)]
825pub enum AbsoluteLength {
826 #[css(dimension)]
828 Px(CSSFloat),
829 #[css(dimension)]
831 In(CSSFloat),
832 #[css(dimension)]
834 Cm(CSSFloat),
835 #[css(dimension)]
837 Mm(CSSFloat),
838 #[css(dimension)]
840 Q(CSSFloat),
841 #[css(dimension)]
843 Pt(CSSFloat),
844 #[css(dimension)]
846 Pc(CSSFloat),
847}
848
849impl AbsoluteLength {
850 fn unitless_value(&self) -> CSSFloat {
852 match *self {
853 Self::Px(v)
854 | Self::In(v)
855 | Self::Cm(v)
856 | Self::Mm(v)
857 | Self::Q(v)
858 | Self::Pt(v)
859 | Self::Pc(v) => v,
860 }
861 }
862
863 fn unit(&self) -> &'static str {
865 match *self {
866 Self::Px(_) => "px",
867 Self::In(_) => "in",
868 Self::Cm(_) => "cm",
869 Self::Mm(_) => "mm",
870 Self::Q(_) => "q",
871 Self::Pt(_) => "pt",
872 Self::Pc(_) => "pc",
873 }
874 }
875
876 #[inline]
878 pub fn to_px(&self) -> CSSFloat {
879 match *self {
880 Self::Px(value) => value,
881 Self::In(value) => value * PX_PER_IN,
882 Self::Cm(value) => value * PX_PER_CM,
883 Self::Mm(value) => value * PX_PER_MM,
884 Self::Q(value) => value * PX_PER_Q,
885 Self::Pt(value) => value * PX_PER_PT,
886 Self::Pc(value) => value * PX_PER_PC,
887 }
888 }
889
890 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
891 where
892 O: Fn(f32, f32) -> f32,
893 {
894 Ok(Self::Px(op(self.to_px(), other.to_px())))
895 }
896
897 fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
898 Self::Px(op(self.to_px()))
899 }
900}
901
902impl ToComputedValue for AbsoluteLength {
903 type ComputedValue = CSSPixelLength;
904
905 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
906 CSSPixelLength::new(self.to_px())
907 .zoom(context.builder.effective_zoom)
908 .finite()
909 }
910
911 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
912 Self::Px(computed.px())
913 }
914}
915
916impl PartialOrd for AbsoluteLength {
917 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
918 self.to_px().partial_cmp(&other.to_px())
919 }
920}
921
922#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
926#[repr(u8)]
927pub enum ContainerRelativeLength {
928 #[css(dimension)]
930 Cqw(CSSFloat),
931 #[css(dimension)]
933 Cqh(CSSFloat),
934 #[css(dimension)]
936 Cqi(CSSFloat),
937 #[css(dimension)]
939 Cqb(CSSFloat),
940 #[css(dimension)]
942 Cqmin(CSSFloat),
943 #[css(dimension)]
945 Cqmax(CSSFloat),
946}
947
948impl ContainerRelativeLength {
949 fn unitless_value(&self) -> CSSFloat {
950 match *self {
951 Self::Cqw(v)
952 | Self::Cqh(v)
953 | Self::Cqi(v)
954 | Self::Cqb(v)
955 | Self::Cqmin(v)
956 | Self::Cqmax(v) => v,
957 }
958 }
959
960 fn unit(&self) -> &'static str {
962 match *self {
963 Self::Cqw(_) => "cqw",
964 Self::Cqh(_) => "cqh",
965 Self::Cqi(_) => "cqi",
966 Self::Cqb(_) => "cqb",
967 Self::Cqmin(_) => "cqmin",
968 Self::Cqmax(_) => "cqmax",
969 }
970 }
971
972 pub(crate) fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
973 where
974 O: Fn(f32, f32) -> f32,
975 {
976 use self::ContainerRelativeLength::*;
977
978 if std::mem::discriminant(self) != std::mem::discriminant(other) {
979 return Err(());
980 }
981
982 Ok(match (self, other) {
983 (&Cqw(one), &Cqw(other)) => Cqw(op(one, other)),
984 (&Cqh(one), &Cqh(other)) => Cqh(op(one, other)),
985 (&Cqi(one), &Cqi(other)) => Cqi(op(one, other)),
986 (&Cqb(one), &Cqb(other)) => Cqb(op(one, other)),
987 (&Cqmin(one), &Cqmin(other)) => Cqmin(op(one, other)),
988 (&Cqmax(one), &Cqmax(other)) => Cqmax(op(one, other)),
989
990 _ => unsafe {
994 match *self {
995 Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {},
996 }
997 debug_unreachable!("Forgot to handle unit in try_op()")
998 },
999 })
1000 }
1001
1002 pub(crate) fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
1003 match self {
1004 Self::Cqw(x) => Self::Cqw(op(*x)),
1005 Self::Cqh(x) => Self::Cqh(op(*x)),
1006 Self::Cqi(x) => Self::Cqi(op(*x)),
1007 Self::Cqb(x) => Self::Cqb(op(*x)),
1008 Self::Cqmin(x) => Self::Cqmin(op(*x)),
1009 Self::Cqmax(x) => Self::Cqmax(op(*x)),
1010 }
1011 }
1012
1013 pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
1015 if context.for_non_inherited_property {
1016 context.rule_cache_conditions.borrow_mut().set_uncacheable();
1017 }
1018 context
1019 .builder
1020 .add_flags(ComputedValueFlags::USES_CONTAINER_UNITS);
1021
1022 let size = context.get_container_size_query();
1026 let (factor, container_length) = match *self {
1027 Self::Cqw(v) => (v, size.get_container_width(context)),
1028 Self::Cqh(v) => (v, size.get_container_height(context)),
1029 Self::Cqi(v) => (v, size.get_container_inline_size(context)),
1030 Self::Cqb(v) => (v, size.get_container_block_size(context)),
1031 Self::Cqmin(v) => (
1032 v,
1033 cmp::min(
1034 size.get_container_inline_size(context),
1035 size.get_container_block_size(context),
1036 ),
1037 ),
1038 Self::Cqmax(v) => (
1039 v,
1040 cmp::max(
1041 size.get_container_inline_size(context),
1042 size.get_container_block_size(context),
1043 ),
1044 ),
1045 };
1046 CSSPixelLength::new((container_length.to_f64_px() * factor as f64 / 100.0) as f32).finite()
1047 }
1048}
1049
1050#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)]
1054#[repr(u8)]
1055pub enum NoCalcLength {
1056 Absolute(AbsoluteLength),
1060
1061 FontRelative(FontRelativeLength),
1065
1066 ViewportPercentage(ViewportPercentageLength),
1070
1071 ContainerRelative(ContainerRelativeLength),
1075 ServoCharacterWidth(CharacterWidth),
1080}
1081
1082impl NoCalcLength {
1083 pub fn unitless_value(&self) -> CSSFloat {
1085 match *self {
1086 Self::Absolute(v) => v.unitless_value(),
1087 Self::FontRelative(v) => v.unitless_value(),
1088 Self::ViewportPercentage(v) => v.unitless_value(),
1089 Self::ContainerRelative(v) => v.unitless_value(),
1090 Self::ServoCharacterWidth(c) => c.0 as f32,
1091 }
1092 }
1093
1094 fn unit(&self) -> &'static str {
1096 match *self {
1097 Self::Absolute(v) => v.unit(),
1098 Self::FontRelative(v) => v.unit(),
1099 Self::ViewportPercentage(v) => v.unit(),
1100 Self::ContainerRelative(v) => v.unit(),
1101 Self::ServoCharacterWidth(_) => "",
1102 }
1103 }
1104
1105 pub fn is_negative(&self) -> bool {
1107 self.unitless_value().is_sign_negative()
1108 }
1109
1110 pub fn is_zero(&self) -> bool {
1112 self.unitless_value() == 0.0
1113 }
1114
1115 pub fn is_infinite(&self) -> bool {
1117 self.unitless_value().is_infinite()
1118 }
1119
1120 pub fn is_nan(&self) -> bool {
1122 self.unitless_value().is_nan()
1123 }
1124
1125 pub fn should_zoom_text(&self) -> bool {
1130 match *self {
1131 Self::Absolute(..) | Self::ViewportPercentage(..) | Self::ContainerRelative(..) => true,
1132 Self::ServoCharacterWidth(..) | Self::FontRelative(..) => false,
1133 }
1134 }
1135
1136 pub fn parse_dimension(
1138 context: &ParserContext,
1139 value: CSSFloat,
1140 unit: &str,
1141 ) -> Result<Self, ()> {
1142 Ok(match_ignore_ascii_case! { unit,
1143 "px" => Self::Absolute(AbsoluteLength::Px(value)),
1144 "in" => Self::Absolute(AbsoluteLength::In(value)),
1145 "cm" => Self::Absolute(AbsoluteLength::Cm(value)),
1146 "mm" => Self::Absolute(AbsoluteLength::Mm(value)),
1147 "q" => Self::Absolute(AbsoluteLength::Q(value)),
1148 "pt" => Self::Absolute(AbsoluteLength::Pt(value)),
1149 "pc" => Self::Absolute(AbsoluteLength::Pc(value)),
1150 "em" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Em(value)),
1152 "ex" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ex(value)),
1153 "rex" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rex(value)),
1154 "ch" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ch(value)),
1155 "rch" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rch(value)),
1156 "cap" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Cap(value)),
1157 "rcap" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rcap(value)),
1158 "ic" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ic(value)),
1159 "ric" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ric(value)),
1160 "rem" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rem(value)),
1161 "lh" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Lh(value)),
1162 "rlh" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rlh(value)),
1163 "vw" if !context.in_page_rule() => {
1165 Self::ViewportPercentage(ViewportPercentageLength::Vw(value))
1166 },
1167 "svw" if !context.in_page_rule() => {
1168 Self::ViewportPercentage(ViewportPercentageLength::Svw(value))
1169 },
1170 "lvw" if !context.in_page_rule() => {
1171 Self::ViewportPercentage(ViewportPercentageLength::Lvw(value))
1172 },
1173 "dvw" if !context.in_page_rule() => {
1174 Self::ViewportPercentage(ViewportPercentageLength::Dvw(value))
1175 },
1176 "vh" if !context.in_page_rule() => {
1177 Self::ViewportPercentage(ViewportPercentageLength::Vh(value))
1178 },
1179 "svh" if !context.in_page_rule() => {
1180 Self::ViewportPercentage(ViewportPercentageLength::Svh(value))
1181 },
1182 "lvh" if !context.in_page_rule() => {
1183 Self::ViewportPercentage(ViewportPercentageLength::Lvh(value))
1184 },
1185 "dvh" if !context.in_page_rule() => {
1186 Self::ViewportPercentage(ViewportPercentageLength::Dvh(value))
1187 },
1188 "vmin" if !context.in_page_rule() => {
1189 Self::ViewportPercentage(ViewportPercentageLength::Vmin(value))
1190 },
1191 "svmin" if !context.in_page_rule() => {
1192 Self::ViewportPercentage(ViewportPercentageLength::Svmin(value))
1193 },
1194 "lvmin" if !context.in_page_rule() => {
1195 Self::ViewportPercentage(ViewportPercentageLength::Lvmin(value))
1196 },
1197 "dvmin" if !context.in_page_rule() => {
1198 Self::ViewportPercentage(ViewportPercentageLength::Dvmin(value))
1199 },
1200 "vmax" if !context.in_page_rule() => {
1201 Self::ViewportPercentage(ViewportPercentageLength::Vmax(value))
1202 },
1203 "svmax" if !context.in_page_rule() => {
1204 Self::ViewportPercentage(ViewportPercentageLength::Svmax(value))
1205 },
1206 "lvmax" if !context.in_page_rule() => {
1207 Self::ViewportPercentage(ViewportPercentageLength::Lvmax(value))
1208 },
1209 "dvmax" if !context.in_page_rule() => {
1210 Self::ViewportPercentage(ViewportPercentageLength::Dvmax(value))
1211 },
1212 "vb" if !context.in_page_rule() => {
1213 Self::ViewportPercentage(ViewportPercentageLength::Vb(value))
1214 },
1215 "svb" if !context.in_page_rule() => {
1216 Self::ViewportPercentage(ViewportPercentageLength::Svb(value))
1217 },
1218 "lvb" if !context.in_page_rule() => {
1219 Self::ViewportPercentage(ViewportPercentageLength::Lvb(value))
1220 },
1221 "dvb" if !context.in_page_rule() => {
1222 Self::ViewportPercentage(ViewportPercentageLength::Dvb(value))
1223 },
1224 "vi" if !context.in_page_rule() => {
1225 Self::ViewportPercentage(ViewportPercentageLength::Vi(value))
1226 },
1227 "svi" if !context.in_page_rule() => {
1228 Self::ViewportPercentage(ViewportPercentageLength::Svi(value))
1229 },
1230 "lvi" if !context.in_page_rule() => {
1231 Self::ViewportPercentage(ViewportPercentageLength::Lvi(value))
1232 },
1233 "dvi" if !context.in_page_rule() => {
1234 Self::ViewportPercentage(ViewportPercentageLength::Dvi(value))
1235 },
1236 "cqw" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1239 Self::ContainerRelative(ContainerRelativeLength::Cqw(value))
1240 },
1241 "cqh" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1242 Self::ContainerRelative(ContainerRelativeLength::Cqh(value))
1243 },
1244 "cqi" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1245 Self::ContainerRelative(ContainerRelativeLength::Cqi(value))
1246 },
1247 "cqb" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1248 Self::ContainerRelative(ContainerRelativeLength::Cqb(value))
1249 },
1250 "cqmin" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1251 Self::ContainerRelative(ContainerRelativeLength::Cqmin(value))
1252 },
1253 "cqmax" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1254 Self::ContainerRelative(ContainerRelativeLength::Cqmax(value))
1255 },
1256 _ => return Err(()),
1257 })
1258 }
1259
1260 pub(crate) fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
1261 where
1262 O: Fn(f32, f32) -> f32,
1263 {
1264 use self::NoCalcLength::*;
1265
1266 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1267 return Err(());
1268 }
1269
1270 Ok(match (self, other) {
1271 (&Absolute(ref one), &Absolute(ref other)) => Absolute(one.try_op(other, op)?),
1272 (&FontRelative(ref one), &FontRelative(ref other)) => {
1273 FontRelative(one.try_op(other, op)?)
1274 },
1275 (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => {
1276 ViewportPercentage(one.try_op(other, op)?)
1277 },
1278 (&ContainerRelative(ref one), &ContainerRelative(ref other)) => {
1279 ContainerRelative(one.try_op(other, op)?)
1280 },
1281 (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => {
1282 ServoCharacterWidth(CharacterWidth(op(one.0 as f32, other.0 as f32) as i32))
1283 },
1284 _ => unsafe {
1287 match *self {
1288 Absolute(..)
1289 | FontRelative(..)
1290 | ViewportPercentage(..)
1291 | ContainerRelative(..)
1292 | ServoCharacterWidth(..) => {},
1293 }
1294 debug_unreachable!("Forgot to handle unit in try_op()")
1295 },
1296 })
1297 }
1298
1299 pub(crate) fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
1300 use self::NoCalcLength::*;
1301
1302 match self {
1303 Absolute(ref one) => Absolute(one.map(op)),
1304 FontRelative(ref one) => FontRelative(one.map(op)),
1305 ViewportPercentage(ref one) => ViewportPercentage(one.map(op)),
1306 ContainerRelative(ref one) => ContainerRelative(one.map(op)),
1307 ServoCharacterWidth(ref one) => {
1308 ServoCharacterWidth(CharacterWidth(op(one.0 as f32) as i32))
1309 },
1310 }
1311 }
1312
1313 #[inline]
1315 pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
1316 match *self {
1317 Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
1318 _ => Err(()),
1319 }
1320 }
1321
1322 #[cfg(feature = "gecko")]
1325 #[inline]
1326 pub fn to_computed_pixel_length_with_font_metrics(
1327 &self,
1328 get_font_metrics: Option<impl Fn() -> GeckoFontMetrics>,
1329 ) -> Result<CSSFloat, ()> {
1330 match *self {
1331 Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
1332 Self::FontRelative(fr) => {
1333 if let Some(getter) = get_font_metrics {
1334 fr.to_computed_pixel_length_with_font_metrics(getter)
1335 } else {
1336 Err(())
1337 }
1338 },
1339 _ => Err(()),
1340 }
1341 }
1342
1343 #[inline]
1345 pub fn from_px(px_value: CSSFloat) -> NoCalcLength {
1346 NoCalcLength::Absolute(AbsoluteLength::Px(px_value))
1347 }
1348}
1349
1350impl ToCss for NoCalcLength {
1351 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1352 where
1353 W: Write,
1354 {
1355 crate::values::serialize_specified_dimension(
1356 self.unitless_value(),
1357 self.unit(),
1358 false,
1359 dest,
1360 )
1361 }
1362}
1363
1364impl ToTyped for NoCalcLength {
1365 fn to_typed(&self) -> Option<TypedValue> {
1366 let value = self.unitless_value();
1367 let unit = CssString::from(self.unit());
1368 Some(TypedValue::Numeric(NumericValue::Unit { value, unit }))
1369 }
1370}
1371
1372impl SpecifiedValueInfo for NoCalcLength {}
1373
1374impl PartialOrd for NoCalcLength {
1375 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1376 use self::NoCalcLength::*;
1377
1378 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1379 return None;
1380 }
1381
1382 match (self, other) {
1383 (&Absolute(ref one), &Absolute(ref other)) => one.to_px().partial_cmp(&other.to_px()),
1384 (&FontRelative(ref one), &FontRelative(ref other)) => one.partial_cmp(other),
1385 (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => {
1386 one.partial_cmp(other)
1387 },
1388 (&ContainerRelative(ref one), &ContainerRelative(ref other)) => one.partial_cmp(other),
1389 (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => {
1390 one.0.partial_cmp(&other.0)
1391 },
1392 _ => unsafe {
1395 match *self {
1396 Absolute(..)
1397 | FontRelative(..)
1398 | ViewportPercentage(..)
1399 | ContainerRelative(..)
1400 | ServoCharacterWidth(..) => {},
1401 }
1402 debug_unreachable!("Forgot an arm in partial_cmp?")
1403 },
1404 }
1405 }
1406}
1407
1408impl Zero for NoCalcLength {
1409 fn zero() -> Self {
1410 NoCalcLength::Absolute(AbsoluteLength::Px(0.))
1411 }
1412
1413 fn is_zero(&self) -> bool {
1414 NoCalcLength::is_zero(self)
1415 }
1416}
1417
1418#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, ToTyped)]
1423#[typed_value(derive_fields)]
1424pub enum Length {
1425 NoCalc(NoCalcLength),
1427 Calc(Box<CalcLengthPercentage>),
1431}
1432
1433impl From<NoCalcLength> for Length {
1434 #[inline]
1435 fn from(len: NoCalcLength) -> Self {
1436 Length::NoCalc(len)
1437 }
1438}
1439
1440impl PartialOrd for FontRelativeLength {
1441 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1442 use self::FontRelativeLength::*;
1443
1444 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1445 return None;
1446 }
1447
1448 match (self, other) {
1449 (&Em(ref one), &Em(ref other)) => one.partial_cmp(other),
1450 (&Ex(ref one), &Ex(ref other)) => one.partial_cmp(other),
1451 (&Rex(ref one), &Rex(ref other)) => one.partial_cmp(other),
1452 (&Ch(ref one), &Ch(ref other)) => one.partial_cmp(other),
1453 (&Rch(ref one), &Rch(ref other)) => one.partial_cmp(other),
1454 (&Cap(ref one), &Cap(ref other)) => one.partial_cmp(other),
1455 (&Rcap(ref one), &Rcap(ref other)) => one.partial_cmp(other),
1456 (&Ic(ref one), &Ic(ref other)) => one.partial_cmp(other),
1457 (&Ric(ref one), &Ric(ref other)) => one.partial_cmp(other),
1458 (&Rem(ref one), &Rem(ref other)) => one.partial_cmp(other),
1459 (&Lh(ref one), &Lh(ref other)) => one.partial_cmp(other),
1460 (&Rlh(ref one), &Rlh(ref other)) => one.partial_cmp(other),
1461 _ => unsafe {
1464 match *self {
1465 Em(..) | Ex(..) | Rex(..) | Ch(..) | Rch(..) | Cap(..) | Rcap(..) | Ic(..)
1466 | Ric(..) | Rem(..) | Lh(..) | Rlh(..) => {},
1467 }
1468 debug_unreachable!("Forgot an arm in partial_cmp?")
1469 },
1470 }
1471 }
1472}
1473
1474impl PartialOrd for ContainerRelativeLength {
1475 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1476 use self::ContainerRelativeLength::*;
1477
1478 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1479 return None;
1480 }
1481
1482 match (self, other) {
1483 (&Cqw(ref one), &Cqw(ref other)) => one.partial_cmp(other),
1484 (&Cqh(ref one), &Cqh(ref other)) => one.partial_cmp(other),
1485 (&Cqi(ref one), &Cqi(ref other)) => one.partial_cmp(other),
1486 (&Cqb(ref one), &Cqb(ref other)) => one.partial_cmp(other),
1487 (&Cqmin(ref one), &Cqmin(ref other)) => one.partial_cmp(other),
1488 (&Cqmax(ref one), &Cqmax(ref other)) => one.partial_cmp(other),
1489
1490 _ => unsafe {
1494 match *self {
1495 Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {},
1496 }
1497 debug_unreachable!("Forgot to handle unit in partial_cmp()")
1498 },
1499 }
1500 }
1501}
1502
1503impl PartialOrd for ViewportPercentageLength {
1504 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1505 use self::ViewportPercentageLength::*;
1506
1507 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1508 return None;
1509 }
1510
1511 match (self, other) {
1512 (&Vw(ref one), &Vw(ref other)) => one.partial_cmp(other),
1513 (&Svw(ref one), &Svw(ref other)) => one.partial_cmp(other),
1514 (&Lvw(ref one), &Lvw(ref other)) => one.partial_cmp(other),
1515 (&Dvw(ref one), &Dvw(ref other)) => one.partial_cmp(other),
1516 (&Vh(ref one), &Vh(ref other)) => one.partial_cmp(other),
1517 (&Svh(ref one), &Svh(ref other)) => one.partial_cmp(other),
1518 (&Lvh(ref one), &Lvh(ref other)) => one.partial_cmp(other),
1519 (&Dvh(ref one), &Dvh(ref other)) => one.partial_cmp(other),
1520 (&Vmin(ref one), &Vmin(ref other)) => one.partial_cmp(other),
1521 (&Svmin(ref one), &Svmin(ref other)) => one.partial_cmp(other),
1522 (&Lvmin(ref one), &Lvmin(ref other)) => one.partial_cmp(other),
1523 (&Dvmin(ref one), &Dvmin(ref other)) => one.partial_cmp(other),
1524 (&Vmax(ref one), &Vmax(ref other)) => one.partial_cmp(other),
1525 (&Svmax(ref one), &Svmax(ref other)) => one.partial_cmp(other),
1526 (&Lvmax(ref one), &Lvmax(ref other)) => one.partial_cmp(other),
1527 (&Dvmax(ref one), &Dvmax(ref other)) => one.partial_cmp(other),
1528 (&Vb(ref one), &Vb(ref other)) => one.partial_cmp(other),
1529 (&Svb(ref one), &Svb(ref other)) => one.partial_cmp(other),
1530 (&Lvb(ref one), &Lvb(ref other)) => one.partial_cmp(other),
1531 (&Dvb(ref one), &Dvb(ref other)) => one.partial_cmp(other),
1532 (&Vi(ref one), &Vi(ref other)) => one.partial_cmp(other),
1533 (&Svi(ref one), &Svi(ref other)) => one.partial_cmp(other),
1534 (&Lvi(ref one), &Lvi(ref other)) => one.partial_cmp(other),
1535 (&Dvi(ref one), &Dvi(ref other)) => one.partial_cmp(other),
1536 _ => unsafe {
1539 match *self {
1540 Vw(..) | Svw(..) | Lvw(..) | Dvw(..) | Vh(..) | Svh(..) | Lvh(..) | Dvh(..)
1541 | Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) | Vmax(..) | Svmax(..)
1542 | Lvmax(..) | Dvmax(..) | Vb(..) | Svb(..) | Lvb(..) | Dvb(..) | Vi(..)
1543 | Svi(..) | Lvi(..) | Dvi(..) => {},
1544 }
1545 debug_unreachable!("Forgot an arm in partial_cmp?")
1546 },
1547 }
1548 }
1549}
1550
1551impl Length {
1552 #[inline]
1553 fn parse_internal<'i, 't>(
1554 context: &ParserContext,
1555 input: &mut Parser<'i, 't>,
1556 num_context: AllowedNumericType,
1557 allow_quirks: AllowQuirks,
1558 ) -> Result<Self, ParseError<'i>> {
1559 let location = input.current_source_location();
1560 let token = input.next()?;
1561 match *token {
1562 Token::Dimension {
1563 value, ref unit, ..
1564 } if num_context.is_ok(context.parsing_mode, value) => {
1565 NoCalcLength::parse_dimension(context, value, unit)
1566 .map(Length::NoCalc)
1567 .map_err(|()| location.new_unexpected_token_error(token.clone()))
1568 },
1569 Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
1570 if value != 0.
1571 && !context.parsing_mode.allows_unitless_lengths()
1572 && !allow_quirks.allowed(context.quirks_mode)
1573 {
1574 return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
1575 }
1576 Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(
1577 value,
1578 ))))
1579 },
1580 Token::Function(ref name) => {
1581 let function = CalcNode::math_function(context, name, location)?;
1582 let calc = CalcNode::parse_length(context, input, num_context, function)?;
1583 Ok(Length::Calc(Box::new(calc)))
1584 },
1585 ref token => return Err(location.new_unexpected_token_error(token.clone())),
1586 }
1587 }
1588
1589 #[inline]
1591 pub fn parse_non_negative<'i, 't>(
1592 context: &ParserContext,
1593 input: &mut Parser<'i, 't>,
1594 ) -> Result<Self, ParseError<'i>> {
1595 Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
1596 }
1597
1598 #[inline]
1600 pub fn parse_non_negative_quirky<'i, 't>(
1601 context: &ParserContext,
1602 input: &mut Parser<'i, 't>,
1603 allow_quirks: AllowQuirks,
1604 ) -> Result<Self, ParseError<'i>> {
1605 Self::parse_internal(
1606 context,
1607 input,
1608 AllowedNumericType::NonNegative,
1609 allow_quirks,
1610 )
1611 }
1612
1613 #[inline]
1615 pub fn from_px(px_value: CSSFloat) -> Length {
1616 Length::NoCalc(NoCalcLength::from_px(px_value))
1617 }
1618
1619 pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
1621 match *self {
1622 Self::NoCalc(ref l) => l.to_computed_pixel_length_without_context(),
1623 Self::Calc(ref l) => l.to_computed_pixel_length_without_context(),
1624 }
1625 }
1626
1627 #[cfg(feature = "gecko")]
1629 pub fn to_computed_pixel_length_with_font_metrics(
1630 &self,
1631 get_font_metrics: Option<impl Fn() -> GeckoFontMetrics>,
1632 ) -> Result<CSSFloat, ()> {
1633 match *self {
1634 Self::NoCalc(ref l) => l.to_computed_pixel_length_with_font_metrics(get_font_metrics),
1635 Self::Calc(ref l) => l.to_computed_pixel_length_with_font_metrics(get_font_metrics),
1636 }
1637 }
1638}
1639
1640impl Parse for Length {
1641 fn parse<'i, 't>(
1642 context: &ParserContext,
1643 input: &mut Parser<'i, 't>,
1644 ) -> Result<Self, ParseError<'i>> {
1645 Self::parse_quirky(context, input, AllowQuirks::No)
1646 }
1647}
1648
1649impl Zero for Length {
1650 fn zero() -> Self {
1651 Length::NoCalc(NoCalcLength::zero())
1652 }
1653
1654 fn is_zero(&self) -> bool {
1655 match *self {
1658 Length::NoCalc(ref l) => l.is_zero(),
1659 Length::Calc(..) => false,
1660 }
1661 }
1662}
1663
1664impl Length {
1665 pub fn parse_quirky<'i, 't>(
1667 context: &ParserContext,
1668 input: &mut Parser<'i, 't>,
1669 allow_quirks: AllowQuirks,
1670 ) -> Result<Self, ParseError<'i>> {
1671 Self::parse_internal(context, input, AllowedNumericType::All, allow_quirks)
1672 }
1673}
1674
1675pub type NonNegativeLength = NonNegative<Length>;
1677
1678impl Parse for NonNegativeLength {
1679 #[inline]
1680 fn parse<'i, 't>(
1681 context: &ParserContext,
1682 input: &mut Parser<'i, 't>,
1683 ) -> Result<Self, ParseError<'i>> {
1684 Ok(NonNegative(Length::parse_non_negative(context, input)?))
1685 }
1686}
1687
1688impl From<NoCalcLength> for NonNegativeLength {
1689 #[inline]
1690 fn from(len: NoCalcLength) -> Self {
1691 NonNegative(Length::NoCalc(len))
1692 }
1693}
1694
1695impl From<Length> for NonNegativeLength {
1696 #[inline]
1697 fn from(len: Length) -> Self {
1698 NonNegative(len)
1699 }
1700}
1701
1702impl NonNegativeLength {
1703 #[inline]
1705 pub fn from_px(px_value: CSSFloat) -> Self {
1706 Length::from_px(px_value.max(0.)).into()
1707 }
1708
1709 #[inline]
1711 pub fn parse_quirky<'i, 't>(
1712 context: &ParserContext,
1713 input: &mut Parser<'i, 't>,
1714 allow_quirks: AllowQuirks,
1715 ) -> Result<Self, ParseError<'i>> {
1716 Ok(NonNegative(Length::parse_non_negative_quirky(
1717 context,
1718 input,
1719 allow_quirks,
1720 )?))
1721 }
1722}
1723
1724#[allow(missing_docs)]
1729#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, ToTyped)]
1730pub enum LengthPercentage {
1731 Length(NoCalcLength),
1732 Percentage(computed::Percentage),
1733 Calc(Box<CalcLengthPercentage>),
1734}
1735
1736impl From<Length> for LengthPercentage {
1737 fn from(len: Length) -> LengthPercentage {
1738 match len {
1739 Length::NoCalc(l) => LengthPercentage::Length(l),
1740 Length::Calc(l) => LengthPercentage::Calc(l),
1741 }
1742 }
1743}
1744
1745impl From<NoCalcLength> for LengthPercentage {
1746 #[inline]
1747 fn from(len: NoCalcLength) -> Self {
1748 LengthPercentage::Length(len)
1749 }
1750}
1751
1752impl From<Percentage> for LengthPercentage {
1753 #[inline]
1754 fn from(pc: Percentage) -> Self {
1755 if let Some(clamping_mode) = pc.calc_clamping_mode() {
1756 LengthPercentage::Calc(Box::new(CalcLengthPercentage {
1757 clamping_mode,
1758 node: CalcNode::Leaf(calc::Leaf::Percentage(pc.get())),
1759 }))
1760 } else {
1761 LengthPercentage::Percentage(computed::Percentage(pc.get()))
1762 }
1763 }
1764}
1765
1766impl From<computed::Percentage> for LengthPercentage {
1767 #[inline]
1768 fn from(pc: computed::Percentage) -> Self {
1769 LengthPercentage::Percentage(pc)
1770 }
1771}
1772
1773impl Parse for LengthPercentage {
1774 #[inline]
1775 fn parse<'i, 't>(
1776 context: &ParserContext,
1777 input: &mut Parser<'i, 't>,
1778 ) -> Result<Self, ParseError<'i>> {
1779 Self::parse_quirky(context, input, AllowQuirks::No)
1780 }
1781}
1782
1783impl LengthPercentage {
1784 #[inline]
1785 pub fn zero_percent() -> LengthPercentage {
1787 LengthPercentage::Percentage(computed::Percentage::zero())
1788 }
1789
1790 #[inline]
1791 pub fn hundred_percent() -> LengthPercentage {
1793 LengthPercentage::Percentage(computed::Percentage::hundred())
1794 }
1795
1796 fn parse_internal<'i, 't>(
1797 context: &ParserContext,
1798 input: &mut Parser<'i, 't>,
1799 num_context: AllowedNumericType,
1800 allow_quirks: AllowQuirks,
1801 allow_anchor: AllowAnchorPositioningFunctions,
1802 ) -> Result<Self, ParseError<'i>> {
1803 let location = input.current_source_location();
1804 let token = input.next()?;
1805 match *token {
1806 Token::Dimension {
1807 value, ref unit, ..
1808 } if num_context.is_ok(context.parsing_mode, value) => {
1809 return NoCalcLength::parse_dimension(context, value, unit)
1810 .map(LengthPercentage::Length)
1811 .map_err(|()| location.new_unexpected_token_error(token.clone()));
1812 },
1813 Token::Percentage { unit_value, .. }
1814 if num_context.is_ok(context.parsing_mode, unit_value) =>
1815 {
1816 return Ok(LengthPercentage::Percentage(computed::Percentage(
1817 unit_value,
1818 )));
1819 },
1820 Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
1821 if value != 0.
1822 && !context.parsing_mode.allows_unitless_lengths()
1823 && !allow_quirks.allowed(context.quirks_mode)
1824 {
1825 return Err(location.new_unexpected_token_error(token.clone()));
1826 } else {
1827 return Ok(LengthPercentage::Length(NoCalcLength::from_px(value)));
1828 }
1829 },
1830 Token::Function(ref name) => {
1831 let function = CalcNode::math_function(context, name, location)?;
1832 let calc = CalcNode::parse_length_or_percentage(
1833 context,
1834 input,
1835 num_context,
1836 function,
1837 allow_anchor,
1838 )?;
1839 Ok(LengthPercentage::Calc(Box::new(calc)))
1840 },
1841 _ => return Err(location.new_unexpected_token_error(token.clone())),
1842 }
1843 }
1844
1845 #[inline]
1848 pub fn parse_quirky<'i, 't>(
1849 context: &ParserContext,
1850 input: &mut Parser<'i, 't>,
1851 allow_quirks: AllowQuirks,
1852 ) -> Result<Self, ParseError<'i>> {
1853 Self::parse_internal(
1854 context,
1855 input,
1856 AllowedNumericType::All,
1857 allow_quirks,
1858 AllowAnchorPositioningFunctions::No,
1859 )
1860 }
1861
1862 #[inline]
1865 fn parse_quirky_with_anchor_size_function<'i, 't>(
1866 context: &ParserContext,
1867 input: &mut Parser<'i, 't>,
1868 allow_quirks: AllowQuirks,
1869 ) -> Result<Self, ParseError<'i>> {
1870 Self::parse_internal(
1871 context,
1872 input,
1873 AllowedNumericType::All,
1874 allow_quirks,
1875 AllowAnchorPositioningFunctions::AllowAnchorSize,
1876 )
1877 }
1878
1879 #[inline]
1882 pub fn parse_quirky_with_anchor_functions<'i, 't>(
1883 context: &ParserContext,
1884 input: &mut Parser<'i, 't>,
1885 allow_quirks: AllowQuirks,
1886 ) -> Result<Self, ParseError<'i>> {
1887 Self::parse_internal(
1888 context,
1889 input,
1890 AllowedNumericType::All,
1891 allow_quirks,
1892 AllowAnchorPositioningFunctions::AllowAnchorAndAnchorSize,
1893 )
1894 }
1895
1896 pub fn parse_non_negative_with_anchor_size<'i, 't>(
1899 context: &ParserContext,
1900 input: &mut Parser<'i, 't>,
1901 allow_quirks: AllowQuirks,
1902 ) -> Result<Self, ParseError<'i>> {
1903 Self::parse_internal(
1904 context,
1905 input,
1906 AllowedNumericType::NonNegative,
1907 allow_quirks,
1908 AllowAnchorPositioningFunctions::AllowAnchorSize,
1909 )
1910 }
1911
1912 #[inline]
1917 pub fn parse_non_negative<'i, 't>(
1918 context: &ParserContext,
1919 input: &mut Parser<'i, 't>,
1920 ) -> Result<Self, ParseError<'i>> {
1921 Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
1922 }
1923
1924 #[inline]
1926 pub fn parse_non_negative_quirky<'i, 't>(
1927 context: &ParserContext,
1928 input: &mut Parser<'i, 't>,
1929 allow_quirks: AllowQuirks,
1930 ) -> Result<Self, ParseError<'i>> {
1931 Self::parse_internal(
1932 context,
1933 input,
1934 AllowedNumericType::NonNegative,
1935 allow_quirks,
1936 AllowAnchorPositioningFunctions::No,
1937 )
1938 }
1939
1940 fn to_calc_node(self) -> CalcNode {
1944 match self {
1945 LengthPercentage::Length(l) => CalcNode::Leaf(calc::Leaf::Length(l)),
1946 LengthPercentage::Percentage(p) => CalcNode::Leaf(calc::Leaf::Percentage(p.0)),
1947 LengthPercentage::Calc(p) => p.node,
1948 }
1949 }
1950
1951 pub fn hundred_percent_minus(self, clamping_mode: AllowedNumericType) -> Self {
1953 let mut sum = smallvec::SmallVec::<[CalcNode; 2]>::new();
1954 sum.push(CalcNode::Leaf(calc::Leaf::Percentage(1.0)));
1955
1956 let mut node = self.to_calc_node();
1957 node.negate();
1958 sum.push(node);
1959
1960 let calc = CalcNode::Sum(sum.into_boxed_slice().into());
1961 LengthPercentage::Calc(Box::new(
1962 calc.into_length_or_percentage(clamping_mode).unwrap(),
1963 ))
1964 }
1965}
1966
1967impl Zero for LengthPercentage {
1968 fn zero() -> Self {
1969 LengthPercentage::Length(NoCalcLength::zero())
1970 }
1971
1972 fn is_zero(&self) -> bool {
1973 match *self {
1974 LengthPercentage::Length(l) => l.is_zero(),
1975 LengthPercentage::Percentage(p) => p.0 == 0.0,
1976 LengthPercentage::Calc(_) => false,
1977 }
1978 }
1979}
1980
1981impl ZeroNoPercent for LengthPercentage {
1982 fn is_zero_no_percent(&self) -> bool {
1983 match *self {
1984 LengthPercentage::Percentage(_) => false,
1985 _ => self.is_zero(),
1986 }
1987 }
1988}
1989
1990pub type LengthPercentageOrAuto = generics::LengthPercentageOrAuto<LengthPercentage>;
1992
1993impl LengthPercentageOrAuto {
1994 #[inline]
1996 pub fn zero_percent() -> Self {
1997 generics::LengthPercentageOrAuto::LengthPercentage(LengthPercentage::zero_percent())
1998 }
1999
2000 #[inline]
2003 pub fn parse_quirky<'i, 't>(
2004 context: &ParserContext,
2005 input: &mut Parser<'i, 't>,
2006 allow_quirks: AllowQuirks,
2007 ) -> Result<Self, ParseError<'i>> {
2008 Self::parse_with(context, input, |context, input| {
2009 LengthPercentage::parse_quirky(context, input, allow_quirks)
2010 })
2011 }
2012}
2013
2014pub type NonNegativeLengthPercentageOrAuto =
2016 generics::LengthPercentageOrAuto<NonNegativeLengthPercentage>;
2017
2018impl NonNegativeLengthPercentageOrAuto {
2019 #[inline]
2021 pub fn zero_percent() -> Self {
2022 generics::LengthPercentageOrAuto::LengthPercentage(
2023 NonNegativeLengthPercentage::zero_percent(),
2024 )
2025 }
2026
2027 #[inline]
2030 pub fn parse_quirky<'i, 't>(
2031 context: &ParserContext,
2032 input: &mut Parser<'i, 't>,
2033 allow_quirks: AllowQuirks,
2034 ) -> Result<Self, ParseError<'i>> {
2035 Self::parse_with(context, input, |context, input| {
2036 NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)
2037 })
2038 }
2039}
2040
2041pub type NonNegativeLengthPercentage = NonNegative<LengthPercentage>;
2043
2044pub type NonNegativeLengthPercentageOrNormal =
2046 GenericLengthPercentageOrNormal<NonNegativeLengthPercentage>;
2047
2048impl From<NoCalcLength> for NonNegativeLengthPercentage {
2049 #[inline]
2050 fn from(len: NoCalcLength) -> Self {
2051 NonNegative(LengthPercentage::from(len))
2052 }
2053}
2054
2055impl Parse for NonNegativeLengthPercentage {
2056 #[inline]
2057 fn parse<'i, 't>(
2058 context: &ParserContext,
2059 input: &mut Parser<'i, 't>,
2060 ) -> Result<Self, ParseError<'i>> {
2061 Self::parse_quirky(context, input, AllowQuirks::No)
2062 }
2063}
2064
2065impl NonNegativeLengthPercentage {
2066 #[inline]
2067 pub fn zero_percent() -> Self {
2069 NonNegative(LengthPercentage::zero_percent())
2070 }
2071
2072 #[inline]
2075 pub fn parse_quirky<'i, 't>(
2076 context: &ParserContext,
2077 input: &mut Parser<'i, 't>,
2078 allow_quirks: AllowQuirks,
2079 ) -> Result<Self, ParseError<'i>> {
2080 LengthPercentage::parse_non_negative_quirky(context, input, allow_quirks).map(NonNegative)
2081 }
2082
2083 #[inline]
2086 pub fn parse_non_negative_with_anchor_size<'i, 't>(
2087 context: &ParserContext,
2088 input: &mut Parser<'i, 't>,
2089 allow_quirks: AllowQuirks,
2090 ) -> Result<Self, ParseError<'i>> {
2091 LengthPercentage::parse_non_negative_with_anchor_size(context, input, allow_quirks)
2092 .map(NonNegative)
2093 }
2094}
2095
2096pub type LengthOrAuto = generics::LengthPercentageOrAuto<Length>;
2102
2103impl LengthOrAuto {
2104 #[inline]
2107 pub fn parse_quirky<'i, 't>(
2108 context: &ParserContext,
2109 input: &mut Parser<'i, 't>,
2110 allow_quirks: AllowQuirks,
2111 ) -> Result<Self, ParseError<'i>> {
2112 Self::parse_with(context, input, |context, input| {
2113 Length::parse_quirky(context, input, allow_quirks)
2114 })
2115 }
2116}
2117
2118pub type NonNegativeLengthOrAuto = generics::LengthPercentageOrAuto<NonNegativeLength>;
2120
2121pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>;
2123
2124pub type Size = GenericSize<NonNegativeLengthPercentage>;
2126
2127impl Parse for Size {
2128 fn parse<'i, 't>(
2129 context: &ParserContext,
2130 input: &mut Parser<'i, 't>,
2131 ) -> Result<Self, ParseError<'i>> {
2132 Size::parse_quirky(context, input, AllowQuirks::No)
2133 }
2134}
2135
2136macro_rules! parse_size_non_length {
2137 ($size:ident, $input:expr, $allow_webkit_fill_available:expr,
2138 $auto_or_none:expr => $auto_or_none_ident:ident) => {{
2139 let size = $input.try_parse(|input| {
2140 Ok(try_match_ident_ignore_ascii_case! { input,
2141 "min-content" | "-moz-min-content" => $size::MinContent,
2142 "max-content" | "-moz-max-content" => $size::MaxContent,
2143 "fit-content" | "-moz-fit-content" => $size::FitContent,
2144 #[cfg(feature = "gecko")]
2145 "-moz-available" => $size::MozAvailable,
2146 "-webkit-fill-available" if $allow_webkit_fill_available => $size::WebkitFillAvailable,
2147 "stretch" if is_stretch_enabled() => $size::Stretch,
2148 $auto_or_none => $size::$auto_or_none_ident,
2149 })
2150 });
2151 if size.is_ok() {
2152 return size;
2153 }
2154 }};
2155}
2156
2157fn is_webkit_fill_available_enabled_in_width_and_height() -> bool {
2158 static_prefs::pref!("layout.css.webkit-fill-available.enabled")
2159}
2160
2161fn is_webkit_fill_available_enabled_in_all_size_properties() -> bool {
2162 static_prefs::pref!("layout.css.webkit-fill-available.enabled")
2166 && static_prefs::pref!("layout.css.webkit-fill-available.all-size-properties.enabled")
2167}
2168
2169fn is_stretch_enabled() -> bool {
2170 static_prefs::pref!("layout.css.stretch-size-keyword.enabled")
2171}
2172
2173fn is_fit_content_function_enabled() -> bool {
2174 static_prefs::pref!("layout.css.fit-content-function.enabled")
2175}
2176
2177macro_rules! parse_fit_content_function {
2178 ($size:ident, $input:expr, $context:expr, $allow_quirks:expr) => {
2179 if is_fit_content_function_enabled() {
2180 if let Ok(length) = $input.try_parse(|input| {
2181 input.expect_function_matching("fit-content")?;
2182 input.parse_nested_block(|i| {
2183 NonNegativeLengthPercentage::parse_quirky($context, i, $allow_quirks)
2184 })
2185 }) {
2186 return Ok($size::FitContentFunction(length));
2187 }
2188 }
2189 };
2190}
2191
2192#[derive(Clone, Copy, PartialEq, Eq)]
2193enum ParseAnchorFunctions {
2194 Yes,
2195 No,
2196}
2197
2198impl Size {
2199 pub fn parse_quirky<'i, 't>(
2201 context: &ParserContext,
2202 input: &mut Parser<'i, 't>,
2203 allow_quirks: AllowQuirks,
2204 ) -> Result<Self, ParseError<'i>> {
2205 let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_all_size_properties();
2206 Self::parse_quirky_internal(
2207 context,
2208 input,
2209 allow_quirks,
2210 allow_webkit_fill_available,
2211 ParseAnchorFunctions::Yes,
2212 )
2213 }
2214
2215 pub fn parse_size_for_flex_basis_width<'i, 't>(
2217 context: &ParserContext,
2218 input: &mut Parser<'i, 't>,
2219 ) -> Result<Self, ParseError<'i>> {
2220 Self::parse_quirky_internal(
2221 context,
2222 input,
2223 AllowQuirks::No,
2224 true,
2225 ParseAnchorFunctions::No,
2226 )
2227 }
2228
2229 fn parse_quirky_internal<'i, 't>(
2234 context: &ParserContext,
2235 input: &mut Parser<'i, 't>,
2236 allow_quirks: AllowQuirks,
2237 allow_webkit_fill_available: bool,
2238 allow_anchor_functions: ParseAnchorFunctions,
2239 ) -> Result<Self, ParseError<'i>> {
2240 parse_size_non_length!(Size, input, allow_webkit_fill_available,
2241 "auto" => Auto);
2242 parse_fit_content_function!(Size, input, context, allow_quirks);
2243
2244 let allow_anchor = allow_anchor_functions == ParseAnchorFunctions::Yes
2245 && static_prefs::pref!("layout.css.anchor-positioning.enabled");
2246 match input
2247 .try_parse(|i| NonNegativeLengthPercentage::parse_quirky(context, i, allow_quirks))
2248 {
2249 Ok(length) => return Ok(GenericSize::LengthPercentage(length)),
2250 Err(e) if !allow_anchor => return Err(e.into()),
2251 Err(_) => (),
2252 };
2253 if let Ok(length) = input.try_parse(|i| {
2254 NonNegativeLengthPercentage::parse_non_negative_with_anchor_size(
2255 context,
2256 i,
2257 allow_quirks,
2258 )
2259 }) {
2260 return Ok(GenericSize::AnchorContainingCalcFunction(length));
2261 }
2262 Ok(Self::AnchorSizeFunction(Box::new(
2263 GenericAnchorSizeFunction::parse(context, input)?,
2264 )))
2265 }
2266
2267 pub fn parse_size_for_width_or_height_quirky<'i, 't>(
2273 context: &ParserContext,
2274 input: &mut Parser<'i, 't>,
2275 allow_quirks: AllowQuirks,
2276 ) -> Result<Self, ParseError<'i>> {
2277 let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_width_and_height();
2278 Self::parse_quirky_internal(
2279 context,
2280 input,
2281 allow_quirks,
2282 allow_webkit_fill_available,
2283 ParseAnchorFunctions::Yes,
2284 )
2285 }
2286
2287 pub fn parse_size_for_width_or_height<'i, 't>(
2293 context: &ParserContext,
2294 input: &mut Parser<'i, 't>,
2295 ) -> Result<Self, ParseError<'i>> {
2296 let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_width_and_height();
2297 Self::parse_quirky_internal(
2298 context,
2299 input,
2300 AllowQuirks::No,
2301 allow_webkit_fill_available,
2302 ParseAnchorFunctions::Yes,
2303 )
2304 }
2305
2306 #[inline]
2308 pub fn zero_percent() -> Self {
2309 GenericSize::LengthPercentage(NonNegativeLengthPercentage::zero_percent())
2310 }
2311}
2312
2313pub type MaxSize = GenericMaxSize<NonNegativeLengthPercentage>;
2315
2316impl Parse for MaxSize {
2317 fn parse<'i, 't>(
2318 context: &ParserContext,
2319 input: &mut Parser<'i, 't>,
2320 ) -> Result<Self, ParseError<'i>> {
2321 MaxSize::parse_quirky(context, input, AllowQuirks::No)
2322 }
2323}
2324
2325impl MaxSize {
2326 pub fn parse_quirky<'i, 't>(
2328 context: &ParserContext,
2329 input: &mut Parser<'i, 't>,
2330 allow_quirks: AllowQuirks,
2331 ) -> Result<Self, ParseError<'i>> {
2332 let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_all_size_properties();
2333 parse_size_non_length!(MaxSize, input, allow_webkit_fill_available,
2334 "none" => None);
2335 parse_fit_content_function!(MaxSize, input, context, allow_quirks);
2336
2337 match input
2338 .try_parse(|i| NonNegativeLengthPercentage::parse_quirky(context, i, allow_quirks))
2339 {
2340 Ok(length) => return Ok(GenericMaxSize::LengthPercentage(length)),
2341 Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
2342 return Err(e.into())
2343 },
2344 Err(_) => (),
2345 };
2346 if let Ok(length) = input.try_parse(|i| {
2347 NonNegativeLengthPercentage::parse_non_negative_with_anchor_size(
2348 context,
2349 i,
2350 allow_quirks,
2351 )
2352 }) {
2353 return Ok(GenericMaxSize::AnchorContainingCalcFunction(length));
2354 }
2355 Ok(Self::AnchorSizeFunction(Box::new(
2356 GenericAnchorSizeFunction::parse(context, input)?,
2357 )))
2358 }
2359}
2360
2361pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
2363
2364pub type Margin = GenericMargin<LengthPercentage>;
2366
2367impl Margin {
2368 #[inline]
2371 pub fn parse_quirky<'i, 't>(
2372 context: &ParserContext,
2373 input: &mut Parser<'i, 't>,
2374 allow_quirks: AllowQuirks,
2375 ) -> Result<Self, ParseError<'i>> {
2376 if let Ok(l) = input.try_parse(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
2377 {
2378 return Ok(Self::LengthPercentage(l));
2379 }
2380 match input.try_parse(|i| i.expect_ident_matching("auto")) {
2381 Ok(_) => return Ok(Self::Auto),
2382 Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
2383 return Err(e.into())
2384 },
2385 Err(_) => (),
2386 };
2387 if let Ok(l) = input.try_parse(|i| {
2388 LengthPercentage::parse_quirky_with_anchor_size_function(context, i, allow_quirks)
2389 }) {
2390 return Ok(Self::AnchorContainingCalcFunction(l));
2391 }
2392 let inner = GenericAnchorSizeFunction::<Margin>::parse(context, input)?;
2393 Ok(Self::AnchorSizeFunction(Box::new(inner)))
2394 }
2395}
2396
2397impl Parse for Margin {
2398 fn parse<'i, 't>(
2399 context: &ParserContext,
2400 input: &mut Parser<'i, 't>,
2401 ) -> Result<Self, ParseError<'i>> {
2402 Self::parse_quirky(context, input, AllowQuirks::No)
2403 }
2404}