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