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::derives::*;
21use crate::font_metrics::{FontMetrics, FontMetricsOrientation};
22use crate::media_queries::Device;
23#[cfg(feature = "gecko")]
24use crate::properties;
25use crate::properties::{ComputedValues, StyleBuilder};
26use crate::rule_cache::RuleCacheConditions;
27use crate::stylesheets::container_rule::{
28 ContainerInfo, ContainerSizeQuery, ContainerSizeQueryResult,
29};
30use crate::stylist::Stylist;
31use crate::values::generics::ClampToNonNegative;
32use crate::values::specified::font::QueryFontMetricsFlags;
33use crate::values::specified::length::FontBaseSize;
34use crate::{ArcSlice, Atom, One};
35use euclid::{default, Point2D, Rect, Size2D};
36use servo_arc::Arc;
37use std::cell::RefCell;
38use std::cmp;
39use std::f32;
40use std::ops::{Add, Sub};
41
42pub use self::align::{ContentDistribution, ItemPlacement, JustifyItems, SelfAlignment};
43pub use self::angle::Angle;
44pub use self::animation::{
45 AnimationComposition, AnimationDirection, AnimationDuration, AnimationFillMode,
46 AnimationIterationCount, AnimationName, AnimationPlayState, AnimationTimeline, ScrollAxis,
47 TimelineName, TransitionBehavior, TransitionProperty, ViewTimelineInset, ViewTransitionClass,
48 ViewTransitionName,
49};
50pub use self::background::{BackgroundRepeat, BackgroundSize};
51pub use self::basic_shape::FillRule;
52pub use self::border::{
53 BorderCornerRadius, BorderImageRepeat, BorderImageSideWidth, BorderImageSlice,
54 BorderImageWidth, BorderRadius, BorderSideOffset, BorderSideWidth, BorderSpacing, LineWidth,
55};
56pub use self::box_::{
57 Appearance, BaselineSource, BreakBetween, BreakWithin, Clear, Contain, ContainIntrinsicSize,
58 ContainerName, ContainerType, ContentVisibility, Display, Float, LineClamp, Overflow,
59 OverflowAnchor, OverflowClipMargin, OverscrollBehavior, Perspective, PositionProperty, Resize,
60 ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStop, ScrollSnapStrictness, ScrollSnapType,
61 ScrollbarGutter, TouchAction, VerticalAlign, WillChange, WritingModeProperty, Zoom,
62};
63pub use self::color::{
64 Color, ColorOrAuto, ColorPropertyValue, ColorScheme, ForcedColorAdjust, PrintColorAdjust,
65};
66pub use self::column::ColumnCount;
67pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset, CounterSet};
68pub use self::easing::TimingFunction;
69pub use self::effects::{BoxShadow, Filter, SimpleShadow};
70pub use self::flex::FlexBasis;
71pub use self::font::{FontFamily, FontLanguageOverride, FontPalette, FontStyle};
72pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
73pub use self::font::{
74 FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontSynthesisStyle, LineHeight,
75};
76pub use self::font::{FontVariantAlternates, FontWeight};
77pub use self::font::{FontVariantEastAsian, FontVariationSettings};
78pub use self::font::{MathDepth, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextScale};
79pub use self::image::{Gradient, Image, ImageRendering, LineDirection};
80pub use self::length::{CSSPixelLength, NonNegativeLength};
81pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
82pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, Margin, MaxSize, Size};
83pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
84#[cfg(feature = "gecko")]
85pub use self::list::ListStyleType;
86pub use self::list::Quotes;
87pub use self::motion::{OffsetPath, OffsetPosition, OffsetRotate};
88pub use self::outline::OutlineStyle;
89pub use self::page::{PageName, PageOrientation, PageSize, PageSizeOrientation, PaperSize};
90pub use self::percentage::{NonNegativePercentage, Percentage};
91pub use self::position::AnchorFunction;
92pub use self::position::AnchorName;
93pub use self::position::AnchorScope;
94pub use self::position::AspectRatio;
95pub use self::position::DashedIdentAndOrTryTactic;
96pub use self::position::Inset;
97pub use self::position::PositionAnchor;
98pub use self::position::PositionTryFallbacks;
99pub use self::position::PositionTryOrder;
100pub use self::position::PositionVisibility;
101pub use self::position::{
102 GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex,
103};
104pub use self::position::{PositionArea, PositionAreaKeyword};
105pub use self::ratio::Ratio;
106pub use self::rect::NonNegativeLengthOrNumberRect;
107pub use self::resolution::Resolution;
108pub use self::svg::{DProperty, MozContextProperties};
109pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
110pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth, VectorEffect};
111pub use self::text::{HyphenateCharacter, HyphenateLimitChars};
112pub use self::text::{InitialLetter, LetterSpacing, LineBreak, TextIndent};
113pub use self::text::{OverflowWrap, RubyPosition, TextOverflow, WordBreak, WordSpacing};
114pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle};
115pub use self::text::{TextAutospace, TextUnderlinePosition};
116pub use self::text::{
117 TextDecorationInset, TextDecorationLength, TextDecorationSkipInk, TextJustify,
118};
119pub use self::time::Time;
120pub use self::transform::{Rotate, Scale, Transform, TransformBox, TransformOperation};
121pub use self::transform::{TransformOrigin, TransformStyle, Translate};
122#[cfg(feature = "gecko")]
123pub use self::ui::CursorImage;
124pub use self::ui::{
125 BoolInteger, Cursor, Inert, MozTheme, PointerEvents, ScrollbarColor, UserFocus, UserSelect,
126};
127pub use super::specified::TextTransform;
128pub use super::specified::ViewportVariant;
129pub use super::specified::{BorderStyle, TextDecorationLine};
130pub use app_units::Au;
131
132pub mod align;
133pub mod angle;
134pub mod animation;
135pub mod background;
136pub mod basic_shape;
137pub mod border;
138#[path = "box.rs"]
139pub mod box_;
140pub mod color;
141pub mod column;
142pub mod counters;
143pub mod easing;
144pub mod effects;
145pub mod flex;
146pub mod font;
147pub mod image;
148pub mod length;
149pub mod length_percentage;
150pub mod list;
151pub mod motion;
152pub mod outline;
153pub mod page;
154pub mod percentage;
155pub mod position;
156pub mod ratio;
157pub mod rect;
158pub mod resolution;
159pub mod svg;
160pub mod table;
161pub mod text;
162pub mod time;
163pub mod transform;
164pub mod ui;
165pub mod url;
166
167pub struct Context<'a> {
170 pub builder: StyleBuilder<'a>,
174
175 #[cfg(feature = "gecko")]
179 pub cached_system_font: Option<properties::longhands::system_font::ComputedSystemFont>,
180
181 #[cfg(feature = "servo")]
186 pub cached_system_font: Option<()>,
187
188 pub in_media_query: bool,
190
191 pub in_container_query: bool,
193
194 pub quirks_mode: QuirksMode,
196
197 pub for_smil_animation: bool,
202
203 pub container_info: Option<ContainerInfo>,
205
206 pub for_non_inherited_property: bool,
210
211 pub rule_cache_conditions: RefCell<&'a mut RuleCacheConditions>,
215
216 container_size_query: RefCell<ContainerSizeQuery<'a>>,
218}
219
220impl<'a> Context<'a> {
221 pub fn get_container_size_query(&self) -> ContainerSizeQueryResult {
223 let mut resolved = self.container_size_query.borrow_mut();
224 resolved.get().clone()
225 }
226
227 pub fn for_media_query_evaluation<F, R>(device: &Device, quirks_mode: QuirksMode, f: F) -> R
231 where
232 F: FnOnce(&Context) -> R,
233 {
234 let mut conditions = RuleCacheConditions::default();
235 let context = Context {
236 builder: StyleBuilder::for_inheritance(device, None, None, None),
237 cached_system_font: None,
238 in_media_query: true,
239 in_container_query: false,
240 quirks_mode,
241 for_smil_animation: false,
242 container_info: None,
243 for_non_inherited_property: false,
244 rule_cache_conditions: RefCell::new(&mut conditions),
245 container_size_query: RefCell::new(ContainerSizeQuery::none()),
246 };
247 f(&context)
248 }
249
250 pub fn for_container_query_evaluation<F, R>(
253 device: &Device,
254 stylist: Option<&Stylist>,
255 container_info_and_style: Option<(ContainerInfo, Arc<ComputedValues>)>,
256 container_size_query: ContainerSizeQuery,
257 f: F,
258 ) -> R
259 where
260 F: FnOnce(&Context) -> R,
261 {
262 let mut conditions = RuleCacheConditions::default();
263
264 let (container_info, style) = match container_info_and_style {
265 Some((ci, s)) => (Some(ci), Some(s)),
266 None => (None, None),
267 };
268
269 let style = style.as_ref().map(|s| &**s);
270 let quirks_mode = device.quirks_mode();
271 let context = Context {
272 builder: StyleBuilder::for_inheritance(device, stylist, style, None),
273 cached_system_font: None,
274 in_media_query: false,
275 in_container_query: true,
276 quirks_mode,
277 for_smil_animation: false,
278 container_info,
279 for_non_inherited_property: false,
280 rule_cache_conditions: RefCell::new(&mut conditions),
281 container_size_query: RefCell::new(container_size_query),
282 };
283
284 f(&context)
285 }
286
287 pub fn new(
289 builder: StyleBuilder<'a>,
290 quirks_mode: QuirksMode,
291 rule_cache_conditions: &'a mut RuleCacheConditions,
292 container_size_query: ContainerSizeQuery<'a>,
293 ) -> Self {
294 Self {
295 builder,
296 cached_system_font: None,
297 in_media_query: false,
298 in_container_query: false,
299 quirks_mode,
300 container_info: None,
301 for_smil_animation: false,
302 for_non_inherited_property: false,
303 rule_cache_conditions: RefCell::new(rule_cache_conditions),
304 container_size_query: RefCell::new(container_size_query),
305 }
306 }
307
308 pub fn new_for_animation(
310 builder: StyleBuilder<'a>,
311 for_smil_animation: bool,
312 quirks_mode: QuirksMode,
313 rule_cache_conditions: &'a mut RuleCacheConditions,
314 container_size_query: ContainerSizeQuery<'a>,
315 ) -> Self {
316 Self {
317 builder,
318 cached_system_font: None,
319 in_media_query: false,
320 in_container_query: false,
321 quirks_mode,
322 container_info: None,
323 for_smil_animation,
324 for_non_inherited_property: false,
325 rule_cache_conditions: RefCell::new(rule_cache_conditions),
326 container_size_query: RefCell::new(container_size_query),
327 }
328 }
329
330 pub fn new_for_initial_at_property_value(
332 stylist: &'a Stylist,
333 rule_cache_conditions: &'a mut RuleCacheConditions,
334 ) -> Self {
335 Self {
336 builder: StyleBuilder::new(stylist.device(), Some(stylist), None, None, None, false),
337 cached_system_font: None,
338 in_media_query: false,
342 in_container_query: false,
343 quirks_mode: stylist.quirks_mode(),
344 container_info: None,
345 for_smil_animation: false,
346 for_non_inherited_property: false,
347 rule_cache_conditions: RefCell::new(rule_cache_conditions),
348 container_size_query: RefCell::new(ContainerSizeQuery::none()),
349 }
350 }
351
352 pub fn device(&self) -> &Device {
354 self.builder.device
355 }
356
357 pub fn inherited_custom_properties(&self) -> &ComputedCustomProperties {
359 &self.builder.inherited_custom_properties()
360 }
361
362 pub fn is_root_element(&self) -> bool {
364 self.builder.is_root_element
365 }
366
367 pub fn query_font_metrics(
369 &self,
370 base_size: FontBaseSize,
371 orientation: FontMetricsOrientation,
372 mut flags: QueryFontMetricsFlags,
373 ) -> FontMetrics {
374 if self.for_non_inherited_property {
375 self.rule_cache_conditions.borrow_mut().set_uncacheable();
376 }
377 self.builder.add_flags(match base_size {
378 FontBaseSize::CurrentStyle => ComputedValueFlags::DEPENDS_ON_SELF_FONT_METRICS,
379 FontBaseSize::InheritedStyle => ComputedValueFlags::DEPENDS_ON_INHERITED_FONT_METRICS,
380 });
381 let size = base_size.resolve(self).used_size();
382 let style = self.style();
383
384 let (wm, font) = match base_size {
385 FontBaseSize::CurrentStyle => (style.writing_mode, style.get_font()),
386 FontBaseSize::InheritedStyle => {
388 (*style.inherited_writing_mode(), style.get_parent_font())
389 },
390 };
391
392 let vertical = match orientation {
393 FontMetricsOrientation::MatchContextPreferHorizontal => {
394 wm.is_vertical() && wm.is_upright()
395 },
396 FontMetricsOrientation::MatchContextPreferVertical => wm.is_text_vertical(),
397 FontMetricsOrientation::Horizontal => false,
398 };
399 if !self.in_media_query {
400 flags |= QueryFontMetricsFlags::USE_USER_FONT_SET
401 }
402 self.device()
403 .query_font_metrics(vertical, font, size, flags, true)
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<'a> {
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()
629 .map(|item| item.to_computed_value(context))
630 .collect()
631 }
632
633 #[inline]
634 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
635 computed.iter().map(T::from_computed_value).collect()
636 }
637}
638
639impl<T> ToComputedValue for crate::OwnedSlice<T>
640where
641 T: ToComputedValue,
642{
643 type ComputedValue = crate::OwnedSlice<<T as ToComputedValue>::ComputedValue>;
644
645 #[inline]
646 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
647 self.iter()
648 .map(|item| item.to_computed_value(context))
649 .collect()
650 }
651
652 #[inline]
653 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
654 computed.iter().map(T::from_computed_value).collect()
655 }
656}
657
658impl<T> ToComputedValue for thin_vec::ThinVec<T>
659where
660 T: ToComputedValue,
661{
662 type ComputedValue = thin_vec::ThinVec<<T as ToComputedValue>::ComputedValue>;
663
664 #[inline]
665 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
666 self.iter()
667 .map(|item| item.to_computed_value(context))
668 .collect()
669 }
670
671 #[inline]
672 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
673 computed.iter().map(T::from_computed_value).collect()
674 }
675}
676
677impl<T> ToComputedValue for Arc<T>
683where
684 T: ToComputedValue<ComputedValue = T>,
685{
686 type ComputedValue = Self;
687
688 #[inline]
689 fn to_computed_value(&self, _: &Context) -> Self {
690 self.clone()
691 }
692
693 #[inline]
694 fn from_computed_value(computed: &Self) -> Self {
695 computed.clone()
696 }
697}
698
699impl<T> ToComputedValue for ArcSlice<T>
701where
702 T: ToComputedValue<ComputedValue = T>,
703{
704 type ComputedValue = Self;
705
706 #[inline]
707 fn to_computed_value(&self, _: &Context) -> Self {
708 self.clone()
709 }
710
711 #[inline]
712 fn from_computed_value(computed: &Self) -> Self {
713 computed.clone()
714 }
715}
716
717trivial_to_computed_value!(());
718trivial_to_computed_value!(bool);
719trivial_to_computed_value!(f32);
720trivial_to_computed_value!(i32);
721trivial_to_computed_value!(u8);
722trivial_to_computed_value!(u16);
723trivial_to_computed_value!(u32);
724trivial_to_computed_value!(usize);
725trivial_to_computed_value!(Atom);
726trivial_to_computed_value!(crate::values::AtomIdent);
727#[cfg(feature = "servo")]
728trivial_to_computed_value!(crate::Namespace);
729#[cfg(feature = "servo")]
730trivial_to_computed_value!(crate::Prefix);
731trivial_to_computed_value!(crate::stylesheets::UrlExtraData);
732trivial_to_computed_value!(String);
733trivial_to_computed_value!(Box<str>);
734trivial_to_computed_value!(crate::OwnedStr);
735trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType);
736trivial_to_computed_value!(crate::values::generics::color::ColorMixFlags);
737
738#[allow(missing_docs)]
739#[derive(
740 Animate,
741 Clone,
742 ComputeSquaredDistance,
743 Copy,
744 Debug,
745 MallocSizeOf,
746 PartialEq,
747 ToAnimatedZero,
748 ToCss,
749 ToResolvedValue,
750)]
751#[repr(C, u8)]
752pub enum AngleOrPercentage {
753 Percentage(Percentage),
754 Angle(Angle),
755}
756
757impl ToComputedValue for specified::AngleOrPercentage {
758 type ComputedValue = AngleOrPercentage;
759
760 #[inline]
761 fn to_computed_value(&self, context: &Context) -> AngleOrPercentage {
762 match *self {
763 specified::AngleOrPercentage::Percentage(percentage) => {
764 AngleOrPercentage::Percentage(percentage.to_computed_value(context))
765 },
766 specified::AngleOrPercentage::Angle(angle) => {
767 AngleOrPercentage::Angle(angle.to_computed_value(context))
768 },
769 }
770 }
771 #[inline]
772 fn from_computed_value(computed: &AngleOrPercentage) -> Self {
773 match *computed {
774 AngleOrPercentage::Percentage(percentage) => specified::AngleOrPercentage::Percentage(
775 ToComputedValue::from_computed_value(&percentage),
776 ),
777 AngleOrPercentage::Angle(angle) => {
778 specified::AngleOrPercentage::Angle(ToComputedValue::from_computed_value(&angle))
779 },
780 }
781 }
782}
783
784pub type Number = CSSFloat;
786
787impl IsParallelTo for (Number, Number, Number) {
788 fn is_parallel_to(&self, vector: &DirectionVector) -> bool {
789 use euclid::approxeq::ApproxEq;
790 let self_vector = DirectionVector::new(self.0, self.1, self.2);
793 self_vector
794 .cross(*vector)
795 .square_length()
796 .approx_eq(&0.0f32)
797 }
798}
799
800pub type NonNegativeNumber = NonNegative<CSSFloat>;
802
803impl From<CSSFloat> for NonNegativeNumber {
804 #[inline]
805 fn from(number: CSSFloat) -> NonNegativeNumber {
806 NonNegative::<CSSFloat>(number)
807 }
808}
809
810impl From<NonNegativeNumber> for CSSFloat {
811 #[inline]
812 fn from(number: NonNegativeNumber) -> CSSFloat {
813 number.0
814 }
815}
816
817impl One for NonNegativeNumber {
818 #[inline]
819 fn one() -> Self {
820 NonNegative(1.0)
821 }
822
823 #[inline]
824 fn is_one(&self) -> bool {
825 self.0 == 1.0
826 }
827}
828
829pub type ZeroToOneNumber = ZeroToOne<CSSFloat>;
831
832impl ToAnimatedValue for ZeroToOneNumber {
833 type AnimatedValue = Self;
834
835 #[inline]
836 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
837 self
838 }
839
840 #[inline]
841 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
842 Self(animated.0.max(0.).min(1.))
843 }
844}
845
846impl From<CSSFloat> for ZeroToOneNumber {
847 #[inline]
848 fn from(number: CSSFloat) -> Self {
849 Self(number)
850 }
851}
852
853pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<CSSFloat>;
855
856impl ToAnimatedValue for GreaterThanOrEqualToOneNumber {
857 type AnimatedValue = CSSFloat;
858
859 #[inline]
860 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
861 self.0
862 }
863
864 #[inline]
865 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
866 animated.max(1.).into()
867 }
868}
869
870impl From<CSSFloat> for GreaterThanOrEqualToOneNumber {
871 #[inline]
872 fn from(number: CSSFloat) -> GreaterThanOrEqualToOneNumber {
873 GreaterThanOrEqualToOne::<CSSFloat>(number)
874 }
875}
876
877impl From<GreaterThanOrEqualToOneNumber> for CSSFloat {
878 #[inline]
879 fn from(number: GreaterThanOrEqualToOneNumber) -> CSSFloat {
880 number.0
881 }
882}
883
884#[allow(missing_docs)]
885#[derive(
886 Animate,
887 Clone,
888 ComputeSquaredDistance,
889 Copy,
890 Debug,
891 MallocSizeOf,
892 PartialEq,
893 ToAnimatedZero,
894 ToAnimatedValue,
895 ToCss,
896 ToResolvedValue,
897)]
898#[repr(C, u8)]
899pub enum NumberOrPercentage {
900 Percentage(Percentage),
901 Number(Number),
902}
903
904impl ClampToNonNegative for NumberOrPercentage {
905 fn clamp_to_non_negative(self) -> Self {
906 match self {
907 NumberOrPercentage::Percentage(p) => {
908 NumberOrPercentage::Percentage(p.clamp_to_non_negative())
909 },
910 NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.clamp_to_non_negative()),
911 }
912 }
913}
914
915impl ToComputedValue for specified::NumberOrPercentage {
916 type ComputedValue = NumberOrPercentage;
917
918 #[inline]
919 fn to_computed_value(&self, context: &Context) -> NumberOrPercentage {
920 match *self {
921 specified::NumberOrPercentage::Percentage(percentage) => {
922 NumberOrPercentage::Percentage(percentage.to_computed_value(context))
923 },
924 specified::NumberOrPercentage::Number(number) => {
925 NumberOrPercentage::Number(number.to_computed_value(context))
926 },
927 }
928 }
929 #[inline]
930 fn from_computed_value(computed: &NumberOrPercentage) -> Self {
931 match *computed {
932 NumberOrPercentage::Percentage(percentage) => {
933 specified::NumberOrPercentage::Percentage(ToComputedValue::from_computed_value(
934 &percentage,
935 ))
936 },
937 NumberOrPercentage::Number(number) => {
938 specified::NumberOrPercentage::Number(ToComputedValue::from_computed_value(&number))
939 },
940 }
941 }
942}
943
944pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
946
947impl NonNegativeNumberOrPercentage {
948 #[inline]
950 pub fn hundred_percent() -> Self {
951 NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
952 }
953}
954
955pub type Opacity = CSSFloat;
957
958pub type Integer = CSSInteger;
960
961pub type PositiveInteger = GreaterThanOrEqualToOne<CSSInteger>;
963
964impl ToAnimatedValue for PositiveInteger {
965 type AnimatedValue = CSSInteger;
966
967 #[inline]
968 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
969 self.0
970 }
971
972 #[inline]
973 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
974 cmp::max(animated, 1).into()
975 }
976}
977
978impl From<CSSInteger> for PositiveInteger {
979 #[inline]
980 fn from(int: CSSInteger) -> PositiveInteger {
981 GreaterThanOrEqualToOne::<CSSInteger>(int)
982 }
983}
984
985pub type ClipRect = generics::GenericClipRect<LengthOrAuto>;
987
988pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>;
990
991pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
993
994pub type TrackSize = GenericTrackSize<LengthPercentage>;
996
997pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>;
999
1000pub type TrackList = GenericTrackList<LengthPercentage, Integer>;
1003
1004pub type GridLine = GenericGridLine<Integer>;
1006
1007pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
1009
1010impl ClipRect {
1011 pub fn for_border_rect<T: Copy + From<Length> + Add<Output = T> + Sub<Output = T>, U>(
1014 &self,
1015 border_box: Rect<T, U>,
1016 ) -> Rect<T, U> {
1017 fn extract_clip_component<T: From<Length>>(p: &LengthOrAuto, or: T) -> T {
1018 match *p {
1019 LengthOrAuto::Auto => or,
1020 LengthOrAuto::LengthPercentage(ref length) => T::from(*length),
1021 }
1022 }
1023
1024 let clip_origin = Point2D::new(
1025 From::from(self.left.auto_is(|| Length::new(0.))),
1026 From::from(self.top.auto_is(|| Length::new(0.))),
1027 );
1028 let right = extract_clip_component(&self.right, border_box.size.width);
1029 let bottom = extract_clip_component(&self.bottom, border_box.size.height);
1030 let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
1031
1032 Rect::new(clip_origin, clip_size).translate(border_box.origin.to_vector())
1033 }
1034}