1use super::CSSFloat;
10use super::computed::{Context, ToComputedValue};
11use super::generics::grid::ImplicitGridTracks as GenericImplicitGridTracks;
12use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth};
13use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
14use super::generics::{self, NonNegative};
15use crate::FxHashMap;
16use crate::context::QuirksMode;
17use crate::derives::*;
18use crate::parser::{Parse, ParserContext};
19use crate::typed_om::NumericBaseType;
20use crate::values::computed;
21use crate::values::specified::calc::PercentageContext;
22use crate::values::specified::number::parse_number_with_clamping_mode;
23use crate::{Namespace, Prefix};
24use cssparser::{Parser, Token};
25use style_traits::values::specified::AllowedNumericType;
26use style_traits::{ParseError, StyleParseErrorKind};
27
28pub use self::align::{ContentDistribution, ItemPlacement, JustifyItems, SelfAlignment};
29pub use self::angle::{AllowUnitlessZeroAngle, Angle, NoCalcAngle};
30pub use self::animation::{
31 AnimationComposition, AnimationDirection, AnimationDuration, AnimationFillMode,
32 AnimationIterationCount, AnimationName, AnimationPlayState, AnimationRangeEnd,
33 AnimationRangeStart, AnimationTimeline, ScrollAxis, TimelineName, TransitionBehavior,
34 TransitionProperty, ViewTimelineInset, ViewTransitionClass, ViewTransitionName,
35};
36pub use self::background::{
37 BackgroundClip, BackgroundOrigin, BackgroundRepeat, BackgroundSize, ImageLayerAttachment,
38};
39pub use self::basic_shape::FillRule;
40pub use self::border::{
41 BorderCornerRadius, BorderImageRepeat, BorderImageSideWidth, BorderImageSlice,
42 BorderImageWidth, BorderRadius, BorderSideOffset, BorderSideWidth, BorderSpacing, BorderStyle,
43 BoxDecorationBreak, FloatEdge, LineWidth,
44};
45pub use self::box_::{
46 AlignmentBaseline, Appearance, BackfaceVisibility, BaselineShift, BaselineSource, BoxAlign,
47 BoxCollapse, BoxDirection, BoxOrient, BoxPack, BreakBetween, BreakWithin, Clear, Contain,
48 ContainIntrinsicSize, ContainerName, ContainerType, ContentVisibility, DirectionProperty,
49 Display, DominantBaseline, Float, ImageOrientation, Isolation, LineClamp, MarginTrim, Orient,
50 Overflow, OverflowAnchor, OverflowClipMargin, OverscrollBehavior, Perspective,
51 PositionProperty, Resize, ScrollBehavior, ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStop,
52 ScrollSnapStrictness, ScrollSnapType, ScrollbarGutter, ScrollbarInset, TextOrientation,
53 TopLayer, TouchAction, Visibility, WillChange, WillChangeBits, WritingModeProperty, Zoom,
54};
55pub use self::calc::{CalcLengthPercentage, CalcNumeric};
56pub use self::color::{
57 Color, ColorOrAuto, ColorPropertyValue, ColorScheme, ForcedColorAdjust, PrintColorAdjust,
58};
59pub use self::column::{ColumnCount, ColumnFill, ColumnSpan};
60pub use self::corner_shape::{CornerShape, CornerShapeRect, SuperellipseArg};
61pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset, CounterSet};
62pub use self::easing::TimingFunction;
63pub use self::effects::{Blend, BoxShadow, Filter, SimpleShadow};
64pub use self::flex::FlexBasis;
65pub use self::font::{
66 FontFamily, FontKerning, FontLanguageOverride, FontOpticalSizing, FontPalette, FontSmoothing,
67 FontStyle, FontVariantCaps, FontVariantEmoji, FontVariantPosition, MathShift, MathStyle,
68 MathVariant,
69};
70pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
71pub use self::font::{
72 FontSize, FontSizeAdjust, FontSizeAdjustFactor, FontSizeKeyword, FontSynthesis,
73 FontSynthesisStyle, FontWidth,
74};
75pub use self::font::{FontVariantAlternates, FontWeight};
76pub use self::font::{FontVariantEastAsian, FontVariationSettings, LineHeight};
77pub use self::font::{MathDepth, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextScale};
78pub use self::image::{
79 EndingShape as GradientEndingShape, Gradient, Image, ImageDecoding, ImageRendering,
80};
81pub use self::length::{Length, LengthOrNumber, LengthUnit, NonNegativeLengthOrNumber};
82pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
83pub use self::length::{Margin, MaxSize, Size};
84pub use self::length::{NoCalcLength, ViewportVariant};
85pub use self::length::{
86 NonNegativeLength, NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto,
87};
88pub use self::list::{ListStylePosition, ListStyleType, Quotes};
89pub use self::motion::{OffsetPath, OffsetPosition, OffsetRotate};
90pub use self::number::{
91 GreaterThanOrEqualToOneNumber, Integer, NoCalcNumber, NonNegativeInteger, NonNegativeNumber,
92 Number, PositiveInteger,
93};
94pub use self::outline::OutlineStyle;
95pub use self::page::{PageName, PageOrientation, PageSize, PageSizeOrientation, PaperSize};
96pub use self::param::LinkParameters;
97pub use self::percentage::{NoCalcPercentage, NonNegativePercentage, Percentage};
98pub use self::position::{
99 AnchorFunction, AnchorName, AnchorNameIdent, AspectRatio, BoxSizing, FlexDirection, FlexWrap,
100 GridAutoFlow, GridTemplateAreas, Inset, ObjectFit, Position, PositionAnchor,
101 PositionAnchorKeyword, PositionArea, PositionAreaKeyword, PositionComponent, PositionOrAuto,
102 PositionTryFallbacks, PositionTryOrder, PositionVisibility, ScopedName, ZIndex,
103};
104pub use self::random::{RandomCacheKey, RandomUaIdent};
105pub use self::ratio::Ratio;
106pub use self::rect::NonNegativeLengthOrNumberRect;
107pub use self::resolution::{NoCalcResolution, Resolution};
108pub use self::svg::{
109 ColorInterpolation, DProperty, MaskComposite, MaskMode, MaskType, MozContextProperties,
110 ShapeRendering, StrokeLinecap, StrokeLinejoin, TextAnchor,
111};
112pub use self::svg::{SVGLength, SVGOpacity, SVGPaint};
113pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth, VectorEffect};
114pub use self::svg_path::SVGPathData;
115pub use self::table::{BorderCollapse, EmptyCells, TableLayout};
116pub use self::text::{
117 HyphenateCharacter, HyphenateLimitChars, Hyphens, RubyAlign, RubyPosition, TextCombineUpright,
118 TextDecorationStyle, TextRendering, TextSecurity, TextSizeAdjust, TextWrapMode, TextWrapStyle,
119 UnicodeBidi, WhiteSpaceCollapse,
120};
121pub use self::text::{InitialLetter, LetterSpacing, LineBreak, TextAlign, TextIndent};
122pub use self::text::{OverflowWrap, TextEmphasisPosition, TextEmphasisStyle, WordBreak};
123pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing};
124pub use self::text::{TextAlignLast, TextAutospace, TextUnderlinePosition};
125pub use self::text::{TextBoxEdge, TextBoxTrim};
126pub use self::text::{
127 TextDecorationInset, TextDecorationLength, TextDecorationSkipInk, TextJustify, TextTransform,
128};
129pub use self::time::{NoCalcTime, Time};
130pub use self::transform::{Rotate, Scale, Transform};
131pub use self::transform::{TransformBox, TransformOrigin, TransformStyle, Translate};
132pub use self::tree_counting::TreeCountingFunction;
133#[cfg(feature = "gecko")]
134pub use self::ui::CursorImage;
135pub use self::ui::{
136 BoolInteger, Cursor, FieldSizing, ImeMode, Inert, MozTheme, PointerEvents, ScrollbarColor,
137 ScrollbarWidth, UserFocus, UserSelect, WindowDragging, WindowShadow,
138};
139pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
140
141pub mod align;
142pub mod angle;
143pub mod animation;
144pub mod background;
145pub mod basic_shape;
146pub mod border;
147#[path = "box.rs"]
148pub mod box_;
149pub mod calc;
150pub mod color;
151pub mod column;
152pub mod corner_shape;
153pub mod counters;
154pub mod easing;
155pub mod effects;
156pub mod flex;
157pub mod font;
158pub mod frequency;
159pub mod grid;
160pub mod image;
161pub mod intersection_observer;
162pub mod length;
163pub mod list;
164pub mod motion;
165pub mod number;
166pub mod outline;
167pub mod page;
168pub mod param;
169pub mod percentage;
170pub mod position;
171pub mod random;
172pub mod ratio;
173pub mod rect;
174pub mod resolution;
175pub mod source_size_list;
176pub mod svg;
177pub mod svg_path;
178pub mod table;
179pub mod text;
180pub mod time;
181pub mod transform;
182pub mod tree_counting;
183pub mod ui;
184pub mod url;
185
186#[allow(missing_docs)]
189#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
190pub enum AngleOrPercentage {
191 Percentage(Percentage),
192 Angle(Angle),
193}
194
195impl AngleOrPercentage {
196 fn parse_internal(
197 context: &ParserContext,
198 input: &mut Parser,
199 allow_unitless_zero: AllowUnitlessZeroAngle,
200 ) -> Result<Self, ParseError> {
201 if let Ok(per) = input.try_parse(|i| Percentage::parse(context, i)) {
202 return Ok(AngleOrPercentage::Percentage(per));
203 }
204
205 Angle::parse_internal(context, input, allow_unitless_zero).map(AngleOrPercentage::Angle)
206 }
207
208 pub fn parse_with_unitless(
211 context: &ParserContext,
212 input: &mut Parser,
213 ) -> Result<Self, ParseError> {
214 AngleOrPercentage::parse_internal(context, input, AllowUnitlessZeroAngle::Yes)
215 }
216}
217
218impl Parse for AngleOrPercentage {
219 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
220 AngleOrPercentage::parse_internal(context, input, AllowUnitlessZeroAngle::No)
221 }
222}
223
224#[allow(missing_docs)]
231#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, ToTyped)]
232pub enum NumberOrPercentage {
233 Percentage(Percentage),
234 Number(Number),
235}
236
237impl NumberOrPercentage {
238 fn parse_with_clamping_mode(
239 context: &ParserContext,
240 input: &mut Parser,
241 type_: AllowedNumericType,
242 ) -> Result<Self, ParseError> {
243 if let Ok(per) =
244 input.try_parse(|i| Percentage::parse_with_clamping_mode(context, i, type_))
245 {
246 return Ok(NumberOrPercentage::Percentage(per));
247 }
248
249 parse_number_with_clamping_mode(
250 context,
251 input,
252 type_,
253 PercentageContext::allowed_with_hint(NumericBaseType::Percent),
254 )
255 .map(NumberOrPercentage::Number)
256 }
257
258 pub fn parse_non_negative(
260 context: &ParserContext,
261 input: &mut Parser,
262 ) -> Result<Self, ParseError> {
263 Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
264 }
265
266 pub fn to_percentage(self) -> Option<Percentage> {
268 match self {
269 Self::Percentage(p) => Some(p),
270 Self::Number(n) => n.to_percentage(),
271 }
272 }
273
274 pub fn to_number(&self) -> Option<Number> {
276 match self {
277 Self::Percentage(p) => p.to_number(),
278 Self::Number(n) => Some(n.clone()),
279 }
280 }
281
282 pub fn as_percentage(&self) -> Option<&Percentage> {
284 match self {
285 NumberOrPercentage::Percentage(percentage) => Some(percentage),
286 _ => None,
287 }
288 }
289
290 pub fn into_simplified_number(self) -> NumberOrPercentage {
293 match self.as_percentage().and_then(|p| p.get()) {
294 Some(p) => NumberOrPercentage::Number(Number::new(p)),
295 None => self,
296 }
297 }
298
299 pub fn to_computed_value_without_context(&self) -> Result<computed::NumberOrPercentage, ()> {
301 Ok(match self {
302 NumberOrPercentage::Percentage(percentage) => computed::NumberOrPercentage::Percentage(
303 computed::Percentage(percentage.resolve().ok_or(())?),
304 ),
305 NumberOrPercentage::Number(number) => {
306 computed::NumberOrPercentage::Number(number.resolve().ok_or(())?)
307 },
308 })
309 }
310}
311
312impl Parse for NumberOrPercentage {
313 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
314 Self::parse_with_clamping_mode(context, input, AllowedNumericType::All)
315 }
316}
317
318pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
320
321impl NonNegativeNumberOrPercentage {
322 #[inline]
324 pub fn hundred_percent() -> Self {
325 NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
326 }
327
328 #[inline]
330 pub fn new_number(n: f32) -> Self {
331 NonNegative(NumberOrPercentage::Number(Number::new(n)))
332 }
333}
334
335impl Parse for NonNegativeNumberOrPercentage {
336 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
337 Ok(NonNegative(NumberOrPercentage::parse_non_negative(
338 context, input,
339 )?))
340 }
341}
342
343#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, ToTyped)]
345pub struct Opacity(NumberOrPercentage);
346
347impl Parse for Opacity {
348 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
352 Ok(Opacity(
353 NumberOrPercentage::parse(context, input)?.into_simplified_number(),
354 ))
355 }
356}
357
358impl ToComputedValue for Opacity {
359 type ComputedValue = CSSFloat;
360
361 #[inline]
362 fn to_computed_value(&self, context: &Context) -> CSSFloat {
363 let value = self.0.to_computed_value(context).value();
364 if context.for_smil_animation {
365 value
368 } else {
369 value.min(1.0).max(0.0)
370 }
371 }
372
373 #[inline]
374 fn from_computed_value(computed: &CSSFloat) -> Self {
375 Opacity(NumberOrPercentage::Number(Number::from_computed_value(
376 computed,
377 )))
378 }
379}
380
381pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
383
384pub type TrackSize = GenericTrackSize<LengthPercentage>;
386
387pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>;
389
390pub type TrackList = GenericTrackList<LengthPercentage, Integer>;
393
394pub type GridLine = GenericGridLine<Integer>;
396
397pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
399
400pub type ClipRect = generics::GenericClipRect<LengthOrAuto>;
402
403impl Parse for ClipRect {
404 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
405 Self::parse_quirky(context, input, AllowQuirks::No)
406 }
407}
408
409impl ClipRect {
410 fn parse_quirky(
412 context: &ParserContext,
413 input: &mut Parser,
414 allow_quirks: AllowQuirks,
415 ) -> Result<Self, ParseError> {
416 input.expect_function_matching("rect")?;
417
418 fn parse_argument(
419 context: &ParserContext,
420 input: &mut Parser,
421 allow_quirks: AllowQuirks,
422 ) -> Result<LengthOrAuto, ParseError> {
423 LengthOrAuto::parse_quirky(context, input, allow_quirks)
424 }
425
426 input.parse_nested_block(|input| {
427 let top = parse_argument(context, input, allow_quirks)?;
428 let right;
429 let bottom;
430 let left;
431
432 if input.try_parse(|input| input.expect_comma()).is_ok() {
433 right = parse_argument(context, input, allow_quirks)?;
434 input.expect_comma()?;
435 bottom = parse_argument(context, input, allow_quirks)?;
436 input.expect_comma()?;
437 left = parse_argument(context, input, allow_quirks)?;
438 } else {
439 right = parse_argument(context, input, allow_quirks)?;
440 bottom = parse_argument(context, input, allow_quirks)?;
441 left = parse_argument(context, input, allow_quirks)?;
442 }
443
444 Ok(ClipRect {
445 top,
446 right,
447 bottom,
448 left,
449 })
450 })
451 }
452}
453
454pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>;
456
457impl ClipRectOrAuto {
458 pub fn parse_quirky(
460 context: &ParserContext,
461 input: &mut Parser,
462 allow_quirks: AllowQuirks,
463 ) -> Result<Self, ParseError> {
464 if let Ok(v) = input.try_parse(|i| ClipRect::parse_quirky(context, i, allow_quirks)) {
465 return Ok(generics::GenericClipRectOrAuto::Rect(v));
466 }
467 input.expect_ident_matching("auto")?;
468 Ok(generics::GenericClipRectOrAuto::Auto)
469 }
470}
471
472#[derive(Clone, Copy, PartialEq)]
474pub enum AllowQuirks {
475 No,
477 Yes,
479 Always,
481}
482
483impl AllowQuirks {
484 pub fn allowed(self, quirks_mode: QuirksMode) -> bool {
486 match self {
487 AllowQuirks::Always => true,
488 AllowQuirks::No => false,
489 AllowQuirks::Yes => quirks_mode == QuirksMode::Quirks,
490 }
491 }
492}
493
494#[derive(Clone, Debug, PartialEq, MallocSizeOf, ToShmem)]
495pub enum ParsedNamespace {
497 Unknown,
499 Known(Namespace),
501}
502
503impl ParsedNamespace {
504 pub fn parse(
507 namespaces: &FxHashMap<Prefix, Namespace>,
508 input: &mut Parser,
509 ) -> Result<Self, ParseError> {
510 parse_namespace(namespaces, input).map(|(_prefix, namespace)| namespace)
515 }
516}
517
518impl Default for ParsedNamespace {
519 fn default() -> Self {
520 Self::Known(Namespace::default())
521 }
522}
523
524pub fn parse_namespace(
526 namespaces: &FxHashMap<Prefix, Namespace>,
527 input: &mut Parser,
528) -> Result<(Prefix, ParsedNamespace), ParseError> {
529 let ns_prefix = match input.next()? {
530 Token::Ident(prefix) => Some(Prefix::from(prefix.as_ref())),
531 Token::Delim('|') => None,
532 _ => return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError)),
533 };
534
535 if ns_prefix.is_some() && !matches!(*input.next_including_whitespace()?, Token::Delim('|')) {
536 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
537 }
538
539 if let Some(prefix) = ns_prefix {
540 let ns = match namespaces.get(&prefix).cloned() {
541 Some(ns) => ParsedNamespace::Known(ns),
542 None => ParsedNamespace::Unknown,
543 };
544 Ok((prefix, ns))
545 } else {
546 Ok((Prefix::default(), ParsedNamespace::default()))
547 }
548}