1use self::transform::DirectionVector;
8use super::animated::ToAnimatedValue;
9use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
10use super::generics::grid::ImplicitGridTracks as GenericImplicitGridTracks;
11use super::generics::grid::{GenericGridLine, GenericTrackBreadth};
12use super::generics::grid::{GenericTrackSize, TrackList as GenericTrackList};
13use super::generics::transform::IsParallelTo;
14use super::generics::{self, GreaterThanOrEqualToOne, NonNegative, ZeroToOne};
15use super::specified;
16use super::{CSSFloat, CSSInteger};
17use crate::computed_value_flags::ComputedValueFlags;
18use crate::context::QuirksMode;
19use crate::custom_properties::ComputedCustomProperties;
20use crate::font_metrics::{FontMetrics, FontMetricsOrientation};
21use crate::media_queries::Device;
22#[cfg(feature = "gecko")]
23use crate::properties;
24use crate::properties::{ComputedValues, StyleBuilder};
25use crate::rule_cache::RuleCacheConditions;
26use crate::stylesheets::container_rule::{
27 ContainerInfo, ContainerSizeQuery, ContainerSizeQueryResult,
28};
29use crate::stylist::Stylist;
30use crate::values::specified::font::QueryFontMetricsFlags;
31use crate::values::specified::length::FontBaseSize;
32use crate::{ArcSlice, Atom, One};
33use euclid::{default, Point2D, Rect, Size2D};
34use servo_arc::Arc;
35use std::cell::RefCell;
36use std::cmp;
37use std::f32;
38use std::ops::{Add, Sub};
39
40pub use self::align::{AlignContent, AlignItems, JustifyContent, JustifyItems, SelfAlignment};
41pub use self::align::{AlignSelf, JustifySelf};
42pub use self::angle::Angle;
43pub use self::animation::{
44 AnimationComposition, AnimationDirection, AnimationDuration, AnimationFillMode,
45 AnimationIterationCount, AnimationName, AnimationPlayState, AnimationTimeline, ScrollAxis,
46 TimelineName, TransitionBehavior, TransitionProperty, ViewTimelineInset, ViewTransitionClass,
47 ViewTransitionName,
48};
49pub use self::background::{BackgroundRepeat, BackgroundSize};
50pub use self::basic_shape::FillRule;
51pub use self::border::{
52 BorderCornerRadius, BorderImageRepeat, BorderImageSideWidth, BorderImageSlice,
53 BorderImageWidth, BorderRadius, BorderSideWidth, BorderSpacing, LineWidth,
54};
55pub use self::box_::{
56 Appearance, BaselineSource, BreakBetween, BreakWithin, Clear, Contain, ContainIntrinsicSize,
57 ContainerName, ContainerType, ContentVisibility, Display, Float, LineClamp, Overflow,
58 OverflowAnchor, OverflowClipBox, OverscrollBehavior, Perspective, PositionProperty, Resize,
59 ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStop, ScrollSnapStrictness, ScrollSnapType,
60 ScrollbarGutter, TouchAction, VerticalAlign, WillChange, WritingModeProperty, Zoom,
61};
62pub use self::color::{
63 Color, ColorOrAuto, ColorPropertyValue, ColorScheme, ForcedColorAdjust, PrintColorAdjust,
64};
65pub use self::column::ColumnCount;
66pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset, CounterSet};
67pub use self::easing::TimingFunction;
68pub use self::effects::{BoxShadow, Filter, SimpleShadow};
69pub use self::flex::FlexBasis;
70pub use self::font::{FontFamily, FontLanguageOverride, FontPalette, FontStyle};
71pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
72pub use self::font::{
73 FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontSynthesisStyle, LineHeight,
74};
75pub use self::font::{FontVariantAlternates, FontWeight};
76pub use self::font::{FontVariantEastAsian, FontVariationSettings};
77pub use self::font::{MathDepth, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextScale};
78pub use self::image::{Gradient, Image, ImageRendering, LineDirection};
79pub use self::length::{CSSPixelLength, NonNegativeLength};
80pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
81pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, Margin, MaxSize, Size};
82pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
83#[cfg(feature = "gecko")]
84pub use self::list::ListStyleType;
85pub use self::list::Quotes;
86pub use self::motion::{OffsetPath, OffsetPosition, OffsetRotate};
87pub use self::outline::OutlineStyle;
88pub use self::page::{PageName, PageOrientation, PageSize, PageSizeOrientation, PaperSize};
89pub use self::percentage::{NonNegativePercentage, Percentage};
90pub use self::position::AnchorFunction;
91pub use self::position::AnchorName;
92pub use self::position::AnchorScope;
93pub use self::position::AspectRatio;
94pub use self::position::DashedIdentAndOrTryTactic;
95pub use self::position::Inset;
96pub use self::position::PositionAnchor;
97pub use self::position::PositionTryFallbacks;
98pub use self::position::PositionTryOrder;
99pub use self::position::PositionVisibility;
100pub use self::position::{
101 GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex,
102};
103pub use self::position::{PositionArea, PositionAreaKeyword};
104pub use self::ratio::Ratio;
105pub use self::rect::NonNegativeLengthOrNumberRect;
106pub use self::resolution::Resolution;
107pub use self::svg::{DProperty, MozContextProperties};
108pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
109pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth, VectorEffect};
110pub use self::text::{HyphenateCharacter, HyphenateLimitChars};
111pub use self::text::{InitialLetter, LetterSpacing, LineBreak, TextIndent};
112pub use self::text::{OverflowWrap, RubyPosition, TextOverflow, WordBreak, WordSpacing};
113pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle};
114pub use self::text::{TextAutospace, TextUnderlinePosition};
115pub use self::text::{
116 TextDecorationLength, TextDecorationSkipInk, TextDecorationTrim, TextJustify,
117};
118pub use self::time::Time;
119pub use self::transform::{Rotate, Scale, Transform, TransformBox, TransformOperation};
120pub use self::transform::{TransformOrigin, TransformStyle, Translate};
121#[cfg(feature = "gecko")]
122pub use self::ui::CursorImage;
123pub use self::ui::{
124 BoolInteger, Cursor, Inert, MozTheme, PointerEvents, ScrollbarColor, UserFocus, UserSelect,
125};
126pub use super::specified::TextTransform;
127pub use super::specified::ViewportVariant;
128pub use super::specified::{BorderStyle, TextDecorationLine};
129pub use app_units::Au;
130
131pub mod align;
132pub mod angle;
133pub mod animation;
134pub mod background;
135pub mod basic_shape;
136pub mod border;
137#[path = "box.rs"]
138pub mod box_;
139pub mod color;
140pub mod column;
141pub mod counters;
142pub mod easing;
143pub mod effects;
144pub mod flex;
145pub mod font;
146pub mod image;
147pub mod length;
148pub mod length_percentage;
149pub mod list;
150pub mod motion;
151pub mod outline;
152pub mod page;
153pub mod percentage;
154pub mod position;
155pub mod ratio;
156pub mod rect;
157pub mod resolution;
158pub mod svg;
159pub mod table;
160pub mod text;
161pub mod time;
162pub mod transform;
163pub mod ui;
164pub mod url;
165
166pub struct Context<'a> {
169 pub builder: StyleBuilder<'a>,
173
174 #[cfg(feature = "gecko")]
178 pub cached_system_font: Option<properties::longhands::system_font::ComputedSystemFont>,
179
180 #[cfg(feature = "servo")]
185 pub cached_system_font: Option<()>,
186
187 pub in_media_query: bool,
189
190 pub in_container_query: bool,
192
193 pub quirks_mode: QuirksMode,
195
196 pub for_smil_animation: bool,
201
202 pub container_info: Option<ContainerInfo>,
204
205 pub for_non_inherited_property: bool,
209
210 pub rule_cache_conditions: RefCell<&'a mut RuleCacheConditions>,
214
215 container_size_query: RefCell<ContainerSizeQuery<'a>>,
217}
218
219impl<'a> Context<'a> {
220 pub fn get_container_size_query(&self) -> ContainerSizeQueryResult {
222 let mut resolved = self.container_size_query.borrow_mut();
223 resolved.get().clone()
224 }
225
226 pub fn for_media_query_evaluation<F, R>(device: &Device, quirks_mode: QuirksMode, f: F) -> R
230 where
231 F: FnOnce(&Context) -> R,
232 {
233 let mut conditions = RuleCacheConditions::default();
234 let context = Context {
235 builder: StyleBuilder::for_inheritance(device, None, None, None),
236 cached_system_font: None,
237 in_media_query: true,
238 in_container_query: false,
239 quirks_mode,
240 for_smil_animation: false,
241 container_info: None,
242 for_non_inherited_property: false,
243 rule_cache_conditions: RefCell::new(&mut conditions),
244 container_size_query: RefCell::new(ContainerSizeQuery::none()),
245 };
246 f(&context)
247 }
248
249 pub fn for_container_query_evaluation<F, R>(
252 device: &Device,
253 stylist: Option<&Stylist>,
254 container_info_and_style: Option<(ContainerInfo, Arc<ComputedValues>)>,
255 container_size_query: ContainerSizeQuery,
256 f: F,
257 ) -> R
258 where
259 F: FnOnce(&Context) -> R,
260 {
261 let mut conditions = RuleCacheConditions::default();
262
263 let (container_info, style) = match container_info_and_style {
264 Some((ci, s)) => (Some(ci), Some(s)),
265 None => (None, None),
266 };
267
268 let style = style.as_ref().map(|s| &**s);
269 let quirks_mode = device.quirks_mode();
270 let context = Context {
271 builder: StyleBuilder::for_inheritance(device, stylist, style, None),
272 cached_system_font: None,
273 in_media_query: false,
274 in_container_query: true,
275 quirks_mode,
276 for_smil_animation: false,
277 container_info,
278 for_non_inherited_property: false,
279 rule_cache_conditions: RefCell::new(&mut conditions),
280 container_size_query: RefCell::new(container_size_query),
281 };
282
283 f(&context)
284 }
285
286 pub fn new(
288 builder: StyleBuilder<'a>,
289 quirks_mode: QuirksMode,
290 rule_cache_conditions: &'a mut RuleCacheConditions,
291 container_size_query: ContainerSizeQuery<'a>,
292 ) -> Self {
293 Self {
294 builder,
295 cached_system_font: None,
296 in_media_query: false,
297 in_container_query: false,
298 quirks_mode,
299 container_info: None,
300 for_smil_animation: false,
301 for_non_inherited_property: false,
302 rule_cache_conditions: RefCell::new(rule_cache_conditions),
303 container_size_query: RefCell::new(container_size_query),
304 }
305 }
306
307 pub fn new_for_animation(
309 builder: StyleBuilder<'a>,
310 for_smil_animation: bool,
311 quirks_mode: QuirksMode,
312 rule_cache_conditions: &'a mut RuleCacheConditions,
313 container_size_query: ContainerSizeQuery<'a>,
314 ) -> Self {
315 Self {
316 builder,
317 cached_system_font: None,
318 in_media_query: false,
319 in_container_query: false,
320 quirks_mode,
321 container_info: None,
322 for_smil_animation,
323 for_non_inherited_property: false,
324 rule_cache_conditions: RefCell::new(rule_cache_conditions),
325 container_size_query: RefCell::new(container_size_query),
326 }
327 }
328
329 pub fn new_for_initial_at_property_value(
331 stylist: &'a Stylist,
332 rule_cache_conditions: &'a mut RuleCacheConditions,
333 ) -> Self {
334 Self {
335 builder: StyleBuilder::new(stylist.device(), Some(stylist), None, None, None, false),
336 cached_system_font: None,
337 in_media_query: false,
341 in_container_query: false,
342 quirks_mode: stylist.quirks_mode(),
343 container_info: None,
344 for_smil_animation: false,
345 for_non_inherited_property: false,
346 rule_cache_conditions: RefCell::new(rule_cache_conditions),
347 container_size_query: RefCell::new(ContainerSizeQuery::none()),
348 }
349 }
350
351 pub fn device(&self) -> &Device {
353 self.builder.device
354 }
355
356 pub fn inherited_custom_properties(&self) -> &ComputedCustomProperties {
358 &self.builder.inherited_custom_properties()
359 }
360
361 pub fn is_root_element(&self) -> bool {
363 self.builder.is_root_element
364 }
365
366 pub fn query_font_metrics(
368 &self,
369 base_size: FontBaseSize,
370 orientation: FontMetricsOrientation,
371 mut flags: QueryFontMetricsFlags,
372 ) -> FontMetrics {
373 if self.for_non_inherited_property {
374 self.rule_cache_conditions.borrow_mut().set_uncacheable();
375 }
376 self.builder.add_flags(match base_size {
377 FontBaseSize::CurrentStyle => ComputedValueFlags::DEPENDS_ON_SELF_FONT_METRICS,
378 FontBaseSize::InheritedStyle => ComputedValueFlags::DEPENDS_ON_INHERITED_FONT_METRICS,
379 });
380 let size = base_size.resolve(self).used_size();
381 let style = self.style();
382
383 let (wm, font) = match base_size {
384 FontBaseSize::CurrentStyle => (style.writing_mode, style.get_font()),
385 FontBaseSize::InheritedStyle => {
387 (*style.inherited_writing_mode(), style.get_parent_font())
388 },
389 };
390
391 let vertical = match orientation {
392 FontMetricsOrientation::MatchContextPreferHorizontal => {
393 wm.is_vertical() && wm.is_upright()
394 },
395 FontMetricsOrientation::MatchContextPreferVertical => wm.is_text_vertical(),
396 FontMetricsOrientation::Horizontal => false,
397 };
398 if !self.in_media_query {
399 flags |= QueryFontMetricsFlags::USE_USER_FONT_SET
400 }
401 self.device()
402 .query_font_metrics(vertical, font, size, flags)
403 }
404
405 pub fn viewport_size_for_viewport_unit_resolution(
407 &self,
408 variant: ViewportVariant,
409 ) -> default::Size2D<Au> {
410 self.builder
411 .add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS);
412 self.builder
413 .device
414 .au_viewport_size_for_viewport_unit_resolution(variant)
415 }
416
417 pub fn in_media_or_container_query(&self) -> bool {
419 self.in_media_query || self.in_container_query
420 }
421
422 pub fn default_style(&self) -> &ComputedValues {
424 self.builder.default_style()
425 }
426
427 pub fn style(&self) -> &StyleBuilder {
429 &self.builder
430 }
431
432 #[cfg(feature = "gecko")]
434 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
435 if self
436 .style()
437 .get_font()
438 .clone__x_text_scale()
439 .text_zoom_enabled()
440 {
441 self.device().zoom_text(size)
442 } else {
443 size
444 }
445 }
446
447 #[cfg(feature = "servo")]
449 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
450 size
451 }
452}
453
454#[derive(Clone)]
456pub struct ComputedVecIter<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> {
457 cx: &'cx Context<'cx_a>,
458 values: &'a [S],
459}
460
461impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ComputedVecIter<'a, 'cx, 'cx_a, S> {
462 pub fn new(cx: &'cx Context<'cx_a>, values: &'a [S]) -> Self {
464 ComputedVecIter { cx, values }
465 }
466}
467
468impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ExactSizeIterator
469 for ComputedVecIter<'a, 'cx, 'cx_a, S>
470{
471 fn len(&self) -> usize {
472 self.values.len()
473 }
474}
475
476impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter<'a, 'cx, 'cx_a, S> {
477 type Item = S::ComputedValue;
478 fn next(&mut self) -> Option<Self::Item> {
479 if let Some((next, rest)) = self.values.split_first() {
480 let ret = next.to_computed_value(self.cx);
481 self.values = rest;
482 Some(ret)
483 } else {
484 None
485 }
486 }
487
488 fn size_hint(&self) -> (usize, Option<usize>) {
489 (self.values.len(), Some(self.values.len()))
490 }
491}
492
493pub trait ToComputedValue {
502 type ComputedValue;
504
505 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue;
508
509 fn from_computed_value(computed: &Self::ComputedValue) -> Self;
514}
515
516impl<A, B> ToComputedValue for (A, B)
517where
518 A: ToComputedValue,
519 B: ToComputedValue,
520{
521 type ComputedValue = (
522 <A as ToComputedValue>::ComputedValue,
523 <B as ToComputedValue>::ComputedValue,
524 );
525
526 #[inline]
527 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
528 (
529 self.0.to_computed_value(context),
530 self.1.to_computed_value(context),
531 )
532 }
533
534 #[inline]
535 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
536 (
537 A::from_computed_value(&computed.0),
538 B::from_computed_value(&computed.1),
539 )
540 }
541}
542
543impl<T> ToComputedValue for Option<T>
544where
545 T: ToComputedValue,
546{
547 type ComputedValue = Option<<T as ToComputedValue>::ComputedValue>;
548
549 #[inline]
550 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
551 self.as_ref().map(|item| item.to_computed_value(context))
552 }
553
554 #[inline]
555 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
556 computed.as_ref().map(T::from_computed_value)
557 }
558}
559
560impl<T> ToComputedValue for default::Size2D<T>
561where
562 T: ToComputedValue,
563{
564 type ComputedValue = default::Size2D<<T as ToComputedValue>::ComputedValue>;
565
566 #[inline]
567 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
568 Size2D::new(
569 self.width.to_computed_value(context),
570 self.height.to_computed_value(context),
571 )
572 }
573
574 #[inline]
575 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
576 Size2D::new(
577 T::from_computed_value(&computed.width),
578 T::from_computed_value(&computed.height),
579 )
580 }
581}
582
583impl<T> ToComputedValue for Vec<T>
584where
585 T: ToComputedValue,
586{
587 type ComputedValue = Vec<<T as ToComputedValue>::ComputedValue>;
588
589 #[inline]
590 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
591 self.iter()
592 .map(|item| item.to_computed_value(context))
593 .collect()
594 }
595
596 #[inline]
597 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
598 computed.iter().map(T::from_computed_value).collect()
599 }
600}
601
602impl<T> ToComputedValue for Box<T>
603where
604 T: ToComputedValue,
605{
606 type ComputedValue = Box<<T as ToComputedValue>::ComputedValue>;
607
608 #[inline]
609 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
610 Box::new(T::to_computed_value(self, context))
611 }
612
613 #[inline]
614 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
615 Box::new(T::from_computed_value(computed))
616 }
617}
618
619impl<T> ToComputedValue for Box<[T]>
620where
621 T: ToComputedValue,
622{
623 type ComputedValue = Box<[<T as ToComputedValue>::ComputedValue]>;
624
625 #[inline]
626 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
627 self.iter()
628 .map(|item| item.to_computed_value(context))
629 .collect()
630 }
631
632 #[inline]
633 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
634 computed.iter().map(T::from_computed_value).collect()
635 }
636}
637
638impl<T> ToComputedValue for crate::OwnedSlice<T>
639where
640 T: ToComputedValue,
641{
642 type ComputedValue = crate::OwnedSlice<<T as ToComputedValue>::ComputedValue>;
643
644 #[inline]
645 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
646 self.iter()
647 .map(|item| item.to_computed_value(context))
648 .collect()
649 }
650
651 #[inline]
652 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
653 computed.iter().map(T::from_computed_value).collect()
654 }
655}
656
657impl<T> ToComputedValue for thin_vec::ThinVec<T>
658where
659 T: ToComputedValue,
660{
661 type ComputedValue = thin_vec::ThinVec<<T as ToComputedValue>::ComputedValue>;
662
663 #[inline]
664 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
665 self.iter()
666 .map(|item| item.to_computed_value(context))
667 .collect()
668 }
669
670 #[inline]
671 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
672 computed.iter().map(T::from_computed_value).collect()
673 }
674}
675
676impl<T> ToComputedValue for Arc<T>
682where
683 T: ToComputedValue<ComputedValue = T>,
684{
685 type ComputedValue = Self;
686
687 #[inline]
688 fn to_computed_value(&self, _: &Context) -> Self {
689 self.clone()
690 }
691
692 #[inline]
693 fn from_computed_value(computed: &Self) -> Self {
694 computed.clone()
695 }
696}
697
698impl<T> ToComputedValue for ArcSlice<T>
700where
701 T: ToComputedValue<ComputedValue = T>,
702{
703 type ComputedValue = Self;
704
705 #[inline]
706 fn to_computed_value(&self, _: &Context) -> Self {
707 self.clone()
708 }
709
710 #[inline]
711 fn from_computed_value(computed: &Self) -> Self {
712 computed.clone()
713 }
714}
715
716trivial_to_computed_value!(());
717trivial_to_computed_value!(bool);
718trivial_to_computed_value!(f32);
719trivial_to_computed_value!(i32);
720trivial_to_computed_value!(u8);
721trivial_to_computed_value!(u16);
722trivial_to_computed_value!(u32);
723trivial_to_computed_value!(usize);
724trivial_to_computed_value!(Atom);
725trivial_to_computed_value!(crate::values::AtomIdent);
726#[cfg(feature = "servo")]
727trivial_to_computed_value!(crate::Namespace);
728#[cfg(feature = "servo")]
729trivial_to_computed_value!(crate::Prefix);
730trivial_to_computed_value!(crate::stylesheets::UrlExtraData);
731trivial_to_computed_value!(String);
732trivial_to_computed_value!(Box<str>);
733trivial_to_computed_value!(crate::OwnedStr);
734trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType);
735trivial_to_computed_value!(crate::values::generics::color::ColorMixFlags);
736
737#[allow(missing_docs)]
738#[derive(
739 Animate,
740 Clone,
741 ComputeSquaredDistance,
742 Copy,
743 Debug,
744 MallocSizeOf,
745 PartialEq,
746 ToAnimatedZero,
747 ToCss,
748 ToResolvedValue,
749)]
750#[repr(C, u8)]
751pub enum AngleOrPercentage {
752 Percentage(Percentage),
753 Angle(Angle),
754}
755
756impl ToComputedValue for specified::AngleOrPercentage {
757 type ComputedValue = AngleOrPercentage;
758
759 #[inline]
760 fn to_computed_value(&self, context: &Context) -> AngleOrPercentage {
761 match *self {
762 specified::AngleOrPercentage::Percentage(percentage) => {
763 AngleOrPercentage::Percentage(percentage.to_computed_value(context))
764 },
765 specified::AngleOrPercentage::Angle(angle) => {
766 AngleOrPercentage::Angle(angle.to_computed_value(context))
767 },
768 }
769 }
770 #[inline]
771 fn from_computed_value(computed: &AngleOrPercentage) -> Self {
772 match *computed {
773 AngleOrPercentage::Percentage(percentage) => specified::AngleOrPercentage::Percentage(
774 ToComputedValue::from_computed_value(&percentage),
775 ),
776 AngleOrPercentage::Angle(angle) => {
777 specified::AngleOrPercentage::Angle(ToComputedValue::from_computed_value(&angle))
778 },
779 }
780 }
781}
782
783pub type Number = CSSFloat;
785
786impl IsParallelTo for (Number, Number, Number) {
787 fn is_parallel_to(&self, vector: &DirectionVector) -> bool {
788 use euclid::approxeq::ApproxEq;
789 let self_vector = DirectionVector::new(self.0, self.1, self.2);
792 self_vector
793 .cross(*vector)
794 .square_length()
795 .approx_eq(&0.0f32)
796 }
797}
798
799pub type NonNegativeNumber = NonNegative<CSSFloat>;
801
802impl ToAnimatedValue for NonNegativeNumber {
803 type AnimatedValue = CSSFloat;
804
805 #[inline]
806 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
807 self.0
808 }
809
810 #[inline]
811 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
812 animated.max(0.).into()
813 }
814}
815
816impl From<CSSFloat> for NonNegativeNumber {
817 #[inline]
818 fn from(number: CSSFloat) -> NonNegativeNumber {
819 NonNegative::<CSSFloat>(number)
820 }
821}
822
823impl From<NonNegativeNumber> for CSSFloat {
824 #[inline]
825 fn from(number: NonNegativeNumber) -> CSSFloat {
826 number.0
827 }
828}
829
830impl One for NonNegativeNumber {
831 #[inline]
832 fn one() -> Self {
833 NonNegative(1.0)
834 }
835
836 #[inline]
837 fn is_one(&self) -> bool {
838 self.0 == 1.0
839 }
840}
841
842pub type ZeroToOneNumber = ZeroToOne<CSSFloat>;
844
845impl ToAnimatedValue for ZeroToOneNumber {
846 type AnimatedValue = CSSFloat;
847
848 #[inline]
849 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
850 self.0
851 }
852
853 #[inline]
854 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
855 Self(animated.max(0.).min(1.))
856 }
857}
858
859impl From<CSSFloat> for ZeroToOneNumber {
860 #[inline]
861 fn from(number: CSSFloat) -> Self {
862 Self(number)
863 }
864}
865
866pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<CSSFloat>;
868
869impl ToAnimatedValue for GreaterThanOrEqualToOneNumber {
870 type AnimatedValue = CSSFloat;
871
872 #[inline]
873 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
874 self.0
875 }
876
877 #[inline]
878 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
879 animated.max(1.).into()
880 }
881}
882
883impl From<CSSFloat> for GreaterThanOrEqualToOneNumber {
884 #[inline]
885 fn from(number: CSSFloat) -> GreaterThanOrEqualToOneNumber {
886 GreaterThanOrEqualToOne::<CSSFloat>(number)
887 }
888}
889
890impl From<GreaterThanOrEqualToOneNumber> for CSSFloat {
891 #[inline]
892 fn from(number: GreaterThanOrEqualToOneNumber) -> CSSFloat {
893 number.0
894 }
895}
896
897#[allow(missing_docs)]
898#[derive(
899 Animate,
900 Clone,
901 ComputeSquaredDistance,
902 Copy,
903 Debug,
904 MallocSizeOf,
905 PartialEq,
906 ToAnimatedZero,
907 ToCss,
908 ToResolvedValue,
909)]
910#[repr(C, u8)]
911pub enum NumberOrPercentage {
912 Percentage(Percentage),
913 Number(Number),
914}
915
916impl NumberOrPercentage {
917 fn clamp_to_non_negative(self) -> Self {
918 match self {
919 NumberOrPercentage::Percentage(p) => {
920 NumberOrPercentage::Percentage(p.clamp_to_non_negative())
921 },
922 NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.max(0.)),
923 }
924 }
925}
926
927impl ToComputedValue for specified::NumberOrPercentage {
928 type ComputedValue = NumberOrPercentage;
929
930 #[inline]
931 fn to_computed_value(&self, context: &Context) -> NumberOrPercentage {
932 match *self {
933 specified::NumberOrPercentage::Percentage(percentage) => {
934 NumberOrPercentage::Percentage(percentage.to_computed_value(context))
935 },
936 specified::NumberOrPercentage::Number(number) => {
937 NumberOrPercentage::Number(number.to_computed_value(context))
938 },
939 }
940 }
941 #[inline]
942 fn from_computed_value(computed: &NumberOrPercentage) -> Self {
943 match *computed {
944 NumberOrPercentage::Percentage(percentage) => {
945 specified::NumberOrPercentage::Percentage(ToComputedValue::from_computed_value(
946 &percentage,
947 ))
948 },
949 NumberOrPercentage::Number(number) => {
950 specified::NumberOrPercentage::Number(ToComputedValue::from_computed_value(&number))
951 },
952 }
953 }
954}
955
956pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
958
959impl NonNegativeNumberOrPercentage {
960 #[inline]
962 pub fn hundred_percent() -> Self {
963 NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
964 }
965}
966
967impl ToAnimatedValue for NonNegativeNumberOrPercentage {
968 type AnimatedValue = NumberOrPercentage;
969
970 #[inline]
971 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
972 self.0
973 }
974
975 #[inline]
976 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
977 NonNegative(animated.clamp_to_non_negative())
978 }
979}
980
981pub type Opacity = CSSFloat;
983
984pub type Integer = CSSInteger;
986
987pub type PositiveInteger = GreaterThanOrEqualToOne<CSSInteger>;
989
990impl ToAnimatedValue for PositiveInteger {
991 type AnimatedValue = CSSInteger;
992
993 #[inline]
994 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
995 self.0
996 }
997
998 #[inline]
999 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
1000 cmp::max(animated, 1).into()
1001 }
1002}
1003
1004impl From<CSSInteger> for PositiveInteger {
1005 #[inline]
1006 fn from(int: CSSInteger) -> PositiveInteger {
1007 GreaterThanOrEqualToOne::<CSSInteger>(int)
1008 }
1009}
1010
1011pub type ClipRect = generics::GenericClipRect<LengthOrAuto>;
1013
1014pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>;
1016
1017pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
1019
1020pub type TrackSize = GenericTrackSize<LengthPercentage>;
1022
1023pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>;
1025
1026pub type TrackList = GenericTrackList<LengthPercentage, Integer>;
1029
1030pub type GridLine = GenericGridLine<Integer>;
1032
1033pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
1035
1036impl ClipRect {
1037 pub fn for_border_rect<T: Copy + From<Length> + Add<Output = T> + Sub<Output = T>, U>(
1040 &self,
1041 border_box: Rect<T, U>,
1042 ) -> Rect<T, U> {
1043 fn extract_clip_component<T: From<Length>>(p: &LengthOrAuto, or: T) -> T {
1044 match *p {
1045 LengthOrAuto::Auto => or,
1046 LengthOrAuto::LengthPercentage(ref length) => T::from(*length),
1047 }
1048 }
1049
1050 let clip_origin = Point2D::new(
1051 From::from(self.left.auto_is(|| Length::new(0.))),
1052 From::from(self.top.auto_is(|| Length::new(0.))),
1053 );
1054 let right = extract_clip_component(&self.right, border_box.size.width);
1055 let bottom = extract_clip_component(&self.bottom, border_box.size.height);
1056 let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
1057
1058 Rect::new(clip_origin, clip_size).translate(border_box.origin.to_vector())
1059 }
1060}