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