Bug 1604173 - Cherry-pick various servo-layout-2020 changes.
authorEmilio Cobos Álvarez <emilio@crisal.io>
Mon, 16 Dec 2019 13:34:23 +0000
changeset 507104 e48f16780da57d3c915e7fed254a0bcaffbe7477
parent 507103 8c1790e4a72707e7813405a2d78f1d6622e3aee9
child 507105 5be17ff9af7a38106a7dc97faf3948f521bc650e
push id36922
push userncsoregi@mozilla.com
push dateMon, 16 Dec 2019 17:21:47 +0000
treeherdermozilla-central@27d0d6cc2131 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1604173
milestone73.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1604173 - Cherry-pick various servo-layout-2020 changes. Depends on D57314 Differential Revision: https://phabricator.services.mozilla.com/D57315
servo/components/style/logical_geometry.rs
servo/components/style/properties/longhands/border.mako.rs
servo/components/style/properties/longhands/box.mako.rs
servo/components/style/properties/longhands/inherited_box.mako.rs
servo/components/style/properties/longhands/inherited_text.mako.rs
servo/components/style/properties/longhands/inherited_ui.mako.rs
servo/components/style/properties/longhands/position.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/properties/shorthands/background.mako.rs
servo/components/style/values/computed/length.rs
servo/components/style/values/computed/percentage.rs
servo/components/style/values/generics/length.rs
servo/components/style/values/specified/box.rs
servo/components/style/values/specified/text.rs
--- a/servo/components/style/logical_geometry.rs
+++ b/servo/components/style/logical_geometry.rs
@@ -168,16 +168,21 @@ impl WritingMode {
         flags
     }
 
     #[inline]
     pub fn is_vertical(&self) -> bool {
         self.intersects(WritingMode::VERTICAL)
     }
 
+    #[inline]
+    pub fn is_horizontal(&self) -> bool {
+        !self.is_vertical()
+    }
+
     /// Assuming .is_vertical(), does the block direction go left to right?
     #[inline]
     pub fn is_vertical_lr(&self) -> bool {
         self.intersects(WritingMode::VERTICAL_LR)
     }
 
     /// Assuming .is_vertical(), does the inline direction go top to bottom?
     #[inline]
@@ -196,16 +201,30 @@ impl WritingMode {
         self.intersects(WritingMode::VERTICAL_SIDEWAYS | WritingMode::TEXT_SIDEWAYS)
     }
 
     #[inline]
     pub fn is_upright(&self) -> bool {
         self.intersects(WritingMode::UPRIGHT)
     }
 
+    /// https://drafts.csswg.org/css-writing-modes/#logical-to-physical
+    ///
+    /// | Return  | line-left is… | line-right is… |
+    /// |---------|---------------|----------------|
+    /// | `true`  | inline-start  | inline-end     |
+    /// | `false` | inline-end    | inline-start   |
+    #[inline]
+    pub fn line_left_is_inline_start(&self) -> bool {
+        // https://drafts.csswg.org/css-writing-modes/#inline-start
+        // “For boxes with a used direction value of ltr, this means the line-left side.
+        //  For boxes with a used direction value of rtl, this means the line-right side.”
+        self.is_bidi_ltr()
+    }
+
     #[inline]
     pub fn inline_start_physical_side(&self) -> PhysicalSide {
         match (self.is_vertical(), self.is_inline_tb(), self.is_bidi_ltr()) {
             (false, _, true) => PhysicalSide::Left,
             (false, _, false) => PhysicalSide::Right,
             (true, true, _) => PhysicalSide::Top,
             (true, false, _) => PhysicalSide::Bottom,
         }
--- a/servo/components/style/properties/longhands/border.mako.rs
+++ b/servo/components/style/properties/longhands/border.mako.rs
@@ -103,64 +103,59 @@
     spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
     animation_value_type="discrete",
 )}
 
 ${helpers.predefined_type(
     "border-image-source",
     "ImageLayer",
     engines="gecko servo-2013 servo-2020",
-    servo_2020_pref="layout.2020.unimplemented",
     initial_value="computed::ImageLayer::none()",
     initial_specified_value="specified::ImageLayer::none()",
     spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
     vector=False,
     animation_value_type="discrete",
     boxed=engine == "servo-2013",
     ignored_when_colors_disabled=True
 )}
 
 ${helpers.predefined_type(
     "border-image-outset",
     "NonNegativeLengthOrNumberRect",
     engines="gecko servo-2013 servo-2020",
-    servo_2020_pref="layout.2020.unimplemented",
     initial_value="generics::rect::Rect::all(computed::NonNegativeLengthOrNumber::zero())",
     initial_specified_value="generics::rect::Rect::all(specified::NonNegativeLengthOrNumber::zero())",
     spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
     animation_value_type="NonNegativeLengthOrNumberRect",
     boxed=True,
 )}
 
 ${helpers.predefined_type(
     "border-image-repeat",
     "BorderImageRepeat",
     "computed::BorderImageRepeat::stretch()",
     engines="gecko servo-2013 servo-2020",
-    servo_2020_pref="layout.2020.unimplemented",
     initial_specified_value="specified::BorderImageRepeat::stretch()",
     animation_value_type="discrete",
     spec="https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat",
 )}
 
 ${helpers.predefined_type(
     "border-image-width",
     "BorderImageWidth",
     engines="gecko servo-2013 servo-2020",
-    servo_2020_pref="layout.2020.unimplemented",
     initial_value="computed::BorderImageWidth::all(computed::BorderImageSideWidth::one())",
     initial_specified_value="specified::BorderImageWidth::all(specified::BorderImageSideWidth::one())",
     spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
     animation_value_type="BorderImageWidth",
     boxed=True,
 )}
 
 ${helpers.predefined_type(
     "border-image-slice",
     "BorderImageSlice",
     engines="gecko servo-2013 servo-2020",
-    servo_2020_pref="layout.2020.unimplemented",
     initial_value="computed::BorderImageSlice::hundred_percent()",
     initial_specified_value="specified::BorderImageSlice::hundred_percent()",
     spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
     animation_value_type="BorderImageSlice",
     boxed=True,
 )}
--- a/servo/components/style/properties/longhands/box.mako.rs
+++ b/servo/components/style/properties/longhands/box.mako.rs
@@ -50,16 +50,19 @@
     flags="CREATES_STACKING_CONTEXT ABSPOS_CB"
     spec="https://drafts.csswg.org/css-position/#position-property"
     servo_restyle_damage="rebuild_and_reflow"
 >
 impl computed_value::T {
     pub fn is_absolutely_positioned(self) -> bool {
         matches!(self, Self::Absolute | Self::Fixed)
     }
+    pub fn is_relative(self) -> bool {
+        self == Self::Relative
+    }
 }
 </%helpers:single_keyword>
 
 ${helpers.predefined_type(
     "float",
     "Float",
     "computed::Float::None",
     engines="gecko servo-2013 servo-2020",
--- a/servo/components/style/properties/longhands/inherited_box.mako.rs
+++ b/servo/components/style/properties/longhands/inherited_box.mako.rs
@@ -68,19 +68,20 @@
     spec="https://drafts.csswg.org/css-color/#propdef-color-adjust",
 )}
 
 // According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
 // And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
 ${helpers.single_keyword(
     "image-rendering",
     "auto crisp-edges",
-    engines="gecko servo-2013",
+    engines="gecko servo-2013 servo-2020",
     extra_gecko_values="optimizespeed optimizequality",
     extra_servo_2013_values="pixelated",
+    extra_servo_2020_values="pixelated",
     gecko_aliases="-moz-crisp-edges=crisp-edges",
     animation_value_type="discrete",
     spec="https://drafts.csswg.org/css-images/#propdef-image-rendering",
 )}
 
 ${helpers.single_keyword(
     "image-orientation",
     "none from-image",
--- a/servo/components/style/properties/longhands/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhands/inherited_text.mako.rs
@@ -151,17 +151,16 @@
 )}
 
 // TODO make this a shorthand and implement text-align-last/text-align-all
 ${helpers.predefined_type(
     "text-align",
     "TextAlign",
     "computed::TextAlign::Start",
     engines="gecko servo-2013 servo-2020",
-    servo_2020_pref="layout.2020.unimplemented",
     animation_value_type="discrete",
     spec="https://drafts.csswg.org/css-text/#propdef-text-align",
     servo_restyle_damage = "reflow",
 )}
 
 ${helpers.predefined_type(
     "letter-spacing",
     "LetterSpacing",
--- a/servo/components/style/properties/longhands/inherited_ui.mako.rs
+++ b/servo/components/style/properties/longhands/inherited_ui.mako.rs
@@ -5,29 +5,29 @@
 <%namespace name="helpers" file="/helpers.mako.rs" />
 
 <% data.new_style_struct("InheritedUI", inherited=True, gecko_name="UI") %>
 
 ${helpers.predefined_type(
     "cursor",
     "Cursor",
     "computed::Cursor::auto()",
-    engines="gecko servo-2013",
+    engines="gecko servo-2013 servo-2020",
     initial_specified_value="specified::Cursor::auto()",
     animation_value_type="discrete",
     spec="https://drafts.csswg.org/css-ui/#cursor",
 )}
 
 // NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact)
 // is nonstandard, slated for CSS4-UI.
 // TODO(pcwalton): SVG-only values.
 ${helpers.single_keyword(
     "pointer-events",
     "auto none",
-    engines="gecko servo-2013",
+    engines="gecko servo-2013 servo-2020",
     animation_value_type="discrete",
     extra_gecko_values="visiblepainted visiblefill visiblestroke visible painted fill stroke all",
     spec="https://www.w3.org/TR/SVG11/interact.html#PointerEventsProperty",
     gecko_enum_prefix="StylePointerEvents",
 )}
 
 ${helpers.single_keyword(
     "-moz-user-input",
--- a/servo/components/style/properties/longhands/position.mako.rs
+++ b/servo/components/style/properties/longhands/position.mako.rs
@@ -284,30 +284,28 @@ macro_rules! impl_align_conversions {
         servo_restyle_damage="reflow",
     )}
     // min-width, min-height, min-block-size, min-inline-size
     ${helpers.predefined_type(
         "min-%s" % size,
         "Size",
         "computed::Size::auto()",
         engines="gecko servo-2013 servo-2020",
-        servo_2020_pref="layout.2020.unimplemented",
         logical=logical,
         logical_group="min-size",
         allow_quirks="No" if logical else "Yes",
         spec=spec % size,
         animation_value_type="Size",
         servo_restyle_damage="reflow",
     )}
     ${helpers.predefined_type(
         "max-%s" % size,
         "MaxSize",
         "computed::MaxSize::none()",
         engines="gecko servo-2013 servo-2020",
-        servo_2020_pref="layout.2020.unimplemented",
         logical=logical,
         logical_group="max-size",
         allow_quirks="No" if logical else "Yes",
         spec=spec % size,
         animation_value_type="MaxSize",
         servo_restyle_damage="reflow",
     )}
 % endfor
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -2585,18 +2585,20 @@ pub mod style_structs {
         % if style_struct.name == "Font":
         #[derive(Clone, Debug, MallocSizeOf)]
         % else:
         #[derive(Clone, Debug, MallocSizeOf, PartialEq)]
         % endif
         /// The ${style_struct.name} style struct.
         pub struct ${style_struct.name} {
             % for longhand in style_struct.longhands:
-                /// The ${longhand.name} computed value.
-                pub ${longhand.ident}: longhands::${longhand.ident}::computed_value::T,
+                % if not longhand.logical:
+                    /// The ${longhand.name} computed value.
+                    pub ${longhand.ident}: longhands::${longhand.ident}::computed_value::T,
+                % endif
             % endfor
             % if style_struct.name == "InheritedText":
                 /// The "used" text-decorations that apply to this box.
                 ///
                 /// FIXME(emilio): This is technically a box-tree concept, and
                 /// would be nice to move away from style.
                 pub text_decorations_in_effect: crate::values::computed::text::TextDecorationsInEffect,
             % endif
@@ -3831,17 +3833,19 @@ mod lazy_static_module {
 
     lazy_static! {
         /// The initial values for all style structs as defined by the specification.
         pub static ref INITIAL_SERVO_VALUES: ComputedValues = ComputedValues {
             inner: ComputedValuesInner {
                 % for style_struct in data.active_style_structs():
                     ${style_struct.ident}: Arc::new(style_structs::${style_struct.name} {
                         % for longhand in style_struct.longhands:
-                            ${longhand.ident}: longhands::${longhand.ident}::get_initial_value(),
+                            % if not longhand.logical:
+                                ${longhand.ident}: longhands::${longhand.ident}::get_initial_value(),
+                            % endif
                         % endfor
                         % if style_struct.name == "InheritedText":
                             text_decorations_in_effect:
                                 crate::values::computed::text::TextDecorationsInEffect::default(),
                         % endif
                         % if style_struct.name == "Font":
                             hash: 0,
                         % endif
--- a/servo/components/style/properties/shorthands/background.mako.rs
+++ b/servo/components/style/properties/shorthands/background.mako.rs
@@ -188,16 +188,39 @@
                 }
             }
 
             Ok(())
         }
     }
 </%helpers:shorthand>
 
+<%helpers:shorthand name="background"
+                    engines="servo-2020"
+                    sub_properties="background-color"
+                    spec="https://drafts.csswg.org/css-backgrounds/#the-background">
+    use crate::values::specified::Color;
+    use crate::parser::Parse;
+
+    pub fn parse_value<'i, 't>(
+        context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Longhands, ParseError<'i>> {
+        Ok(expanded! {
+            background_color: Color::parse(context, input)?
+        })
+    }
+
+    impl<'a> ToCss for LonghandsToSerialize<'a>  {
+        fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
+            self.background_color.to_css(dest)
+        }
+    }
+</%helpers:shorthand>
+
 <%helpers:shorthand name="background-position"
                     engines="gecko servo-2013"
                     flags="SHORTHAND_IN_GETCS"
                     sub_properties="background-position-x background-position-y"
                     spec="https://drafts.csswg.org/css-backgrounds-4/#the-background-position">
     use crate::properties::longhands::{background_position_x, background_position_y};
     use crate::values::specified::AllowQuirks;
     use crate::values::specified::position::Position;
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -163,32 +163,48 @@ impl LengthPercentage {
     }
 
     /// Returns the `<length>` component of this `calc()`, unclamped.
     #[inline]
     pub fn unclamped_length(&self) -> CSSPixelLength {
         self.length
     }
 
+    /// Returns the percentage component of this `calc()`
+    #[inline]
+    pub fn percentage_component(&self) -> Percentage {
+        Percentage(self.clamping_mode.clamp(self.percentage.0))
+    }
+
     /// Return the percentage value as CSSFloat.
     #[inline]
     pub fn percentage(&self) -> CSSFloat {
         self.percentage.0
     }
 
     /// Return the specified percentage if any.
     #[inline]
     pub fn specified_percentage(&self) -> Option<Percentage> {
         if self.has_percentage {
             Some(self.percentage)
         } else {
             None
         }
     }
 
+    /// Returns the length component if this could be represented as a
+    /// non-calc length.
+    pub fn as_length(&self) -> Option<Length> {
+        if !self.has_percentage {
+            Some(self.length_component())
+        } else {
+            None
+        }
+    }
+
     /// Returns the percentage component if this could be represented as a
     /// non-calc percentage.
     pub fn as_percentage(&self) -> Option<Percentage> {
         if !self.has_percentage || self.length.px() != 0. {
             return None;
         }
 
         Some(Percentage(self.clamping_mode.clamp(self.percentage.0)))
@@ -634,24 +650,24 @@ impl CSSPixelLength {
     /// Return a new CSSPixelLength.
     #[inline]
     pub fn new(px: CSSFloat) -> Self {
         CSSPixelLength(px)
     }
 
     /// Return the containing pixel value.
     #[inline]
-    pub fn px(&self) -> CSSFloat {
+    pub fn px(self) -> CSSFloat {
         self.0
     }
 
     /// Return the length with app_unit i32 type.
     #[inline]
-    pub fn to_i32_au(&self) -> i32 {
-        Au::from(*self).0
+    pub fn to_i32_au(self) -> i32 {
+        Au::from(self).0
     }
 
     /// Return the absolute value of this length.
     #[inline]
     pub fn abs(self) -> Self {
         CSSPixelLength::new(self.0.abs())
     }
 
@@ -669,19 +685,39 @@ impl CSSPixelLength {
 
     /// Returns the maximum between `self` and `other`.
     #[inline]
     pub fn max(self, other: Self) -> Self {
         CSSPixelLength::new(self.0.max(other.0))
     }
 
     /// Sets `self` to the maximum between `self` and `other`.
+    #[inline]
     pub fn max_assign(&mut self, other: Self) {
         *self = self.max(other);
     }
+
+    /// Clamp the value to a lower bound and an optional upper bound.
+    ///
+    /// Can be used for example with `min-width` and `max-width`.
+    #[inline]
+    pub fn clamp_between_extremums(self, min_size: Self, max_size: Option<Self>) -> Self {
+        self.clamp_below_max(max_size).max(min_size)
+    }
+
+    /// Clamp the value to an optional upper bound.
+    ///
+    /// Can be used for example with `max-width`.
+    #[inline]
+    pub fn clamp_below_max(self, max_size: Option<Self>) -> Self {
+        match max_size {
+            None => self,
+            Some(max_size) => self.min(max_size),
+        }
+    }
 }
 
 impl Zero for CSSPixelLength {
     fn zero() -> Self {
         CSSPixelLength::new(0.)
     }
 
     fn is_zero(&self) -> bool {
--- a/servo/components/style/values/computed/percentage.rs
+++ b/servo/components/style/values/computed/percentage.rs
@@ -59,16 +59,22 @@ impl Zero for Percentage {
         Percentage(0.)
     }
 
     fn is_zero(&self) -> bool {
         self.0 == 0.
     }
 }
 
+impl std::ops::AddAssign for Percentage {
+    fn add_assign(&mut self, other: Self) {
+        self.0 += other.0
+    }
+}
+
 impl ToCss for Percentage {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: fmt::Write,
     {
         serialize_percentage(self.0, dest)
     }
 }
--- a/servo/components/style/values/generics/length.rs
+++ b/servo/components/style/values/generics/length.rs
@@ -87,17 +87,17 @@ where
     pub fn non_auto(&self) -> Option<LengthPercentage> {
         match self {
             LengthPercentageOrAuto::LengthPercentage(length) => Some(length.clone()),
             LengthPercentageOrAuto::Auto => None,
         }
     }
 
     /// Maps the length of this value.
-    pub fn map(&self, f: impl FnOnce(LengthPercentage) -> LengthPercentage) -> Self {
+    pub fn map<T>(&self, f: impl FnOnce(LengthPercentage) -> T) -> LengthPercentageOrAuto<T> {
         match self {
             LengthPercentageOrAuto::LengthPercentage(l) => {
                 LengthPercentageOrAuto::LengthPercentage(f(l.clone()))
             },
             LengthPercentageOrAuto::Auto => LengthPercentageOrAuto::Auto,
         }
     }
 }
--- a/servo/components/style/values/specified/box.rs
+++ b/servo/components/style/values/specified/box.rs
@@ -438,20 +438,21 @@ impl Display {
     }
 }
 
 impl ToCss for Display {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: fmt::Write,
     {
+        #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
         debug_assert_ne!(
             self.inside(),
             DisplayInside::Flow,
-            "`flow` never appears in `display` computed value"
+            "`flow` fears in `display` computed value"
         );
         let outside = self.outside();
         let inside = match self.inside() {
             #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
             DisplayInside::Block | DisplayInside::Inline => DisplayInside::Flow,
             inside => inside,
         };
         match *self {
--- a/servo/components/style/values/specified/text.rs
+++ b/servo/components/style/values/specified/text.rs
@@ -530,28 +530,29 @@ impl ToCss for TextTransformOther {
 )]
 #[allow(missing_docs)]
 pub enum TextAlignKeyword {
     Start,
     End,
     Left,
     Right,
     Center,
+    #[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
     Justify,
     #[cfg(feature = "gecko")]
     MozCenter,
     #[cfg(feature = "gecko")]
     MozLeft,
     #[cfg(feature = "gecko")]
     MozRight,
-    #[cfg(feature = "servo")]
+    #[cfg(feature = "servo-layout-2013")]
     ServoCenter,
-    #[cfg(feature = "servo")]
+    #[cfg(feature = "servo-layout-2013")]
     ServoLeft,
-    #[cfg(feature = "servo")]
+    #[cfg(feature = "servo-layout-2013")]
     ServoRight,
     #[css(skip)]
     #[cfg(feature = "gecko")]
     Char,
 }
 
 /// Specified value of text-align property.
 #[derive(