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