tor-browser

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

basic_shape.rs (10144B)


      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 //! CSS handling for the computed value of
      6 //! [`basic-shape`][basic-shape]s
      7 //!
      8 //! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape
      9 
     10 use crate::values::animated::{Animate, Procedure};
     11 use crate::values::computed::angle::Angle;
     12 use crate::values::computed::url::ComputedUrl;
     13 use crate::values::computed::{Image, LengthPercentage, Position};
     14 use crate::values::generics::basic_shape as generic;
     15 use crate::values::generics::basic_shape::ShapePosition;
     16 use crate::values::specified::svg_path::{CoordPair, PathCommand};
     17 use crate::values::CSSFloat;
     18 
     19 /// A computed alias for FillRule.
     20 pub use crate::values::generics::basic_shape::FillRule;
     21 
     22 /// A computed `clip-path` value.
     23 pub type ClipPath = generic::GenericClipPath<BasicShape, ComputedUrl>;
     24 
     25 /// A computed `shape-outside` value.
     26 pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>;
     27 
     28 /// A computed basic shape.
     29 pub type BasicShape = generic::GenericBasicShape<Angle, Position, LengthPercentage, InsetRect>;
     30 
     31 /// The computed value of `inset()`.
     32 pub type InsetRect = generic::GenericInsetRect<LengthPercentage>;
     33 
     34 /// A computed circle.
     35 pub type Circle = generic::Circle<LengthPercentage>;
     36 
     37 /// A computed ellipse.
     38 pub type Ellipse = generic::Ellipse<LengthPercentage>;
     39 
     40 /// The computed value of `ShapeRadius`.
     41 pub type ShapeRadius = generic::GenericShapeRadius<LengthPercentage>;
     42 
     43 /// The computed value of `shape()`.
     44 pub type Shape = generic::Shape<Angle, Position, LengthPercentage>;
     45 
     46 /// The computed value of `ShapeCommand`.
     47 pub type ShapeCommand = generic::GenericShapeCommand<Angle, Position, LengthPercentage>;
     48 
     49 /// The computed value of `PathOrShapeFunction`.
     50 pub type PathOrShapeFunction =
     51    generic::GenericPathOrShapeFunction<Angle, Position, LengthPercentage>;
     52 
     53 /// The computed value of `CoordinatePair`.
     54 pub type CoordinatePair = generic::CoordinatePair<LengthPercentage>;
     55 
     56 /// The computed value of 'ControlPoint'.
     57 pub type ControlPoint = generic::ControlPoint<Position, LengthPercentage>;
     58 
     59 /// The computed value of 'RelativeControlPoint'.
     60 pub type RelativeControlPoint = generic::RelativeControlPoint<LengthPercentage>;
     61 
     62 /// The computed value of 'CommandEndPoint'.
     63 pub type CommandEndPoint = generic::CommandEndPoint<Position, LengthPercentage>;
     64 
     65 /// The computed value of hline and vline's endpoint.
     66 pub type AxisEndPoint = generic::AxisEndPoint<LengthPercentage>;
     67 
     68 /// Animate from `Shape` to `Path`, and vice versa.
     69 macro_rules! animate_shape {
     70    (
     71        $from:ident,
     72        $to:ident,
     73        $procedure:ident,
     74        $from_as_shape:tt,
     75        $to_as_shape:tt
     76    ) => {{
     77        // Check fill-rule.
     78        if $from.fill != $to.fill {
     79            return Err(());
     80        }
     81 
     82        // Check the list of commands. (This is a specialized lists::by_computed_value::animate().)
     83        let from_cmds = $from.commands();
     84        let to_cmds = $to.commands();
     85        if from_cmds.len() != to_cmds.len() {
     86            return Err(());
     87        }
     88        let commands = from_cmds
     89            .iter()
     90            .zip(to_cmds.iter())
     91            .map(|(from_cmd, to_cmd)| {
     92                $from_as_shape(from_cmd).animate(&$to_as_shape(to_cmd), $procedure)
     93            })
     94            .collect::<Result<Vec<ShapeCommand>, ()>>()?;
     95 
     96        Ok(Shape {
     97            fill: $from.fill,
     98            commands: commands.into(),
     99        })
    100    }};
    101 }
    102 
    103 impl Animate for PathOrShapeFunction {
    104    #[inline]
    105    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
    106        // Per spec, commands are "the same" if they use the same command keyword, and use the same
    107        // <by-to> keyword. For curve and smooth, they also must have the same number of control
    108        // points. Therefore, we don't have to do normalization here. (Note that we do
    109        // normalization if we animate from path() to path(). See svg_path.rs for more details.)
    110        //
    111        // https://drafts.csswg.org/css-shapes-2/#interpolating-shape
    112        match (self, other) {
    113            (Self::Path(ref from), Self::Path(ref to)) => {
    114                from.animate(to, procedure).map(Self::Path)
    115            },
    116            (Self::Shape(ref from), Self::Shape(ref to)) => {
    117                from.animate(to, procedure).map(Self::Shape)
    118            },
    119            (Self::Shape(ref from), Self::Path(ref to)) => {
    120                // Animate from shape() to path(). We convert each PathCommand into ShapeCommand,
    121                // and return shape().
    122                animate_shape!(
    123                    from,
    124                    to,
    125                    procedure,
    126                    (|shape_cmd| shape_cmd),
    127                    (|path_cmd| ShapeCommand::from(path_cmd))
    128                )
    129                .map(Self::Shape)
    130            },
    131            (Self::Path(ref from), Self::Shape(ref to)) => {
    132                // Animate from path() to shape(). We convert each PathCommand into ShapeCommand,
    133                // and return shape().
    134                animate_shape!(
    135                    from,
    136                    to,
    137                    procedure,
    138                    (|path_cmd| ShapeCommand::from(path_cmd)),
    139                    (|shape_cmd| shape_cmd)
    140                )
    141                .map(Self::Shape)
    142            },
    143        }
    144    }
    145 }
    146 
    147 impl From<&PathCommand> for ShapeCommand {
    148    #[inline]
    149    fn from(path: &PathCommand) -> Self {
    150        match path {
    151            &PathCommand::Close => Self::Close,
    152            &PathCommand::Move { ref point } => Self::Move {
    153                point: point.into(),
    154            },
    155            &PathCommand::Line { ref point } => Self::Move {
    156                point: point.into(),
    157            },
    158            &PathCommand::HLine { ref x } => Self::HLine { x: x.into() },
    159            &PathCommand::VLine { ref y } => Self::VLine { y: y.into() },
    160            &PathCommand::CubicCurve {
    161                ref point,
    162                ref control1,
    163                ref control2,
    164            } => Self::CubicCurve {
    165                point: point.into(),
    166                control1: control1.into(),
    167                control2: control2.into(),
    168            },
    169            &PathCommand::QuadCurve {
    170                ref point,
    171                ref control1,
    172            } => Self::QuadCurve {
    173                point: point.into(),
    174                control1: control1.into(),
    175            },
    176            &PathCommand::SmoothCubic {
    177                ref point,
    178                ref control2,
    179            } => Self::SmoothCubic {
    180                point: point.into(),
    181                control2: control2.into(),
    182            },
    183            &PathCommand::SmoothQuad { ref point } => Self::SmoothQuad {
    184                point: point.into(),
    185            },
    186            &PathCommand::Arc {
    187                ref point,
    188                ref radii,
    189                arc_sweep,
    190                arc_size,
    191                rotate,
    192            } => Self::Arc {
    193                point: point.into(),
    194                radii: radii.into(),
    195                arc_sweep,
    196                arc_size,
    197                rotate: Angle::from_degrees(rotate),
    198            },
    199        }
    200    }
    201 }
    202 
    203 impl From<&CoordPair> for CoordinatePair {
    204    #[inline]
    205    fn from(p: &CoordPair) -> Self {
    206        use crate::values::computed::CSSPixelLength;
    207        Self::new(
    208            LengthPercentage::new_length(CSSPixelLength::new(p.x)),
    209            LengthPercentage::new_length(CSSPixelLength::new(p.y)),
    210        )
    211    }
    212 }
    213 
    214 impl From<&ShapePosition<CSSFloat>> for Position {
    215    #[inline]
    216    fn from(p: &ShapePosition<CSSFloat>) -> Self {
    217        use crate::values::computed::CSSPixelLength;
    218        Self::new(
    219            LengthPercentage::new_length(CSSPixelLength::new(p.horizontal)),
    220            LengthPercentage::new_length(CSSPixelLength::new(p.vertical)),
    221        )
    222    }
    223 }
    224 
    225 impl From<&generic::CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>> for CommandEndPoint {
    226    #[inline]
    227    fn from(p: &generic::CommandEndPoint<ShapePosition<CSSFloat>, CSSFloat>) -> Self {
    228        match p {
    229            generic::CommandEndPoint::ToPosition(pos) => Self::ToPosition(pos.into()),
    230            generic::CommandEndPoint::ByCoordinate(coord) => Self::ByCoordinate(coord.into()),
    231        }
    232    }
    233 }
    234 
    235 impl From<&generic::AxisEndPoint<CSSFloat>> for AxisEndPoint {
    236    #[inline]
    237    fn from(p: &generic::AxisEndPoint<CSSFloat>) -> Self {
    238        use crate::values::computed::CSSPixelLength;
    239        use generic::AxisPosition;
    240        match p {
    241            generic::AxisEndPoint::ToPosition(AxisPosition::LengthPercent(lp)) => Self::ToPosition(
    242                AxisPosition::LengthPercent(LengthPercentage::new_length(CSSPixelLength::new(*lp))),
    243            ),
    244            generic::AxisEndPoint::ToPosition(AxisPosition::Keyword(_)) => {
    245                unreachable!("Invalid state: SVG path commands cannot contain a keyword.")
    246            },
    247            generic::AxisEndPoint::ByCoordinate(pos) => {
    248                Self::ByCoordinate(LengthPercentage::new_length(CSSPixelLength::new(*pos)))
    249            },
    250        }
    251    }
    252 }
    253 
    254 impl From<&generic::ControlPoint<ShapePosition<CSSFloat>, CSSFloat>> for ControlPoint {
    255    #[inline]
    256    fn from(p: &generic::ControlPoint<ShapePosition<CSSFloat>, CSSFloat>) -> Self {
    257        match p {
    258            generic::ControlPoint::Absolute(pos) => Self::Absolute(pos.into()),
    259            generic::ControlPoint::Relative(point) => Self::Relative(RelativeControlPoint {
    260                coord: CoordinatePair::from(&point.coord),
    261                reference: point.reference,
    262            }),
    263        }
    264    }
    265 }
    266 
    267 impl From<&generic::ArcRadii<CSSFloat>> for generic::ArcRadii<LengthPercentage> {
    268    #[inline]
    269    fn from(p: &generic::ArcRadii<CSSFloat>) -> Self {
    270        use crate::values::computed::CSSPixelLength;
    271        Self {
    272            rx: LengthPercentage::new_length(CSSPixelLength::new(p.rx)),
    273            ry: p
    274                .ry
    275                .map(|v| LengthPercentage::new_length(CSSPixelLength::new(v))),
    276        }
    277    }
    278 }