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::device::Device;
22use crate::font_metrics::{FontMetrics, FontMetricsOrientation};
23#[cfg(feature = "gecko")]
24use crate::properties;
25use crate::properties::{ComputedValues, StyleBuilder};
26use crate::rule_cache::RuleCacheConditions;
27use crate::rule_tree::{CascadeLevel, RuleCascadeFlags};
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::corner_shape::{CornerShape, CornerShapeRect};
70pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset, CounterSet};
71pub use self::easing::TimingFunction;
72pub use self::effects::{BoxShadow, Filter, SimpleShadow};
73pub use self::flex::FlexBasis;
74pub use self::font::{FontFamily, FontLanguageOverride, FontPalette, FontStyle};
75pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
76pub use self::font::{
77 FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontSynthesisStyle, LineHeight,
78};
79pub use self::font::{FontVariantAlternates, FontWeight};
80pub use self::font::{FontVariantEastAsian, FontVariationSettings};
81pub use self::font::{MathDepth, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextScale};
82pub use self::image::{Gradient, Image, ImageRendering, LineDirection};
83pub use self::length::{CSSPixelLength, NonNegativeLength};
84pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
85pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, Margin, MaxSize, Size};
86pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
87pub use self::list::ListStyleType;
88pub use self::list::Quotes;
89pub use self::motion::{OffsetPath, OffsetPosition, OffsetRotate};
90pub use self::outline::OutlineStyle;
91pub use self::page::{PageName, PageOrientation, PageSize, PageSizeOrientation, PaperSize};
92pub use self::percentage::{NonNegativePercentage, Percentage};
93pub use self::position::AnchorFunction;
94pub use self::position::AnchorName;
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::ScopedName;
103pub use self::position::{
104 GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex,
105};
106pub use self::position::{PositionArea, PositionAreaKeyword};
107pub use self::ratio::Ratio;
108pub use self::rect::NonNegativeLengthOrNumberRect;
109pub use self::resolution::Resolution;
110pub use self::svg::{DProperty, MozContextProperties};
111pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
112pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth, VectorEffect};
113pub use self::text::{HyphenateCharacter, HyphenateLimitChars};
114pub use self::text::{InitialLetter, LetterSpacing, LineBreak, TextIndent};
115pub use self::text::{OverflowWrap, RubyPosition, TextOverflow, WordBreak, WordSpacing};
116pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle};
117pub use self::text::{TextAutospace, TextUnderlinePosition};
118pub use self::text::{TextBoxEdge, TextBoxTrim};
119pub use self::text::{
120 TextDecorationInset, TextDecorationLength, TextDecorationSkipInk, TextJustify,
121};
122pub use self::time::Time;
123pub use self::transform::{Rotate, Scale, Transform, TransformBox, TransformOperation};
124pub use self::transform::{TransformOrigin, TransformStyle, Translate};
125#[cfg(feature = "gecko")]
126pub use self::ui::CursorImage;
127pub use self::ui::{
128 BoolInteger, Cursor, Inert, MozTheme, PointerEvents, ScrollbarColor, UserFocus, UserSelect,
129};
130pub use super::specified::TextTransform;
131pub use super::specified::ViewportVariant;
132pub use super::specified::{BorderStyle, TextDecorationLine};
133pub use app_units::Au;
134
135pub mod align;
136pub mod angle;
137pub mod animation;
138pub mod background;
139pub mod basic_shape;
140pub mod border;
141#[path = "box.rs"]
142pub mod box_;
143pub mod calc;
144pub mod color;
145pub mod column;
146pub mod corner_shape;
147pub mod counters;
148pub mod easing;
149pub mod effects;
150pub mod flex;
151pub mod font;
152pub mod image;
153pub mod length;
154pub mod length_percentage;
155pub mod list;
156pub mod motion;
157pub mod outline;
158pub mod page;
159pub mod percentage;
160pub mod position;
161pub mod ratio;
162pub mod rect;
163pub mod resolution;
164pub mod svg;
165pub mod table;
166pub mod text;
167pub mod time;
168pub mod transform;
169pub mod ui;
170pub mod url;
171
172pub struct Context<'a> {
175 pub builder: StyleBuilder<'a>,
179
180 #[cfg(feature = "gecko")]
184 pub cached_system_font: Option<properties::gecko::system_font::ComputedSystemFont>,
185
186 #[cfg(feature = "servo")]
191 pub cached_system_font: Option<()>,
192
193 pub in_media_query: bool,
195
196 pub in_container_query: bool,
198
199 pub quirks_mode: QuirksMode,
201
202 pub for_animation: bool,
206
207 pub container_info: Option<ContainerInfo>,
209
210 pub for_non_inherited_property: bool,
214
215 pub rule_cache_conditions: RefCell<&'a mut RuleCacheConditions>,
219
220 pub scope: CascadeLevel,
222
223 pub included_cascade_flags: RuleCascadeFlags,
228
229 container_size_query: RefCell<ContainerSizeQuery<'a>>,
231}
232
233impl<'a> Context<'a> {
234 pub fn get_container_size_query(&self) -> ContainerSizeQueryResult {
236 let mut resolved = self.container_size_query.borrow_mut();
237 resolved.get().clone()
238 }
239
240 pub fn for_media_query_evaluation<F, R>(device: &Device, quirks_mode: QuirksMode, f: F) -> R
244 where
245 F: FnOnce(&Context) -> R,
246 {
247 let mut conditions = RuleCacheConditions::default();
248 let context = Context {
249 builder: StyleBuilder::for_inheritance(device, None, None, None),
250 cached_system_font: None,
251 in_media_query: true,
252 in_container_query: false,
253 quirks_mode,
254 for_animation: false,
255 container_info: None,
256 for_non_inherited_property: false,
257 rule_cache_conditions: RefCell::new(&mut conditions),
258 scope: CascadeLevel::same_tree_author_normal(),
259 included_cascade_flags: RuleCascadeFlags::empty(),
260 container_size_query: RefCell::new(ContainerSizeQuery::none()),
261 };
262 f(&context)
263 }
264
265 pub fn for_container_query_evaluation<F, R>(
268 device: &Device,
269 stylist: Option<&Stylist>,
270 container_info_and_style: Option<(ContainerInfo, Arc<ComputedValues>)>,
271 container_size_query: ContainerSizeQuery,
272 f: F,
273 ) -> R
274 where
275 F: FnOnce(&Context) -> R,
276 {
277 let mut conditions = RuleCacheConditions::default();
278
279 let (container_info, style) = match container_info_and_style {
280 Some((ci, s)) => (Some(ci), Some(s)),
281 None => (None, None),
282 };
283
284 let style = style.as_ref().map(|s| &**s);
285 let quirks_mode = device.quirks_mode();
286 let context = Context {
287 builder: StyleBuilder::for_inheritance(device, stylist, style, None),
288 cached_system_font: None,
289 in_media_query: false,
290 in_container_query: true,
291 quirks_mode,
292 for_animation: false,
293 container_info,
294 for_non_inherited_property: false,
295 rule_cache_conditions: RefCell::new(&mut conditions),
296 scope: CascadeLevel::same_tree_author_normal(),
297 included_cascade_flags: RuleCascadeFlags::empty(),
298 container_size_query: RefCell::new(container_size_query),
299 };
300
301 f(&context)
302 }
303
304 pub fn new(
306 builder: StyleBuilder<'a>,
307 quirks_mode: QuirksMode,
308 rule_cache_conditions: &'a mut RuleCacheConditions,
309 container_size_query: ContainerSizeQuery<'a>,
310 mut included_cascade_flags: RuleCascadeFlags,
311 ) -> Self {
312 if builder
313 .flags()
314 .intersects(ComputedValueFlags::IS_IN_APPEARANCE_BASE_SUBTREE)
315 {
316 included_cascade_flags.insert(RuleCascadeFlags::APPEARANCE_BASE);
317 }
318 Self {
319 builder,
320 cached_system_font: None,
321 in_media_query: false,
322 in_container_query: false,
323 quirks_mode,
324 container_info: None,
325 for_animation: false,
326 for_non_inherited_property: false,
327 rule_cache_conditions: RefCell::new(rule_cache_conditions),
328 scope: CascadeLevel::same_tree_author_normal(),
329 included_cascade_flags,
330 container_size_query: RefCell::new(container_size_query),
331 }
332 }
333
334 pub fn new_for_animation(
336 builder: StyleBuilder<'a>,
337 quirks_mode: QuirksMode,
338 rule_cache_conditions: &'a mut RuleCacheConditions,
339 container_size_query: ContainerSizeQuery<'a>,
340 ) -> Self {
341 Self {
342 builder,
343 cached_system_font: None,
344 in_media_query: false,
345 in_container_query: false,
346 quirks_mode,
347 container_info: None,
348 for_animation: true,
349 for_non_inherited_property: false,
350 rule_cache_conditions: RefCell::new(rule_cache_conditions),
351 scope: CascadeLevel::same_tree_author_normal(),
352 included_cascade_flags: RuleCascadeFlags::empty(),
353 container_size_query: RefCell::new(container_size_query),
354 }
355 }
356
357 pub fn new_for_initial_at_property_value(
359 stylist: &'a Stylist,
360 rule_cache_conditions: &'a mut RuleCacheConditions,
361 ) -> Self {
362 Self {
363 builder: StyleBuilder::new(stylist.device(), Some(stylist), None, None, None, false),
364 cached_system_font: None,
365 in_media_query: false,
369 in_container_query: false,
370 quirks_mode: stylist.quirks_mode(),
371 container_info: None,
372 for_animation: false,
373 for_non_inherited_property: false,
374 rule_cache_conditions: RefCell::new(rule_cache_conditions),
375 scope: CascadeLevel::same_tree_author_normal(),
376 included_cascade_flags: RuleCascadeFlags::empty(),
377 container_size_query: RefCell::new(ContainerSizeQuery::none()),
378 }
379 }
380
381 pub fn device(&self) -> &Device {
383 self.builder.device
384 }
385
386 pub fn inherited_custom_properties(&self) -> &ComputedCustomProperties {
388 &self.builder.inherited_custom_properties()
389 }
390
391 pub fn is_root_element(&self) -> bool {
393 self.builder.is_root_element
394 }
395
396 pub fn query_font_metrics(
398 &self,
399 base_size: FontBaseSize,
400 orientation: FontMetricsOrientation,
401 mut flags: QueryFontMetricsFlags,
402 ) -> FontMetrics {
403 if self.for_non_inherited_property {
404 self.rule_cache_conditions.borrow_mut().set_uncacheable();
405 }
406 self.builder.add_flags(match base_size {
407 FontBaseSize::CurrentStyle => ComputedValueFlags::DEPENDS_ON_SELF_FONT_METRICS,
408 FontBaseSize::InheritedStyle => ComputedValueFlags::DEPENDS_ON_INHERITED_FONT_METRICS,
409 });
410 let size = base_size.resolve(self).used_size();
411 let style = self.style();
412
413 let (wm, font) = match base_size {
414 FontBaseSize::CurrentStyle => (style.writing_mode, style.get_font()),
415 FontBaseSize::InheritedStyle => {
417 (*style.inherited_writing_mode(), style.get_parent_font())
418 },
419 };
420
421 let vertical = match orientation {
422 FontMetricsOrientation::MatchContextPreferHorizontal => {
423 wm.is_vertical() && wm.is_upright()
424 },
425 FontMetricsOrientation::MatchContextPreferVertical => wm.is_text_vertical(),
426 FontMetricsOrientation::Horizontal => false,
427 };
428 if !self.in_media_query {
429 flags |= QueryFontMetricsFlags::USE_USER_FONT_SET
430 }
431 self.device()
432 .query_font_metrics(vertical, font, size, flags, true)
433 }
434
435 pub fn viewport_size_for_viewport_unit_resolution(
437 &self,
438 variant: ViewportVariant,
439 ) -> default::Size2D<Au> {
440 self.builder
441 .add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS);
442 self.builder
443 .device
444 .au_viewport_size_for_viewport_unit_resolution(variant)
445 }
446
447 pub fn in_media_or_container_query(&self) -> bool {
449 self.in_media_query || self.in_container_query
450 }
451
452 pub fn default_style(&self) -> &ComputedValues {
454 self.builder.default_style()
455 }
456
457 pub fn style(&self) -> &StyleBuilder<'a> {
459 &self.builder
460 }
461
462 pub fn current_scope(&self) -> CascadeLevel {
464 self.scope
465 }
466
467 #[cfg(feature = "gecko")]
469 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
470 if self
471 .style()
472 .get_font()
473 .clone__x_text_scale()
474 .text_zoom_enabled()
475 {
476 self.device().zoom_text(size)
477 } else {
478 size
479 }
480 }
481
482 #[cfg(feature = "servo")]
484 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
485 size
486 }
487}
488
489#[derive(Clone)]
491pub struct ComputedVecIter<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> {
492 cx: &'cx Context<'cx_a>,
493 values: &'a [S],
494}
495
496impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ComputedVecIter<'a, 'cx, 'cx_a, S> {
497 pub fn new(cx: &'cx Context<'cx_a>, values: &'a [S]) -> Self {
499 ComputedVecIter { cx, values }
500 }
501}
502
503impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ExactSizeIterator
504 for ComputedVecIter<'a, 'cx, 'cx_a, S>
505{
506 fn len(&self) -> usize {
507 self.values.len()
508 }
509}
510
511impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter<'a, 'cx, 'cx_a, S> {
512 type Item = S::ComputedValue;
513 fn next(&mut self) -> Option<Self::Item> {
514 if let Some((next, rest)) = self.values.split_first() {
515 let ret = next.to_computed_value(self.cx);
516 self.values = rest;
517 Some(ret)
518 } else {
519 None
520 }
521 }
522
523 fn size_hint(&self) -> (usize, Option<usize>) {
524 (self.values.len(), Some(self.values.len()))
525 }
526}
527
528pub trait ToComputedValue {
537 type ComputedValue;
539
540 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue;
543
544 fn from_computed_value(computed: &Self::ComputedValue) -> Self;
549}
550
551impl<A, B> ToComputedValue for (A, B)
552where
553 A: ToComputedValue,
554 B: ToComputedValue,
555{
556 type ComputedValue = (
557 <A as ToComputedValue>::ComputedValue,
558 <B as ToComputedValue>::ComputedValue,
559 );
560
561 #[inline]
562 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
563 (
564 self.0.to_computed_value(context),
565 self.1.to_computed_value(context),
566 )
567 }
568
569 #[inline]
570 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
571 (
572 A::from_computed_value(&computed.0),
573 B::from_computed_value(&computed.1),
574 )
575 }
576}
577
578impl<T> ToComputedValue for Option<T>
579where
580 T: ToComputedValue,
581{
582 type ComputedValue = Option<<T as ToComputedValue>::ComputedValue>;
583
584 #[inline]
585 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
586 self.as_ref().map(|item| item.to_computed_value(context))
587 }
588
589 #[inline]
590 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
591 computed.as_ref().map(T::from_computed_value)
592 }
593}
594
595impl<T> ToComputedValue for default::Size2D<T>
596where
597 T: ToComputedValue,
598{
599 type ComputedValue = default::Size2D<<T as ToComputedValue>::ComputedValue>;
600
601 #[inline]
602 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
603 Size2D::new(
604 self.width.to_computed_value(context),
605 self.height.to_computed_value(context),
606 )
607 }
608
609 #[inline]
610 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
611 Size2D::new(
612 T::from_computed_value(&computed.width),
613 T::from_computed_value(&computed.height),
614 )
615 }
616}
617
618impl<T> ToComputedValue for Vec<T>
619where
620 T: ToComputedValue,
621{
622 type ComputedValue = Vec<<T as ToComputedValue>::ComputedValue>;
623
624 #[inline]
625 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
626 self.iter()
627 .map(|item| item.to_computed_value(context))
628 .collect()
629 }
630
631 #[inline]
632 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
633 computed.iter().map(T::from_computed_value).collect()
634 }
635}
636
637impl<T> ToComputedValue for Box<T>
638where
639 T: ToComputedValue,
640{
641 type ComputedValue = Box<<T as ToComputedValue>::ComputedValue>;
642
643 #[inline]
644 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
645 Box::new(T::to_computed_value(self, context))
646 }
647
648 #[inline]
649 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
650 Box::new(T::from_computed_value(computed))
651 }
652}
653
654impl<T> ToComputedValue for Box<[T]>
655where
656 T: ToComputedValue,
657{
658 type ComputedValue = Box<[<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 crate::OwnedSlice<T>
674where
675 T: ToComputedValue,
676{
677 type ComputedValue = crate::OwnedSlice<<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 thin_vec::ThinVec<T>
693where
694 T: ToComputedValue,
695{
696 type ComputedValue = thin_vec::ThinVec<<T as ToComputedValue>::ComputedValue>;
697
698 #[inline]
699 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
700 self.iter()
701 .map(|item| item.to_computed_value(context))
702 .collect()
703 }
704
705 #[inline]
706 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
707 computed.iter().map(T::from_computed_value).collect()
708 }
709}
710
711impl<T> ToComputedValue for Arc<T>
717where
718 T: ToComputedValue<ComputedValue = T>,
719{
720 type ComputedValue = Self;
721
722 #[inline]
723 fn to_computed_value(&self, _: &Context) -> Self {
724 self.clone()
725 }
726
727 #[inline]
728 fn from_computed_value(computed: &Self) -> Self {
729 computed.clone()
730 }
731}
732
733impl<T> ToComputedValue for ArcSlice<T>
735where
736 T: ToComputedValue<ComputedValue = T>,
737{
738 type ComputedValue = Self;
739
740 #[inline]
741 fn to_computed_value(&self, _: &Context) -> Self {
742 self.clone()
743 }
744
745 #[inline]
746 fn from_computed_value(computed: &Self) -> Self {
747 computed.clone()
748 }
749}
750
751trivial_to_computed_value!(());
752trivial_to_computed_value!(bool);
753trivial_to_computed_value!(f32);
754trivial_to_computed_value!(i32);
755trivial_to_computed_value!(u8);
756trivial_to_computed_value!(i8);
757trivial_to_computed_value!(u16);
758trivial_to_computed_value!(u32);
759trivial_to_computed_value!(usize);
760trivial_to_computed_value!(Atom);
761trivial_to_computed_value!(crate::values::AtomIdent);
762#[cfg(feature = "servo")]
763trivial_to_computed_value!(crate::Namespace);
764#[cfg(feature = "servo")]
765trivial_to_computed_value!(crate::Prefix);
766trivial_to_computed_value!(crate::stylesheets::UrlExtraData);
767trivial_to_computed_value!(String);
768trivial_to_computed_value!(Box<str>);
769trivial_to_computed_value!(crate::OwnedStr);
770trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType);
771trivial_to_computed_value!(crate::values::generics::color::ColorMixFlags);
772
773#[allow(missing_docs)]
774#[derive(
775 Animate,
776 Clone,
777 ComputeSquaredDistance,
778 Copy,
779 Debug,
780 MallocSizeOf,
781 PartialEq,
782 ToAnimatedZero,
783 ToCss,
784 ToResolvedValue,
785)]
786#[repr(C, u8)]
787pub enum AngleOrPercentage {
788 Percentage(Percentage),
789 Angle(Angle),
790}
791
792impl ToComputedValue for specified::AngleOrPercentage {
793 type ComputedValue = AngleOrPercentage;
794
795 #[inline]
796 fn to_computed_value(&self, context: &Context) -> AngleOrPercentage {
797 match self {
798 specified::AngleOrPercentage::Percentage(percentage) => {
799 AngleOrPercentage::Percentage(percentage.to_computed_value(context))
800 },
801 specified::AngleOrPercentage::Angle(angle) => {
802 AngleOrPercentage::Angle(angle.to_computed_value(context))
803 },
804 }
805 }
806 #[inline]
807 fn from_computed_value(computed: &AngleOrPercentage) -> Self {
808 match *computed {
809 AngleOrPercentage::Percentage(percentage) => specified::AngleOrPercentage::Percentage(
810 ToComputedValue::from_computed_value(&percentage),
811 ),
812 AngleOrPercentage::Angle(angle) => {
813 specified::AngleOrPercentage::Angle(ToComputedValue::from_computed_value(&angle))
814 },
815 }
816 }
817}
818
819pub type Number = CSSFloat;
821
822impl IsParallelTo for (Number, Number, Number) {
823 fn is_parallel_to(&self, vector: &DirectionVector) -> bool {
824 use euclid::approxeq::ApproxEq;
825 let self_vector = DirectionVector::new(self.0, self.1, self.2);
828 self_vector
829 .cross(*vector)
830 .square_length()
831 .approx_eq(&0.0f32)
832 }
833}
834
835pub type NonNegativeNumber = NonNegative<CSSFloat>;
837
838impl From<CSSFloat> for NonNegativeNumber {
839 #[inline]
840 fn from(number: CSSFloat) -> NonNegativeNumber {
841 NonNegative::<CSSFloat>(number)
842 }
843}
844
845impl From<NonNegativeNumber> for CSSFloat {
846 #[inline]
847 fn from(number: NonNegativeNumber) -> CSSFloat {
848 number.0
849 }
850}
851
852impl One for NonNegativeNumber {
853 #[inline]
854 fn one() -> Self {
855 NonNegative(1.0)
856 }
857
858 #[inline]
859 fn is_one(&self) -> bool {
860 self.0 == 1.0
861 }
862}
863
864pub type ZeroToOneNumber = ZeroToOne<CSSFloat>;
866
867impl ToAnimatedValue for ZeroToOneNumber {
868 type AnimatedValue = Self;
869
870 #[inline]
871 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
872 self
873 }
874
875 #[inline]
876 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
877 Self(animated.0.max(0.).min(1.))
878 }
879}
880
881impl From<CSSFloat> for ZeroToOneNumber {
882 #[inline]
883 fn from(number: CSSFloat) -> Self {
884 Self(number)
885 }
886}
887
888pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<CSSFloat>;
890
891impl ToAnimatedValue for GreaterThanOrEqualToOneNumber {
892 type AnimatedValue = CSSFloat;
893
894 #[inline]
895 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
896 self.0
897 }
898
899 #[inline]
900 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
901 animated.max(1.).into()
902 }
903}
904
905impl From<CSSFloat> for GreaterThanOrEqualToOneNumber {
906 #[inline]
907 fn from(number: CSSFloat) -> GreaterThanOrEqualToOneNumber {
908 GreaterThanOrEqualToOne::<CSSFloat>(number)
909 }
910}
911
912impl From<GreaterThanOrEqualToOneNumber> for CSSFloat {
913 #[inline]
914 fn from(number: GreaterThanOrEqualToOneNumber) -> CSSFloat {
915 number.0
916 }
917}
918
919#[allow(missing_docs)]
920#[derive(
921 Animate,
922 Clone,
923 ComputeSquaredDistance,
924 Copy,
925 Debug,
926 MallocSizeOf,
927 PartialEq,
928 ToAnimatedZero,
929 ToAnimatedValue,
930 ToCss,
931 ToResolvedValue,
932)]
933#[repr(C, u8)]
934pub enum NumberOrPercentage {
935 Percentage(Percentage),
936 Number(Number),
937}
938
939impl NumberOrPercentage {
940 pub fn value(&self) -> f32 {
942 match self {
943 NumberOrPercentage::Percentage(p) => p.0,
944 NumberOrPercentage::Number(n) => *n,
945 }
946 }
947}
948
949impl ClampToNonNegative for NumberOrPercentage {
950 fn clamp_to_non_negative(self) -> Self {
951 match self {
952 NumberOrPercentage::Percentage(p) => {
953 NumberOrPercentage::Percentage(p.clamp_to_non_negative())
954 },
955 NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.clamp_to_non_negative()),
956 }
957 }
958}
959
960impl ToComputedValue for specified::NumberOrPercentage {
961 type ComputedValue = NumberOrPercentage;
962
963 #[inline]
964 fn to_computed_value(&self, context: &Context) -> NumberOrPercentage {
965 match self {
966 specified::NumberOrPercentage::Percentage(percentage) => {
967 NumberOrPercentage::Percentage(percentage.to_computed_value(context))
968 },
969 specified::NumberOrPercentage::Number(number) => {
970 NumberOrPercentage::Number(number.to_computed_value(context))
971 },
972 }
973 }
974 #[inline]
975 fn from_computed_value(computed: &NumberOrPercentage) -> Self {
976 match *computed {
977 NumberOrPercentage::Percentage(percentage) => {
978 specified::NumberOrPercentage::Percentage(ToComputedValue::from_computed_value(
979 &percentage,
980 ))
981 },
982 NumberOrPercentage::Number(number) => {
983 specified::NumberOrPercentage::Number(ToComputedValue::from_computed_value(&number))
984 },
985 }
986 }
987}
988
989pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
991
992impl NonNegativeNumberOrPercentage {
993 #[inline]
995 pub fn hundred_percent() -> Self {
996 NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
997 }
998}
999
1000pub type Opacity = CSSFloat;
1002
1003pub type Integer = CSSInteger;
1005
1006pub type PositiveInteger = GreaterThanOrEqualToOne<CSSInteger>;
1008
1009impl ToAnimatedValue for PositiveInteger {
1010 type AnimatedValue = CSSInteger;
1011
1012 #[inline]
1013 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
1014 self.0
1015 }
1016
1017 #[inline]
1018 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
1019 cmp::max(animated, 1).into()
1020 }
1021}
1022
1023impl From<CSSInteger> for PositiveInteger {
1024 #[inline]
1025 fn from(int: CSSInteger) -> PositiveInteger {
1026 GreaterThanOrEqualToOne::<CSSInteger>(int)
1027 }
1028}
1029
1030pub type ClipRect = generics::GenericClipRect<LengthOrAuto>;
1032
1033pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>;
1035
1036pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
1038
1039pub type TrackSize = GenericTrackSize<LengthPercentage>;
1041
1042pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>;
1044
1045pub type TrackList = GenericTrackList<LengthPercentage, Integer>;
1048
1049pub type GridLine = GenericGridLine<Integer>;
1051
1052pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
1054
1055impl ClipRect {
1056 pub fn for_border_rect<T: Copy + From<Length> + Add<Output = T> + Sub<Output = T>, U>(
1059 &self,
1060 border_box: Rect<T, U>,
1061 ) -> Rect<T, U> {
1062 fn extract_clip_component<T: From<Length>>(p: &LengthOrAuto, or: T) -> T {
1063 match *p {
1064 LengthOrAuto::Auto => or,
1065 LengthOrAuto::LengthPercentage(ref length) => T::from(*length),
1066 }
1067 }
1068
1069 let clip_origin = Point2D::new(
1070 From::from(self.left.auto_is(|| Length::new(0.))),
1071 From::from(self.top.auto_is(|| Length::new(0.))),
1072 );
1073 let right = extract_clip_component(&self.right, border_box.size.width);
1074 let bottom = extract_clip_component(&self.bottom, border_box.size.height);
1075 let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
1076
1077 Rect::new(clip_origin, clip_size).translate(border_box.origin.to_vector())
1078 }
1079}