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