summaryrefslogtreecommitdiffstats
path: root/servo/components/style/values
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/values')
-rw-r--r--servo/components/style/values/computed/basic_shape.rs188
-rw-r--r--servo/components/style/values/computed/box.rs11
-rw-r--r--servo/components/style/values/computed/font.rs14
-rw-r--r--servo/components/style/values/computed/length.rs23
-rw-r--r--servo/components/style/values/computed/length_percentage.rs20
-rw-r--r--servo/components/style/values/computed/ratio.rs2
-rw-r--r--servo/components/style/values/generics/basic_shape.rs532
-rw-r--r--servo/components/style/values/generics/counters.rs14
-rw-r--r--servo/components/style/values/generics/image.rs4
-rw-r--r--servo/components/style/values/generics/transform.rs1
-rw-r--r--servo/components/style/values/resolved/mod.rs1
-rw-r--r--servo/components/style/values/specified/animation.rs40
-rw-r--r--servo/components/style/values/specified/basic_shape.rs206
-rw-r--r--servo/components/style/values/specified/box.rs50
-rw-r--r--servo/components/style/values/specified/color.rs159
-rw-r--r--servo/components/style/values/specified/counters.rs11
-rw-r--r--servo/components/style/values/specified/easing.rs11
-rw-r--r--servo/components/style/values/specified/effects.rs2
-rw-r--r--servo/components/style/values/specified/image.rs2
-rw-r--r--servo/components/style/values/specified/length.rs57
-rw-r--r--servo/components/style/values/specified/motion.rs23
-rw-r--r--servo/components/style/values/specified/svg_path.rs562
-rw-r--r--servo/components/style/values/specified/text.rs7
23 files changed, 1250 insertions, 690 deletions
diff --git a/servo/components/style/values/computed/basic_shape.rs b/servo/components/style/values/computed/basic_shape.rs
index d39110ec1c..21df7baf93 100644
--- a/servo/components/style/values/computed/basic_shape.rs
+++ b/servo/components/style/values/computed/basic_shape.rs
@@ -7,9 +7,12 @@
//!
//! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape
+use crate::values::animated::{Animate, Procedure};
+use crate::values::computed::angle::Angle;
use crate::values::computed::url::ComputedUrl;
use crate::values::computed::{Image, LengthPercentage, NonNegativeLengthPercentage, Position};
use crate::values::generics::basic_shape as generic;
+use crate::values::specified::svg_path::{CoordPair, PathCommand};
/// A computed alias for FillRule.
pub use crate::values::generics::basic_shape::FillRule;
@@ -21,8 +24,13 @@ pub type ClipPath = generic::GenericClipPath<BasicShape, ComputedUrl>;
pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>;
/// A computed basic shape.
-pub type BasicShape =
- generic::GenericBasicShape<Position, LengthPercentage, NonNegativeLengthPercentage, InsetRect>;
+pub type BasicShape = generic::GenericBasicShape<
+ Angle,
+ Position,
+ LengthPercentage,
+ NonNegativeLengthPercentage,
+ InsetRect,
+>;
/// The computed value of `inset()`.
pub type InsetRect = generic::GenericInsetRect<LengthPercentage, NonNegativeLengthPercentage>;
@@ -35,3 +43,179 @@ pub type Ellipse = generic::Ellipse<Position, NonNegativeLengthPercentage>;
/// The computed value of `ShapeRadius`.
pub type ShapeRadius = generic::GenericShapeRadius<NonNegativeLengthPercentage>;
+
+/// The computed value of `shape()`.
+pub type Shape = generic::Shape<Angle, LengthPercentage>;
+
+/// The computed value of `ShapeCommand`.
+pub type ShapeCommand = generic::GenericShapeCommand<Angle, LengthPercentage>;
+
+/// The computed value of `PathOrShapeFunction`.
+pub type PathOrShapeFunction = generic::GenericPathOrShapeFunction<Angle, LengthPercentage>;
+
+/// The computed value of `CoordinatePair`.
+pub type CoordinatePair = generic::CoordinatePair<LengthPercentage>;
+
+/// Animate from `Shape` to `Path`, and vice versa.
+macro_rules! animate_shape {
+ (
+ $from:ident,
+ $to:ident,
+ $procedure:ident,
+ $from_as_shape:tt,
+ $to_as_shape:tt
+ ) => {{
+ // Check fill-rule.
+ if $from.fill != $to.fill {
+ return Err(());
+ }
+
+ // Check the list of commands. (This is a specialized lists::by_computed_value::animate().)
+ let from_cmds = $from.commands();
+ let to_cmds = $to.commands();
+ if from_cmds.len() != to_cmds.len() {
+ return Err(());
+ }
+ let commands = from_cmds
+ .iter()
+ .zip(to_cmds.iter())
+ .map(|(from_cmd, to_cmd)| {
+ $from_as_shape(from_cmd).animate(&$to_as_shape(to_cmd), $procedure)
+ })
+ .collect::<Result<Vec<ShapeCommand>, ()>>()?;
+
+ Ok(Shape {
+ fill: $from.fill,
+ commands: commands.into(),
+ })
+ }};
+}
+
+impl Animate for PathOrShapeFunction {
+ #[inline]
+ fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+ // Per spec, commands are "the same" if they use the same command keyword, and use the same
+ // <by-to> keyword. For curve and smooth, they also must have the same number of control
+ // points. Therefore, we don't have to do normalization here. (Note that we do
+ // normalization if we animate from path() to path(). See svg_path.rs for more details.)
+ //
+ // https://drafts.csswg.org/css-shapes-2/#interpolating-shape
+ match (self, other) {
+ (Self::Path(ref from), Self::Path(ref to)) => {
+ from.animate(to, procedure).map(Self::Path)
+ },
+ (Self::Shape(ref from), Self::Shape(ref to)) => {
+ from.animate(to, procedure).map(Self::Shape)
+ },
+ (Self::Shape(ref from), Self::Path(ref to)) => {
+ // Animate from shape() to path(). We convert each PathCommand into ShapeCommand,
+ // and return shape().
+ animate_shape!(
+ from,
+ to,
+ procedure,
+ (|shape_cmd| shape_cmd),
+ (|path_cmd| ShapeCommand::from(path_cmd))
+ )
+ .map(Self::Shape)
+ },
+ (Self::Path(ref from), Self::Shape(ref to)) => {
+ // Animate from path() to shape(). We convert each PathCommand into ShapeCommand,
+ // and return shape().
+ animate_shape!(
+ from,
+ to,
+ procedure,
+ (|path_cmd| ShapeCommand::from(path_cmd)),
+ (|shape_cmd| shape_cmd)
+ )
+ .map(Self::Shape)
+ },
+ }
+ }
+}
+
+impl From<&PathCommand> for ShapeCommand {
+ #[inline]
+ fn from(path: &PathCommand) -> Self {
+ use crate::values::computed::CSSPixelLength;
+ match path {
+ &PathCommand::Close => Self::Close,
+ &PathCommand::Move { by_to, ref point } => Self::Move {
+ by_to,
+ point: point.into(),
+ },
+ &PathCommand::Line { by_to, ref point } => Self::Move {
+ by_to,
+ point: point.into(),
+ },
+ &PathCommand::HLine { by_to, x } => Self::HLine {
+ by_to,
+ x: LengthPercentage::new_length(CSSPixelLength::new(x)),
+ },
+ &PathCommand::VLine { by_to, y } => Self::VLine {
+ by_to,
+ y: LengthPercentage::new_length(CSSPixelLength::new(y)),
+ },
+ &PathCommand::CubicCurve {
+ by_to,
+ ref point,
+ ref control1,
+ ref control2,
+ } => Self::CubicCurve {
+ by_to,
+ point: point.into(),
+ control1: control1.into(),
+ control2: control2.into(),
+ },
+ &PathCommand::QuadCurve {
+ by_to,
+ ref point,
+ ref control1,
+ } => Self::QuadCurve {
+ by_to,
+ point: point.into(),
+ control1: control1.into(),
+ },
+ &PathCommand::SmoothCubic {
+ by_to,
+ ref point,
+ ref control2,
+ } => Self::SmoothCubic {
+ by_to,
+ point: point.into(),
+ control2: control2.into(),
+ },
+ &PathCommand::SmoothQuad { by_to, ref point } => Self::SmoothQuad {
+ by_to,
+ point: point.into(),
+ },
+ &PathCommand::Arc {
+ by_to,
+ ref point,
+ ref radii,
+ arc_sweep,
+ arc_size,
+ rotate,
+ } => Self::Arc {
+ by_to,
+ point: point.into(),
+ radii: radii.into(),
+ arc_sweep,
+ arc_size,
+ rotate: Angle::from_degrees(rotate),
+ },
+ }
+ }
+}
+
+impl From<&CoordPair> for CoordinatePair {
+ #[inline]
+ fn from(p: &CoordPair) -> Self {
+ use crate::values::computed::CSSPixelLength;
+ Self::new(
+ LengthPercentage::new_length(CSSPixelLength::new(p.x)),
+ LengthPercentage::new_length(CSSPixelLength::new(p.y)),
+ )
+ }
+}
diff --git a/servo/components/style/values/computed/box.rs b/servo/components/style/values/computed/box.rs
index 62811d9851..0dea1c7ab9 100644
--- a/servo/components/style/values/computed/box.rs
+++ b/servo/components/style/values/computed/box.rs
@@ -383,6 +383,15 @@ impl Zoom {
if self == Self::ONE {
return value;
}
- self.value() * value
+ value * self.value()
+ }
+
+ /// Returns the un-zoomed value.
+ #[inline]
+ pub fn unzoom(self, value: f32) -> f32 {
+ if self == Self::ONE {
+ return value;
+ }
+ value / self.value()
}
}
diff --git a/servo/components/style/values/computed/font.rs b/servo/components/style/values/computed/font.rs
index de0a5e372b..e492584f75 100644
--- a/servo/components/style/values/computed/font.rs
+++ b/servo/components/style/values/computed/font.rs
@@ -8,7 +8,7 @@ use crate::parser::{Parse, ParserContext};
use crate::values::animated::ToAnimatedValue;
use crate::values::computed::{
Angle, Context, Integer, Length, NonNegativeLength, NonNegativeNumber, Number, Percentage,
- ToComputedValue,
+ ToComputedValue, Zoom,
};
use crate::values::generics::font::{
FeatureTagValue, FontSettings, TaggedFontValue, VariationValue,
@@ -278,6 +278,16 @@ impl FontSize {
self.used_size.0
}
+ /// Apply zoom to the font-size. This is usually done by ToComputedValue.
+ #[inline]
+ pub fn zoom(&self, zoom: Zoom) -> Self {
+ Self {
+ computed_size: NonNegative(Length::new(zoom.zoom(self.computed_size.0.px()))),
+ used_size: NonNegative(Length::new(zoom.zoom(self.used_size.0.px()))),
+ keyword_info: self.keyword_info,
+ }
+ }
+
#[inline]
/// Get default value of font size.
pub fn medium() -> Self {
@@ -1359,7 +1369,7 @@ impl ToResolvedValue for LineHeight {
context.style.get_font(),
wm,
Some(context.element_info.element),
- ))
+ ).to_resolved_value(context))
}
#[inline]
diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs
index e75676a76d..881efed126 100644
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -6,12 +6,13 @@
use super::{Context, Number, ToComputedValue};
use crate::values::animated::ToAnimatedValue;
-use crate::values::computed::NonNegativeNumber;
+use crate::values::computed::{NonNegativeNumber, Zoom};
use crate::values::generics::length as generics;
use crate::values::generics::length::{
GenericLengthOrNumber, GenericLengthPercentageOrNormal, GenericMaxSize, GenericSize,
};
use crate::values::generics::NonNegative;
+use crate::values::resolved::{Context as ResolvedContext, ToResolvedValue};
use crate::values::specified::length::{AbsoluteLength, FontBaseSize, LineHeightBase};
use crate::values::{specified, CSSFloat};
use crate::Zero;
@@ -227,12 +228,24 @@ impl Size {
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
- ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct CSSPixelLength(CSSFloat);
+impl ToResolvedValue for CSSPixelLength {
+ type ResolvedValue = Self;
+
+ fn to_resolved_value(self, context: &ResolvedContext) -> Self::ResolvedValue {
+ Self(context.style.effective_zoom.unzoom(self.0))
+ }
+
+ #[inline]
+ fn from_resolved_value(value: Self::ResolvedValue) -> Self {
+ value
+ }
+}
+
impl fmt::Debug for CSSPixelLength {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)?;
@@ -271,6 +284,12 @@ impl CSSPixelLength {
self.0
}
+ /// Zooms a particular length.
+ #[inline]
+ pub fn zoom(self, zoom: Zoom) -> Self {
+ Self::new(zoom.zoom(self.px()))
+ }
+
/// Return the length with app_unit i32 type.
#[inline]
pub fn to_i32_au(self) -> i32 {
diff --git a/servo/components/style/values/computed/length_percentage.rs b/servo/components/style/values/computed/length_percentage.rs
index 0dbd2de76d..c448025dd1 100644
--- a/servo/components/style/values/computed/length_percentage.rs
+++ b/servo/components/style/values/computed/length_percentage.rs
@@ -30,6 +30,7 @@ use crate::values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZer
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
use crate::values::generics::calc::{CalcUnits, PositivePercentageBasis};
use crate::values::generics::{calc, NonNegative};
+use crate::values::resolved::{Context as ResolvedContext, ToResolvedValue};
use crate::values::specified::length::{FontBaseSize, LineHeightBase};
use crate::values::{specified, CSSFloat};
use crate::{Zero, ZeroNoPercent};
@@ -164,6 +165,25 @@ impl MallocSizeOf for LengthPercentage {
}
}
+impl ToResolvedValue for LengthPercentage {
+ type ResolvedValue = Self;
+
+ fn to_resolved_value(self, context: &ResolvedContext) -> Self::ResolvedValue {
+ if context.style.effective_zoom.is_one() {
+ return self;
+ }
+ match self.unpack() {
+ Unpacked::Length(l) => Self::new_length(l.to_resolved_value(context)),
+ Unpacked::Percentage(..) | Unpacked::Calc(..) => self,
+ }
+ }
+
+ #[inline]
+ fn from_resolved_value(value: Self::ResolvedValue) -> Self {
+ value
+ }
+}
+
/// An unpacked `<length-percentage>` that borrows the `calc()` variant.
#[derive(Clone, Debug, PartialEq, ToCss)]
enum Unpacked<'a> {
diff --git a/servo/components/style/values/computed/ratio.rs b/servo/components/style/values/computed/ratio.rs
index ae8997cfc0..6964eec3e4 100644
--- a/servo/components/style/values/computed/ratio.rs
+++ b/servo/components/style/values/computed/ratio.rs
@@ -9,7 +9,7 @@ use crate::values::computed::NonNegativeNumber;
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
use crate::values::generics::ratio::Ratio as GenericRatio;
use crate::{One, Zero};
-use std::cmp::{Ordering, PartialOrd};
+use std::cmp::Ordering;
/// A computed <ratio> value.
pub type Ratio = GenericRatio<NonNegativeNumber>;
diff --git a/servo/components/style/values/generics/basic_shape.rs b/servo/components/style/values/generics/basic_shape.rs
index 13d27995c1..ca7646fb13 100644
--- a/servo/components/style/values/generics/basic_shape.rs
+++ b/servo/components/style/values/generics/basic_shape.rs
@@ -10,7 +10,7 @@ use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
use crate::values::generics::border::GenericBorderRadius;
use crate::values::generics::position::GenericPositionOrAuto;
use crate::values::generics::rect::Rect;
-use crate::values::specified::SVGPathData;
+use crate::values::specified::svg_path::{PathCommand, SVGPathData};
use crate::Zero;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
@@ -181,8 +181,13 @@ pub use self::GenericShapeOutside as ShapeOutside;
ToShmem,
)]
#[repr(C, u8)]
-pub enum GenericBasicShape<Position, LengthPercentage, NonNegativeLengthPercentage, BasicShapeRect>
-{
+pub enum GenericBasicShape<
+ Angle,
+ Position,
+ LengthPercentage,
+ NonNegativeLengthPercentage,
+ BasicShapeRect,
+> {
/// The <basic-shape-rect>.
Rect(BasicShapeRect),
/// Defines a circle with a center and a radius.
@@ -199,10 +204,11 @@ pub enum GenericBasicShape<Position, LengthPercentage, NonNegativeLengthPercenta
),
/// Defines a polygon with pair arguments.
Polygon(GenericPolygon<LengthPercentage>),
- /// Defines a path with SVG path syntax.
- Path(Path),
- // TODO: Bug 1823463. Add shape().
- // https://drafts.csswg.org/css-shapes-2/#shape-function
+ /// Defines a path() or shape().
+ PathOrShape(
+ #[animation(field_bound)]
+ #[css(field_bound)]
+ GenericPathOrShapeFunction<Angle, LengthPercentage>),
}
pub use self::GenericBasicShape as BasicShape;
@@ -366,6 +372,30 @@ pub use self::GenericPolygon as Polygon;
#[repr(C)]
pub struct PolygonCoord<LengthPercentage>(pub LengthPercentage, pub LengthPercentage);
+/// path() function or shape() function.
+#[derive(
+ Clone,
+ ComputeSquaredDistance,
+ Debug,
+ Deserialize,
+ MallocSizeOf,
+ PartialEq,
+ Serialize,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(C, u8)]
+pub enum GenericPathOrShapeFunction<Angle, LengthPercentage> {
+ /// Defines a path with SVG path syntax.
+ Path(Path),
+ /// Defines a shape function, which is identical to path() but it uses the CSS syntax.
+ Shape(#[css(field_bound)] Shape<Angle, LengthPercentage>),
+}
+
// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
// NOTE: Basic shapes spec says that these are the only two values, however
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
@@ -397,9 +427,9 @@ pub enum FillRule {
Evenodd,
}
-/// The path function defined in css-shape-2.
+/// The path function.
///
-/// https://drafts.csswg.org/css-shapes-2/#funcdef-path
+/// https://drafts.csswg.org/css-shapes-1/#funcdef-basic-shape-path
#[derive(
Animate,
Clone,
@@ -426,6 +456,14 @@ pub struct Path {
pub path: SVGPathData,
}
+impl Path {
+ /// Returns the slice of PathCommand.
+ #[inline]
+ pub fn commands(&self) -> &[PathCommand] {
+ self.path.commands()
+ }
+}
+
impl<B, U> ToAnimatedZero for ClipPath<B, U> {
fn to_animated_zero(&self) -> Result<Self, ()> {
Err(())
@@ -565,3 +603,479 @@ impl Default for FillRule {
fn is_default<T: Default + PartialEq>(fill: &T) -> bool {
*fill == Default::default()
}
+
+/// The shape function defined in css-shape-2.
+/// shape() = shape(<fill-rule>? from <coordinate-pair>, <shape-command>#)
+///
+/// https://drafts.csswg.org/css-shapes-2/#shape-function
+#[derive(
+ Clone,
+ Debug,
+ Deserialize,
+ MallocSizeOf,
+ PartialEq,
+ Serialize,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(C)]
+pub struct Shape<Angle, LengthPercentage> {
+ /// The filling rule for this shape.
+ pub fill: FillRule,
+ /// The shape command data. Note that the starting point will be the first command in this
+ /// slice.
+ // Note: The first command is always GenericShapeCommand::Move.
+ pub commands: crate::OwnedSlice<GenericShapeCommand<Angle, LengthPercentage>>,
+}
+
+impl<Angle, LengthPercentage> Shape<Angle, LengthPercentage> {
+ /// Returns the slice of GenericShapeCommand<..>.
+ #[inline]
+ pub fn commands(&self) -> &[GenericShapeCommand<Angle, LengthPercentage>] {
+ &self.commands
+ }
+}
+
+impl<Angle, LengthPercentage> Animate for Shape<Angle, LengthPercentage>
+where
+ Angle: Animate,
+ LengthPercentage: Animate,
+{
+ fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+ if self.fill != other.fill {
+ return Err(());
+ }
+ let commands =
+ lists::by_computed_value::animate(&self.commands, &other.commands, procedure)?;
+ Ok(Self {
+ fill: self.fill,
+ commands,
+ })
+ }
+}
+
+impl<Angle, LengthPercentage> ComputeSquaredDistance for Shape<Angle, LengthPercentage>
+where
+ Angle: ComputeSquaredDistance,
+ LengthPercentage: ComputeSquaredDistance,
+{
+ fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+ if self.fill != other.fill {
+ return Err(());
+ }
+ lists::by_computed_value::squared_distance(&self.commands, &other.commands)
+ }
+}
+
+impl<Angle, LengthPercentage> ToCss for Shape<Angle, LengthPercentage>
+where
+ Angle: ToCss + Zero,
+ LengthPercentage: PartialEq + ToCss,
+{
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: Write,
+ {
+ use style_traits::values::SequenceWriter;
+
+ // Per spec, we must have the first move command and at least one following command.
+ debug_assert!(self.commands.len() > 1);
+
+ dest.write_str("shape(")?;
+ if !is_default(&self.fill) {
+ self.fill.to_css(dest)?;
+ dest.write_char(' ')?;
+ }
+ dest.write_str("from ")?;
+ match self.commands[0] {
+ ShapeCommand::Move {
+ by_to: _,
+ ref point,
+ } => point.to_css(dest)?,
+ _ => unreachable!("The first command must be move"),
+ }
+ dest.write_str(", ")?;
+ {
+ let mut writer = SequenceWriter::new(dest, ", ");
+ for command in self.commands.iter().skip(1) {
+ writer.item(command)?;
+ }
+ }
+ dest.write_char(')')
+ }
+}
+
+/// This is a more general shape(path) command type, for both shape() and path().
+///
+/// https://www.w3.org/TR/SVG11/paths.html#PathData
+/// https://drafts.csswg.org/css-shapes-2/#shape-function
+#[derive(
+ Animate,
+ Clone,
+ ComputeSquaredDistance,
+ Copy,
+ Debug,
+ Deserialize,
+ MallocSizeOf,
+ PartialEq,
+ Serialize,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToAnimatedZero,
+ ToComputedValue,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[allow(missing_docs)]
+#[repr(C, u8)]
+pub enum GenericShapeCommand<Angle, LengthPercentage> {
+ /// The move command.
+ Move {
+ by_to: ByTo,
+ point: CoordinatePair<LengthPercentage>,
+ },
+ /// The line command.
+ Line {
+ by_to: ByTo,
+ point: CoordinatePair<LengthPercentage>,
+ },
+ /// The hline command.
+ HLine { by_to: ByTo, x: LengthPercentage },
+ /// The vline command.
+ VLine { by_to: ByTo, y: LengthPercentage },
+ /// The cubic Bézier curve command.
+ CubicCurve {
+ by_to: ByTo,
+ point: CoordinatePair<LengthPercentage>,
+ control1: CoordinatePair<LengthPercentage>,
+ control2: CoordinatePair<LengthPercentage>,
+ },
+ /// The quadratic Bézier curve command.
+ QuadCurve {
+ by_to: ByTo,
+ point: CoordinatePair<LengthPercentage>,
+ control1: CoordinatePair<LengthPercentage>,
+ },
+ /// The smooth command.
+ SmoothCubic {
+ by_to: ByTo,
+ point: CoordinatePair<LengthPercentage>,
+ control2: CoordinatePair<LengthPercentage>,
+ },
+ /// The smooth quadratic Bézier curve command.
+ SmoothQuad {
+ by_to: ByTo,
+ point: CoordinatePair<LengthPercentage>,
+ },
+ /// The arc command.
+ Arc {
+ by_to: ByTo,
+ point: CoordinatePair<LengthPercentage>,
+ radii: CoordinatePair<LengthPercentage>,
+ arc_sweep: ArcSweep,
+ arc_size: ArcSize,
+ rotate: Angle,
+ },
+ /// The closepath command.
+ Close,
+}
+
+pub use self::GenericShapeCommand as ShapeCommand;
+
+impl<Angle, LengthPercentage> ToCss for ShapeCommand<Angle, LengthPercentage>
+where
+ Angle: ToCss + Zero,
+ LengthPercentage: PartialEq + ToCss,
+{
+ fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ where
+ W: fmt::Write,
+ {
+ use self::ShapeCommand::*;
+ match *self {
+ Move { by_to, ref point } => {
+ dest.write_str("move ")?;
+ by_to.to_css(dest)?;
+ dest.write_char(' ')?;
+ point.to_css(dest)
+ },
+ Line { by_to, ref point } => {
+ dest.write_str("line ")?;
+ by_to.to_css(dest)?;
+ dest.write_char(' ')?;
+ point.to_css(dest)
+ },
+ HLine { by_to, ref x } => {
+ dest.write_str("hline ")?;
+ by_to.to_css(dest)?;
+ dest.write_char(' ')?;
+ x.to_css(dest)
+ },
+ VLine { by_to, ref y } => {
+ dest.write_str("vline ")?;
+ by_to.to_css(dest)?;
+ dest.write_char(' ')?;
+ y.to_css(dest)
+ },
+ CubicCurve {
+ by_to,
+ ref point,
+ ref control1,
+ ref control2,
+ } => {
+ dest.write_str("curve ")?;
+ by_to.to_css(dest)?;
+ dest.write_char(' ')?;
+ point.to_css(dest)?;
+ dest.write_str(" via ")?;
+ control1.to_css(dest)?;
+ dest.write_char(' ')?;
+ control2.to_css(dest)
+ },
+ QuadCurve {
+ by_to,
+ ref point,
+ ref control1,
+ } => {
+ dest.write_str("curve ")?;
+ by_to.to_css(dest)?;
+ dest.write_char(' ')?;
+ point.to_css(dest)?;
+ dest.write_str(" via ")?;
+ control1.to_css(dest)
+ },
+ SmoothCubic {
+ by_to,
+ ref point,
+ ref control2,
+ } => {
+ dest.write_str("smooth ")?;
+ by_to.to_css(dest)?;
+ dest.write_char(' ')?;
+ point.to_css(dest)?;
+ dest.write_str(" via ")?;
+ control2.to_css(dest)
+ },
+ SmoothQuad { by_to, ref point } => {
+ dest.write_str("smooth ")?;
+ by_to.to_css(dest)?;
+ dest.write_char(' ')?;
+ point.to_css(dest)
+ },
+ Arc {
+ by_to,
+ ref point,
+ ref radii,
+ arc_sweep,
+ arc_size,
+ ref rotate,
+ } => {
+ dest.write_str("arc ")?;
+ by_to.to_css(dest)?;
+ dest.write_char(' ')?;
+ point.to_css(dest)?;
+ dest.write_str(" of ")?;
+ radii.x.to_css(dest)?;
+ if radii.x != radii.y {
+ dest.write_char(' ')?;
+ radii.y.to_css(dest)?;
+ }
+
+ if matches!(arc_sweep, ArcSweep::Cw) {
+ dest.write_str(" cw")?;
+ }
+
+ if matches!(arc_size, ArcSize::Large) {
+ dest.write_str(" large")?;
+ }
+
+ if !rotate.is_zero() {
+ dest.write_str(" rotate ")?;
+ rotate.to_css(dest)?;
+ }
+ Ok(())
+ },
+ Close => dest.write_str("close"),
+ }
+ }
+}
+
+/// This indicates the command is absolute or relative.
+/// https://drafts.csswg.org/css-shapes-2/#typedef-shape-by-to
+#[derive(
+ Animate,
+ Clone,
+ ComputeSquaredDistance,
+ Copy,
+ Debug,
+ Deserialize,
+ MallocSizeOf,
+ Parse,
+ PartialEq,
+ Serialize,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToAnimatedZero,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(u8)]
+pub enum ByTo {
+ /// This indicates that the <coordinate-pair>s are relative to the command’s starting point.
+ By,
+ /// This relative to the top-left corner of the reference box.
+ To,
+}
+
+impl ByTo {
+ /// Return true if it is absolute, i.e. it is To.
+ #[inline]
+ pub fn is_abs(&self) -> bool {
+ matches!(self, ByTo::To)
+ }
+
+ /// Create ByTo based on the flag if it is absolute.
+ #[inline]
+ pub fn new(is_abs: bool) -> Self {
+ if is_abs {
+ Self::To
+ } else {
+ Self::By
+ }
+ }
+}
+
+/// Defines a pair of coordinates, representing a rightward and downward offset, respectively, from
+/// a specified reference point. Percentages are resolved against the width or height,
+/// respectively, of the reference box.
+/// https://drafts.csswg.org/css-shapes-2/#typedef-shape-coordinate-pair
+#[allow(missing_docs)]
+#[derive(
+ AddAssign,
+ Animate,
+ Clone,
+ ComputeSquaredDistance,
+ Copy,
+ Debug,
+ Deserialize,
+ MallocSizeOf,
+ PartialEq,
+ Serialize,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToAnimatedZero,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(C)]
+pub struct CoordinatePair<LengthPercentage> {
+ pub x: LengthPercentage,
+ pub y: LengthPercentage,
+}
+
+impl<LengthPercentage> CoordinatePair<LengthPercentage> {
+ /// Create a CoordinatePair.
+ #[inline]
+ pub fn new(x: LengthPercentage, y: LengthPercentage) -> Self {
+ Self { x, y }
+ }
+}
+
+/// This indicates that the arc that is traced around the ellipse clockwise or counter-clockwise
+/// from the center.
+/// https://drafts.csswg.org/css-shapes-2/#typedef-shape-arc-sweep
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Deserialize,
+ FromPrimitive,
+ MallocSizeOf,
+ Parse,
+ PartialEq,
+ Serialize,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToAnimatedZero,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(u8)]
+pub enum ArcSweep {
+ /// Counter-clockwise. The default value. (This also represents 0 in the svg path.)
+ Ccw = 0,
+ /// Clockwise. (This also represents 1 in the svg path.)
+ Cw = 1,
+}
+
+impl Animate for ArcSweep {
+ fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+ use num_traits::FromPrimitive;
+ // If an arc command has different <arc-sweep> between its starting and ending list, then
+ // the interpolated result uses cw for any progress value between 0 and 1.
+ (*self as i32)
+ .animate(&(*other as i32), procedure)
+ .map(|v| ArcSweep::from_u8((v > 0) as u8).unwrap_or(ArcSweep::Ccw))
+ }
+}
+
+impl ComputeSquaredDistance for ArcSweep {
+ fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+ (*self as i32).compute_squared_distance(&(*other as i32))
+ }
+}
+
+/// This indicates that the larger or smaller, respectively, of the two possible arcs must be
+/// chosen.
+/// https://drafts.csswg.org/css-shapes-2/#typedef-shape-arc-size
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Deserialize,
+ FromPrimitive,
+ MallocSizeOf,
+ Parse,
+ PartialEq,
+ Serialize,
+ SpecifiedValueInfo,
+ ToAnimatedValue,
+ ToAnimatedZero,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(u8)]
+pub enum ArcSize {
+ /// Choose the small one. The default value. (This also represents 0 in the svg path.)
+ Small = 0,
+ /// Choose the large one. (This also represents 1 in the svg path.)
+ Large = 1,
+}
+
+impl Animate for ArcSize {
+ fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+ use num_traits::FromPrimitive;
+ // If it has different <arc-size> keywords, then the interpolated result uses large for any
+ // progress value between 0 and 1.
+ (*self as i32)
+ .animate(&(*other as i32), procedure)
+ .map(|v| ArcSize::from_u8((v > 0) as u8).unwrap_or(ArcSize::Small))
+ }
+}
+
+impl ComputeSquaredDistance for ArcSize {
+ fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+ (*self as i32).compute_squared_distance(&(*other as i32))
+ }
+}
diff --git a/servo/components/style/values/generics/counters.rs b/servo/components/style/values/generics/counters.rs
index 1d4518c57b..3f23c74b33 100644
--- a/servo/components/style/values/generics/counters.rs
+++ b/servo/components/style/values/generics/counters.rs
@@ -4,11 +4,10 @@
//! Generic types for counters-related CSS values.
-#[cfg(feature = "servo-layout-2013")]
+#[cfg(feature = "servo")]
use crate::computed_values::list_style_type::T as ListStyleType;
#[cfg(feature = "gecko")]
use crate::values::generics::CounterStyle;
-#[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
use crate::values::specified::Attr;
use crate::values::CustomIdent;
use std::fmt::{self, Write};
@@ -186,13 +185,13 @@ pub struct GenericCounters<I>(
);
pub use self::GenericCounters as Counters;
-#[cfg(feature = "servo-layout-2013")]
+#[cfg(feature = "servo")]
type CounterStyleType = ListStyleType;
#[cfg(feature = "gecko")]
type CounterStyleType = CounterStyle;
-#[cfg(feature = "servo-layout-2013")]
+#[cfg(feature = "servo")]
#[inline]
fn is_decimal(counter_type: &CounterStyleType) -> bool {
*counter_type == ListStyleType::Decimal
@@ -254,11 +253,9 @@ pub enum GenericContentItem<I> {
/// Literal string content.
String(crate::OwnedStr),
/// `counter(name, style)`.
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
#[css(comma, function)]
Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType),
/// `counters(name, separator, style)`.
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
#[css(comma, function)]
Counters(
CustomIdent,
@@ -266,16 +263,12 @@ pub enum GenericContentItem<I> {
#[css(skip_if = "is_decimal")] CounterStyleType,
),
/// `open-quote`.
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
OpenQuote,
/// `close-quote`.
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
CloseQuote,
/// `no-open-quote`.
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
NoOpenQuote,
/// `no-close-quote`.
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
NoCloseQuote,
/// `-moz-alt-content`.
#[cfg(feature = "gecko")]
@@ -286,7 +279,6 @@ pub enum GenericContentItem<I> {
#[cfg(feature = "gecko")]
MozLabelContent,
/// `attr([namespace? `|`]? ident)`
- #[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
Attr(Attr),
/// image-set(url) | url(url)
Image(I),
diff --git a/servo/components/style/values/generics/image.rs b/servo/components/style/values/generics/image.rs
index 6fc0870e15..ca1c716052 100644
--- a/servo/components/style/values/generics/image.rs
+++ b/servo/components/style/values/generics/image.rs
@@ -41,7 +41,7 @@ pub enum GenericImage<G, ImageUrl, Color, Percentage, Resolution> {
/// A paint worklet image.
/// <https://drafts.css-houdini.org/css-paint-api/>
- #[cfg(feature = "servo-layout-2013")]
+ #[cfg(feature = "servo")]
PaintWorklet(PaintWorklet),
/// A `<cross-fade()>` image. Storing this directly inside of
@@ -416,7 +416,7 @@ where
Image::None => dest.write_str("none"),
Image::Url(ref url) => url.to_css(dest),
Image::Gradient(ref gradient) => gradient.to_css(dest),
- #[cfg(feature = "servo-layout-2013")]
+ #[cfg(feature = "servo")]
Image::PaintWorklet(ref paint_worklet) => paint_worklet.to_css(dest),
#[cfg(feature = "gecko")]
Image::Element(ref selector) => {
diff --git a/servo/components/style/values/generics/transform.rs b/servo/components/style/values/generics/transform.rs
index 3a65c460a7..4d70e4465c 100644
--- a/servo/components/style/values/generics/transform.rs
+++ b/servo/components/style/values/generics/transform.rs
@@ -11,7 +11,6 @@ use crate::values::specified::length::Length as SpecifiedLength;
use crate::values::specified::length::LengthPercentage as SpecifiedLengthPercentage;
use crate::values::{computed, CSSFloat};
use crate::{Zero, ZeroNoPercent};
-use euclid;
use euclid::default::{Rect, Transform3D};
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
diff --git a/servo/components/style/values/resolved/mod.rs b/servo/components/style/values/resolved/mod.rs
index 675f3cca68..d830474fe6 100644
--- a/servo/components/style/values/resolved/mod.rs
+++ b/servo/components/style/values/resolved/mod.rs
@@ -95,7 +95,6 @@ trivial_to_resolved_value!(computed::url::ComputedImageUrl);
trivial_to_resolved_value!(crate::Namespace);
#[cfg(feature = "servo")]
trivial_to_resolved_value!(crate::Prefix);
-trivial_to_resolved_value!(computed::LengthPercentage);
trivial_to_resolved_value!(style_traits::values::specified::AllowedNumericType);
trivial_to_resolved_value!(computed::TimingFunction);
diff --git a/servo/components/style/values/specified/animation.rs b/servo/components/style/values/specified/animation.rs
index 5a1f5003f3..552521711c 100644
--- a/servo/components/style/values/specified/animation.rs
+++ b/servo/components/style/values/specified/animation.rs
@@ -165,6 +165,12 @@ impl AnimationIterationCount {
pub fn one() -> Self {
Self::Number(NonNegativeNumber::new(1.0))
}
+
+ /// Returns true if it's `1.0`.
+ #[inline]
+ pub fn is_one(&self) -> bool {
+ *self == Self::one()
+ }
}
/// A value for the `animation-name` property.
@@ -230,6 +236,17 @@ pub enum AnimationDirection {
AlternateReverse,
}
+impl AnimationDirection {
+ /// Returns true if the name matches any animation-direction keyword.
+ #[inline]
+ pub fn match_keywords(name: &AnimationName) -> bool {
+ if let Some(name) = name.as_atom() {
+ return name.with_str(|n| Self::from_ident(n).is_ok());
+ }
+ false
+ }
+}
+
/// https://drafts.csswg.org/css-animations/#animation-play-state
#[derive(Copy, Clone, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem)]
#[repr(u8)]
@@ -239,6 +256,17 @@ pub enum AnimationPlayState {
Paused,
}
+impl AnimationPlayState {
+ /// Returns true if the name matches any animation-play-state keyword.
+ #[inline]
+ pub fn match_keywords(name: &AnimationName) -> bool {
+ if let Some(name) = name.as_atom() {
+ return name.with_str(|n| Self::from_ident(n).is_ok());
+ }
+ false
+ }
+}
+
/// https://drafts.csswg.org/css-animations/#propdef-animation-fill-mode
#[derive(Copy, Clone, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem)]
#[repr(u8)]
@@ -250,6 +278,18 @@ pub enum AnimationFillMode {
Both,
}
+impl AnimationFillMode {
+ /// Returns true if the name matches any animation-fill-mode keyword.
+ /// Note: animation-name:none is its initial value, so we don't have to match none here.
+ #[inline]
+ pub fn match_keywords(name: &AnimationName) -> bool {
+ if let Some(atom) = name.as_atom() {
+ return !name.is_none() && atom.with_str(|n| Self::from_ident(n).is_ok());
+ }
+ false
+ }
+}
+
/// https://drafts.csswg.org/css-animations-2/#animation-composition
#[derive(Copy, Clone, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem)]
#[repr(u8)]
diff --git a/servo/components/style/values/specified/basic_shape.rs b/servo/components/style/values/specified/basic_shape.rs
index 526296b735..8ed32c40c5 100644
--- a/servo/components/style/values/specified/basic_shape.rs
+++ b/servo/components/style/values/specified/basic_shape.rs
@@ -14,6 +14,7 @@ use crate::values::generics::basic_shape as generic;
use crate::values::generics::basic_shape::{Path, PolygonCoord};
use crate::values::generics::position::{GenericPosition, GenericPositionOrAuto};
use crate::values::generics::rect::Rect;
+use crate::values::specified::angle::Angle;
use crate::values::specified::border::BorderRadius;
use crate::values::specified::image::Image;
use crate::values::specified::length::LengthPercentageOrAuto;
@@ -40,6 +41,7 @@ pub type ShapePosition = GenericPosition<LengthPercentage, LengthPercentage>;
/// A specified basic shape.
pub type BasicShape = generic::GenericBasicShape<
+ Angle,
ShapePosition,
LengthPercentage,
NonNegativeLengthPercentage,
@@ -61,6 +63,12 @@ pub type ShapeRadius = generic::ShapeRadius<NonNegativeLengthPercentage>;
/// The specified value of `Polygon`.
pub type Polygon = generic::GenericPolygon<LengthPercentage>;
+/// The specified value of `PathOrShapeFunction`.
+pub type PathOrShapeFunction = generic::GenericPathOrShapeFunction<Angle, LengthPercentage>;
+
+/// The specified value of `ShapeCommand`.
+pub type ShapeCommand = generic::GenericShapeCommand<Angle, LengthPercentage>;
+
/// The specified value of `xywh()`.
/// Defines a rectangle via offsets from the top and left edge of the reference box, and a
/// specified width and height.
@@ -168,8 +176,8 @@ bitflags! {
const POLYGON = 1 << 5;
/// path().
const PATH = 1 << 6;
- // TODO: Bug 1823463. Add shape().
- // const SHAPE = 1 << 7;
+ /// shape().
+ const SHAPE = 1 << 7;
/// All flags.
const ALL =
@@ -179,7 +187,8 @@ bitflags! {
Self::CIRCLE.bits() |
Self::ELLIPSE.bits() |
Self::POLYGON.bits() |
- Self::PATH.bits();
+ Self::PATH.bits() |
+ Self::SHAPE.bits();
/// For shape-outside.
const SHAPE_OUTSIDE =
@@ -329,7 +338,17 @@ impl BasicShape {
.map(BasicShape::Polygon)
},
"path" if flags.contains(AllowedBasicShapes::PATH) => {
- Path::parse_function_arguments(i, shape_type).map(BasicShape::Path)
+ Path::parse_function_arguments(i, shape_type)
+ .map(PathOrShapeFunction::Path)
+ .map(BasicShape::PathOrShape)
+ },
+ "shape"
+ if flags.contains(AllowedBasicShapes::SHAPE)
+ && static_prefs::pref!("layout.css.basic-shape-shape.enabled") =>
+ {
+ generic::Shape::parse_function_arguments(context, i, shape_type)
+ .map(PathOrShapeFunction::Shape)
+ .map(BasicShape::PathOrShape)
},
_ => Err(location
.new_custom_error(StyleParseErrorKind::UnexpectedFunction(function.clone()))),
@@ -490,7 +509,11 @@ impl Ellipse {
}
}
-fn parse_fill_rule<'i, 't>(input: &mut Parser<'i, 't>, shape_type: ShapeType) -> FillRule {
+fn parse_fill_rule<'i, 't>(
+ input: &mut Parser<'i, 't>,
+ shape_type: ShapeType,
+ expect_comma: bool,
+) -> FillRule {
match shape_type {
// Per [1] and [2], we ignore `<fill-rule>` for outline shapes, so always use a default
// value.
@@ -508,7 +531,9 @@ fn parse_fill_rule<'i, 't>(input: &mut Parser<'i, 't>, shape_type: ShapeType) ->
ShapeType::Filled => input
.try_parse(|i| -> Result<_, ParseError> {
let fill = FillRule::parse(i)?;
- i.expect_comma()?;
+ if expect_comma {
+ i.expect_comma()?;
+ }
Ok(fill)
})
.unwrap_or_default(),
@@ -532,7 +557,7 @@ impl Polygon {
input: &mut Parser<'i, 't>,
shape_type: ShapeType,
) -> Result<Self, ParseError<'i>> {
- let fill = parse_fill_rule(input, shape_type);
+ let fill = parse_fill_rule(input, shape_type, true /* has comma */);
let coordinates = input
.parse_comma_separated(|i| {
Ok(PolygonCoord(
@@ -554,7 +579,7 @@ impl Path {
) -> Result<Self, ParseError<'i>> {
use crate::values::specified::svg_path::AllowEmpty;
- let fill = parse_fill_rule(input, shape_type);
+ let fill = parse_fill_rule(input, shape_type, true /* has comma */);
let path = SVGPathData::parse(input, AllowEmpty::No)?;
Ok(Path { fill, path })
}
@@ -717,3 +742,168 @@ impl ToComputedValue for BasicShapeRect {
Self::Inset(ToComputedValue::from_computed_value(computed))
}
}
+
+impl generic::Shape<Angle, LengthPercentage> {
+ /// Parse the inner arguments of a `shape` function.
+ /// shape() = shape(<fill-rule>? from <coordinate-pair>, <shape-command>#)
+ fn parse_function_arguments<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ shape_type: ShapeType,
+ ) -> Result<Self, ParseError<'i>> {
+ let fill = parse_fill_rule(input, shape_type, false /* no following comma */);
+
+ let mut first = true;
+ let commands = input.parse_comma_separated(|i| {
+ if first {
+ first = false;
+
+ // The starting point for the first shape-command. It adds an initial absolute
+ // moveto to the list of path data commands, with the <coordinate-pair> measured
+ // from the top-left corner of the reference
+ i.expect_ident_matching("from")?;
+ Ok(ShapeCommand::Move {
+ by_to: generic::ByTo::To,
+ point: generic::CoordinatePair::parse(context, i)?,
+ })
+ } else {
+ // The further path data commands.
+ ShapeCommand::parse(context, i)
+ }
+ })?;
+
+ // We must have one starting point and at least one following <shape-command>.
+ if commands.len() < 2 {
+ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
+ }
+
+ Ok(Self {
+ fill,
+ commands: commands.into(),
+ })
+ }
+}
+
+impl Parse for ShapeCommand {
+ fn parse<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ use crate::values::generics::basic_shape::{ArcSize, ArcSweep, ByTo, CoordinatePair};
+
+ // <shape-command> = <move-command> | <line-command> | <hv-line-command> |
+ // <curve-command> | <smooth-command> | <arc-command> | close
+ Ok(try_match_ident_ignore_ascii_case! { input,
+ "close" => Self::Close,
+ "move" => {
+ let by_to = ByTo::parse(input)?;
+ let point = CoordinatePair::parse(context, input)?;
+ Self::Move { by_to, point }
+ },
+ "line" => {
+ let by_to = ByTo::parse(input)?;
+ let point = CoordinatePair::parse(context, input)?;
+ Self::Line { by_to, point }
+ },
+ "hline" => {
+ let by_to = ByTo::parse(input)?;
+ let x = LengthPercentage::parse(context, input)?;
+ Self::HLine { by_to, x }
+ },
+ "vline" => {
+ let by_to = ByTo::parse(input)?;
+ let y = LengthPercentage::parse(context, input)?;
+ Self::VLine { by_to, y }
+ },
+ "curve" => {
+ let by_to = ByTo::parse(input)?;
+ let point = CoordinatePair::parse(context, input)?;
+ input.expect_ident_matching("via")?;
+ let control1 = CoordinatePair::parse(context, input)?;
+ match input.try_parse(|i| CoordinatePair::parse(context, i)) {
+ Ok(control2) => Self::CubicCurve {
+ by_to,
+ point,
+ control1,
+ control2,
+ },
+ Err(_) => Self::QuadCurve {
+ by_to,
+ point,
+ control1,
+ },
+ }
+ },
+ "smooth" => {
+ let by_to = ByTo::parse(input)?;
+ let point = CoordinatePair::parse(context, input)?;
+ if input.try_parse(|i| i.expect_ident_matching("via")).is_ok() {
+ let control2 = CoordinatePair::parse(context, input)?;
+ Self::SmoothCubic {
+ by_to,
+ point,
+ control2,
+ }
+ } else {
+ Self::SmoothQuad { by_to, point }
+ }
+ },
+ "arc" => {
+ let by_to = ByTo::parse(input)?;
+ let point = CoordinatePair::parse(context, input)?;
+ input.expect_ident_matching("of")?;
+ let rx = LengthPercentage::parse(context, input)?;
+ let ry = input
+ .try_parse(|i| LengthPercentage::parse(context, i))
+ .unwrap_or(rx.clone());
+ let radii = CoordinatePair::new(rx, ry);
+
+ // [<arc-sweep> || <arc-size> || rotate <angle>]?
+ let mut arc_sweep = None;
+ let mut arc_size = None;
+ let mut rotate = None;
+ loop {
+ if arc_sweep.is_none() {
+ arc_sweep = input.try_parse(ArcSweep::parse).ok();
+ }
+
+ if arc_size.is_none() {
+ arc_size = input.try_parse(ArcSize::parse).ok();
+ if arc_size.is_some() {
+ continue;
+ }
+ }
+
+ if rotate.is_none()
+ && input
+ .try_parse(|i| i.expect_ident_matching("rotate"))
+ .is_ok()
+ {
+ rotate = Some(Angle::parse(context, input)?);
+ continue;
+ }
+ break;
+ }
+ Self::Arc {
+ by_to,
+ point,
+ radii,
+ arc_sweep: arc_sweep.unwrap_or(ArcSweep::Ccw),
+ arc_size: arc_size.unwrap_or(ArcSize::Small),
+ rotate: rotate.unwrap_or(Angle::zero()),
+ }
+ },
+ })
+ }
+}
+
+impl Parse for generic::CoordinatePair<LengthPercentage> {
+ fn parse<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ let x = LengthPercentage::parse(context, input)?;
+ let y = LengthPercentage::parse(context, input)?;
+ Ok(Self::new(x, y))
+ }
+}
diff --git a/servo/components/style/values/specified/box.rs b/servo/components/style/values/specified/box.rs
index 8414591c2b..ee50227504 100644
--- a/servo/components/style/values/specified/box.rs
+++ b/servo/components/style/values/specified/box.rs
@@ -19,12 +19,12 @@ use std::fmt::{self, Write};
use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
-#[cfg(not(feature = "servo-layout-2020"))]
+#[cfg(not(feature = "servo"))]
fn flexbox_enabled() -> bool {
true
}
-#[cfg(feature = "servo-layout-2020")]
+#[cfg(feature = "servo")]
fn flexbox_enabled() -> bool {
servo_config::prefs::pref_map()
.get("layout.flexbox.enabled")
@@ -42,9 +42,7 @@ pub enum DisplayOutside {
None = 0,
Inline,
Block,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
TableCaption,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
InternalTable,
#[cfg(feature = "gecko")]
InternalRuby,
@@ -55,28 +53,19 @@ pub enum DisplayOutside {
#[repr(u8)]
pub enum DisplayInside {
None = 0,
- #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
Contents,
Flow,
FlowRoot,
Flex,
#[cfg(feature = "gecko")]
Grid,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
Table,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
TableRowGroup,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
TableColumn,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
TableColumnGroup,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
TableHeaderGroup,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
TableFooterGroup,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
TableRow,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
TableCell,
#[cfg(feature = "gecko")]
Ruby,
@@ -145,7 +134,6 @@ impl Display {
/// ::new() inlined so cbindgen can use it
pub const None: Self =
Self(((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::None as u16);
- #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
pub const Contents: Self = Self(
((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Contents as u16,
);
@@ -170,14 +158,11 @@ impl Display {
#[cfg(feature = "gecko")]
pub const InlineGrid: Self =
Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const Table: Self =
Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16);
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const InlineTable: Self = Self(
((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16,
);
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const TableCaption: Self = Self(
((DisplayOutside::TableCaption as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16,
);
@@ -195,37 +180,30 @@ impl Display {
// Internal table boxes.
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const TableRowGroup: Self = Self(
((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
DisplayInside::TableRowGroup as u16,
);
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const TableHeaderGroup: Self = Self(
((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
DisplayInside::TableHeaderGroup as u16,
);
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const TableFooterGroup: Self = Self(
((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
DisplayInside::TableFooterGroup as u16,
);
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const TableColumn: Self = Self(
((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
DisplayInside::TableColumn as u16,
);
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const TableColumnGroup: Self = Self(
((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
DisplayInside::TableColumnGroup as u16,
);
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const TableRow: Self = Self(
((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
DisplayInside::TableRow as u16,
);
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
pub const TableCell: Self = Self(
((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
DisplayInside::TableCell as u16,
@@ -336,7 +314,6 @@ impl Display {
pub fn is_atomic_inline_level(&self) -> bool {
match *self {
Display::InlineBlock | Display::InlineFlex => true,
- #[cfg(any(feature = "servo-layout-2013"))]
Display::InlineTable => true,
_ => false,
}
@@ -373,7 +350,6 @@ impl Display {
///
/// Also used for :root style adjustments.
pub fn equivalent_block_display(&self, _is_root_element: bool) -> Self {
- #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
{
// Special handling for `contents` and `list-item`s on the root element.
if _is_root_element && (self.is_contents() || self.is_list_item()) {
@@ -392,7 +368,6 @@ impl Display {
Display::from3(DisplayOutside::Block, inside, self.is_list_item())
},
DisplayOutside::Block | DisplayOutside::None => *self,
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
_ => Display::Block,
}
}
@@ -419,7 +394,6 @@ impl Display {
#[inline]
pub fn is_contents(&self) -> bool {
match *self {
- #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
Display::Contents => true,
_ => false,
}
@@ -444,30 +418,20 @@ impl DisplayKeyword {
use self::DisplayKeyword::*;
Ok(try_match_ident_ignore_ascii_case! { input,
"none" => Full(Display::None),
- #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
"contents" => Full(Display::Contents),
"inline-block" => Full(Display::InlineBlock),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"inline-table" => Full(Display::InlineTable),
"-webkit-flex" if flexbox_enabled() => Full(Display::Flex),
"inline-flex" | "-webkit-inline-flex" if flexbox_enabled() => Full(Display::InlineFlex),
#[cfg(feature = "gecko")]
"inline-grid" => Full(Display::InlineGrid),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"table-caption" => Full(Display::TableCaption),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"table-row-group" => Full(Display::TableRowGroup),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"table-header-group" => Full(Display::TableHeaderGroup),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"table-footer-group" => Full(Display::TableFooterGroup),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"table-column" => Full(Display::TableColumn),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"table-column-group" => Full(Display::TableColumnGroup),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"table-row" => Full(Display::TableRow),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"table-cell" => Full(Display::TableCell),
#[cfg(feature = "gecko")]
"ruby-base" => Full(Display::RubyBase),
@@ -493,9 +457,7 @@ impl DisplayKeyword {
/// https://drafts.csswg.org/css-display/#typedef-display-inside
"flow" => Inside(DisplayInside::Flow),
"flex" if flexbox_enabled() => Inside(DisplayInside::Flex),
- #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
"flow-root" => Inside(DisplayInside::FlowRoot),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
"table" => Inside(DisplayInside::Table),
#[cfg(feature = "gecko")]
"grid" => Inside(DisplayInside::Grid),
@@ -517,13 +479,11 @@ impl ToCss for Display {
Display::InlineBlock => dest.write_str("inline-block"),
#[cfg(feature = "gecko")]
Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
Display::TableCaption => dest.write_str("table-caption"),
_ => match (outside, inside) {
#[cfg(feature = "gecko")]
(DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"),
(DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"),
- #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
(DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"),
#[cfg(feature = "gecko")]
(DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"),
@@ -1607,18 +1567,12 @@ pub enum Appearance {
TabScrollArrowBack,
#[parse(condition = "ParserContext::chrome_rules_enabled")]
TabScrollArrowForward,
- /// A toolbar in an application window.
- #[parse(condition = "ParserContext::chrome_rules_enabled")]
- Toolbar,
/// A single toolbar button (with no associated dropdown).
#[parse(condition = "ParserContext::chrome_rules_enabled")]
Toolbarbutton,
/// The dropdown portion of a toolbar button
#[parse(condition = "ParserContext::chrome_rules_enabled")]
ToolbarbuttonDropdown,
- /// The toolbox that contains the toolbars.
- #[parse(condition = "ParserContext::chrome_rules_enabled")]
- Toolbox,
/// A tooltip.
#[parse(condition = "ParserContext::chrome_rules_enabled")]
Tooltip,
diff --git a/servo/components/style/values/specified/color.rs b/servo/components/style/values/specified/color.rs
index 3694b4e9bc..f823ba7d30 100644
--- a/servo/components/style/values/specified/color.rs
+++ b/servo/components/style/values/specified/color.rs
@@ -7,21 +7,20 @@
use super::AllowQuirks;
use crate::color::component::ColorComponent;
use crate::color::convert::normalize_hue;
-use crate::color::parsing::{self, FromParsedColor, NumberOrAngle, NumberOrPercentage};
+use crate::color::parsing::{
+ self, ColorParser, FromParsedColor, NumberOrAngle, NumberOrPercentage,
+};
use crate::color::{mix::ColorInterpolationMethod, AbsoluteColor, ColorSpace};
use crate::media_queries::Device;
use crate::parser::{Parse, ParserContext};
use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue};
-use crate::values::generics::calc::CalcUnits;
use crate::values::generics::color::{
ColorMixFlags, GenericCaretColor, GenericColorMix, GenericColorOrAuto,
};
-use crate::values::specified::calc::{CalcNode, Leaf};
use crate::values::specified::Percentage;
use crate::values::{normalize, CustomIdent};
use cssparser::color::OPAQUE;
use cssparser::{color::PredefinedColorSpace, BasicParseErrorKind, ParseErrorKind, Parser, Token};
-use itoa;
use std::fmt::{self, Write};
use std::io::Write as IoWrite;
use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError, StyleParseErrorKind};
@@ -623,156 +622,6 @@ impl FromParsedColor for Color {
}
}
-struct ColorParser<'a, 'b: 'a>(&'a ParserContext<'b>);
-
-impl<'a, 'b: 'a, 'i: 'a> parsing::ColorParser<'i> for ColorParser<'a, 'b> {
- type Output = Color;
-
- fn parse_number_or_angle<'t>(
- &self,
- input: &mut Parser<'i, 't>,
- allow_none: bool,
- ) -> Result<ColorComponent<NumberOrAngle>, ParseError<'i>> {
- use crate::values::specified::Angle;
-
- let location = input.current_source_location();
- let token = input.next()?.clone();
- Ok(match token {
- Token::Ident(ref value) if allow_none && value.eq_ignore_ascii_case("none") => {
- ColorComponent::None
- },
- Token::Dimension {
- value, ref unit, ..
- } => {
- let angle = Angle::parse_dimension(value, unit, /* from_calc = */ false);
-
- let degrees = match angle {
- Ok(angle) => angle.degrees(),
- Err(()) => return Err(location.new_unexpected_token_error(token.clone())),
- };
-
- ColorComponent::Value(NumberOrAngle::Angle { degrees })
- },
- Token::Number { value, .. } => ColorComponent::Value(NumberOrAngle::Number { value }),
- Token::Function(ref name) => {
- let function = CalcNode::math_function(self.0, name, location)?;
- let node = CalcNode::parse(self.0, input, function, CalcUnits::ANGLE)?;
-
- // If we can resolve the calc node, then use the value.
- match node.resolve() {
- Ok(Leaf::Number(value)) => {
- ColorComponent::Value(NumberOrAngle::Number { value })
- },
- Ok(Leaf::Angle(angle)) => ColorComponent::Value(NumberOrAngle::Angle {
- degrees: angle.degrees(),
- }),
- _ => {
- return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
- },
- }
- },
- t => return Err(location.new_unexpected_token_error(t)),
- })
- }
-
- fn parse_percentage<'t>(
- &self,
- input: &mut Parser<'i, 't>,
- allow_none: bool,
- ) -> Result<ColorComponent<f32>, ParseError<'i>> {
- let location = input.current_source_location();
-
- Ok(match *input.next()? {
- Token::Ident(ref value) if allow_none && value.eq_ignore_ascii_case("none") => {
- ColorComponent::None
- },
- Token::Percentage { unit_value, .. } => ColorComponent::Value(unit_value),
- Token::Function(ref name) => {
- let function = CalcNode::math_function(self.0, name, location)?;
- let node = CalcNode::parse(self.0, input, function, CalcUnits::PERCENTAGE)?;
-
- // If we can resolve the calc node, then use the value.
- let Ok(resolved_leaf) = node.resolve() else {
- return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- };
- if let Leaf::Percentage(value) = resolved_leaf {
- ColorComponent::Value(value)
- } else {
- return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- }
- },
- ref t => return Err(location.new_unexpected_token_error(t.clone())),
- })
- }
-
- fn parse_number<'t>(
- &self,
- input: &mut Parser<'i, 't>,
- allow_none: bool,
- ) -> Result<ColorComponent<f32>, ParseError<'i>> {
- let location = input.current_source_location();
-
- Ok(match *input.next()? {
- Token::Ident(ref value) if allow_none && value.eq_ignore_ascii_case("none") => {
- ColorComponent::None
- },
- Token::Number { value, .. } => ColorComponent::Value(value),
- Token::Function(ref name) => {
- let function = CalcNode::math_function(self.0, name, location)?;
- let node = CalcNode::parse(self.0, input, function, CalcUnits::empty())?;
-
- // If we can resolve the calc node, then use the value.
- let Ok(resolved_leaf) = node.resolve() else {
- return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- };
- if let Leaf::Number(value) = resolved_leaf {
- ColorComponent::Value(value)
- } else {
- return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- }
- },
- ref t => return Err(location.new_unexpected_token_error(t.clone())),
- })
- }
-
- fn parse_number_or_percentage<'t>(
- &self,
- input: &mut Parser<'i, 't>,
- allow_none: bool,
- ) -> Result<ColorComponent<NumberOrPercentage>, ParseError<'i>> {
- let location = input.current_source_location();
-
- Ok(match *input.next()? {
- Token::Ident(ref value) if allow_none && value.eq_ignore_ascii_case("none") => {
- ColorComponent::None
- },
- Token::Number { value, .. } => {
- ColorComponent::Value(NumberOrPercentage::Number { value })
- },
- Token::Percentage { unit_value, .. } => {
- ColorComponent::Value(NumberOrPercentage::Percentage { unit_value })
- },
- Token::Function(ref name) => {
- let function = CalcNode::math_function(self.0, name, location)?;
- let node = CalcNode::parse(self.0, input, function, CalcUnits::PERCENTAGE)?;
-
- // If we can resolve the calc node, then use the value.
- let Ok(resolved_leaf) = node.resolve() else {
- return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- };
- if let Leaf::Percentage(unit_value) = resolved_leaf {
- ColorComponent::Value(NumberOrPercentage::Percentage { unit_value })
- } else if let Leaf::Number(value) = resolved_leaf {
- ColorComponent::Value(NumberOrPercentage::Number { value })
- } else {
- return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- }
- },
- ref t => return Err(location.new_unexpected_token_error(t.clone())),
- })
- }
-}
-
/// Whether to preserve authored colors during parsing. That's useful only if we
/// plan to serialize the color back.
#[derive(Copy, Clone)]
@@ -809,7 +658,7 @@ impl Color {
},
};
- let color_parser = ColorParser(&*context);
+ let color_parser = ColorParser { context: &context };
match input.try_parse(|i| parsing::parse_color_with(&color_parser, i)) {
Ok(mut color) => {
if let Color::Absolute(ref mut absolute) = color {
diff --git a/servo/components/style/values/specified/counters.rs b/servo/components/style/values/specified/counters.rs
index 9d8261ce6c..7760be91d7 100644
--- a/servo/components/style/values/specified/counters.rs
+++ b/servo/components/style/values/specified/counters.rs
@@ -4,7 +4,7 @@
//! Specified types for counter properties.
-#[cfg(feature = "servo-layout-2013")]
+#[cfg(feature = "servo")]
use crate::computed_values::list_style_type::T as ListStyleType;
use crate::parser::{Parse, ParserContext};
use crate::values::generics::counters as generics;
@@ -12,12 +12,10 @@ use crate::values::generics::counters::CounterPair;
#[cfg(feature = "gecko")]
use crate::values::generics::CounterStyle;
use crate::values::specified::image::Image;
-#[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
use crate::values::specified::Attr;
use crate::values::specified::Integer;
use crate::values::CustomIdent;
use cssparser::{Parser, Token};
-#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
use selectors::parser::SelectorParseErrorKind;
use style_traits::{ParseError, StyleParseErrorKind};
@@ -151,7 +149,7 @@ pub type Content = generics::GenericContent<Image>;
pub type ContentItem = generics::GenericContentItem<Image>;
impl Content {
- #[cfg(feature = "servo-layout-2013")]
+ #[cfg(feature = "servo")]
fn parse_counter_style(_: &ParserContext, input: &mut Parser) -> ListStyleType {
input
.try_parse(|input| {
@@ -197,7 +195,6 @@ impl Parse for Content {
let mut content = vec![];
let mut has_alt_content = false;
loop {
- #[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
{
if let Ok(image) = input.try_parse(|i| Image::parse_forbid_none(context, i)) {
content.push(generics::ContentItem::Image(image));
@@ -212,13 +209,11 @@ impl Parse for Content {
},
Ok(&Token::Function(ref name)) => {
let result = match_ignore_ascii_case! { &name,
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
"counter" => input.parse_nested_block(|input| {
let name = CustomIdent::parse(input, &[])?;
let style = Content::parse_counter_style(context, input);
Ok(generics::ContentItem::Counter(name, style))
}),
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
"counters" => input.parse_nested_block(|input| {
let name = CustomIdent::parse(input, &[])?;
input.expect_comma()?;
@@ -226,7 +221,6 @@ impl Parse for Content {
let style = Content::parse_counter_style(context, input);
Ok(generics::ContentItem::Counters(name, separator, style))
}),
- #[cfg(any(feature = "gecko", feature = "servo-layout-2020"))]
"attr" => input.parse_nested_block(|input| {
Ok(generics::ContentItem::Attr(Attr::parse_function(context, input)?))
}),
@@ -240,7 +234,6 @@ impl Parse for Content {
}?;
content.push(result);
},
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
Ok(&Token::Ident(ref ident)) => {
content.push(match_ignore_ascii_case! { &ident,
"open-quote" => generics::ContentItem::OpenQuote,
diff --git a/servo/components/style/values/specified/easing.rs b/servo/components/style/values/specified/easing.rs
index 5e4d8ae1ea..7697e6a5d7 100644
--- a/servo/components/style/values/specified/easing.rs
+++ b/servo/components/style/values/specified/easing.rs
@@ -9,7 +9,7 @@ use crate::values::computed::easing::TimingFunction as ComputedTimingFunction;
use crate::values::computed::{Context, ToComputedValue};
use crate::values::generics::easing::TimingFunction as GenericTimingFunction;
use crate::values::generics::easing::{StepPosition, TimingKeyword};
-use crate::values::specified::{Integer, Number, Percentage};
+use crate::values::specified::{AnimationName, Integer, Number, Percentage};
use cssparser::{Delimiter, Parser, Token};
use selectors::parser::SelectorParseErrorKind;
use style_traits::{ParseError, StyleParseErrorKind};
@@ -140,6 +140,15 @@ impl TimingFunction {
Ok(GenericTimingFunction::LinearFunction(builder.build()))
}
+
+ /// Returns true if the name matches any keyword.
+ #[inline]
+ pub fn match_keywords(name: &AnimationName) -> bool {
+ if let Some(name) = name.as_atom() {
+ return name.with_str(|n| TimingKeyword::from_ident(n).is_ok());
+ }
+ false
+ }
}
// We need this for converting the specified TimingFunction into computed TimingFunction without
diff --git a/servo/components/style/values/specified/effects.rs b/servo/components/style/values/specified/effects.rs
index 0453582768..a32390e148 100644
--- a/servo/components/style/values/specified/effects.rs
+++ b/servo/components/style/values/specified/effects.rs
@@ -28,7 +28,7 @@ use crate::values::specified::{Angle, Number, NumberOrPercentage};
#[cfg(feature = "servo")]
use crate::values::Impossible;
use crate::Zero;
-use cssparser::{self, BasicParseErrorKind, Parser, Token};
+use cssparser::{BasicParseErrorKind, Parser, Token};
use style_traits::{ParseError, StyleParseErrorKind, ValueParseErrorKind};
/// A specified value for a single shadow of the `box-shadow` property.
diff --git a/servo/components/style/values/specified/image.rs b/servo/components/style/values/specified/image.rs
index 76bbbf85df..bedced1a27 100644
--- a/servo/components/style/values/specified/image.rs
+++ b/servo/components/style/values/specified/image.rs
@@ -241,7 +241,7 @@ impl Image {
let function = input.expect_function()?.clone();
input.parse_nested_block(|input| {
Ok(match_ignore_ascii_case! { &function,
- #[cfg(feature = "servo-layout-2013")]
+ #[cfg(feature = "servo")]
"paint" => Self::PaintWorklet(PaintWorklet::parse_args(context, input)?),
"cross-fade" if cross_fade_enabled() => Self::CrossFade(Box::new(CrossFade::parse_args(context, input, cors_mode, flags)?)),
#[cfg(feature = "gecko")]
diff --git a/servo/components/style/values/specified/length.rs b/servo/components/style/values/specified/length.rs
index d2e1d7d346..17ff43cd6f 100644
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -97,9 +97,15 @@ pub enum LineHeightBase {
impl FontBaseSize {
/// Calculate the actual size for a given context
pub fn resolve(&self, context: &Context) -> computed::FontSize {
+ let style = context.style();
match *self {
- Self::CurrentStyle => context.style().get_font().clone_font_size(),
- Self::InheritedStyle => context.style().get_parent_font().clone_font_size(),
+ Self::CurrentStyle => style.get_font().clone_font_size(),
+ Self::InheritedStyle => {
+ // If we're using the size from our inherited style, we still need to apply our
+ // own zoom.
+ let zoom = style.get_box().clone_zoom();
+ style.get_parent_font().clone_font_size().zoom(zoom)
+ },
}
}
}
@@ -351,7 +357,7 @@ impl FontRelativeLength {
let reference_size = if context.builder.is_root_element || context.in_media_query {
reference_font_size.computed_size()
} else {
- context.device().root_font_size()
+ context.device().root_font_size().zoom(context.builder.effective_zoom)
};
(reference_size, length)
},
@@ -394,19 +400,19 @@ impl FontRelativeLength {
// When specified on the root element, the rlh units refer
// to the initial values of font and line-height properties.
//
- let reference_size: CSSPixelLength =
- if context.builder.is_root_element || context.in_media_query {
- context
- .device()
- .calc_line_height(
- &context.default_style().get_font(),
- context.style().writing_mode,
- None,
- )
- .0
- } else {
- context.device().root_line_height()
- };
+ let reference_size = if context.builder.is_root_element || context.in_media_query {
+ context
+ .device()
+ .calc_line_height(
+ &context.default_style().get_font(),
+ context.style().writing_mode,
+ None,
+ )
+ .0
+ } else {
+ context.device().root_line_height()
+ };
+ let reference_size = reference_size.zoom(context.builder.effective_zoom);
(reference_size, length)
},
}
@@ -668,7 +674,7 @@ impl ViewportPercentageLength {
pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
let (variant, unit, factor) = self.unpack();
let size = context.viewport_size_for_viewport_unit_resolution(variant);
- let length = match unit {
+ let length: app_units::Au = match unit {
ViewportUnit::Vw => size.width,
ViewportUnit::Vh => size.height,
ViewportUnit::Vmin => cmp::min(size.width, size.height),
@@ -686,13 +692,15 @@ impl ViewportPercentageLength {
},
};
+ // NOTE: This is in app units!
+ let length = context.builder.effective_zoom.zoom(length.0 as f32);
+
// FIXME: Bug 1396535, we need to fix the extremely small viewport length for transform.
- // See bug 989802. We truncate so that adding multiple viewport units
- // that add up to 100 does not overflow due to rounding differences.
- // We convert appUnits to CSS px manually here to avoid premature clamping by
- // going through the Au type.
+ // See bug 989802. We truncate so that adding multiple viewport units that add up to 100
+ // does not overflow due to rounding differences. We convert appUnits to CSS px manually
+ // here to avoid premature clamping by going through the Au type.
let trunc_scaled =
- ((length.0 as f64 * factor as f64 / 100.).trunc() / AU_PER_PX as f64) as f32;
+ ((length as f64 * factor as f64 / 100.).trunc() / AU_PER_PX as f64) as f32;
CSSPixelLength::new(crate::values::normalize(trunc_scaled))
}
}
@@ -797,7 +805,7 @@ impl ToComputedValue for AbsoluteLength {
type ComputedValue = CSSPixelLength;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
- CSSPixelLength::new(context.builder.effective_zoom().zoom(self.to_px())).finite()
+ CSSPixelLength::new(self.to_px()).zoom(context.builder.effective_zoom).finite()
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
@@ -910,6 +918,9 @@ impl ContainerRelativeLength {
.builder
.add_flags(ComputedValueFlags::USES_CONTAINER_UNITS);
+ // TODO(emilio, bug 1894104): Need to handle zoom here, probably something like
+ // container_zoom - effective_zoom or so. See
+ // https://github.com/w3c/csswg-drafts/issues/10268
let size = context.get_container_size_query();
let (factor, container_length) = match *self {
Self::Cqw(v) => (v, size.get_container_width(context)),
diff --git a/servo/components/style/values/specified/motion.rs b/servo/components/style/values/specified/motion.rs
index 98858c712c..15c76bc640 100644
--- a/servo/components/style/values/specified/motion.rs
+++ b/servo/components/style/values/specified/motion.rs
@@ -76,10 +76,6 @@ impl Parse for RayFunction {
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
- if !static_prefs::pref!("layout.css.motion-path-ray.enabled") {
- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
- }
-
input.expect_function_matching("ray")?;
input.parse_nested_block(|i| Self::parse_function_arguments(context, i))
}
@@ -154,11 +150,8 @@ impl Parse for OffsetPathFunction {
// <offset-path> = <ray()> | <url> | <basic-shape>
// https://drafts.fxtf.org/motion-1/#typedef-offset-path
-
- if static_prefs::pref!("layout.css.motion-path-ray.enabled") {
- if let Ok(ray) = input.try_parse(|i| RayFunction::parse(context, i)) {
- return Ok(OffsetPathFunction::Ray(ray));
- }
+ if let Ok(ray) = input.try_parse(|i| RayFunction::parse(context, i)) {
+ return Ok(OffsetPathFunction::Ray(ray));
}
if static_prefs::pref!("layout.css.motion-path-url.enabled") {
@@ -167,13 +160,7 @@ impl Parse for OffsetPathFunction {
}
}
- let allowed_shapes = if static_prefs::pref!("layout.css.motion-path-basic-shapes.enabled") {
- AllowedBasicShapes::ALL
- } else {
- AllowedBasicShapes::PATH
- };
-
- BasicShape::parse(context, input, allowed_shapes, ShapeType::Outline)
+ BasicShape::parse(context, input, AllowedBasicShapes::ALL, ShapeType::Outline)
.map(OffsetPathFunction::Shape)
}
}
@@ -197,9 +184,7 @@ impl Parse for OffsetPath {
.ok();
}
- if static_prefs::pref!("layout.css.motion-path-coord-box.enabled") &&
- coord_box.is_none()
- {
+ if coord_box.is_none() {
coord_box = input.try_parse(CoordBox::parse).ok();
if coord_box.is_some() {
continue;
diff --git a/servo/components/style/values/specified/svg_path.rs b/servo/components/style/values/specified/svg_path.rs
index 1eb9866dd1..56342b48bb 100644
--- a/servo/components/style/values/specified/svg_path.rs
+++ b/servo/components/style/values/specified/svg_path.rs
@@ -5,10 +5,13 @@
//! Specified types for SVG Path.
use crate::parser::{Parse, ParserContext};
-use crate::values::animated::{lists, Animate, Procedure, ToAnimatedZero};
+use crate::values::animated::{lists, Animate, Procedure};
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
+use crate::values::generics::basic_shape::GenericShapeCommand;
+use crate::values::generics::basic_shape::{ArcSize, ArcSweep, ByTo, CoordinatePair};
use crate::values::CSSFloat;
use cssparser::Parser;
+use num_traits::FromPrimitive;
use std::fmt::{self, Write};
use std::iter::{Cloned, Peekable};
use std::slice;
@@ -70,6 +73,7 @@ impl SVGPathData {
#[cfg(feature = "gecko")]
pub fn decode_from_f32_array(path: &[f32]) -> Result<Self, ()> {
use crate::gecko_bindings::structs::dom::SVGPathSeg_Binding::*;
+ use crate::values::generics::basic_shape::GenericShapeCommand::*;
let mut result: Vec<PathCommand> = Vec::new();
let mut i: usize = 0;
@@ -80,85 +84,84 @@ impl SVGPathData {
let seg_type = path[i].to_bits() as u16;
i = i + 1;
match seg_type {
- PATHSEG_CLOSEPATH => result.push(PathCommand::ClosePath),
+ PATHSEG_CLOSEPATH => result.push(Close),
PATHSEG_MOVETO_ABS | PATHSEG_MOVETO_REL => {
debug_assert!(i + 1 < path.len());
- result.push(PathCommand::MoveTo {
+ result.push(Move {
point: CoordPair::new(path[i], path[i + 1]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_MOVETO_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_MOVETO_ABS),
});
i = i + 2;
},
PATHSEG_LINETO_ABS | PATHSEG_LINETO_REL => {
debug_assert!(i + 1 < path.len());
- result.push(PathCommand::LineTo {
+ result.push(Line {
point: CoordPair::new(path[i], path[i + 1]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_LINETO_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_LINETO_ABS),
});
i = i + 2;
},
PATHSEG_CURVETO_CUBIC_ABS | PATHSEG_CURVETO_CUBIC_REL => {
debug_assert!(i + 5 < path.len());
- result.push(PathCommand::CurveTo {
+ result.push(CubicCurve {
control1: CoordPair::new(path[i], path[i + 1]),
control2: CoordPair::new(path[i + 2], path[i + 3]),
point: CoordPair::new(path[i + 4], path[i + 5]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_CURVETO_CUBIC_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_CURVETO_CUBIC_ABS),
});
i = i + 6;
},
PATHSEG_CURVETO_QUADRATIC_ABS | PATHSEG_CURVETO_QUADRATIC_REL => {
debug_assert!(i + 3 < path.len());
- result.push(PathCommand::QuadBezierCurveTo {
+ result.push(QuadCurve {
control1: CoordPair::new(path[i], path[i + 1]),
point: CoordPair::new(path[i + 2], path[i + 3]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_CURVETO_QUADRATIC_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_CURVETO_QUADRATIC_ABS),
});
i = i + 4;
},
PATHSEG_ARC_ABS | PATHSEG_ARC_REL => {
debug_assert!(i + 6 < path.len());
- result.push(PathCommand::EllipticalArc {
- rx: path[i],
- ry: path[i + 1],
- angle: path[i + 2],
- large_arc_flag: ArcFlag(path[i + 3] != 0.0f32),
- sweep_flag: ArcFlag(path[i + 4] != 0.0f32),
+ result.push(Arc {
+ radii: CoordPair::new(path[i], path[i + 1]),
+ rotate: path[i + 2],
+ arc_size: ArcSize::from_u8((path[i + 3] != 0.0f32) as u8).unwrap(),
+ arc_sweep: ArcSweep::from_u8((path[i + 4] != 0.0f32) as u8).unwrap(),
point: CoordPair::new(path[i + 5], path[i + 6]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_ARC_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_ARC_ABS),
});
i = i + 7;
},
PATHSEG_LINETO_HORIZONTAL_ABS | PATHSEG_LINETO_HORIZONTAL_REL => {
debug_assert!(i < path.len());
- result.push(PathCommand::HorizontalLineTo {
+ result.push(HLine {
x: path[i],
- absolute: IsAbsolute::new(seg_type == PATHSEG_LINETO_HORIZONTAL_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_LINETO_HORIZONTAL_ABS),
});
i = i + 1;
},
PATHSEG_LINETO_VERTICAL_ABS | PATHSEG_LINETO_VERTICAL_REL => {
debug_assert!(i < path.len());
- result.push(PathCommand::VerticalLineTo {
+ result.push(VLine {
y: path[i],
- absolute: IsAbsolute::new(seg_type == PATHSEG_LINETO_VERTICAL_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_LINETO_VERTICAL_ABS),
});
i = i + 1;
},
PATHSEG_CURVETO_CUBIC_SMOOTH_ABS | PATHSEG_CURVETO_CUBIC_SMOOTH_REL => {
debug_assert!(i + 3 < path.len());
- result.push(PathCommand::SmoothCurveTo {
+ result.push(SmoothCubic {
control2: CoordPair::new(path[i], path[i + 1]),
point: CoordPair::new(path[i + 2], path[i + 3]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_CURVETO_CUBIC_SMOOTH_ABS),
});
i = i + 4;
},
PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS | PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL => {
debug_assert!(i + 1 < path.len());
- result.push(PathCommand::SmoothQuadBezierCurveTo {
+ result.push(SmoothQuad {
point: CoordPair::new(path[i], path[i + 1]),
- absolute: IsAbsolute::new(seg_type == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS),
+ by_to: ByTo::new(seg_type == PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS),
});
i = i + 2;
},
@@ -215,7 +218,7 @@ impl ToCss for SVGPathData {
{
let mut writer = SequenceWriter::new(dest, " ");
for command in self.commands() {
- writer.item(command)?;
+ writer.write_item(|inner| command.to_css_for_svg(inner))?;
}
}
dest.write_char('"')
@@ -268,79 +271,7 @@ impl ComputeSquaredDistance for SVGPathData {
/// points of the Bézier curve in the spec.
///
/// https://www.w3.org/TR/SVG11/paths.html#PathData
-#[derive(
- Animate,
- Clone,
- ComputeSquaredDistance,
- Copy,
- Debug,
- Deserialize,
- MallocSizeOf,
- PartialEq,
- Serialize,
- SpecifiedValueInfo,
- ToAnimatedZero,
- ToComputedValue,
- ToResolvedValue,
- ToShmem,
-)]
-#[allow(missing_docs)]
-#[repr(C, u8)]
-pub enum PathCommand {
- /// The unknown type.
- /// https://www.w3.org/TR/SVG/paths.html#__svg__SVGPathSeg__PATHSEG_UNKNOWN
- Unknown,
- /// The "moveto" command.
- MoveTo {
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The "lineto" command.
- LineTo {
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The horizontal "lineto" command.
- HorizontalLineTo { x: CSSFloat, absolute: IsAbsolute },
- /// The vertical "lineto" command.
- VerticalLineTo { y: CSSFloat, absolute: IsAbsolute },
- /// The cubic Bézier curve command.
- CurveTo {
- control1: CoordPair,
- control2: CoordPair,
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The smooth curve command.
- SmoothCurveTo {
- control2: CoordPair,
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The quadratic Bézier curve command.
- QuadBezierCurveTo {
- control1: CoordPair,
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The smooth quadratic Bézier curve command.
- SmoothQuadBezierCurveTo {
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The elliptical arc curve command.
- EllipticalArc {
- rx: CSSFloat,
- ry: CSSFloat,
- angle: CSSFloat,
- large_arc_flag: ArcFlag,
- sweep_flag: ArcFlag,
- point: CoordPair,
- absolute: IsAbsolute,
- },
- /// The "closepath" command.
- ClosePath,
-}
+pub type PathCommand = GenericShapeCommand<CSSFloat, CSSFloat>;
/// For internal SVGPath normalization.
#[allow(missing_docs)]
@@ -355,177 +286,157 @@ impl PathCommand {
///
/// See discussion: https://github.com/w3c/svgwg/issues/321
fn normalize(&self, state: &mut PathTraversalState) -> Self {
- use self::PathCommand::*;
+ use crate::values::generics::basic_shape::GenericShapeCommand::*;
match *self {
- Unknown => Unknown,
- ClosePath => {
+ Close => {
state.pos = state.subpath_start;
- ClosePath
+ Close
},
- MoveTo {
- mut point,
- absolute,
- } => {
- if !absolute.is_yes() {
+ Move { by_to, mut point } => {
+ if !by_to.is_abs() {
point += state.pos;
}
state.pos = point;
state.subpath_start = point;
- MoveTo {
+ Move {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
}
},
- LineTo {
- mut point,
- absolute,
- } => {
- if !absolute.is_yes() {
+ Line { by_to, mut point } => {
+ if !by_to.is_abs() {
point += state.pos;
}
state.pos = point;
- LineTo {
+ Line {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
}
},
- HorizontalLineTo { mut x, absolute } => {
- if !absolute.is_yes() {
+ HLine { by_to, mut x } => {
+ if !by_to.is_abs() {
x += state.pos.x;
}
state.pos.x = x;
- HorizontalLineTo {
- x,
- absolute: IsAbsolute::Yes,
- }
+ HLine { by_to: ByTo::To, x }
},
- VerticalLineTo { mut y, absolute } => {
- if !absolute.is_yes() {
+ VLine { by_to, mut y } => {
+ if !by_to.is_abs() {
y += state.pos.y;
}
state.pos.y = y;
- VerticalLineTo {
- y,
- absolute: IsAbsolute::Yes,
- }
+ VLine { by_to: ByTo::To, y }
},
- CurveTo {
+ CubicCurve {
+ by_to,
+ mut point,
mut control1,
mut control2,
- mut point,
- absolute,
} => {
- if !absolute.is_yes() {
+ if !by_to.is_abs() {
+ point += state.pos;
control1 += state.pos;
control2 += state.pos;
- point += state.pos;
}
state.pos = point;
- CurveTo {
+ CubicCurve {
+ by_to: ByTo::To,
+ point,
control1,
control2,
- point,
- absolute: IsAbsolute::Yes,
}
},
- SmoothCurveTo {
- mut control2,
+ QuadCurve {
+ by_to,
mut point,
- absolute,
+ mut control1,
} => {
- if !absolute.is_yes() {
- control2 += state.pos;
+ if !by_to.is_abs() {
point += state.pos;
+ control1 += state.pos;
}
state.pos = point;
- SmoothCurveTo {
- control2,
+ QuadCurve {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
+ control1,
}
},
- QuadBezierCurveTo {
- mut control1,
+ SmoothCubic {
+ by_to,
mut point,
- absolute,
+ mut control2,
} => {
- if !absolute.is_yes() {
- control1 += state.pos;
+ if !by_to.is_abs() {
point += state.pos;
+ control2 += state.pos;
}
state.pos = point;
- QuadBezierCurveTo {
- control1,
+ SmoothCubic {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
+ control2,
}
},
- SmoothQuadBezierCurveTo {
- mut point,
- absolute,
- } => {
- if !absolute.is_yes() {
+ SmoothQuad { by_to, mut point } => {
+ if !by_to.is_abs() {
point += state.pos;
}
state.pos = point;
- SmoothQuadBezierCurveTo {
+ SmoothQuad {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
}
},
- EllipticalArc {
- rx,
- ry,
- angle,
- large_arc_flag,
- sweep_flag,
+ Arc {
+ by_to,
mut point,
- absolute,
+ radii,
+ arc_sweep,
+ arc_size,
+ rotate,
} => {
- if !absolute.is_yes() {
+ if !by_to.is_abs() {
point += state.pos;
}
state.pos = point;
- EllipticalArc {
- rx,
- ry,
- angle,
- large_arc_flag,
- sweep_flag,
+ Arc {
+ by_to: ByTo::To,
point,
- absolute: IsAbsolute::Yes,
+ radii,
+ arc_sweep,
+ arc_size,
+ rotate,
}
},
}
}
-}
-impl ToCss for PathCommand {
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+ /// The serialization of the svg path.
+ fn to_css_for_svg<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write,
{
- use self::PathCommand::*;
+ use crate::values::generics::basic_shape::GenericShapeCommand::*;
match *self {
- Unknown => dest.write_char('X'),
- ClosePath => dest.write_char('Z'),
- MoveTo { point, absolute } => {
- dest.write_char(if absolute.is_yes() { 'M' } else { 'm' })?;
+ Close => dest.write_char('Z'),
+ Move { by_to, point } => {
+ dest.write_char(if by_to.is_abs() { 'M' } else { 'm' })?;
dest.write_char(' ')?;
point.to_css(dest)
},
- LineTo { point, absolute } => {
- dest.write_char(if absolute.is_yes() { 'L' } else { 'l' })?;
+ Line { by_to, point } => {
+ dest.write_char(if by_to.is_abs() { 'L' } else { 'l' })?;
dest.write_char(' ')?;
point.to_css(dest)
},
- CurveTo {
+ CubicCurve {
+ by_to,
+ point,
control1,
control2,
- point,
- absolute,
} => {
- dest.write_char(if absolute.is_yes() { 'C' } else { 'c' })?;
+ dest.write_char(if by_to.is_abs() { 'C' } else { 'c' })?;
dest.write_char(' ')?;
control1.to_css(dest)?;
dest.write_char(' ')?;
@@ -533,63 +444,60 @@ impl ToCss for PathCommand {
dest.write_char(' ')?;
point.to_css(dest)
},
- QuadBezierCurveTo {
- control1,
+ QuadCurve {
+ by_to,
point,
- absolute,
+ control1,
} => {
- dest.write_char(if absolute.is_yes() { 'Q' } else { 'q' })?;
+ dest.write_char(if by_to.is_abs() { 'Q' } else { 'q' })?;
dest.write_char(' ')?;
control1.to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
- EllipticalArc {
- rx,
- ry,
- angle,
- large_arc_flag,
- sweep_flag,
+ Arc {
+ by_to,
point,
- absolute,
+ radii,
+ arc_sweep,
+ arc_size,
+ rotate,
} => {
- dest.write_char(if absolute.is_yes() { 'A' } else { 'a' })?;
- dest.write_char(' ')?;
- rx.to_css(dest)?;
+ dest.write_char(if by_to.is_abs() { 'A' } else { 'a' })?;
dest.write_char(' ')?;
- ry.to_css(dest)?;
+ radii.to_css(dest)?;
dest.write_char(' ')?;
- angle.to_css(dest)?;
+ rotate.to_css(dest)?;
dest.write_char(' ')?;
- large_arc_flag.to_css(dest)?;
+ (arc_size as i32).to_css(dest)?;
dest.write_char(' ')?;
- sweep_flag.to_css(dest)?;
+ (arc_sweep as i32).to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
- HorizontalLineTo { x, absolute } => {
- dest.write_char(if absolute.is_yes() { 'H' } else { 'h' })?;
+ HLine { by_to, x } => {
+ dest.write_char(if by_to.is_abs() { 'H' } else { 'h' })?;
dest.write_char(' ')?;
x.to_css(dest)
},
- VerticalLineTo { y, absolute } => {
- dest.write_char(if absolute.is_yes() { 'V' } else { 'v' })?;
+ VLine { by_to, y } => {
+ dest.write_char(if by_to.is_abs() { 'V' } else { 'v' })?;
dest.write_char(' ')?;
y.to_css(dest)
},
- SmoothCurveTo {
- control2,
+ SmoothCubic {
+ by_to,
point,
- absolute,
+ control2,
} => {
- dest.write_char(if absolute.is_yes() { 'S' } else { 's' })?;
+ dest.write_char(if by_to.is_abs() { 'S' } else { 's' })?;
dest.write_char(' ')?;
control2.to_css(dest)?;
dest.write_char(' ')?;
point.to_css(dest)
},
- SmoothQuadBezierCurveTo { point, absolute } => {
- dest.write_char(if absolute.is_yes() { 'T' } else { 't' })?;
+ SmoothQuad { by_to, point } => {
+ dest.write_char(if by_to.is_abs() { 'T' } else { 't' })?;
dest.write_char(' ')?;
point.to_css(dest)
},
@@ -597,135 +505,8 @@ impl ToCss for PathCommand {
}
}
-/// The path command absolute type.
-#[allow(missing_docs)]
-#[derive(
- Animate,
- Clone,
- ComputeSquaredDistance,
- Copy,
- Debug,
- Deserialize,
- MallocSizeOf,
- PartialEq,
- Serialize,
- SpecifiedValueInfo,
- ToAnimatedZero,
- ToComputedValue,
- ToResolvedValue,
- ToShmem,
-)]
-#[repr(u8)]
-pub enum IsAbsolute {
- Yes,
- No,
-}
-
-impl IsAbsolute {
- /// Return true if this is IsAbsolute::Yes.
- #[inline]
- pub fn is_yes(&self) -> bool {
- *self == IsAbsolute::Yes
- }
-
- /// Return Yes if value is true. Otherwise, return No.
- #[inline]
- fn new(value: bool) -> Self {
- if value {
- IsAbsolute::Yes
- } else {
- IsAbsolute::No
- }
- }
-}
-
/// The path coord type.
-#[allow(missing_docs)]
-#[derive(
- AddAssign,
- Animate,
- Clone,
- ComputeSquaredDistance,
- Copy,
- Debug,
- Deserialize,
- MallocSizeOf,
- PartialEq,
- Serialize,
- SpecifiedValueInfo,
- ToAnimatedZero,
- ToComputedValue,
- ToCss,
- ToResolvedValue,
- ToShmem,
-)]
-#[repr(C)]
-pub struct CoordPair {
- x: CSSFloat,
- y: CSSFloat,
-}
-
-impl CoordPair {
- /// Create a CoordPair.
- #[inline]
- pub fn new(x: CSSFloat, y: CSSFloat) -> Self {
- CoordPair { x, y }
- }
-}
-
-/// The EllipticalArc flag type.
-#[derive(
- Clone,
- Copy,
- Debug,
- Deserialize,
- MallocSizeOf,
- PartialEq,
- Serialize,
- SpecifiedValueInfo,
- ToComputedValue,
- ToResolvedValue,
- ToShmem,
-)]
-#[repr(C)]
-pub struct ArcFlag(bool);
-
-impl ToCss for ArcFlag {
- #[inline]
- fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
- where
- W: fmt::Write,
- {
- (self.0 as i32).to_css(dest)
- }
-}
-
-impl Animate for ArcFlag {
- #[inline]
- fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
- (self.0 as i32)
- .animate(&(other.0 as i32), procedure)
- .map(|v| ArcFlag(v > 0))
- }
-}
-
-impl ComputeSquaredDistance for ArcFlag {
- #[inline]
- fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
- (self.0 as i32).compute_squared_distance(&(other.0 as i32))
- }
-}
-
-impl ToAnimatedZero for ArcFlag {
- #[inline]
- fn to_animated_zero(&self) -> Result<Self, ()> {
- // The 2 ArcFlags in EllipticalArc determine which one of the 4 different arcs will be
- // used. (i.e. From 4 combinations). In other words, if we change the flag, we get a
- // different arc. Therefore, we return *self.
- // https://svgwg.org/svg2-draft/paths.html#PathDataEllipticalArcCommands
- Ok(*self)
- }
-}
+pub type CoordPair = CoordinatePair<CSSFloat>;
/// SVG Path parser.
struct PathParser<'a> {
@@ -736,7 +517,7 @@ struct PathParser<'a> {
macro_rules! parse_arguments {
(
$parser:ident,
- $abs:ident,
+ $by_to:ident,
$enum:ident,
[ $para:ident => $func:ident $(, $other_para:ident => $other_func:ident)* ]
) => {
@@ -747,7 +528,9 @@ macro_rules! parse_arguments {
skip_comma_wsp(&mut $parser.chars);
let $other_para = $other_func(&mut $parser.chars)?;
)*
- $parser.path.push(PathCommand::$enum { $para $(, $other_para)*, $abs });
+ $parser.path.push(
+ PathCommand::$enum { $by_to, $para $(, $other_para)* }
+ );
// End of string or the next character is a possible new command.
if !skip_wsp(&mut $parser.chars) ||
@@ -785,23 +568,23 @@ impl<'a> PathParser<'a> {
}
let command = self.chars.next().unwrap();
- let abs = if command.is_ascii_uppercase() {
- IsAbsolute::Yes
+ let by_to = if command.is_ascii_uppercase() {
+ ByTo::To
} else {
- IsAbsolute::No
+ ByTo::By
};
skip_wsp(&mut self.chars);
match command {
b'Z' | b'z' => self.parse_closepath(),
- b'L' | b'l' => self.parse_lineto(abs),
- b'H' | b'h' => self.parse_h_lineto(abs),
- b'V' | b'v' => self.parse_v_lineto(abs),
- b'C' | b'c' => self.parse_curveto(abs),
- b'S' | b's' => self.parse_smooth_curveto(abs),
- b'Q' | b'q' => self.parse_quadratic_bezier_curveto(abs),
- b'T' | b't' => self.parse_smooth_quadratic_bezier_curveto(abs),
- b'A' | b'a' => self.parse_elliptical_arc(abs),
+ b'L' | b'l' => self.parse_lineto(by_to),
+ b'H' | b'h' => self.parse_h_lineto(by_to),
+ b'V' | b'v' => self.parse_v_lineto(by_to),
+ b'C' | b'c' => self.parse_curveto(by_to),
+ b'S' | b's' => self.parse_smooth_curveto(by_to),
+ b'Q' | b'q' => self.parse_quadratic_bezier_curveto(by_to),
+ b'T' | b't' => self.parse_smooth_quadratic_bezier_curveto(by_to),
+ b'A' | b'a' => self.parse_elliptical_arc(by_to),
_ => return Err(()),
}?;
}
@@ -817,12 +600,8 @@ impl<'a> PathParser<'a> {
skip_wsp(&mut self.chars);
let point = parse_coord(&mut self.chars)?;
- let absolute = if command == b'M' {
- IsAbsolute::Yes
- } else {
- IsAbsolute::No
- };
- self.path.push(PathCommand::MoveTo { point, absolute });
+ let by_to = if command == b'M' { ByTo::To } else { ByTo::By };
+ self.path.push(PathCommand::Move { by_to, point });
// End of string or the next character is a possible new command.
if !skip_wsp(&mut self.chars) || self.chars.peek().map_or(true, |c| c.is_ascii_alphabetic())
@@ -833,69 +612,74 @@ impl<'a> PathParser<'a> {
// If a moveto is followed by multiple pairs of coordinates, the subsequent
// pairs are treated as implicit lineto commands.
- self.parse_lineto(absolute)
+ self.parse_lineto(by_to)
}
/// Parse "closepath" command.
fn parse_closepath(&mut self) -> Result<(), ()> {
- self.path.push(PathCommand::ClosePath);
+ self.path.push(PathCommand::Close);
Ok(())
}
/// Parse "lineto" command.
- fn parse_lineto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, LineTo, [ point => parse_coord ])
+ fn parse_lineto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, Line, [ point => parse_coord ])
}
/// Parse horizontal "lineto" command.
- fn parse_h_lineto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, HorizontalLineTo, [ x => parse_number ])
+ fn parse_h_lineto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, HLine, [ x => parse_number ])
}
/// Parse vertical "lineto" command.
- fn parse_v_lineto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, VerticalLineTo, [ y => parse_number ])
+ fn parse_v_lineto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, VLine, [ y => parse_number ])
}
/// Parse cubic Bézier curve command.
- fn parse_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, CurveTo, [
+ fn parse_curveto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, CubicCurve, [
control1 => parse_coord, control2 => parse_coord, point => parse_coord
])
}
/// Parse smooth "curveto" command.
- fn parse_smooth_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, SmoothCurveTo, [
+ fn parse_smooth_curveto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, SmoothCubic, [
control2 => parse_coord, point => parse_coord
])
}
/// Parse quadratic Bézier curve command.
- fn parse_quadratic_bezier_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, QuadBezierCurveTo, [
+ fn parse_quadratic_bezier_curveto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, QuadCurve, [
control1 => parse_coord, point => parse_coord
])
}
/// Parse smooth quadratic Bézier curveto command.
- fn parse_smooth_quadratic_bezier_curveto(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
- parse_arguments!(self, absolute, SmoothQuadBezierCurveTo, [ point => parse_coord ])
+ fn parse_smooth_quadratic_bezier_curveto(&mut self, by_to: ByTo) -> Result<(), ()> {
+ parse_arguments!(self, by_to, SmoothQuad, [ point => parse_coord ])
}
/// Parse elliptical arc curve command.
- fn parse_elliptical_arc(&mut self, absolute: IsAbsolute) -> Result<(), ()> {
+ fn parse_elliptical_arc(&mut self, by_to: ByTo) -> Result<(), ()> {
// Parse a flag whose value is '0' or '1'; otherwise, return Err(()).
- let parse_flag = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| match iter.next() {
- Some(c) if c == b'0' || c == b'1' => Ok(ArcFlag(c == b'1')),
+ let parse_arc_size = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| match iter.next() {
+ Some(c) if c == b'1' => Ok(ArcSize::Large),
+ Some(c) if c == b'0' => Ok(ArcSize::Small),
+ _ => Err(()),
+ };
+ let parse_arc_sweep = |iter: &mut Peekable<Cloned<slice::Iter<u8>>>| match iter.next() {
+ Some(c) if c == b'1' => Ok(ArcSweep::Cw),
+ Some(c) if c == b'0' => Ok(ArcSweep::Ccw),
_ => Err(()),
};
- parse_arguments!(self, absolute, EllipticalArc, [
- rx => parse_number,
- ry => parse_number,
- angle => parse_number,
- large_arc_flag => parse_flag,
- sweep_flag => parse_flag,
+ parse_arguments!(self, by_to, Arc, [
+ radii => parse_coord,
+ rotate => parse_number,
+ arc_size => parse_arc_size,
+ arc_sweep => parse_arc_sweep,
point => parse_coord
])
}
diff --git a/servo/components/style/values/specified/text.rs b/servo/components/style/values/specified/text.rs
index 0e70bd26ac..e26a17ba27 100644
--- a/servo/components/style/values/specified/text.rs
+++ b/servo/components/style/values/specified/text.rs
@@ -454,7 +454,6 @@ pub enum TextAlignKeyword {
Left,
Right,
Center,
- #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
Justify,
#[css(skip)]
#[cfg(feature = "gecko")]
@@ -466,11 +465,11 @@ pub enum TextAlignKeyword {
MozLeft,
#[cfg(feature = "gecko")]
MozRight,
- #[cfg(feature = "servo-layout-2013")]
+ #[cfg(feature = "servo")]
ServoCenter,
- #[cfg(feature = "servo-layout-2013")]
+ #[cfg(feature = "servo")]
ServoLeft,
- #[cfg(feature = "servo-layout-2013")]
+ #[cfg(feature = "servo")]
ServoRight,
}