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::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontSynthesisStyle, LineHeight};
73pub use self::font::{FontVariantAlternates, FontWeight};
74pub use self::font::{FontVariantEastAsian, FontVariationSettings};
75pub use self::font::{MathDepth, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextScale};
76pub use self::image::{Gradient, Image, ImageRendering, LineDirection};
77pub use self::length::{AnchorSizeFunction, CSSPixelLength, NonNegativeLength};
78pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
79pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Margin, Size};
80pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
81#[cfg(feature = "gecko")]
82pub use self::list::ListStyleType;
83pub use self::list::Quotes;
84pub use self::motion::{OffsetPath, OffsetPosition, OffsetRotate};
85pub use self::outline::OutlineStyle;
86pub use self::page::{PageName, PageOrientation, PageSize, PageSizeOrientation, PaperSize};
87pub use self::percentage::{NonNegativePercentage, Percentage};
88pub use self::position::AnchorFunction;
89pub use self::position::AnchorName;
90pub use self::position::AnchorScope;
91pub use self::position::AspectRatio;
92pub use self::position::DashedIdentAndOrTryTactic;
93pub use self::position::Inset;
94pub use self::position::PositionAnchor;
95pub use self::position::PositionTryFallbacks;
96pub use self::position::PositionTryOrder;
97pub use self::position::PositionVisibility;
98pub use self::position::{
99 GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex,
100};
101pub use self::position::{PositionArea, PositionAreaKeyword};
102pub use self::ratio::Ratio;
103pub use self::rect::NonNegativeLengthOrNumberRect;
104pub use self::resolution::Resolution;
105pub use self::svg::{DProperty, MozContextProperties};
106pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
107pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth, VectorEffect};
108pub use self::text::{HyphenateCharacter, HyphenateLimitChars};
109pub use self::text::TextUnderlinePosition;
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::{TextDecorationLength, TextDecorationSkipInk, TextJustify};
114pub use self::time::Time;
115pub use self::transform::{Rotate, Scale, Transform, TransformBox, TransformOperation};
116pub use self::transform::{TransformOrigin, TransformStyle, Translate};
117#[cfg(feature = "gecko")]
118pub use self::ui::CursorImage;
119pub use self::ui::{
120 BoolInteger, Cursor, Inert, MozTheme, PointerEvents, ScrollbarColor, UserFocus, UserInput,
121 UserSelect,
122};
123pub use super::specified::TextTransform;
124pub use super::specified::ViewportVariant;
125pub use super::specified::{BorderStyle, TextDecorationLine};
126pub use app_units::Au;
127
128pub mod align;
129pub mod angle;
130pub mod animation;
131pub mod background;
132pub mod basic_shape;
133pub mod border;
134#[path = "box.rs"]
135pub mod box_;
136pub mod color;
137pub mod column;
138pub mod counters;
139pub mod easing;
140pub mod effects;
141pub mod flex;
142pub mod font;
143pub mod image;
144pub mod length;
145pub mod length_percentage;
146pub mod list;
147pub mod motion;
148pub mod outline;
149pub mod page;
150pub mod percentage;
151pub mod position;
152pub mod ratio;
153pub mod rect;
154pub mod resolution;
155pub mod svg;
156pub mod table;
157pub mod text;
158pub mod time;
159pub mod transform;
160pub mod ui;
161pub mod url;
162
163pub struct Context<'a> {
166 pub builder: StyleBuilder<'a>,
170
171 #[cfg(feature = "gecko")]
175 pub cached_system_font: Option<properties::longhands::system_font::ComputedSystemFont>,
176
177 #[cfg(feature = "servo")]
182 pub cached_system_font: Option<()>,
183
184 pub in_media_query: bool,
186
187 pub in_container_query: bool,
189
190 pub quirks_mode: QuirksMode,
192
193 pub for_smil_animation: bool,
198
199 pub container_info: Option<ContainerInfo>,
201
202 pub for_non_inherited_property: bool,
206
207 pub rule_cache_conditions: RefCell<&'a mut RuleCacheConditions>,
211
212 container_size_query: RefCell<ContainerSizeQuery<'a>>,
214}
215
216impl<'a> Context<'a> {
217 pub fn get_container_size_query(&self) -> ContainerSizeQueryResult {
219 let mut resolved = self.container_size_query.borrow_mut();
220 resolved.get().clone()
221 }
222
223 pub fn for_media_query_evaluation<F, R>(device: &Device, quirks_mode: QuirksMode, f: F) -> R
227 where
228 F: FnOnce(&Context) -> R,
229 {
230 let mut conditions = RuleCacheConditions::default();
231 let context = Context {
232 builder: StyleBuilder::for_inheritance(device, None, None, None),
233 cached_system_font: None,
234 in_media_query: true,
235 in_container_query: false,
236 quirks_mode,
237 for_smil_animation: false,
238 container_info: None,
239 for_non_inherited_property: false,
240 rule_cache_conditions: RefCell::new(&mut conditions),
241 container_size_query: RefCell::new(ContainerSizeQuery::none()),
242 };
243 f(&context)
244 }
245
246 pub fn for_container_query_evaluation<F, R>(
249 device: &Device,
250 stylist: Option<&Stylist>,
251 container_info_and_style: Option<(ContainerInfo, Arc<ComputedValues>)>,
252 container_size_query: ContainerSizeQuery,
253 f: F,
254 ) -> R
255 where
256 F: FnOnce(&Context) -> R,
257 {
258 let mut conditions = RuleCacheConditions::default();
259
260 let (container_info, style) = match container_info_and_style {
261 Some((ci, s)) => (Some(ci), Some(s)),
262 None => (None, None),
263 };
264
265 let style = style.as_ref().map(|s| &**s);
266 let quirks_mode = device.quirks_mode();
267 let context = Context {
268 builder: StyleBuilder::for_inheritance(device, stylist, style, None),
269 cached_system_font: None,
270 in_media_query: false,
271 in_container_query: true,
272 quirks_mode,
273 for_smil_animation: false,
274 container_info,
275 for_non_inherited_property: false,
276 rule_cache_conditions: RefCell::new(&mut conditions),
277 container_size_query: RefCell::new(container_size_query),
278 };
279
280 f(&context)
281 }
282
283 pub fn new(
285 builder: StyleBuilder<'a>,
286 quirks_mode: QuirksMode,
287 rule_cache_conditions: &'a mut RuleCacheConditions,
288 container_size_query: ContainerSizeQuery<'a>,
289 ) -> Self {
290 Self {
291 builder,
292 cached_system_font: None,
293 in_media_query: false,
294 in_container_query: false,
295 quirks_mode,
296 container_info: None,
297 for_smil_animation: false,
298 for_non_inherited_property: false,
299 rule_cache_conditions: RefCell::new(rule_cache_conditions),
300 container_size_query: RefCell::new(container_size_query),
301 }
302 }
303
304 pub fn new_for_animation(
306 builder: StyleBuilder<'a>,
307 for_smil_animation: bool,
308 quirks_mode: QuirksMode,
309 rule_cache_conditions: &'a mut RuleCacheConditions,
310 container_size_query: ContainerSizeQuery<'a>,
311 ) -> Self {
312 Self {
313 builder,
314 cached_system_font: None,
315 in_media_query: false,
316 in_container_query: false,
317 quirks_mode,
318 container_info: None,
319 for_smil_animation,
320 for_non_inherited_property: false,
321 rule_cache_conditions: RefCell::new(rule_cache_conditions),
322 container_size_query: RefCell::new(container_size_query),
323 }
324 }
325
326 pub fn new_for_initial_at_property_value(
328 stylist: &'a Stylist,
329 rule_cache_conditions: &'a mut RuleCacheConditions,
330 ) -> Self {
331 Self {
332 builder: StyleBuilder::new(stylist.device(), Some(stylist), None, None, None, false),
333 cached_system_font: None,
334 in_media_query: false,
338 in_container_query: false,
339 quirks_mode: stylist.quirks_mode(),
340 container_info: None,
341 for_smil_animation: false,
342 for_non_inherited_property: false,
343 rule_cache_conditions: RefCell::new(rule_cache_conditions),
344 container_size_query: RefCell::new(ContainerSizeQuery::none()),
345 }
346 }
347
348 pub fn device(&self) -> &Device {
350 self.builder.device
351 }
352
353 pub fn inherited_custom_properties(&self) -> &ComputedCustomProperties {
355 &self.builder.inherited_custom_properties()
356 }
357
358 pub fn is_root_element(&self) -> bool {
360 self.builder.is_root_element
361 }
362
363 pub fn query_font_metrics(
365 &self,
366 base_size: FontBaseSize,
367 orientation: FontMetricsOrientation,
368 mut flags: QueryFontMetricsFlags,
369 ) -> FontMetrics {
370 if self.for_non_inherited_property {
371 self.rule_cache_conditions.borrow_mut().set_uncacheable();
372 }
373 self.builder.add_flags(match base_size {
374 FontBaseSize::CurrentStyle => ComputedValueFlags::DEPENDS_ON_SELF_FONT_METRICS,
375 FontBaseSize::InheritedStyle => ComputedValueFlags::DEPENDS_ON_INHERITED_FONT_METRICS,
376 });
377 let size = base_size.resolve(self).used_size();
378 let style = self.style();
379
380 let (wm, font) = match base_size {
381 FontBaseSize::CurrentStyle => (style.writing_mode, style.get_font()),
382 FontBaseSize::InheritedStyle => {
384 (*style.inherited_writing_mode(), style.get_parent_font())
385 },
386 };
387
388 let vertical = match orientation {
389 FontMetricsOrientation::MatchContextPreferHorizontal => {
390 wm.is_vertical() && wm.is_upright()
391 },
392 FontMetricsOrientation::MatchContextPreferVertical => wm.is_text_vertical(),
393 FontMetricsOrientation::Horizontal => false,
394 };
395 if !self.in_media_query {
396 flags |= QueryFontMetricsFlags::USE_USER_FONT_SET
397 }
398 self.device().query_font_metrics(
399 vertical,
400 font,
401 size,
402 flags,
403 )
404 }
405
406 pub fn viewport_size_for_viewport_unit_resolution(
408 &self,
409 variant: ViewportVariant,
410 ) -> default::Size2D<Au> {
411 self.builder
412 .add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS);
413 self.builder
414 .device
415 .au_viewport_size_for_viewport_unit_resolution(variant)
416 }
417
418 pub fn in_media_or_container_query(&self) -> bool {
420 self.in_media_query || self.in_container_query
421 }
422
423 pub fn default_style(&self) -> &ComputedValues {
425 self.builder.default_style()
426 }
427
428 pub fn style(&self) -> &StyleBuilder {
430 &self.builder
431 }
432
433 #[cfg(feature = "gecko")]
435 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
436 if self
437 .style()
438 .get_font()
439 .clone__x_text_scale()
440 .text_zoom_enabled()
441 {
442 self.device().zoom_text(size)
443 } else {
444 size
445 }
446 }
447
448 #[cfg(feature = "servo")]
450 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
451 size
452 }
453}
454
455#[derive(Clone)]
457pub struct ComputedVecIter<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> {
458 cx: &'cx Context<'cx_a>,
459 values: &'a [S],
460}
461
462impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ComputedVecIter<'a, 'cx, 'cx_a, S> {
463 pub fn new(cx: &'cx Context<'cx_a>, values: &'a [S]) -> Self {
465 ComputedVecIter { cx, values }
466 }
467}
468
469impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ExactSizeIterator
470 for ComputedVecIter<'a, 'cx, 'cx_a, S>
471{
472 fn len(&self) -> usize {
473 self.values.len()
474 }
475}
476
477impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter<'a, 'cx, 'cx_a, S> {
478 type Item = S::ComputedValue;
479 fn next(&mut self) -> Option<Self::Item> {
480 if let Some((next, rest)) = self.values.split_first() {
481 let ret = next.to_computed_value(self.cx);
482 self.values = rest;
483 Some(ret)
484 } else {
485 None
486 }
487 }
488
489 fn size_hint(&self) -> (usize, Option<usize>) {
490 (self.values.len(), Some(self.values.len()))
491 }
492}
493
494pub trait ToComputedValue {
503 type ComputedValue;
505
506 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue;
509
510 fn from_computed_value(computed: &Self::ComputedValue) -> Self;
515}
516
517impl<A, B> ToComputedValue for (A, B)
518where
519 A: ToComputedValue,
520 B: ToComputedValue,
521{
522 type ComputedValue = (
523 <A as ToComputedValue>::ComputedValue,
524 <B as ToComputedValue>::ComputedValue,
525 );
526
527 #[inline]
528 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
529 (
530 self.0.to_computed_value(context),
531 self.1.to_computed_value(context),
532 )
533 }
534
535 #[inline]
536 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
537 (
538 A::from_computed_value(&computed.0),
539 B::from_computed_value(&computed.1),
540 )
541 }
542}
543
544impl<T> ToComputedValue for Option<T>
545where
546 T: ToComputedValue,
547{
548 type ComputedValue = Option<<T as ToComputedValue>::ComputedValue>;
549
550 #[inline]
551 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
552 self.as_ref().map(|item| item.to_computed_value(context))
553 }
554
555 #[inline]
556 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
557 computed.as_ref().map(T::from_computed_value)
558 }
559}
560
561impl<T> ToComputedValue for default::Size2D<T>
562where
563 T: ToComputedValue,
564{
565 type ComputedValue = default::Size2D<<T as ToComputedValue>::ComputedValue>;
566
567 #[inline]
568 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
569 Size2D::new(
570 self.width.to_computed_value(context),
571 self.height.to_computed_value(context),
572 )
573 }
574
575 #[inline]
576 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
577 Size2D::new(
578 T::from_computed_value(&computed.width),
579 T::from_computed_value(&computed.height),
580 )
581 }
582}
583
584impl<T> ToComputedValue for Vec<T>
585where
586 T: ToComputedValue,
587{
588 type ComputedValue = Vec<<T as ToComputedValue>::ComputedValue>;
589
590 #[inline]
591 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
592 self.iter()
593 .map(|item| item.to_computed_value(context))
594 .collect()
595 }
596
597 #[inline]
598 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
599 computed.iter().map(T::from_computed_value).collect()
600 }
601}
602
603impl<T> ToComputedValue for Box<T>
604where
605 T: ToComputedValue,
606{
607 type ComputedValue = Box<<T as ToComputedValue>::ComputedValue>;
608
609 #[inline]
610 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
611 Box::new(T::to_computed_value(self, context))
612 }
613
614 #[inline]
615 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
616 Box::new(T::from_computed_value(computed))
617 }
618}
619
620impl<T> ToComputedValue for Box<[T]>
621where
622 T: ToComputedValue,
623{
624 type ComputedValue = Box<[<T as ToComputedValue>::ComputedValue]>;
625
626 #[inline]
627 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
628 self.iter().map(|item| item.to_computed_value(context)).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}