diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 24bf2471633..2eb82fc3184 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -60,7 +60,7 @@ use selector_parser::PseudoElement; use servo_arc::{Arc, RawOffsetArc}; use std::mem::{forget, uninitialized, transmute, zeroed}; use std::{cmp, ops, ptr}; -use values::{Auto, CustomIdent, Either, KeyframesName}; +use values::{self, Auto, CustomIdent, Either, KeyframesName}; use values::computed::ToComputedValue; use values::computed::effects::{BoxShadow, Filter, SimpleShadow}; use values::computed::length::Percentage; @@ -1366,8 +1366,35 @@ fn static_assert() { % for kind in ["align", "justify"]: ${impl_simple_type_with_conversion(kind + "_content")} ${impl_simple_type_with_conversion(kind + "_self")} - ${impl_simple_type_with_conversion(kind + "_items")} % endfor + ${impl_simple_type_with_conversion("align_items")} + + pub fn set_justify_items(&mut self, v: longhands::justify_items::computed_value::T) { + self.gecko.mSpecifiedJustifyItems = v.specified.into(); + self.set_computed_justify_items(v.computed); + } + + pub fn set_computed_justify_items(&mut self, v: values::specified::JustifyItems) { + debug_assert!(v.0 != ::values::specified::align::ALIGN_AUTO); + self.gecko.mJustifyItems = v.into(); + } + + pub fn reset_justify_items(&mut self, reset_style: &Self) { + self.gecko.mJustifyItems = reset_style.gecko.mJustifyItems; + self.gecko.mSpecifiedJustifyItems = reset_style.gecko.mSpecifiedJustifyItems; + } + + pub fn copy_justify_items_from(&mut self, other: &Self) { + self.gecko.mJustifyItems = other.gecko.mJustifyItems; + self.gecko.mSpecifiedJustifyItems = other.gecko.mJustifyItems; + } + + pub fn clone_justify_items(&self) -> longhands::justify_items::computed_value::T { + longhands::justify_items::computed_value::T { + computed: self.gecko.mJustifyItems.into(), + specified: self.gecko.mSpecifiedJustifyItems.into(), + } + } pub fn set_order(&mut self, v: longhands::order::computed_value::T) { self.gecko.mOrder = v; diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index 04d0f295eb1..780b7ebabca 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -108,7 +108,7 @@ ${helpers.single_keyword("flex-wrap", "nowrap wrap wrap-reverse", ${helpers.predefined_type(name="justify-items", type="JustifyItems", - initial_value="specified::JustifyItems::auto()", + initial_value="computed::JustifyItems::auto()", spec="https://drafts.csswg.org/css-align/#propdef-justify-items", animation_value_type="discrete")} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 877ec1a1b9f..e7771a2819c 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2606,13 +2606,13 @@ impl<'a> StyleBuilder<'a> { /// Inherit `${property.ident}` from our parent style. #[allow(non_snake_case)] pub fn inherit_${property.ident}(&mut self) { - % if property.style_struct.inherited: let inherited_struct = + % if property.style_struct.inherited: self.inherited_style.get_${property.style_struct.name_lower}(); % else: - let inherited_struct = self.inherited_style_ignoring_first_line.get_${property.style_struct.name_lower}(); % endif + self.${property.style_struct.ident}.mutate() .copy_${property.ident}_from( inherited_struct, @@ -2625,14 +2625,21 @@ impl<'a> StyleBuilder<'a> { /// Reset `${property.ident}` to the initial value. #[allow(non_snake_case)] pub fn reset_${property.ident}(&mut self) { - let reset_struct = self.reset_style.get_${property.style_struct.name_lower}(); - self.${property.style_struct.ident}.mutate() - .copy_${property.ident}_from( - reset_struct, - % if property.logical: - self.writing_mode, - % endif - ); + let reset_struct = + self.reset_style.get_${property.style_struct.name_lower}(); + % if property.ident == "justify_items": + // TODO(emilio): Generalise this! + self.${property.style_struct.ident}.mutate() + .reset_${property.ident}(reset_struct) + % else: + self.${property.style_struct.ident}.mutate() + .copy_${property.ident}_from( + reset_struct, + % if property.logical: + self.writing_mode, + % endif + ); + % endif } % if not property.is_vector: diff --git a/components/style/style_adjuster.rs b/components/style/style_adjuster.rs index 022e5e54264..03b15916b23 100644 --- a/components/style/style_adjuster.rs +++ b/components/style/style_adjuster.rs @@ -454,6 +454,36 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { } } + /// Resolves "justify-items: auto" based on the inherited style if needed to + /// comply with: + /// + /// https://drafts.csswg.org/css-align/#valdef-justify-items-legacy + /// + /// (Note that "auto" is being renamed to "legacy") + #[cfg(feature = "gecko")] + fn adjust_for_justify_items(&mut self) { + use values::specified::align; + let justify_items = self.style.get_position().clone_justify_items(); + if justify_items.specified.0 != align::ALIGN_AUTO { + return; + } + + let parent_justify_items = + self.style.get_parent_position().clone_justify_items(); + + if !parent_justify_items.computed.0.contains(align::ALIGN_LEGACY) { + return; + } + + if parent_justify_items.computed == justify_items.computed { + return; + } + + self.style + .mutate_position() + .set_computed_justify_items(parent_justify_items.computed); + } + /// Adjusts the style to account for various fixups that don't fit naturally /// into the cascade. /// @@ -478,6 +508,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> { self.adjust_for_table_text_align(); self.adjust_for_contain(); self.adjust_for_mathvariant(); + self.adjust_for_justify_items(); } #[cfg(feature = "servo")] { diff --git a/components/style/values/computed/align.rs b/components/style/values/computed/align.rs new file mode 100644 index 00000000000..3d997915cad --- /dev/null +++ b/components/style/values/computed/align.rs @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Values for CSS Box Alignment properties +//! +//! https://drafts.csswg.org/css-align/ + +use std::fmt; +use style_traits::ToCss; +use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue}; +use values::specified; + +pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf}; + +/// The computed value for the `justify-items` property. +/// +/// Need to carry around both the specified and computed value to handle the +/// special legacy keyword. Sigh. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct JustifyItems { + /// The specified value for the property. Can contain `auto`. + pub specified: specified::JustifyItems, + /// The computed value for the property. Cannot contain `auto`. + pub computed: specified::JustifyItems, +} + +impl ToCss for JustifyItems { + fn to_css(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write, + { + self.computed.to_css(dest) + } +} + +impl JustifyItems { + /// Returns the `auto` value. + pub fn auto() -> Self { + Self { + specified: specified::JustifyItems::auto(), + computed: specified::JustifyItems::normal(), + } + } +} + +impl ToComputedValue for specified::JustifyItems { + type ComputedValue = JustifyItems; + + /// https://drafts.csswg.org/css-align/#valdef-justify-items-legacy + fn to_computed_value(&self, _context: &Context) -> JustifyItems { + use values::specified::align; + let specified = *self; + let computed = + if self.0 != align::ALIGN_AUTO { + *self + } else { + // If the inherited value of `justify-items` includes the + // `legacy` keyword, `auto` computes to the inherited value, + // but we assume it computes to `normal`, and handle that + // special-case in StyleAdjuster. + Self::normal() + }; + + JustifyItems { specified, computed } + } + + #[inline] + fn from_computed_value(computed: &JustifyItems) -> Self { + computed.specified + } +} + +impl ComputedValueAsSpecified for AlignItems {} +impl ComputedValueAsSpecified for AlignJustifyContent {} +impl ComputedValueAsSpecified for AlignJustifySelf {} diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 8e01eda014c..e9ae9474469 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -25,6 +25,8 @@ use super::specified; pub use app_units::Au; pub use properties::animated_properties::TransitionProperty; +#[cfg(feature = "gecko")] +pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems}; pub use self::background::BackgroundSize; pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth}; pub use self::border::{BorderRadius, BorderCornerRadius}; @@ -36,8 +38,6 @@ pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, pub use self::gecko::ScrollSnapPoint; pub use self::rect::LengthOrNumberRect; pub use super::{Auto, Either, None_}; -#[cfg(feature = "gecko")] -pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems}; pub use super::specified::{BorderStyle, UrlOrNone}; pub use super::generics::grid::GridLine; pub use super::specified::url::SpecifiedUrl; @@ -47,6 +47,8 @@ pub use self::position::Position; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, WordSpacing}; pub use self::transform::{TimingFunction, TransformOrigin}; +#[cfg(feature = "gecko")] +pub mod align; pub mod background; pub mod basic_shape; pub mod border; @@ -396,36 +398,6 @@ impl ToCss for Time { } } -#[cfg(feature = "gecko")] -impl ToComputedValue for specified::JustifyItems { - type ComputedValue = JustifyItems; - - // https://drafts.csswg.org/css-align/#valdef-justify-items-auto - fn to_computed_value(&self, context: &Context) -> JustifyItems { - use values::specified::align; - // If the inherited value of `justify-items` includes the `legacy` keyword, `auto` computes - // to the inherited value. - if self.0 == align::ALIGN_AUTO { - let inherited = context.builder.get_parent_position().clone_justify_items(); - if inherited.0.contains(align::ALIGN_LEGACY) { - return inherited - } - } - return *self - } - - #[inline] - fn from_computed_value(computed: &JustifyItems) -> Self { - *computed - } -} - -#[cfg(feature = "gecko")] -impl ComputedValueAsSpecified for specified::AlignItems {} -#[cfg(feature = "gecko")] -impl ComputedValueAsSpecified for specified::AlignJustifyContent {} -#[cfg(feature = "gecko")] -impl ComputedValueAsSpecified for specified::AlignJustifySelf {} impl ComputedValueAsSpecified for specified::BorderStyle {} /// A `` value. diff --git a/components/style/values/specified/align.rs b/components/style/values/specified/align.rs index d56c42d639c..dc7fd43ed94 100644 --- a/components/style/values/specified/align.rs +++ b/components/style/values/specified/align.rs @@ -292,6 +292,12 @@ impl JustifyItems { JustifyItems(ALIGN_AUTO) } + /// The value 'normal' + #[inline] + pub fn normal() -> Self { + JustifyItems(ALIGN_NORMAL) + } + /// Whether this value has extra flags. #[inline] pub fn has_extra_flags(self) -> bool {