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