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, AnimationRangeEnd,
48 AnimationRangeStart, AnimationTimeline, ScrollAxis, TimelineName, TransitionBehavior,
49 TransitionProperty, ViewTimelineInset, ViewTransitionClass, 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,
60 DominantBaseline, Float, LineClamp, Overflow, OverflowAnchor, OverflowClipMargin,
61 OverscrollBehavior, Perspective, PositionProperty, Resize, ScrollSnapAlign, ScrollSnapAxis,
62 ScrollSnapStop, 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::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::ScopedName;
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::{TextBoxEdge, TextBoxTrim};
118pub use self::text::{
119 TextDecorationInset, TextDecorationLength, TextDecorationSkipInk, TextJustify,
120};
121pub use self::time::Time;
122pub use self::transform::{Rotate, Scale, Transform, TransformBox, TransformOperation};
123pub use self::transform::{TransformOrigin, TransformStyle, Translate};
124#[cfg(feature = "gecko")]
125pub use self::ui::CursorImage;
126pub use self::ui::{
127 BoolInteger, Cursor, Inert, MozTheme, PointerEvents, ScrollbarColor, UserFocus, UserSelect,
128};
129pub use super::specified::TextTransform;
130pub use super::specified::ViewportVariant;
131pub use super::specified::{BorderStyle, TextDecorationLine};
132pub use app_units::Au;
133
134pub mod align;
135pub mod angle;
136pub mod animation;
137pub mod background;
138pub mod basic_shape;
139pub mod border;
140#[path = "box.rs"]
141pub mod box_;
142pub mod color;
143pub mod column;
144pub mod counters;
145pub mod easing;
146pub mod effects;
147pub mod flex;
148pub mod font;
149pub mod image;
150pub mod length;
151pub mod length_percentage;
152pub mod list;
153pub mod motion;
154pub mod outline;
155pub mod page;
156pub mod percentage;
157pub mod position;
158pub mod ratio;
159pub mod rect;
160pub mod resolution;
161pub mod svg;
162pub mod table;
163pub mod text;
164pub mod time;
165pub mod transform;
166pub mod ui;
167pub mod url;
168
169pub struct Context<'a> {
172 pub builder: StyleBuilder<'a>,
176
177 #[cfg(feature = "gecko")]
181 pub cached_system_font: Option<properties::gecko::system_font::ComputedSystemFont>,
182
183 #[cfg(feature = "servo")]
188 pub cached_system_font: Option<()>,
189
190 pub in_media_query: bool,
192
193 pub in_container_query: bool,
195
196 pub quirks_mode: QuirksMode,
198
199 pub for_smil_animation: bool,
204
205 pub container_info: Option<ContainerInfo>,
207
208 pub for_non_inherited_property: bool,
212
213 pub rule_cache_conditions: RefCell<&'a mut RuleCacheConditions>,
217
218 pub scope: CascadeLevel,
220
221 container_size_query: RefCell<ContainerSizeQuery<'a>>,
223}
224
225impl<'a> Context<'a> {
226 pub fn get_container_size_query(&self) -> ContainerSizeQueryResult {
228 let mut resolved = self.container_size_query.borrow_mut();
229 resolved.get().clone()
230 }
231
232 pub fn for_media_query_evaluation<F, R>(device: &Device, quirks_mode: QuirksMode, f: F) -> R
236 where
237 F: FnOnce(&Context) -> R,
238 {
239 let mut conditions = RuleCacheConditions::default();
240 let context = Context {
241 builder: StyleBuilder::for_inheritance(device, None, None, None),
242 cached_system_font: None,
243 in_media_query: true,
244 in_container_query: false,
245 quirks_mode,
246 for_smil_animation: false,
247 container_info: None,
248 for_non_inherited_property: false,
249 rule_cache_conditions: RefCell::new(&mut conditions),
250 scope: CascadeLevel::same_tree_author_normal(),
251 container_size_query: RefCell::new(ContainerSizeQuery::none()),
252 };
253 f(&context)
254 }
255
256 pub fn for_container_query_evaluation<F, R>(
259 device: &Device,
260 stylist: Option<&Stylist>,
261 container_info_and_style: Option<(ContainerInfo, Arc<ComputedValues>)>,
262 container_size_query: ContainerSizeQuery,
263 f: F,
264 ) -> R
265 where
266 F: FnOnce(&Context) -> R,
267 {
268 let mut conditions = RuleCacheConditions::default();
269
270 let (container_info, style) = match container_info_and_style {
271 Some((ci, s)) => (Some(ci), Some(s)),
272 None => (None, None),
273 };
274
275 let style = style.as_ref().map(|s| &**s);
276 let quirks_mode = device.quirks_mode();
277 let context = Context {
278 builder: StyleBuilder::for_inheritance(device, stylist, style, None),
279 cached_system_font: None,
280 in_media_query: false,
281 in_container_query: true,
282 quirks_mode,
283 for_smil_animation: false,
284 container_info,
285 for_non_inherited_property: false,
286 rule_cache_conditions: RefCell::new(&mut conditions),
287 scope: CascadeLevel::same_tree_author_normal(),
288 container_size_query: RefCell::new(container_size_query),
289 };
290
291 f(&context)
292 }
293
294 pub fn new(
296 builder: StyleBuilder<'a>,
297 quirks_mode: QuirksMode,
298 rule_cache_conditions: &'a mut RuleCacheConditions,
299 container_size_query: ContainerSizeQuery<'a>,
300 ) -> Self {
301 Self {
302 builder,
303 cached_system_font: None,
304 in_media_query: false,
305 in_container_query: false,
306 quirks_mode,
307 container_info: None,
308 for_smil_animation: false,
309 for_non_inherited_property: false,
310 rule_cache_conditions: RefCell::new(rule_cache_conditions),
311 scope: CascadeLevel::same_tree_author_normal(),
312 container_size_query: RefCell::new(container_size_query),
313 }
314 }
315
316 pub fn new_for_animation(
318 builder: StyleBuilder<'a>,
319 for_smil_animation: bool,
320 quirks_mode: QuirksMode,
321 rule_cache_conditions: &'a mut RuleCacheConditions,
322 container_size_query: ContainerSizeQuery<'a>,
323 ) -> Self {
324 Self {
325 builder,
326 cached_system_font: None,
327 in_media_query: false,
328 in_container_query: false,
329 quirks_mode,
330 container_info: None,
331 for_smil_animation,
332 for_non_inherited_property: false,
333 rule_cache_conditions: RefCell::new(rule_cache_conditions),
334 scope: CascadeLevel::same_tree_author_normal(),
335 container_size_query: RefCell::new(container_size_query),
336 }
337 }
338
339 pub fn new_for_initial_at_property_value(
341 stylist: &'a Stylist,
342 rule_cache_conditions: &'a mut RuleCacheConditions,
343 ) -> Self {
344 Self {
345 builder: StyleBuilder::new(stylist.device(), Some(stylist), None, None, None, false),
346 cached_system_font: None,
347 in_media_query: false,
351 in_container_query: false,
352 quirks_mode: stylist.quirks_mode(),
353 container_info: None,
354 for_smil_animation: false,
355 for_non_inherited_property: false,
356 rule_cache_conditions: RefCell::new(rule_cache_conditions),
357 scope: CascadeLevel::same_tree_author_normal(),
358 container_size_query: RefCell::new(ContainerSizeQuery::none()),
359 }
360 }
361
362 pub fn device(&self) -> &Device {
364 self.builder.device
365 }
366
367 pub fn inherited_custom_properties(&self) -> &ComputedCustomProperties {
369 &self.builder.inherited_custom_properties()
370 }
371
372 pub fn is_root_element(&self) -> bool {
374 self.builder.is_root_element
375 }
376
377 pub fn query_font_metrics(
379 &self,
380 base_size: FontBaseSize,
381 orientation: FontMetricsOrientation,
382 mut flags: QueryFontMetricsFlags,
383 ) -> FontMetrics {
384 if self.for_non_inherited_property {
385 self.rule_cache_conditions.borrow_mut().set_uncacheable();
386 }
387 self.builder.add_flags(match base_size {
388 FontBaseSize::CurrentStyle => ComputedValueFlags::DEPENDS_ON_SELF_FONT_METRICS,
389 FontBaseSize::InheritedStyle => ComputedValueFlags::DEPENDS_ON_INHERITED_FONT_METRICS,
390 });
391 let size = base_size.resolve(self).used_size();
392 let style = self.style();
393
394 let (wm, font) = match base_size {
395 FontBaseSize::CurrentStyle => (style.writing_mode, style.get_font()),
396 FontBaseSize::InheritedStyle => {
398 (*style.inherited_writing_mode(), style.get_parent_font())
399 },
400 };
401
402 let vertical = match orientation {
403 FontMetricsOrientation::MatchContextPreferHorizontal => {
404 wm.is_vertical() && wm.is_upright()
405 },
406 FontMetricsOrientation::MatchContextPreferVertical => wm.is_text_vertical(),
407 FontMetricsOrientation::Horizontal => false,
408 };
409 if !self.in_media_query {
410 flags |= QueryFontMetricsFlags::USE_USER_FONT_SET
411 }
412 self.device()
413 .query_font_metrics(vertical, font, size, flags, true)
414 }
415
416 pub fn viewport_size_for_viewport_unit_resolution(
418 &self,
419 variant: ViewportVariant,
420 ) -> default::Size2D<Au> {
421 self.builder
422 .add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS);
423 self.builder
424 .device
425 .au_viewport_size_for_viewport_unit_resolution(variant)
426 }
427
428 pub fn in_media_or_container_query(&self) -> bool {
430 self.in_media_query || self.in_container_query
431 }
432
433 pub fn default_style(&self) -> &ComputedValues {
435 self.builder.default_style()
436 }
437
438 pub fn style(&self) -> &StyleBuilder<'a> {
440 &self.builder
441 }
442
443 pub fn current_scope(&self) -> CascadeLevel {
445 self.scope
446 }
447
448 #[cfg(feature = "gecko")]
450 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
451 if self
452 .style()
453 .get_font()
454 .clone__x_text_scale()
455 .text_zoom_enabled()
456 {
457 self.device().zoom_text(size)
458 } else {
459 size
460 }
461 }
462
463 #[cfg(feature = "servo")]
465 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
466 size
467 }
468}
469
470#[derive(Clone)]
472pub struct ComputedVecIter<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> {
473 cx: &'cx Context<'cx_a>,
474 values: &'a [S],
475}
476
477impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ComputedVecIter<'a, 'cx, 'cx_a, S> {
478 pub fn new(cx: &'cx Context<'cx_a>, values: &'a [S]) -> Self {
480 ComputedVecIter { cx, values }
481 }
482}
483
484impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ExactSizeIterator
485 for ComputedVecIter<'a, 'cx, 'cx_a, S>
486{
487 fn len(&self) -> usize {
488 self.values.len()
489 }
490}
491
492impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter<'a, 'cx, 'cx_a, S> {
493 type Item = S::ComputedValue;
494 fn next(&mut self) -> Option<Self::Item> {
495 if let Some((next, rest)) = self.values.split_first() {
496 let ret = next.to_computed_value(self.cx);
497 self.values = rest;
498 Some(ret)
499 } else {
500 None
501 }
502 }
503
504 fn size_hint(&self) -> (usize, Option<usize>) {
505 (self.values.len(), Some(self.values.len()))
506 }
507}
508
509pub trait ToComputedValue {
518 type ComputedValue;
520
521 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue;
524
525 fn from_computed_value(computed: &Self::ComputedValue) -> Self;
530}
531
532impl<A, B> ToComputedValue for (A, B)
533where
534 A: ToComputedValue,
535 B: ToComputedValue,
536{
537 type ComputedValue = (
538 <A as ToComputedValue>::ComputedValue,
539 <B as ToComputedValue>::ComputedValue,
540 );
541
542 #[inline]
543 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
544 (
545 self.0.to_computed_value(context),
546 self.1.to_computed_value(context),
547 )
548 }
549
550 #[inline]
551 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
552 (
553 A::from_computed_value(&computed.0),
554 B::from_computed_value(&computed.1),
555 )
556 }
557}
558
559impl<T> ToComputedValue for Option<T>
560where
561 T: ToComputedValue,
562{
563 type ComputedValue = Option<<T as ToComputedValue>::ComputedValue>;
564
565 #[inline]
566 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
567 self.as_ref().map(|item| item.to_computed_value(context))
568 }
569
570 #[inline]
571 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
572 computed.as_ref().map(T::from_computed_value)
573 }
574}
575
576impl<T> ToComputedValue for default::Size2D<T>
577where
578 T: ToComputedValue,
579{
580 type ComputedValue = default::Size2D<<T as ToComputedValue>::ComputedValue>;
581
582 #[inline]
583 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
584 Size2D::new(
585 self.width.to_computed_value(context),
586 self.height.to_computed_value(context),
587 )
588 }
589
590 #[inline]
591 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
592 Size2D::new(
593 T::from_computed_value(&computed.width),
594 T::from_computed_value(&computed.height),
595 )
596 }
597}
598
599impl<T> ToComputedValue for Vec<T>
600where
601 T: ToComputedValue,
602{
603 type ComputedValue = Vec<<T as ToComputedValue>::ComputedValue>;
604
605 #[inline]
606 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
607 self.iter()
608 .map(|item| item.to_computed_value(context))
609 .collect()
610 }
611
612 #[inline]
613 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
614 computed.iter().map(T::from_computed_value).collect()
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 Box::new(T::to_computed_value(self, context))
627 }
628
629 #[inline]
630 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
631 Box::new(T::from_computed_value(computed))
632 }
633}
634
635impl<T> ToComputedValue for Box<[T]>
636where
637 T: ToComputedValue,
638{
639 type ComputedValue = Box<[<T as ToComputedValue>::ComputedValue]>;
640
641 #[inline]
642 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
643 self.iter()
644 .map(|item| item.to_computed_value(context))
645 .collect()
646 }
647
648 #[inline]
649 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
650 computed.iter().map(T::from_computed_value).collect()
651 }
652}
653
654impl<T> ToComputedValue for crate::OwnedSlice<T>
655where
656 T: ToComputedValue,
657{
658 type ComputedValue = crate::OwnedSlice<<T as ToComputedValue>::ComputedValue>;
659
660 #[inline]
661 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
662 self.iter()
663 .map(|item| item.to_computed_value(context))
664 .collect()
665 }
666
667 #[inline]
668 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
669 computed.iter().map(T::from_computed_value).collect()
670 }
671}
672
673impl<T> ToComputedValue for thin_vec::ThinVec<T>
674where
675 T: ToComputedValue,
676{
677 type ComputedValue = thin_vec::ThinVec<<T as ToComputedValue>::ComputedValue>;
678
679 #[inline]
680 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
681 self.iter()
682 .map(|item| item.to_computed_value(context))
683 .collect()
684 }
685
686 #[inline]
687 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
688 computed.iter().map(T::from_computed_value).collect()
689 }
690}
691
692impl<T> ToComputedValue for Arc<T>
698where
699 T: ToComputedValue<ComputedValue = T>,
700{
701 type ComputedValue = Self;
702
703 #[inline]
704 fn to_computed_value(&self, _: &Context) -> Self {
705 self.clone()
706 }
707
708 #[inline]
709 fn from_computed_value(computed: &Self) -> Self {
710 computed.clone()
711 }
712}
713
714impl<T> ToComputedValue for ArcSlice<T>
716where
717 T: ToComputedValue<ComputedValue = T>,
718{
719 type ComputedValue = Self;
720
721 #[inline]
722 fn to_computed_value(&self, _: &Context) -> Self {
723 self.clone()
724 }
725
726 #[inline]
727 fn from_computed_value(computed: &Self) -> Self {
728 computed.clone()
729 }
730}
731
732trivial_to_computed_value!(());
733trivial_to_computed_value!(bool);
734trivial_to_computed_value!(f32);
735trivial_to_computed_value!(i32);
736trivial_to_computed_value!(u8);
737trivial_to_computed_value!(i8);
738trivial_to_computed_value!(u16);
739trivial_to_computed_value!(u32);
740trivial_to_computed_value!(usize);
741trivial_to_computed_value!(Atom);
742trivial_to_computed_value!(crate::values::AtomIdent);
743#[cfg(feature = "servo")]
744trivial_to_computed_value!(crate::Namespace);
745#[cfg(feature = "servo")]
746trivial_to_computed_value!(crate::Prefix);
747trivial_to_computed_value!(crate::stylesheets::UrlExtraData);
748trivial_to_computed_value!(String);
749trivial_to_computed_value!(Box<str>);
750trivial_to_computed_value!(crate::OwnedStr);
751trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType);
752trivial_to_computed_value!(crate::values::generics::color::ColorMixFlags);
753
754#[allow(missing_docs)]
755#[derive(
756 Animate,
757 Clone,
758 ComputeSquaredDistance,
759 Copy,
760 Debug,
761 MallocSizeOf,
762 PartialEq,
763 ToAnimatedZero,
764 ToCss,
765 ToResolvedValue,
766)]
767#[repr(C, u8)]
768pub enum AngleOrPercentage {
769 Percentage(Percentage),
770 Angle(Angle),
771}
772
773impl ToComputedValue for specified::AngleOrPercentage {
774 type ComputedValue = AngleOrPercentage;
775
776 #[inline]
777 fn to_computed_value(&self, context: &Context) -> AngleOrPercentage {
778 match *self {
779 specified::AngleOrPercentage::Percentage(percentage) => {
780 AngleOrPercentage::Percentage(percentage.to_computed_value(context))
781 },
782 specified::AngleOrPercentage::Angle(angle) => {
783 AngleOrPercentage::Angle(angle.to_computed_value(context))
784 },
785 }
786 }
787 #[inline]
788 fn from_computed_value(computed: &AngleOrPercentage) -> Self {
789 match *computed {
790 AngleOrPercentage::Percentage(percentage) => specified::AngleOrPercentage::Percentage(
791 ToComputedValue::from_computed_value(&percentage),
792 ),
793 AngleOrPercentage::Angle(angle) => {
794 specified::AngleOrPercentage::Angle(ToComputedValue::from_computed_value(&angle))
795 },
796 }
797 }
798}
799
800pub type Number = CSSFloat;
802
803impl IsParallelTo for (Number, Number, Number) {
804 fn is_parallel_to(&self, vector: &DirectionVector) -> bool {
805 use euclid::approxeq::ApproxEq;
806 let self_vector = DirectionVector::new(self.0, self.1, self.2);
809 self_vector
810 .cross(*vector)
811 .square_length()
812 .approx_eq(&0.0f32)
813 }
814}
815
816pub type NonNegativeNumber = NonNegative<CSSFloat>;
818
819impl From<CSSFloat> for NonNegativeNumber {
820 #[inline]
821 fn from(number: CSSFloat) -> NonNegativeNumber {
822 NonNegative::<CSSFloat>(number)
823 }
824}
825
826impl From<NonNegativeNumber> for CSSFloat {
827 #[inline]
828 fn from(number: NonNegativeNumber) -> CSSFloat {
829 number.0
830 }
831}
832
833impl One for NonNegativeNumber {
834 #[inline]
835 fn one() -> Self {
836 NonNegative(1.0)
837 }
838
839 #[inline]
840 fn is_one(&self) -> bool {
841 self.0 == 1.0
842 }
843}
844
845pub type ZeroToOneNumber = ZeroToOne<CSSFloat>;
847
848impl ToAnimatedValue for ZeroToOneNumber {
849 type AnimatedValue = Self;
850
851 #[inline]
852 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
853 self
854 }
855
856 #[inline]
857 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
858 Self(animated.0.max(0.).min(1.))
859 }
860}
861
862impl From<CSSFloat> for ZeroToOneNumber {
863 #[inline]
864 fn from(number: CSSFloat) -> Self {
865 Self(number)
866 }
867}
868
869pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<CSSFloat>;
871
872impl ToAnimatedValue for GreaterThanOrEqualToOneNumber {
873 type AnimatedValue = CSSFloat;
874
875 #[inline]
876 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
877 self.0
878 }
879
880 #[inline]
881 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
882 animated.max(1.).into()
883 }
884}
885
886impl From<CSSFloat> for GreaterThanOrEqualToOneNumber {
887 #[inline]
888 fn from(number: CSSFloat) -> GreaterThanOrEqualToOneNumber {
889 GreaterThanOrEqualToOne::<CSSFloat>(number)
890 }
891}
892
893impl From<GreaterThanOrEqualToOneNumber> for CSSFloat {
894 #[inline]
895 fn from(number: GreaterThanOrEqualToOneNumber) -> CSSFloat {
896 number.0
897 }
898}
899
900#[allow(missing_docs)]
901#[derive(
902 Animate,
903 Clone,
904 ComputeSquaredDistance,
905 Copy,
906 Debug,
907 MallocSizeOf,
908 PartialEq,
909 ToAnimatedZero,
910 ToAnimatedValue,
911 ToCss,
912 ToResolvedValue,
913)]
914#[repr(C, u8)]
915pub enum NumberOrPercentage {
916 Percentage(Percentage),
917 Number(Number),
918}
919
920impl ClampToNonNegative for NumberOrPercentage {
921 fn clamp_to_non_negative(self) -> Self {
922 match self {
923 NumberOrPercentage::Percentage(p) => {
924 NumberOrPercentage::Percentage(p.clamp_to_non_negative())
925 },
926 NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.clamp_to_non_negative()),
927 }
928 }
929}
930
931impl ToComputedValue for specified::NumberOrPercentage {
932 type ComputedValue = NumberOrPercentage;
933
934 #[inline]
935 fn to_computed_value(&self, context: &Context) -> NumberOrPercentage {
936 match *self {
937 specified::NumberOrPercentage::Percentage(percentage) => {
938 NumberOrPercentage::Percentage(percentage.to_computed_value(context))
939 },
940 specified::NumberOrPercentage::Number(number) => {
941 NumberOrPercentage::Number(number.to_computed_value(context))
942 },
943 }
944 }
945 #[inline]
946 fn from_computed_value(computed: &NumberOrPercentage) -> Self {
947 match *computed {
948 NumberOrPercentage::Percentage(percentage) => {
949 specified::NumberOrPercentage::Percentage(ToComputedValue::from_computed_value(
950 &percentage,
951 ))
952 },
953 NumberOrPercentage::Number(number) => {
954 specified::NumberOrPercentage::Number(ToComputedValue::from_computed_value(&number))
955 },
956 }
957 }
958}
959
960pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
962
963impl NonNegativeNumberOrPercentage {
964 #[inline]
966 pub fn hundred_percent() -> Self {
967 NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
968 }
969}
970
971pub type Opacity = CSSFloat;
973
974pub type Integer = CSSInteger;
976
977pub type PositiveInteger = GreaterThanOrEqualToOne<CSSInteger>;
979
980impl ToAnimatedValue for PositiveInteger {
981 type AnimatedValue = CSSInteger;
982
983 #[inline]
984 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
985 self.0
986 }
987
988 #[inline]
989 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
990 cmp::max(animated, 1).into()
991 }
992}
993
994impl From<CSSInteger> for PositiveInteger {
995 #[inline]
996 fn from(int: CSSInteger) -> PositiveInteger {
997 GreaterThanOrEqualToOne::<CSSInteger>(int)
998 }
999}
1000
1001pub type ClipRect = generics::GenericClipRect<LengthOrAuto>;
1003
1004pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>;
1006
1007pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
1009
1010pub type TrackSize = GenericTrackSize<LengthPercentage>;
1012
1013pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>;
1015
1016pub type TrackList = GenericTrackList<LengthPercentage, Integer>;
1019
1020pub type GridLine = GenericGridLine<Integer>;
1022
1023pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
1025
1026impl ClipRect {
1027 pub fn for_border_rect<T: Copy + From<Length> + Add<Output = T> + Sub<Output = T>, U>(
1030 &self,
1031 border_box: Rect<T, U>,
1032 ) -> Rect<T, U> {
1033 fn extract_clip_component<T: From<Length>>(p: &LengthOrAuto, or: T) -> T {
1034 match *p {
1035 LengthOrAuto::Auto => or,
1036 LengthOrAuto::LengthPercentage(ref length) => T::from(*length),
1037 }
1038 }
1039
1040 let clip_origin = Point2D::new(
1041 From::from(self.left.auto_is(|| Length::new(0.))),
1042 From::from(self.top.auto_is(|| Length::new(0.))),
1043 );
1044 let right = extract_clip_component(&self.right, border_box.size.width);
1045 let bottom = extract_clip_component(&self.bottom, border_box.size.height);
1046 let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
1047
1048 Rect::new(clip_origin, clip_size).translate(border_box.origin.to_vector())
1049 }
1050}