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