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::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 pub included_cascade_flags: RuleCascadeFlags,
226
227 container_size_query: RefCell<ContainerSizeQuery<'a>>,
229}
230
231impl<'a> Context<'a> {
232 pub fn get_container_size_query(&self) -> ContainerSizeQueryResult {
234 let mut resolved = self.container_size_query.borrow_mut();
235 resolved.get().clone()
236 }
237
238 pub fn for_media_query_evaluation<F, R>(device: &Device, quirks_mode: QuirksMode, f: F) -> R
242 where
243 F: FnOnce(&Context) -> R,
244 {
245 let mut conditions = RuleCacheConditions::default();
246 let context = Context {
247 builder: StyleBuilder::for_inheritance(device, None, None, None),
248 cached_system_font: None,
249 in_media_query: true,
250 in_container_query: false,
251 quirks_mode,
252 for_smil_animation: false,
253 container_info: None,
254 for_non_inherited_property: false,
255 rule_cache_conditions: RefCell::new(&mut conditions),
256 scope: CascadeLevel::same_tree_author_normal(),
257 included_cascade_flags: RuleCascadeFlags::empty(),
258 container_size_query: RefCell::new(ContainerSizeQuery::none()),
259 };
260 f(&context)
261 }
262
263 pub fn for_container_query_evaluation<F, R>(
266 device: &Device,
267 stylist: Option<&Stylist>,
268 container_info_and_style: Option<(ContainerInfo, Arc<ComputedValues>)>,
269 container_size_query: ContainerSizeQuery,
270 f: F,
271 ) -> R
272 where
273 F: FnOnce(&Context) -> R,
274 {
275 let mut conditions = RuleCacheConditions::default();
276
277 let (container_info, style) = match container_info_and_style {
278 Some((ci, s)) => (Some(ci), Some(s)),
279 None => (None, None),
280 };
281
282 let style = style.as_ref().map(|s| &**s);
283 let quirks_mode = device.quirks_mode();
284 let context = Context {
285 builder: StyleBuilder::for_inheritance(device, stylist, style, None),
286 cached_system_font: None,
287 in_media_query: false,
288 in_container_query: true,
289 quirks_mode,
290 for_smil_animation: false,
291 container_info,
292 for_non_inherited_property: false,
293 rule_cache_conditions: RefCell::new(&mut conditions),
294 scope: CascadeLevel::same_tree_author_normal(),
295 included_cascade_flags: RuleCascadeFlags::empty(),
296 container_size_query: RefCell::new(container_size_query),
297 };
298
299 f(&context)
300 }
301
302 pub fn new(
304 builder: StyleBuilder<'a>,
305 quirks_mode: QuirksMode,
306 rule_cache_conditions: &'a mut RuleCacheConditions,
307 container_size_query: ContainerSizeQuery<'a>,
308 mut included_cascade_flags: RuleCascadeFlags,
309 ) -> Self {
310 if builder
311 .flags()
312 .intersects(ComputedValueFlags::IS_IN_APPEARANCE_BASE_SUBTREE)
313 {
314 included_cascade_flags.insert(RuleCascadeFlags::APPEARANCE_BASE);
315 }
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: false,
324 for_non_inherited_property: false,
325 rule_cache_conditions: RefCell::new(rule_cache_conditions),
326 scope: CascadeLevel::same_tree_author_normal(),
327 included_cascade_flags,
328 container_size_query: RefCell::new(container_size_query),
329 }
330 }
331
332 pub fn new_for_animation(
334 builder: StyleBuilder<'a>,
335 for_smil_animation: bool,
336 quirks_mode: QuirksMode,
337 rule_cache_conditions: &'a mut RuleCacheConditions,
338 container_size_query: ContainerSizeQuery<'a>,
339 ) -> Self {
340 Self {
341 builder,
342 cached_system_font: None,
343 in_media_query: false,
344 in_container_query: false,
345 quirks_mode,
346 container_info: None,
347 for_smil_animation,
348 for_non_inherited_property: false,
349 rule_cache_conditions: RefCell::new(rule_cache_conditions),
350 scope: CascadeLevel::same_tree_author_normal(),
351 included_cascade_flags: RuleCascadeFlags::empty(),
352 container_size_query: RefCell::new(container_size_query),
353 }
354 }
355
356 pub fn new_for_initial_at_property_value(
358 stylist: &'a Stylist,
359 rule_cache_conditions: &'a mut RuleCacheConditions,
360 ) -> Self {
361 Self {
362 builder: StyleBuilder::new(stylist.device(), Some(stylist), None, None, None, false),
363 cached_system_font: None,
364 in_media_query: false,
368 in_container_query: false,
369 quirks_mode: stylist.quirks_mode(),
370 container_info: None,
371 for_smil_animation: false,
372 for_non_inherited_property: false,
373 rule_cache_conditions: RefCell::new(rule_cache_conditions),
374 scope: CascadeLevel::same_tree_author_normal(),
375 included_cascade_flags: RuleCascadeFlags::empty(),
376 container_size_query: RefCell::new(ContainerSizeQuery::none()),
377 }
378 }
379
380 pub fn device(&self) -> &Device {
382 self.builder.device
383 }
384
385 pub fn inherited_custom_properties(&self) -> &ComputedCustomProperties {
387 &self.builder.inherited_custom_properties()
388 }
389
390 pub fn is_root_element(&self) -> bool {
392 self.builder.is_root_element
393 }
394
395 pub fn query_font_metrics(
397 &self,
398 base_size: FontBaseSize,
399 orientation: FontMetricsOrientation,
400 mut flags: QueryFontMetricsFlags,
401 ) -> FontMetrics {
402 if self.for_non_inherited_property {
403 self.rule_cache_conditions.borrow_mut().set_uncacheable();
404 }
405 self.builder.add_flags(match base_size {
406 FontBaseSize::CurrentStyle => ComputedValueFlags::DEPENDS_ON_SELF_FONT_METRICS,
407 FontBaseSize::InheritedStyle => ComputedValueFlags::DEPENDS_ON_INHERITED_FONT_METRICS,
408 });
409 let size = base_size.resolve(self).used_size();
410 let style = self.style();
411
412 let (wm, font) = match base_size {
413 FontBaseSize::CurrentStyle => (style.writing_mode, style.get_font()),
414 FontBaseSize::InheritedStyle => {
416 (*style.inherited_writing_mode(), style.get_parent_font())
417 },
418 };
419
420 let vertical = match orientation {
421 FontMetricsOrientation::MatchContextPreferHorizontal => {
422 wm.is_vertical() && wm.is_upright()
423 },
424 FontMetricsOrientation::MatchContextPreferVertical => wm.is_text_vertical(),
425 FontMetricsOrientation::Horizontal => false,
426 };
427 if !self.in_media_query {
428 flags |= QueryFontMetricsFlags::USE_USER_FONT_SET
429 }
430 self.device()
431 .query_font_metrics(vertical, font, size, flags, true)
432 }
433
434 pub fn viewport_size_for_viewport_unit_resolution(
436 &self,
437 variant: ViewportVariant,
438 ) -> default::Size2D<Au> {
439 self.builder
440 .add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS);
441 self.builder
442 .device
443 .au_viewport_size_for_viewport_unit_resolution(variant)
444 }
445
446 pub fn in_media_or_container_query(&self) -> bool {
448 self.in_media_query || self.in_container_query
449 }
450
451 pub fn default_style(&self) -> &ComputedValues {
453 self.builder.default_style()
454 }
455
456 pub fn style(&self) -> &StyleBuilder<'a> {
458 &self.builder
459 }
460
461 pub fn current_scope(&self) -> CascadeLevel {
463 self.scope
464 }
465
466 #[cfg(feature = "gecko")]
468 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
469 if self
470 .style()
471 .get_font()
472 .clone__x_text_scale()
473 .text_zoom_enabled()
474 {
475 self.device().zoom_text(size)
476 } else {
477 size
478 }
479 }
480
481 #[cfg(feature = "servo")]
483 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
484 size
485 }
486}
487
488#[derive(Clone)]
490pub struct ComputedVecIter<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> {
491 cx: &'cx Context<'cx_a>,
492 values: &'a [S],
493}
494
495impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ComputedVecIter<'a, 'cx, 'cx_a, S> {
496 pub fn new(cx: &'cx Context<'cx_a>, values: &'a [S]) -> Self {
498 ComputedVecIter { cx, values }
499 }
500}
501
502impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ExactSizeIterator
503 for ComputedVecIter<'a, 'cx, 'cx_a, S>
504{
505 fn len(&self) -> usize {
506 self.values.len()
507 }
508}
509
510impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter<'a, 'cx, 'cx_a, S> {
511 type Item = S::ComputedValue;
512 fn next(&mut self) -> Option<Self::Item> {
513 if let Some((next, rest)) = self.values.split_first() {
514 let ret = next.to_computed_value(self.cx);
515 self.values = rest;
516 Some(ret)
517 } else {
518 None
519 }
520 }
521
522 fn size_hint(&self) -> (usize, Option<usize>) {
523 (self.values.len(), Some(self.values.len()))
524 }
525}
526
527pub trait ToComputedValue {
536 type ComputedValue;
538
539 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue;
542
543 fn from_computed_value(computed: &Self::ComputedValue) -> Self;
548}
549
550impl<A, B> ToComputedValue for (A, B)
551where
552 A: ToComputedValue,
553 B: ToComputedValue,
554{
555 type ComputedValue = (
556 <A as ToComputedValue>::ComputedValue,
557 <B as ToComputedValue>::ComputedValue,
558 );
559
560 #[inline]
561 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
562 (
563 self.0.to_computed_value(context),
564 self.1.to_computed_value(context),
565 )
566 }
567
568 #[inline]
569 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
570 (
571 A::from_computed_value(&computed.0),
572 B::from_computed_value(&computed.1),
573 )
574 }
575}
576
577impl<T> ToComputedValue for Option<T>
578where
579 T: ToComputedValue,
580{
581 type ComputedValue = Option<<T as ToComputedValue>::ComputedValue>;
582
583 #[inline]
584 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
585 self.as_ref().map(|item| item.to_computed_value(context))
586 }
587
588 #[inline]
589 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
590 computed.as_ref().map(T::from_computed_value)
591 }
592}
593
594impl<T> ToComputedValue for default::Size2D<T>
595where
596 T: ToComputedValue,
597{
598 type ComputedValue = default::Size2D<<T as ToComputedValue>::ComputedValue>;
599
600 #[inline]
601 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
602 Size2D::new(
603 self.width.to_computed_value(context),
604 self.height.to_computed_value(context),
605 )
606 }
607
608 #[inline]
609 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
610 Size2D::new(
611 T::from_computed_value(&computed.width),
612 T::from_computed_value(&computed.height),
613 )
614 }
615}
616
617impl<T> ToComputedValue for Vec<T>
618where
619 T: ToComputedValue,
620{
621 type ComputedValue = Vec<<T as ToComputedValue>::ComputedValue>;
622
623 #[inline]
624 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
625 self.iter()
626 .map(|item| item.to_computed_value(context))
627 .collect()
628 }
629
630 #[inline]
631 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
632 computed.iter().map(T::from_computed_value).collect()
633 }
634}
635
636impl<T> ToComputedValue for Box<T>
637where
638 T: ToComputedValue,
639{
640 type ComputedValue = Box<<T as ToComputedValue>::ComputedValue>;
641
642 #[inline]
643 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
644 Box::new(T::to_computed_value(self, context))
645 }
646
647 #[inline]
648 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
649 Box::new(T::from_computed_value(computed))
650 }
651}
652
653impl<T> ToComputedValue for Box<[T]>
654where
655 T: ToComputedValue,
656{
657 type ComputedValue = Box<[<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 crate::OwnedSlice<T>
673where
674 T: ToComputedValue,
675{
676 type ComputedValue = crate::OwnedSlice<<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 thin_vec::ThinVec<T>
692where
693 T: ToComputedValue,
694{
695 type ComputedValue = thin_vec::ThinVec<<T as ToComputedValue>::ComputedValue>;
696
697 #[inline]
698 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
699 self.iter()
700 .map(|item| item.to_computed_value(context))
701 .collect()
702 }
703
704 #[inline]
705 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
706 computed.iter().map(T::from_computed_value).collect()
707 }
708}
709
710impl<T> ToComputedValue for Arc<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
732impl<T> ToComputedValue for ArcSlice<T>
734where
735 T: ToComputedValue<ComputedValue = T>,
736{
737 type ComputedValue = Self;
738
739 #[inline]
740 fn to_computed_value(&self, _: &Context) -> Self {
741 self.clone()
742 }
743
744 #[inline]
745 fn from_computed_value(computed: &Self) -> Self {
746 computed.clone()
747 }
748}
749
750trivial_to_computed_value!(());
751trivial_to_computed_value!(bool);
752trivial_to_computed_value!(f32);
753trivial_to_computed_value!(i32);
754trivial_to_computed_value!(u8);
755trivial_to_computed_value!(i8);
756trivial_to_computed_value!(u16);
757trivial_to_computed_value!(u32);
758trivial_to_computed_value!(usize);
759trivial_to_computed_value!(Atom);
760trivial_to_computed_value!(crate::values::AtomIdent);
761#[cfg(feature = "servo")]
762trivial_to_computed_value!(crate::Namespace);
763#[cfg(feature = "servo")]
764trivial_to_computed_value!(crate::Prefix);
765trivial_to_computed_value!(crate::stylesheets::UrlExtraData);
766trivial_to_computed_value!(String);
767trivial_to_computed_value!(Box<str>);
768trivial_to_computed_value!(crate::OwnedStr);
769trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType);
770trivial_to_computed_value!(crate::values::generics::color::ColorMixFlags);
771
772#[allow(missing_docs)]
773#[derive(
774 Animate,
775 Clone,
776 ComputeSquaredDistance,
777 Copy,
778 Debug,
779 MallocSizeOf,
780 PartialEq,
781 ToAnimatedZero,
782 ToCss,
783 ToResolvedValue,
784)]
785#[repr(C, u8)]
786pub enum AngleOrPercentage {
787 Percentage(Percentage),
788 Angle(Angle),
789}
790
791impl ToComputedValue for specified::AngleOrPercentage {
792 type ComputedValue = AngleOrPercentage;
793
794 #[inline]
795 fn to_computed_value(&self, context: &Context) -> AngleOrPercentage {
796 match *self {
797 specified::AngleOrPercentage::Percentage(percentage) => {
798 AngleOrPercentage::Percentage(percentage.to_computed_value(context))
799 },
800 specified::AngleOrPercentage::Angle(angle) => {
801 AngleOrPercentage::Angle(angle.to_computed_value(context))
802 },
803 }
804 }
805 #[inline]
806 fn from_computed_value(computed: &AngleOrPercentage) -> Self {
807 match *computed {
808 AngleOrPercentage::Percentage(percentage) => specified::AngleOrPercentage::Percentage(
809 ToComputedValue::from_computed_value(&percentage),
810 ),
811 AngleOrPercentage::Angle(angle) => {
812 specified::AngleOrPercentage::Angle(ToComputedValue::from_computed_value(&angle))
813 },
814 }
815 }
816}
817
818pub type Number = CSSFloat;
820
821impl IsParallelTo for (Number, Number, Number) {
822 fn is_parallel_to(&self, vector: &DirectionVector) -> bool {
823 use euclid::approxeq::ApproxEq;
824 let self_vector = DirectionVector::new(self.0, self.1, self.2);
827 self_vector
828 .cross(*vector)
829 .square_length()
830 .approx_eq(&0.0f32)
831 }
832}
833
834pub type NonNegativeNumber = NonNegative<CSSFloat>;
836
837impl From<CSSFloat> for NonNegativeNumber {
838 #[inline]
839 fn from(number: CSSFloat) -> NonNegativeNumber {
840 NonNegative::<CSSFloat>(number)
841 }
842}
843
844impl From<NonNegativeNumber> for CSSFloat {
845 #[inline]
846 fn from(number: NonNegativeNumber) -> CSSFloat {
847 number.0
848 }
849}
850
851impl One for NonNegativeNumber {
852 #[inline]
853 fn one() -> Self {
854 NonNegative(1.0)
855 }
856
857 #[inline]
858 fn is_one(&self) -> bool {
859 self.0 == 1.0
860 }
861}
862
863pub type ZeroToOneNumber = ZeroToOne<CSSFloat>;
865
866impl ToAnimatedValue for ZeroToOneNumber {
867 type AnimatedValue = Self;
868
869 #[inline]
870 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
871 self
872 }
873
874 #[inline]
875 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
876 Self(animated.0.max(0.).min(1.))
877 }
878}
879
880impl From<CSSFloat> for ZeroToOneNumber {
881 #[inline]
882 fn from(number: CSSFloat) -> Self {
883 Self(number)
884 }
885}
886
887pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<CSSFloat>;
889
890impl ToAnimatedValue for GreaterThanOrEqualToOneNumber {
891 type AnimatedValue = CSSFloat;
892
893 #[inline]
894 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
895 self.0
896 }
897
898 #[inline]
899 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
900 animated.max(1.).into()
901 }
902}
903
904impl From<CSSFloat> for GreaterThanOrEqualToOneNumber {
905 #[inline]
906 fn from(number: CSSFloat) -> GreaterThanOrEqualToOneNumber {
907 GreaterThanOrEqualToOne::<CSSFloat>(number)
908 }
909}
910
911impl From<GreaterThanOrEqualToOneNumber> for CSSFloat {
912 #[inline]
913 fn from(number: GreaterThanOrEqualToOneNumber) -> CSSFloat {
914 number.0
915 }
916}
917
918#[allow(missing_docs)]
919#[derive(
920 Animate,
921 Clone,
922 ComputeSquaredDistance,
923 Copy,
924 Debug,
925 MallocSizeOf,
926 PartialEq,
927 ToAnimatedZero,
928 ToAnimatedValue,
929 ToCss,
930 ToResolvedValue,
931)]
932#[repr(C, u8)]
933pub enum NumberOrPercentage {
934 Percentage(Percentage),
935 Number(Number),
936}
937
938impl ClampToNonNegative for NumberOrPercentage {
939 fn clamp_to_non_negative(self) -> Self {
940 match self {
941 NumberOrPercentage::Percentage(p) => {
942 NumberOrPercentage::Percentage(p.clamp_to_non_negative())
943 },
944 NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.clamp_to_non_negative()),
945 }
946 }
947}
948
949impl ToComputedValue for specified::NumberOrPercentage {
950 type ComputedValue = NumberOrPercentage;
951
952 #[inline]
953 fn to_computed_value(&self, context: &Context) -> NumberOrPercentage {
954 match *self {
955 specified::NumberOrPercentage::Percentage(percentage) => {
956 NumberOrPercentage::Percentage(percentage.to_computed_value(context))
957 },
958 specified::NumberOrPercentage::Number(number) => {
959 NumberOrPercentage::Number(number.to_computed_value(context))
960 },
961 }
962 }
963 #[inline]
964 fn from_computed_value(computed: &NumberOrPercentage) -> Self {
965 match *computed {
966 NumberOrPercentage::Percentage(percentage) => {
967 specified::NumberOrPercentage::Percentage(ToComputedValue::from_computed_value(
968 &percentage,
969 ))
970 },
971 NumberOrPercentage::Number(number) => {
972 specified::NumberOrPercentage::Number(ToComputedValue::from_computed_value(&number))
973 },
974 }
975 }
976}
977
978pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
980
981impl NonNegativeNumberOrPercentage {
982 #[inline]
984 pub fn hundred_percent() -> Self {
985 NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
986 }
987}
988
989pub type Opacity = CSSFloat;
991
992pub type Integer = CSSInteger;
994
995pub type PositiveInteger = GreaterThanOrEqualToOne<CSSInteger>;
997
998impl ToAnimatedValue for PositiveInteger {
999 type AnimatedValue = CSSInteger;
1000
1001 #[inline]
1002 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
1003 self.0
1004 }
1005
1006 #[inline]
1007 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
1008 cmp::max(animated, 1).into()
1009 }
1010}
1011
1012impl From<CSSInteger> for PositiveInteger {
1013 #[inline]
1014 fn from(int: CSSInteger) -> PositiveInteger {
1015 GreaterThanOrEqualToOne::<CSSInteger>(int)
1016 }
1017}
1018
1019pub type ClipRect = generics::GenericClipRect<LengthOrAuto>;
1021
1022pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>;
1024
1025pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
1027
1028pub type TrackSize = GenericTrackSize<LengthPercentage>;
1030
1031pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>;
1033
1034pub type TrackList = GenericTrackList<LengthPercentage, Integer>;
1037
1038pub type GridLine = GenericGridLine<Integer>;
1040
1041pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
1043
1044impl ClipRect {
1045 pub fn for_border_rect<T: Copy + From<Length> + Add<Output = T> + Sub<Output = T>, U>(
1048 &self,
1049 border_box: Rect<T, U>,
1050 ) -> Rect<T, U> {
1051 fn extract_clip_component<T: From<Length>>(p: &LengthOrAuto, or: T) -> T {
1052 match *p {
1053 LengthOrAuto::Auto => or,
1054 LengthOrAuto::LengthPercentage(ref length) => T::from(*length),
1055 }
1056 }
1057
1058 let clip_origin = Point2D::new(
1059 From::from(self.left.auto_is(|| Length::new(0.))),
1060 From::from(self.top.auto_is(|| Length::new(0.))),
1061 );
1062 let right = extract_clip_component(&self.right, border_box.size.width);
1063 let bottom = extract_clip_component(&self.bottom, border_box.size.height);
1064 let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
1065
1066 Rect::new(clip_origin, clip_size).translate(border_box.origin.to_vector())
1067 }
1068}