tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

mod.rs (34283B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 //! Computed values.
      6 
      7 use self::transform::DirectionVector;
      8 use super::animated::ToAnimatedValue;
      9 use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
     10 use super::generics::grid::ImplicitGridTracks as GenericImplicitGridTracks;
     11 use super::generics::grid::{GenericGridLine, GenericTrackBreadth};
     12 use super::generics::grid::{GenericTrackSize, TrackList as GenericTrackList};
     13 use super::generics::transform::IsParallelTo;
     14 use super::generics::{self, GreaterThanOrEqualToOne, NonNegative, ZeroToOne};
     15 use super::specified;
     16 use super::{CSSFloat, CSSInteger};
     17 use crate::computed_value_flags::ComputedValueFlags;
     18 use crate::context::QuirksMode;
     19 use crate::custom_properties::ComputedCustomProperties;
     20 use crate::derives::*;
     21 use crate::font_metrics::{FontMetrics, FontMetricsOrientation};
     22 use crate::media_queries::Device;
     23 #[cfg(feature = "gecko")]
     24 use crate::properties;
     25 use crate::properties::{ComputedValues, StyleBuilder};
     26 use crate::rule_cache::RuleCacheConditions;
     27 use crate::stylesheets::container_rule::{
     28    ContainerInfo, ContainerSizeQuery, ContainerSizeQueryResult,
     29 };
     30 use crate::stylist::Stylist;
     31 use crate::values::generics::ClampToNonNegative;
     32 use crate::values::specified::font::QueryFontMetricsFlags;
     33 use crate::values::specified::length::FontBaseSize;
     34 use crate::{ArcSlice, Atom, One};
     35 use euclid::{default, Point2D, Rect, Size2D};
     36 use servo_arc::Arc;
     37 use std::cell::RefCell;
     38 use std::cmp;
     39 use std::f32;
     40 use std::ops::{Add, Sub};
     41 
     42 pub use self::align::{ContentDistribution, ItemPlacement, JustifyItems, SelfAlignment};
     43 pub use self::angle::Angle;
     44 pub use self::animation::{
     45    AnimationComposition, AnimationDirection, AnimationDuration, AnimationFillMode,
     46    AnimationIterationCount, AnimationName, AnimationPlayState, AnimationTimeline, ScrollAxis,
     47    TimelineName, TransitionBehavior, TransitionProperty, ViewTimelineInset, ViewTransitionClass,
     48    ViewTransitionName,
     49 };
     50 pub use self::background::{BackgroundRepeat, BackgroundSize};
     51 pub use self::basic_shape::FillRule;
     52 pub use self::border::{
     53    BorderCornerRadius, BorderImageRepeat, BorderImageSideWidth, BorderImageSlice,
     54    BorderImageWidth, BorderRadius, BorderSideOffset, BorderSideWidth, BorderSpacing, LineWidth,
     55 };
     56 pub use self::box_::{
     57    Appearance, BaselineSource, BreakBetween, BreakWithin, Clear, Contain, ContainIntrinsicSize,
     58    ContainerName, ContainerType, ContentVisibility, Display, Float, LineClamp, Overflow,
     59    OverflowAnchor, OverflowClipMargin, OverscrollBehavior, Perspective, PositionProperty, Resize,
     60    ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStop, ScrollSnapStrictness, ScrollSnapType,
     61    ScrollbarGutter, TouchAction, VerticalAlign, WillChange, WritingModeProperty, Zoom,
     62 };
     63 pub use self::color::{
     64    Color, ColorOrAuto, ColorPropertyValue, ColorScheme, ForcedColorAdjust, PrintColorAdjust,
     65 };
     66 pub use self::column::ColumnCount;
     67 pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset, CounterSet};
     68 pub use self::easing::TimingFunction;
     69 pub use self::effects::{BoxShadow, Filter, SimpleShadow};
     70 pub use self::flex::FlexBasis;
     71 pub use self::font::{FontFamily, FontLanguageOverride, FontPalette, FontStyle};
     72 pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
     73 pub use self::font::{
     74    FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontSynthesisStyle, LineHeight,
     75 };
     76 pub use self::font::{FontVariantAlternates, FontWeight};
     77 pub use self::font::{FontVariantEastAsian, FontVariationSettings};
     78 pub use self::font::{MathDepth, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextScale};
     79 pub use self::image::{Gradient, Image, ImageRendering, LineDirection};
     80 pub use self::length::{CSSPixelLength, NonNegativeLength};
     81 pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
     82 pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, Margin, MaxSize, Size};
     83 pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto};
     84 #[cfg(feature = "gecko")]
     85 pub use self::list::ListStyleType;
     86 pub use self::list::Quotes;
     87 pub use self::motion::{OffsetPath, OffsetPosition, OffsetRotate};
     88 pub use self::outline::OutlineStyle;
     89 pub use self::page::{PageName, PageOrientation, PageSize, PageSizeOrientation, PaperSize};
     90 pub use self::percentage::{NonNegativePercentage, Percentage};
     91 pub use self::position::AnchorFunction;
     92 pub use self::position::AnchorName;
     93 pub use self::position::AnchorScope;
     94 pub use self::position::AspectRatio;
     95 pub use self::position::DashedIdentAndOrTryTactic;
     96 pub use self::position::Inset;
     97 pub use self::position::PositionAnchor;
     98 pub use self::position::PositionTryFallbacks;
     99 pub use self::position::PositionTryOrder;
    100 pub use self::position::PositionVisibility;
    101 pub use self::position::{
    102    GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex,
    103 };
    104 pub use self::position::{PositionArea, PositionAreaKeyword};
    105 pub use self::ratio::Ratio;
    106 pub use self::rect::NonNegativeLengthOrNumberRect;
    107 pub use self::resolution::Resolution;
    108 pub use self::svg::{DProperty, MozContextProperties};
    109 pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind};
    110 pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth, VectorEffect};
    111 pub use self::text::{HyphenateCharacter, HyphenateLimitChars};
    112 pub use self::text::{InitialLetter, LetterSpacing, LineBreak, TextIndent};
    113 pub use self::text::{OverflowWrap, RubyPosition, TextOverflow, WordBreak, WordSpacing};
    114 pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle};
    115 pub use self::text::{TextAutospace, TextUnderlinePosition};
    116 pub use self::text::{
    117    TextDecorationInset, TextDecorationLength, TextDecorationSkipInk, TextJustify,
    118 };
    119 pub use self::time::Time;
    120 pub use self::transform::{Rotate, Scale, Transform, TransformBox, TransformOperation};
    121 pub use self::transform::{TransformOrigin, TransformStyle, Translate};
    122 #[cfg(feature = "gecko")]
    123 pub use self::ui::CursorImage;
    124 pub use self::ui::{
    125    BoolInteger, Cursor, Inert, MozTheme, PointerEvents, ScrollbarColor, UserFocus, UserSelect,
    126 };
    127 pub use super::specified::TextTransform;
    128 pub use super::specified::ViewportVariant;
    129 pub use super::specified::{BorderStyle, TextDecorationLine};
    130 pub use app_units::Au;
    131 
    132 pub mod align;
    133 pub mod angle;
    134 pub mod animation;
    135 pub mod background;
    136 pub mod basic_shape;
    137 pub mod border;
    138 #[path = "box.rs"]
    139 pub mod box_;
    140 pub mod color;
    141 pub mod column;
    142 pub mod counters;
    143 pub mod easing;
    144 pub mod effects;
    145 pub mod flex;
    146 pub mod font;
    147 pub mod image;
    148 pub mod length;
    149 pub mod length_percentage;
    150 pub mod list;
    151 pub mod motion;
    152 pub mod outline;
    153 pub mod page;
    154 pub mod percentage;
    155 pub mod position;
    156 pub mod ratio;
    157 pub mod rect;
    158 pub mod resolution;
    159 pub mod svg;
    160 pub mod table;
    161 pub mod text;
    162 pub mod time;
    163 pub mod transform;
    164 pub mod ui;
    165 pub mod url;
    166 
    167 /// A `Context` is all the data a specified value could ever need to compute
    168 /// itself and be transformed to a computed value.
    169 pub struct Context<'a> {
    170    /// Values accessed through this need to be in the properties "computed
    171    /// early": color, text-decoration, font-size, display, position, float,
    172    /// border-*-style, outline-style, font-family, writing-mode...
    173    pub builder: StyleBuilder<'a>,
    174 
    175    /// A cached computed system font value, for use by gecko.
    176    ///
    177    /// See properties/longhands/font.mako.rs
    178    #[cfg(feature = "gecko")]
    179    pub cached_system_font: Option<properties::longhands::system_font::ComputedSystemFont>,
    180 
    181    /// A dummy option for servo so initializing a computed::Context isn't
    182    /// painful.
    183    ///
    184    /// TODO(emilio): Make constructors for Context, and drop this.
    185    #[cfg(feature = "servo")]
    186    pub cached_system_font: Option<()>,
    187 
    188    /// Whether or not we are computing the media list in a media query.
    189    pub in_media_query: bool,
    190 
    191    /// Whether or not we are computing the container query condition.
    192    pub in_container_query: bool,
    193 
    194    /// The quirks mode of this context.
    195    pub quirks_mode: QuirksMode,
    196 
    197    /// Whether this computation is being done for a SMIL animation.
    198    ///
    199    /// This is used to allow certain properties to generate out-of-range
    200    /// values, which SMIL allows.
    201    pub for_smil_animation: bool,
    202 
    203    /// Returns the container information to evaluate a given container query.
    204    pub container_info: Option<ContainerInfo>,
    205 
    206    /// Whether we're computing a value for a non-inherited property.
    207    /// False if we are computed a value for an inherited property or not computing for a property
    208    /// at all (e.g. in a media query evaluation).
    209    pub for_non_inherited_property: bool,
    210 
    211    /// The conditions to cache a rule node on the rule cache.
    212    ///
    213    /// FIXME(emilio): Drop the refcell.
    214    pub rule_cache_conditions: RefCell<&'a mut RuleCacheConditions>,
    215 
    216    /// Container size query for this context.
    217    container_size_query: RefCell<ContainerSizeQuery<'a>>,
    218 }
    219 
    220 impl<'a> Context<'a> {
    221    /// Lazily evaluate the container size query, returning the result.
    222    pub fn get_container_size_query(&self) -> ContainerSizeQueryResult {
    223        let mut resolved = self.container_size_query.borrow_mut();
    224        resolved.get().clone()
    225    }
    226 
    227    /// Creates a suitable context for media query evaluation, in which
    228    /// font-relative units compute against the system_font, and executes `f`
    229    /// with it.
    230    pub fn for_media_query_evaluation<F, R>(device: &Device, quirks_mode: QuirksMode, f: F) -> R
    231    where
    232        F: FnOnce(&Context) -> R,
    233    {
    234        let mut conditions = RuleCacheConditions::default();
    235        let context = Context {
    236            builder: StyleBuilder::for_inheritance(device, None, None, None),
    237            cached_system_font: None,
    238            in_media_query: true,
    239            in_container_query: false,
    240            quirks_mode,
    241            for_smil_animation: false,
    242            container_info: None,
    243            for_non_inherited_property: false,
    244            rule_cache_conditions: RefCell::new(&mut conditions),
    245            container_size_query: RefCell::new(ContainerSizeQuery::none()),
    246        };
    247        f(&context)
    248    }
    249 
    250    /// Creates a suitable context for container query evaluation for the style
    251    /// specified.
    252    pub fn for_container_query_evaluation<F, R>(
    253        device: &Device,
    254        stylist: Option<&Stylist>,
    255        container_info_and_style: Option<(ContainerInfo, Arc<ComputedValues>)>,
    256        container_size_query: ContainerSizeQuery,
    257        f: F,
    258    ) -> R
    259    where
    260        F: FnOnce(&Context) -> R,
    261    {
    262        let mut conditions = RuleCacheConditions::default();
    263 
    264        let (container_info, style) = match container_info_and_style {
    265            Some((ci, s)) => (Some(ci), Some(s)),
    266            None => (None, None),
    267        };
    268 
    269        let style = style.as_ref().map(|s| &**s);
    270        let quirks_mode = device.quirks_mode();
    271        let context = Context {
    272            builder: StyleBuilder::for_inheritance(device, stylist, style, None),
    273            cached_system_font: None,
    274            in_media_query: false,
    275            in_container_query: true,
    276            quirks_mode,
    277            for_smil_animation: false,
    278            container_info,
    279            for_non_inherited_property: false,
    280            rule_cache_conditions: RefCell::new(&mut conditions),
    281            container_size_query: RefCell::new(container_size_query),
    282        };
    283 
    284        f(&context)
    285    }
    286 
    287    /// Creates a context suitable for more general cases.
    288    pub fn new(
    289        builder: StyleBuilder<'a>,
    290        quirks_mode: QuirksMode,
    291        rule_cache_conditions: &'a mut RuleCacheConditions,
    292        container_size_query: ContainerSizeQuery<'a>,
    293    ) -> Self {
    294        Self {
    295            builder,
    296            cached_system_font: None,
    297            in_media_query: false,
    298            in_container_query: false,
    299            quirks_mode,
    300            container_info: None,
    301            for_smil_animation: false,
    302            for_non_inherited_property: false,
    303            rule_cache_conditions: RefCell::new(rule_cache_conditions),
    304            container_size_query: RefCell::new(container_size_query),
    305        }
    306    }
    307 
    308    /// Creates a context suitable for computing animations.
    309    pub fn new_for_animation(
    310        builder: StyleBuilder<'a>,
    311        for_smil_animation: bool,
    312        quirks_mode: QuirksMode,
    313        rule_cache_conditions: &'a mut RuleCacheConditions,
    314        container_size_query: ContainerSizeQuery<'a>,
    315    ) -> Self {
    316        Self {
    317            builder,
    318            cached_system_font: None,
    319            in_media_query: false,
    320            in_container_query: false,
    321            quirks_mode,
    322            container_info: None,
    323            for_smil_animation,
    324            for_non_inherited_property: false,
    325            rule_cache_conditions: RefCell::new(rule_cache_conditions),
    326            container_size_query: RefCell::new(container_size_query),
    327        }
    328    }
    329 
    330    /// Creates a context suitable for computing the initial value of @property.
    331    pub fn new_for_initial_at_property_value(
    332        stylist: &'a Stylist,
    333        rule_cache_conditions: &'a mut RuleCacheConditions,
    334    ) -> Self {
    335        Self {
    336            builder: StyleBuilder::new(stylist.device(), Some(stylist), None, None, None, false),
    337            cached_system_font: None,
    338            // Because font-relative values are disallowed in @property initial values, we do not
    339            // need to keep track of whether we're in a media query, whether we're in a container
    340            // query, and so on.
    341            in_media_query: false,
    342            in_container_query: false,
    343            quirks_mode: stylist.quirks_mode(),
    344            container_info: None,
    345            for_smil_animation: false,
    346            for_non_inherited_property: false,
    347            rule_cache_conditions: RefCell::new(rule_cache_conditions),
    348            container_size_query: RefCell::new(ContainerSizeQuery::none()),
    349        }
    350    }
    351 
    352    /// The current device.
    353    pub fn device(&self) -> &Device {
    354        self.builder.device
    355    }
    356 
    357    /// Get the inherited custom properties map.
    358    pub fn inherited_custom_properties(&self) -> &ComputedCustomProperties {
    359        &self.builder.inherited_custom_properties()
    360    }
    361 
    362    /// Whether the style is for the root element.
    363    pub fn is_root_element(&self) -> bool {
    364        self.builder.is_root_element
    365    }
    366 
    367    /// Queries font metrics.
    368    pub fn query_font_metrics(
    369        &self,
    370        base_size: FontBaseSize,
    371        orientation: FontMetricsOrientation,
    372        mut flags: QueryFontMetricsFlags,
    373    ) -> FontMetrics {
    374        if self.for_non_inherited_property {
    375            self.rule_cache_conditions.borrow_mut().set_uncacheable();
    376        }
    377        self.builder.add_flags(match base_size {
    378            FontBaseSize::CurrentStyle => ComputedValueFlags::DEPENDS_ON_SELF_FONT_METRICS,
    379            FontBaseSize::InheritedStyle => ComputedValueFlags::DEPENDS_ON_INHERITED_FONT_METRICS,
    380        });
    381        let size = base_size.resolve(self).used_size();
    382        let style = self.style();
    383 
    384        let (wm, font) = match base_size {
    385            FontBaseSize::CurrentStyle => (style.writing_mode, style.get_font()),
    386            // This is only used for font-size computation.
    387            FontBaseSize::InheritedStyle => {
    388                (*style.inherited_writing_mode(), style.get_parent_font())
    389            },
    390        };
    391 
    392        let vertical = match orientation {
    393            FontMetricsOrientation::MatchContextPreferHorizontal => {
    394                wm.is_vertical() && wm.is_upright()
    395            },
    396            FontMetricsOrientation::MatchContextPreferVertical => wm.is_text_vertical(),
    397            FontMetricsOrientation::Horizontal => false,
    398        };
    399        if !self.in_media_query {
    400            flags |= QueryFontMetricsFlags::USE_USER_FONT_SET
    401        }
    402        self.device()
    403            .query_font_metrics(vertical, font, size, flags, /* track_changes = */ true)
    404    }
    405 
    406    /// The current viewport size, used to resolve viewport units.
    407    pub fn viewport_size_for_viewport_unit_resolution(
    408        &self,
    409        variant: ViewportVariant,
    410    ) -> default::Size2D<Au> {
    411        self.builder
    412            .add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS);
    413        self.builder
    414            .device
    415            .au_viewport_size_for_viewport_unit_resolution(variant)
    416    }
    417 
    418    /// Whether we're in a media or container query.
    419    pub fn in_media_or_container_query(&self) -> bool {
    420        self.in_media_query || self.in_container_query
    421    }
    422 
    423    /// The default computed style we're getting our reset style from.
    424    pub fn default_style(&self) -> &ComputedValues {
    425        self.builder.default_style()
    426    }
    427 
    428    /// The current style.
    429    pub fn style(&self) -> &StyleBuilder<'a> {
    430        &self.builder
    431    }
    432 
    433    /// Apply text-zoom if enabled.
    434    #[cfg(feature = "gecko")]
    435    pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
    436        if self
    437            .style()
    438            .get_font()
    439            .clone__x_text_scale()
    440            .text_zoom_enabled()
    441        {
    442            self.device().zoom_text(size)
    443        } else {
    444            size
    445        }
    446    }
    447 
    448    /// (Servo doesn't do text-zoom)
    449    #[cfg(feature = "servo")]
    450    pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength {
    451        size
    452    }
    453 }
    454 
    455 /// An iterator over a slice of computed values
    456 #[derive(Clone)]
    457 pub struct ComputedVecIter<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> {
    458    cx: &'cx Context<'cx_a>,
    459    values: &'a [S],
    460 }
    461 
    462 impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ComputedVecIter<'a, 'cx, 'cx_a, S> {
    463    /// Construct an iterator from a slice of specified values and a context
    464    pub fn new(cx: &'cx Context<'cx_a>, values: &'a [S]) -> Self {
    465        ComputedVecIter { cx, values }
    466    }
    467 }
    468 
    469 impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ExactSizeIterator
    470    for ComputedVecIter<'a, 'cx, 'cx_a, S>
    471 {
    472    fn len(&self) -> usize {
    473        self.values.len()
    474    }
    475 }
    476 
    477 impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter<'a, 'cx, 'cx_a, S> {
    478    type Item = S::ComputedValue;
    479    fn next(&mut self) -> Option<Self::Item> {
    480        if let Some((next, rest)) = self.values.split_first() {
    481            let ret = next.to_computed_value(self.cx);
    482            self.values = rest;
    483            Some(ret)
    484        } else {
    485            None
    486        }
    487    }
    488 
    489    fn size_hint(&self) -> (usize, Option<usize>) {
    490        (self.values.len(), Some(self.values.len()))
    491    }
    492 }
    493 
    494 /// A trait to represent the conversion between computed and specified values.
    495 ///
    496 /// This trait is derivable with `#[derive(ToComputedValue)]`. The derived
    497 /// implementation just calls `ToComputedValue::to_computed_value` on each field
    498 /// of the passed value. The deriving code assumes that if the type isn't
    499 /// generic, then the trait can be implemented as simple `Clone::clone` calls,
    500 /// this means that a manual implementation with `ComputedValue = Self` is bogus
    501 /// if it returns anything else than a clone.
    502 pub trait ToComputedValue {
    503    /// The computed value type we're going to be converted to.
    504    type ComputedValue;
    505 
    506    /// Convert a specified value to a computed value, using itself and the data
    507    /// inside the `Context`.
    508    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue;
    509 
    510    /// Convert a computed value to specified value form.
    511    ///
    512    /// This will be used for recascading during animation.
    513    /// Such from_computed_valued values should recompute to the same value.
    514    fn from_computed_value(computed: &Self::ComputedValue) -> Self;
    515 }
    516 
    517 impl<A, B> ToComputedValue for (A, B)
    518 where
    519    A: ToComputedValue,
    520    B: ToComputedValue,
    521 {
    522    type ComputedValue = (
    523        <A as ToComputedValue>::ComputedValue,
    524        <B as ToComputedValue>::ComputedValue,
    525    );
    526 
    527    #[inline]
    528    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
    529        (
    530            self.0.to_computed_value(context),
    531            self.1.to_computed_value(context),
    532        )
    533    }
    534 
    535    #[inline]
    536    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    537        (
    538            A::from_computed_value(&computed.0),
    539            B::from_computed_value(&computed.1),
    540        )
    541    }
    542 }
    543 
    544 impl<T> ToComputedValue for Option<T>
    545 where
    546    T: ToComputedValue,
    547 {
    548    type ComputedValue = Option<<T as ToComputedValue>::ComputedValue>;
    549 
    550    #[inline]
    551    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
    552        self.as_ref().map(|item| item.to_computed_value(context))
    553    }
    554 
    555    #[inline]
    556    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    557        computed.as_ref().map(T::from_computed_value)
    558    }
    559 }
    560 
    561 impl<T> ToComputedValue for default::Size2D<T>
    562 where
    563    T: ToComputedValue,
    564 {
    565    type ComputedValue = default::Size2D<<T as ToComputedValue>::ComputedValue>;
    566 
    567    #[inline]
    568    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
    569        Size2D::new(
    570            self.width.to_computed_value(context),
    571            self.height.to_computed_value(context),
    572        )
    573    }
    574 
    575    #[inline]
    576    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    577        Size2D::new(
    578            T::from_computed_value(&computed.width),
    579            T::from_computed_value(&computed.height),
    580        )
    581    }
    582 }
    583 
    584 impl<T> ToComputedValue for Vec<T>
    585 where
    586    T: ToComputedValue,
    587 {
    588    type ComputedValue = Vec<<T as ToComputedValue>::ComputedValue>;
    589 
    590    #[inline]
    591    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
    592        self.iter()
    593            .map(|item| item.to_computed_value(context))
    594            .collect()
    595    }
    596 
    597    #[inline]
    598    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    599        computed.iter().map(T::from_computed_value).collect()
    600    }
    601 }
    602 
    603 impl<T> ToComputedValue for Box<T>
    604 where
    605    T: ToComputedValue,
    606 {
    607    type ComputedValue = Box<<T as ToComputedValue>::ComputedValue>;
    608 
    609    #[inline]
    610    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
    611        Box::new(T::to_computed_value(self, context))
    612    }
    613 
    614    #[inline]
    615    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    616        Box::new(T::from_computed_value(computed))
    617    }
    618 }
    619 
    620 impl<T> ToComputedValue for Box<[T]>
    621 where
    622    T: ToComputedValue,
    623 {
    624    type ComputedValue = Box<[<T as ToComputedValue>::ComputedValue]>;
    625 
    626    #[inline]
    627    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
    628        self.iter()
    629            .map(|item| item.to_computed_value(context))
    630            .collect()
    631    }
    632 
    633    #[inline]
    634    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    635        computed.iter().map(T::from_computed_value).collect()
    636    }
    637 }
    638 
    639 impl<T> ToComputedValue for crate::OwnedSlice<T>
    640 where
    641    T: ToComputedValue,
    642 {
    643    type ComputedValue = crate::OwnedSlice<<T as ToComputedValue>::ComputedValue>;
    644 
    645    #[inline]
    646    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
    647        self.iter()
    648            .map(|item| item.to_computed_value(context))
    649            .collect()
    650    }
    651 
    652    #[inline]
    653    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    654        computed.iter().map(T::from_computed_value).collect()
    655    }
    656 }
    657 
    658 impl<T> ToComputedValue for thin_vec::ThinVec<T>
    659 where
    660    T: ToComputedValue,
    661 {
    662    type ComputedValue = thin_vec::ThinVec<<T as ToComputedValue>::ComputedValue>;
    663 
    664    #[inline]
    665    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
    666        self.iter()
    667            .map(|item| item.to_computed_value(context))
    668            .collect()
    669    }
    670 
    671    #[inline]
    672    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    673        computed.iter().map(T::from_computed_value).collect()
    674    }
    675 }
    676 
    677 // NOTE(emilio): This is implementable more generically, but it's unlikely
    678 // what you want there, as it forces you to have an extra allocation.
    679 //
    680 // We could do that if needed, ideally with specialization for the case where
    681 // ComputedValue = T. But we don't need it for now.
    682 impl<T> ToComputedValue for Arc<T>
    683 where
    684    T: ToComputedValue<ComputedValue = T>,
    685 {
    686    type ComputedValue = Self;
    687 
    688    #[inline]
    689    fn to_computed_value(&self, _: &Context) -> Self {
    690        self.clone()
    691    }
    692 
    693    #[inline]
    694    fn from_computed_value(computed: &Self) -> Self {
    695        computed.clone()
    696    }
    697 }
    698 
    699 // Same caveat as above applies.
    700 impl<T> ToComputedValue for ArcSlice<T>
    701 where
    702    T: ToComputedValue<ComputedValue = T>,
    703 {
    704    type ComputedValue = Self;
    705 
    706    #[inline]
    707    fn to_computed_value(&self, _: &Context) -> Self {
    708        self.clone()
    709    }
    710 
    711    #[inline]
    712    fn from_computed_value(computed: &Self) -> Self {
    713        computed.clone()
    714    }
    715 }
    716 
    717 trivial_to_computed_value!(());
    718 trivial_to_computed_value!(bool);
    719 trivial_to_computed_value!(f32);
    720 trivial_to_computed_value!(i32);
    721 trivial_to_computed_value!(u8);
    722 trivial_to_computed_value!(u16);
    723 trivial_to_computed_value!(u32);
    724 trivial_to_computed_value!(usize);
    725 trivial_to_computed_value!(Atom);
    726 trivial_to_computed_value!(crate::values::AtomIdent);
    727 #[cfg(feature = "servo")]
    728 trivial_to_computed_value!(crate::Namespace);
    729 #[cfg(feature = "servo")]
    730 trivial_to_computed_value!(crate::Prefix);
    731 trivial_to_computed_value!(crate::stylesheets::UrlExtraData);
    732 trivial_to_computed_value!(String);
    733 trivial_to_computed_value!(Box<str>);
    734 trivial_to_computed_value!(crate::OwnedStr);
    735 trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType);
    736 trivial_to_computed_value!(crate::values::generics::color::ColorMixFlags);
    737 
    738 #[allow(missing_docs)]
    739 #[derive(
    740    Animate,
    741    Clone,
    742    ComputeSquaredDistance,
    743    Copy,
    744    Debug,
    745    MallocSizeOf,
    746    PartialEq,
    747    ToAnimatedZero,
    748    ToCss,
    749    ToResolvedValue,
    750 )]
    751 #[repr(C, u8)]
    752 pub enum AngleOrPercentage {
    753    Percentage(Percentage),
    754    Angle(Angle),
    755 }
    756 
    757 impl ToComputedValue for specified::AngleOrPercentage {
    758    type ComputedValue = AngleOrPercentage;
    759 
    760    #[inline]
    761    fn to_computed_value(&self, context: &Context) -> AngleOrPercentage {
    762        match *self {
    763            specified::AngleOrPercentage::Percentage(percentage) => {
    764                AngleOrPercentage::Percentage(percentage.to_computed_value(context))
    765            },
    766            specified::AngleOrPercentage::Angle(angle) => {
    767                AngleOrPercentage::Angle(angle.to_computed_value(context))
    768            },
    769        }
    770    }
    771    #[inline]
    772    fn from_computed_value(computed: &AngleOrPercentage) -> Self {
    773        match *computed {
    774            AngleOrPercentage::Percentage(percentage) => specified::AngleOrPercentage::Percentage(
    775                ToComputedValue::from_computed_value(&percentage),
    776            ),
    777            AngleOrPercentage::Angle(angle) => {
    778                specified::AngleOrPercentage::Angle(ToComputedValue::from_computed_value(&angle))
    779            },
    780        }
    781    }
    782 }
    783 
    784 /// A `<number>` value.
    785 pub type Number = CSSFloat;
    786 
    787 impl IsParallelTo for (Number, Number, Number) {
    788    fn is_parallel_to(&self, vector: &DirectionVector) -> bool {
    789        use euclid::approxeq::ApproxEq;
    790        // If a and b is parallel, the angle between them is 0deg, so
    791        // a x b = |a|*|b|*sin(0)*n = 0 * n, |a x b| == 0.
    792        let self_vector = DirectionVector::new(self.0, self.1, self.2);
    793        self_vector
    794            .cross(*vector)
    795            .square_length()
    796            .approx_eq(&0.0f32)
    797    }
    798 }
    799 
    800 /// A wrapper of Number, but the value >= 0.
    801 pub type NonNegativeNumber = NonNegative<CSSFloat>;
    802 
    803 impl From<CSSFloat> for NonNegativeNumber {
    804    #[inline]
    805    fn from(number: CSSFloat) -> NonNegativeNumber {
    806        NonNegative::<CSSFloat>(number)
    807    }
    808 }
    809 
    810 impl From<NonNegativeNumber> for CSSFloat {
    811    #[inline]
    812    fn from(number: NonNegativeNumber) -> CSSFloat {
    813        number.0
    814    }
    815 }
    816 
    817 impl One for NonNegativeNumber {
    818    #[inline]
    819    fn one() -> Self {
    820        NonNegative(1.0)
    821    }
    822 
    823    #[inline]
    824    fn is_one(&self) -> bool {
    825        self.0 == 1.0
    826    }
    827 }
    828 
    829 /// A wrapper of Number, but the value between 0 and 1
    830 pub type ZeroToOneNumber = ZeroToOne<CSSFloat>;
    831 
    832 impl ToAnimatedValue for ZeroToOneNumber {
    833    type AnimatedValue = Self;
    834 
    835    #[inline]
    836    fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
    837        self
    838    }
    839 
    840    #[inline]
    841    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
    842        Self(animated.0.max(0.).min(1.))
    843    }
    844 }
    845 
    846 impl From<CSSFloat> for ZeroToOneNumber {
    847    #[inline]
    848    fn from(number: CSSFloat) -> Self {
    849        Self(number)
    850    }
    851 }
    852 
    853 /// A wrapper of Number, but the value >= 1.
    854 pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<CSSFloat>;
    855 
    856 impl ToAnimatedValue for GreaterThanOrEqualToOneNumber {
    857    type AnimatedValue = CSSFloat;
    858 
    859    #[inline]
    860    fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
    861        self.0
    862    }
    863 
    864    #[inline]
    865    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
    866        animated.max(1.).into()
    867    }
    868 }
    869 
    870 impl From<CSSFloat> for GreaterThanOrEqualToOneNumber {
    871    #[inline]
    872    fn from(number: CSSFloat) -> GreaterThanOrEqualToOneNumber {
    873        GreaterThanOrEqualToOne::<CSSFloat>(number)
    874    }
    875 }
    876 
    877 impl From<GreaterThanOrEqualToOneNumber> for CSSFloat {
    878    #[inline]
    879    fn from(number: GreaterThanOrEqualToOneNumber) -> CSSFloat {
    880        number.0
    881    }
    882 }
    883 
    884 #[allow(missing_docs)]
    885 #[derive(
    886    Animate,
    887    Clone,
    888    ComputeSquaredDistance,
    889    Copy,
    890    Debug,
    891    MallocSizeOf,
    892    PartialEq,
    893    ToAnimatedZero,
    894    ToAnimatedValue,
    895    ToCss,
    896    ToResolvedValue,
    897 )]
    898 #[repr(C, u8)]
    899 pub enum NumberOrPercentage {
    900    Percentage(Percentage),
    901    Number(Number),
    902 }
    903 
    904 impl ClampToNonNegative for NumberOrPercentage {
    905    fn clamp_to_non_negative(self) -> Self {
    906        match self {
    907            NumberOrPercentage::Percentage(p) => {
    908                NumberOrPercentage::Percentage(p.clamp_to_non_negative())
    909            },
    910            NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.clamp_to_non_negative()),
    911        }
    912    }
    913 }
    914 
    915 impl ToComputedValue for specified::NumberOrPercentage {
    916    type ComputedValue = NumberOrPercentage;
    917 
    918    #[inline]
    919    fn to_computed_value(&self, context: &Context) -> NumberOrPercentage {
    920        match *self {
    921            specified::NumberOrPercentage::Percentage(percentage) => {
    922                NumberOrPercentage::Percentage(percentage.to_computed_value(context))
    923            },
    924            specified::NumberOrPercentage::Number(number) => {
    925                NumberOrPercentage::Number(number.to_computed_value(context))
    926            },
    927        }
    928    }
    929    #[inline]
    930    fn from_computed_value(computed: &NumberOrPercentage) -> Self {
    931        match *computed {
    932            NumberOrPercentage::Percentage(percentage) => {
    933                specified::NumberOrPercentage::Percentage(ToComputedValue::from_computed_value(
    934                    &percentage,
    935                ))
    936            },
    937            NumberOrPercentage::Number(number) => {
    938                specified::NumberOrPercentage::Number(ToComputedValue::from_computed_value(&number))
    939            },
    940        }
    941    }
    942 }
    943 
    944 /// A non-negative <number-percentage>.
    945 pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>;
    946 
    947 impl NonNegativeNumberOrPercentage {
    948    /// Returns the `100%` value.
    949    #[inline]
    950    pub fn hundred_percent() -> Self {
    951        NonNegative(NumberOrPercentage::Percentage(Percentage::hundred()))
    952    }
    953 }
    954 
    955 /// A type used for opacity.
    956 pub type Opacity = CSSFloat;
    957 
    958 /// A `<integer>` value.
    959 pub type Integer = CSSInteger;
    960 
    961 /// A wrapper of Integer, but only accept a value >= 1.
    962 pub type PositiveInteger = GreaterThanOrEqualToOne<CSSInteger>;
    963 
    964 impl ToAnimatedValue for PositiveInteger {
    965    type AnimatedValue = CSSInteger;
    966 
    967    #[inline]
    968    fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
    969        self.0
    970    }
    971 
    972    #[inline]
    973    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
    974        cmp::max(animated, 1).into()
    975    }
    976 }
    977 
    978 impl From<CSSInteger> for PositiveInteger {
    979    #[inline]
    980    fn from(int: CSSInteger) -> PositiveInteger {
    981        GreaterThanOrEqualToOne::<CSSInteger>(int)
    982    }
    983 }
    984 
    985 /// rect(...) | auto
    986 pub type ClipRect = generics::GenericClipRect<LengthOrAuto>;
    987 
    988 /// rect(...) | auto
    989 pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>;
    990 
    991 /// The computed value of a grid `<track-breadth>`
    992 pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;
    993 
    994 /// The computed value of a grid `<track-size>`
    995 pub type TrackSize = GenericTrackSize<LengthPercentage>;
    996 
    997 /// The computed value of a grid `<track-size>+`
    998 pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>;
    999 
   1000 /// The computed value of a grid `<track-list>`
   1001 /// (could also be `<auto-track-list>` or `<explicit-track-list>`)
   1002 pub type TrackList = GenericTrackList<LengthPercentage, Integer>;
   1003 
   1004 /// The computed value of a `<grid-line>`.
   1005 pub type GridLine = GenericGridLine<Integer>;
   1006 
   1007 /// `<grid-template-rows> | <grid-template-columns>`
   1008 pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
   1009 
   1010 impl ClipRect {
   1011    /// Given a border box, resolves the clip rect against the border box
   1012    /// in the same space the border box is in
   1013    pub fn for_border_rect<T: Copy + From<Length> + Add<Output = T> + Sub<Output = T>, U>(
   1014        &self,
   1015        border_box: Rect<T, U>,
   1016    ) -> Rect<T, U> {
   1017        fn extract_clip_component<T: From<Length>>(p: &LengthOrAuto, or: T) -> T {
   1018            match *p {
   1019                LengthOrAuto::Auto => or,
   1020                LengthOrAuto::LengthPercentage(ref length) => T::from(*length),
   1021            }
   1022        }
   1023 
   1024        let clip_origin = Point2D::new(
   1025            From::from(self.left.auto_is(|| Length::new(0.))),
   1026            From::from(self.top.auto_is(|| Length::new(0.))),
   1027        );
   1028        let right = extract_clip_component(&self.right, border_box.size.width);
   1029        let bottom = extract_clip_component(&self.bottom, border_box.size.height);
   1030        let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
   1031 
   1032        Rect::new(clip_origin, clip_size).translate(border_box.origin.to_vector())
   1033    }
   1034 }