aboutsummaryrefslogtreecommitdiffstats
path: root/components/style
diff options
context:
space:
mode:
authorMats Palmgren <mats@mozilla.com>2020-04-28 01:18:44 +0000
committerEmilio Cobos Álvarez <emilio@crisal.io>2020-06-04 01:50:36 +0200
commit6f58c665899c23fe8b3965ec687cecfd2ee67aa0 (patch)
treeee064d9503998839810e19a4d7da3405d8b0ee98 /components/style
parent21d48e00cc9c268ded420991e14a98a53f2ced90 (diff)
downloadservo-6f58c665899c23fe8b3965ec687cecfd2ee67aa0.tar.gz
servo-6f58c665899c23fe8b3965ec687cecfd2ee67aa0.zip
style: Implement style system support for Masonry layout.
This implements support for this CSS Masonry layout proposal: https://github.com/w3c/csswg-drafts/issues/4650 I've intentionally left out a shorthand (place-tracks?) for now until we have a draft CSS spec for this. Differential Revision: https://phabricator.services.mozilla.com/D67061
Diffstat (limited to 'components/style')
-rw-r--r--components/style/properties/data.py1
-rw-r--r--components/style/properties/gecko.mako.rs4
-rw-r--r--components/style/properties/longhands/position.mako.rs32
-rw-r--r--components/style/values/computed/align.rs2
-rw-r--r--components/style/values/computed/mod.rs4
-rw-r--r--components/style/values/computed/position.rs2
-rw-r--r--components/style/values/generics/grid.rs3
-rw-r--r--components/style/values/specified/align.rs87
-rw-r--r--components/style/values/specified/grid.rs18
-rw-r--r--components/style/values/specified/mod.rs6
-rw-r--r--components/style/values/specified/position.rs166
11 files changed, 295 insertions, 30 deletions
diff --git a/components/style/properties/data.py b/components/style/properties/data.py
index 472d1eb34dd..56ac30dd458 100644
--- a/components/style/properties/data.py
+++ b/components/style/properties/data.py
@@ -356,6 +356,7 @@ class Longhand(object):
"JustifyItems",
"JustifySelf",
"LineBreak",
+ "MasonryAutoFlow",
"MozForceBrokenImageIcon",
"MozListReversed",
"MozScriptLevel",
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs
index f3db987d8f9..545e8cc77b5 100644
--- a/components/style/properties/gecko.mako.rs
+++ b/components/style/properties/gecko.mako.rs
@@ -802,7 +802,8 @@ fn static_assert() {
<% skip_position_longhands = " ".join(x.ident for x in SIDES) %>
<%self:impl_trait style_struct_name="Position"
- skip_longhands="${skip_position_longhands}">
+ skip_longhands="${skip_position_longhands}
+ masonry-auto-flow">
% for side in SIDES:
<% impl_split_style_coord(side.ident, "mOffset", side.index) %>
% endfor
@@ -811,6 +812,7 @@ fn static_assert() {
self.gecko.mJustifyItems.computed = v;
}
+ ${impl_simple_type_with_conversion("masonry_auto_flow", "mMasonryAutoFlow")}
</%self:impl_trait>
<% skip_outline_longhands = " ".join("outline-style outline-width".split() +
diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs
index d9403be5864..04d735201d4 100644
--- a/components/style/properties/longhands/position.mako.rs
+++ b/components/style/properties/longhands/position.mako.rs
@@ -114,6 +114,17 @@ ${helpers.single_keyword(
animation_value_type="discrete",
servo_restyle_damage="reflow",
)}
+
+ ${helpers.predefined_type(
+ "justify-tracks",
+ "JustifyTracks",
+ "specified::JustifyTracks::default()",
+ engines="gecko",
+ gecko_pref="layout.css.grid-template-masonry-value.enabled",
+ animation_value_type="discrete",
+ servo_restyle_damage="reflow",
+ spec="https://github.com/w3c/csswg-drafts/issues/4650",
+ )}
% endif
% if engine in ["servo-2013", "servo-2020"]:
@@ -152,6 +163,17 @@ ${helpers.single_keyword(
)}
${helpers.predefined_type(
+ "align-tracks",
+ "AlignTracks",
+ "specified::AlignTracks::default()",
+ engines="gecko",
+ gecko_pref="layout.css.grid-template-masonry-value.enabled",
+ animation_value_type="discrete",
+ servo_restyle_damage="reflow",
+ spec="https://github.com/w3c/csswg-drafts/issues/4650",
+ )}
+
+ ${helpers.predefined_type(
"align-items",
"AlignItems",
"specified::AlignItems::normal()",
@@ -373,6 +395,16 @@ ${helpers.predefined_type(
% endfor
${helpers.predefined_type(
+ "masonry-auto-flow",
+ "MasonryAutoFlow",
+ "computed::MasonryAutoFlow::initial()",
+ engines="gecko",
+ gecko_pref="layout.css.grid-template-masonry-value.enabled",
+ animation_value_type="discrete",
+ spec="https://github.com/w3c/csswg-drafts/issues/4650",
+)}
+
+${helpers.predefined_type(
"grid-auto-flow",
"GridAutoFlow",
"computed::GridAutoFlow::ROW",
diff --git a/components/style/values/computed/align.rs b/components/style/values/computed/align.rs
index 45d6cfac323..893f6fcce51 100644
--- a/components/style/values/computed/align.rs
+++ b/components/style/values/computed/align.rs
@@ -10,7 +10,7 @@ use crate::values::computed::{Context, ToComputedValue};
use crate::values::specified;
pub use super::specified::{
- AlignContent, AlignItems, ContentDistribution, JustifyContent, SelfAlignment,
+ AlignContent, AlignItems, AlignTracks, ContentDistribution, JustifyContent, JustifyTracks, SelfAlignment,
};
pub use super::specified::{AlignSelf, JustifySelf};
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 841cc3df22a..468deac4592 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -29,7 +29,7 @@ use std::cmp;
use std::f32;
#[cfg(feature = "gecko")]
-pub use self::align::{AlignContent, AlignItems, JustifyContent, JustifyItems, SelfAlignment};
+pub use self::align::{AlignContent, AlignItems, AlignTracks, JustifyContent, JustifyItems, JustifyTracks, SelfAlignment};
#[cfg(feature = "gecko")]
pub use self::align::{AlignSelf, JustifySelf};
pub use self::angle::Angle;
@@ -68,7 +68,7 @@ pub use self::list::Quotes;
pub use self::motion::{OffsetPath, OffsetRotate};
pub use self::outline::OutlineStyle;
pub use self::percentage::{NonNegativePercentage, Percentage};
-pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, PositionOrAuto, ZIndex};
+pub use self::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex};
pub use self::rect::NonNegativeLengthOrNumberRect;
pub use self::resolution::Resolution;
pub use self::svg::MozContextProperties;
diff --git a/components/style/values/computed/position.rs b/components/style/values/computed/position.rs
index 3eff231de88..554c36295c7 100644
--- a/components/style/values/computed/position.rs
+++ b/components/style/values/computed/position.rs
@@ -12,7 +12,7 @@ use crate::values::generics::position::Position as GenericPosition;
use crate::values::generics::position::PositionComponent as GenericPositionComponent;
use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto;
use crate::values::generics::position::ZIndex as GenericZIndex;
-pub use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas};
+pub use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow};
use crate::Zero;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs
index 6f0f155912d..0fbeebea1fb 100644
--- a/components/style/values/generics/grid.rs
+++ b/components/style/values/generics/grid.rs
@@ -786,6 +786,9 @@ pub enum GenericGridTemplateComponent<L, I> {
/// TODO: Support animations for this after subgrid is addressed in [grid-2] spec.
#[animation(error)]
Subgrid(Box<LineNameList>),
+ /// `masonry` value.
+ /// https://github.com/w3c/csswg-drafts/issues/4650
+ Masonry,
}
pub use self::GenericGridTemplateComponent as GridTemplateComponent;
diff --git a/components/style/values/specified/align.rs b/components/style/values/specified/align.rs
index 10f7f3efbfc..4b483962f2f 100644
--- a/components/style/values/specified/align.rs
+++ b/components/style/values/specified/align.rs
@@ -171,16 +171,6 @@ impl ContentDistribution {
Self { primary }
}
- fn from_bits(bits: u16) -> Self {
- Self {
- primary: AlignFlags::from_bits_truncate(bits as u8),
- }
- }
-
- fn as_bits(&self) -> u16 {
- self.primary.bits() as u16
- }
-
/// Returns whether this value is a <baseline-position>.
pub fn is_baseline_position(&self) -> bool {
matches!(
@@ -292,6 +282,41 @@ impl SpecifiedValueInfo for AlignContent {
}
}
+/// Value for the `align-tracks` property.
+///
+/// <https://github.com/w3c/csswg-drafts/issues/4650>
+#[derive(
+ Clone,
+ Debug,
+ Default,
+ Eq,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(transparent)]
+#[css(comma)]
+pub struct AlignTracks(
+ #[css(iterable, if_empty = "normal")]
+ pub crate::OwnedSlice<AlignContent>
+);
+
+impl Parse for AlignTracks {
+ fn parse<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ let values = input.parse_comma_separated(|input| {
+ AlignContent::parse(context, input)
+ })?;
+ Ok(AlignTracks(values.into()))
+ }
+}
+
/// Value for the `justify-content` property.
///
/// <https://drafts.csswg.org/css-align/#propdef-justify-content>
@@ -329,18 +354,38 @@ impl SpecifiedValueInfo for JustifyContent {
ContentDistribution::list_keywords(f, AxisDirection::Inline);
}
}
+/// Value for the `justify-tracks` property.
+///
+/// <https://github.com/w3c/csswg-drafts/issues/4650>
+#[derive(
+ Clone,
+ Debug,
+ Default,
+ Eq,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+#[repr(transparent)]
+#[css(comma)]
+pub struct JustifyTracks(
+ #[css(iterable, if_empty = "normal")]
+ pub crate::OwnedSlice<JustifyContent>
+);
-#[cfg(feature = "gecko")]
-impl From<u16> for JustifyContent {
- fn from(bits: u16) -> Self {
- JustifyContent(ContentDistribution::from_bits(bits))
- }
-}
-
-#[cfg(feature = "gecko")]
-impl From<JustifyContent> for u16 {
- fn from(v: JustifyContent) -> u16 {
- v.0.as_bits()
+impl Parse for JustifyTracks {
+ fn parse<'i, 't>(
+ context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<Self, ParseError<'i>> {
+ let values = input.parse_comma_separated(|input| {
+ JustifyContent::parse(context, input)
+ })?;
+ Ok(JustifyTracks(values.into()))
}
}
diff --git a/components/style/values/specified/grid.rs b/components/style/values/specified/grid.rs
index 54d31d5826d..9c6bf385d31 100644
--- a/components/style/values/specified/grid.rs
+++ b/components/style/values/specified/grid.rs
@@ -295,6 +295,18 @@ fn allow_grid_template_subgrids() -> bool {
false
}
+#[cfg(feature = "gecko")]
+#[inline]
+fn allow_grid_template_masonry() -> bool {
+ static_prefs::pref!("layout.css.grid-template-masonry-value.enabled")
+}
+
+#[cfg(feature = "servo")]
+#[inline]
+fn allow_grid_template_masonry() -> bool {
+ false
+}
+
impl Parse for GridTemplateComponent<LengthPercentage, Integer> {
fn parse<'i, 't>(
context: &ParserContext,
@@ -319,7 +331,11 @@ impl GridTemplateComponent<LengthPercentage, Integer> {
return Ok(GridTemplateComponent::Subgrid(Box::new(t)));
}
}
-
+ if allow_grid_template_masonry() {
+ if input.try(|i| i.expect_ident_matching("masonry")).is_ok() {
+ return Ok(GridTemplateComponent::Masonry);
+ }
+ }
let track_list = TrackList::parse(context, input)?;
Ok(GridTemplateComponent::TrackList(Box::new(track_list)))
}
diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs
index 63af3015386..c1c11d5f816 100644
--- a/components/style/values/specified/mod.rs
+++ b/components/style/values/specified/mod.rs
@@ -28,9 +28,9 @@ use style_traits::values::specified::AllowedNumericType;
use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
#[cfg(feature = "gecko")]
-pub use self::align::{AlignContent, AlignItems, AlignSelf, ContentDistribution};
+pub use self::align::{AlignContent, AlignItems, AlignSelf, AlignTracks, ContentDistribution};
#[cfg(feature = "gecko")]
-pub use self::align::{JustifyContent, JustifyItems, JustifySelf, SelfAlignment};
+pub use self::align::{JustifyContent, JustifyItems, JustifySelf, JustifyTracks, SelfAlignment};
pub use self::angle::{AllowUnitlessZeroAngle, Angle};
pub use self::background::{BackgroundRepeat, BackgroundSize};
pub use self::basic_shape::FillRule;
@@ -72,7 +72,7 @@ pub use self::list::Quotes;
pub use self::motion::{OffsetPath, OffsetRotate};
pub use self::outline::OutlineStyle;
pub use self::percentage::Percentage;
-pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, PositionOrAuto};
+pub use self::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto};
pub use self::position::{PositionComponent, ZIndex};
pub use self::rect::NonNegativeLengthOrNumberRect;
pub use self::resolution::Resolution;
diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs
index b843de29a41..33b9ddcf5b5 100644
--- a/components/style/values/specified/position.rs
+++ b/components/style/values/specified/position.rs
@@ -383,6 +383,172 @@ bitflags! {
}
}
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+/// Masonry auto-placement algorithm packing.
+pub enum MasonryPlacement {
+ /// Place the item in the track(s) with the smallest extent so far.
+ Pack,
+ /// Place the item after the last item, from start to end.
+ Next,
+}
+
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+/// Masonry auto-placement algorithm item sorting option.
+pub enum MasonryItemOrder {
+ /// Place all items with a definite placement before auto-placed items.
+ DefiniteFirst,
+ /// Place items in `order-modified document order`.
+ Ordered,
+}
+
+#[derive(
+ Clone,
+ Copy,
+ Debug,
+ Eq,
+ MallocSizeOf,
+ PartialEq,
+ SpecifiedValueInfo,
+ ToComputedValue,
+ ToCss,
+ ToResolvedValue,
+ ToShmem,
+)]
+/// Controls how the Masonry layout algorithm works
+/// specifying exactly how auto-placed items get flowed in the masonry axis.
+pub struct MasonryAutoFlow {
+ /// Specify how to pick a auto-placement track.
+ #[css(contextual_skip_if = "is_pack_with_non_default_order")]
+ pub placement: MasonryPlacement,
+ /// Specify how to pick an item to place.
+ #[css(skip_if = "is_item_order_definite_first")]
+ pub order: MasonryItemOrder,
+}
+
+#[inline]
+fn is_pack_with_non_default_order(placement: &MasonryPlacement, order: &MasonryItemOrder) -> bool {
+ *placement == MasonryPlacement::Pack &&
+ *order != MasonryItemOrder::DefiniteFirst
+}
+
+#[inline]
+fn is_item_order_definite_first(order: &MasonryItemOrder) -> bool {
+ *order == MasonryItemOrder::DefiniteFirst
+}
+
+impl MasonryAutoFlow {
+ #[inline]
+ /// Get initial `masonry-auto-flow` value.
+ pub fn initial() -> MasonryAutoFlow {
+ MasonryAutoFlow {
+ placement: MasonryPlacement::Pack,
+ order: MasonryItemOrder::DefiniteFirst,
+ }
+ }
+}
+
+impl Parse for MasonryAutoFlow {
+ /// [ definite-first | ordered ] || [ pack | next ]
+ fn parse<'i, 't>(
+ _context: &ParserContext,
+ input: &mut Parser<'i, 't>,
+ ) -> Result<MasonryAutoFlow, ParseError<'i>> {
+ let mut value = MasonryAutoFlow::initial();
+ let mut got_placement = false;
+ let mut got_order = false;
+ while !input.is_exhausted() {
+ let location = input.current_source_location();
+ let ident = input.expect_ident()?;
+ let success = match_ignore_ascii_case! { &ident,
+ "pack" if !got_placement => {
+ got_placement = true;
+ true
+ },
+ "next" if !got_placement => {
+ value.placement = MasonryPlacement::Next;
+ got_placement = true;
+ true
+ },
+ "definite-first" if !got_order => {
+ got_order = true;
+ true
+ },
+ "ordered" if !got_order => {
+ value.order = MasonryItemOrder::Ordered;
+ got_order = true;
+ true
+ },
+ _ => false
+ };
+ if !success {
+ return Err(location
+ .new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())));
+ }
+ }
+
+ if got_placement || got_order {
+ Ok(value)
+ } else {
+ Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+ }
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl From<u8> for MasonryAutoFlow {
+ fn from(bits: u8) -> MasonryAutoFlow {
+ use crate::gecko_bindings::structs;
+ let mut value = MasonryAutoFlow::initial();
+ if bits & structs::NS_STYLE_MASONRY_PLACEMENT_PACK as u8 == 0 {
+ value.placement = MasonryPlacement::Next;
+ }
+ if bits & structs::NS_STYLE_MASONRY_ORDER_DEFINITE_FIRST as u8 == 0 {
+ value.order = MasonryItemOrder::Ordered;
+ }
+ value
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl From<MasonryAutoFlow> for u8 {
+ fn from(v: MasonryAutoFlow) -> u8 {
+ use crate::gecko_bindings::structs;
+
+ let mut result: u8 = 0;
+ if v.placement == MasonryPlacement::Pack {
+ result |= structs::NS_STYLE_MASONRY_PLACEMENT_PACK as u8;
+ }
+ if v.order == MasonryItemOrder::DefiniteFirst {
+ result |= structs::NS_STYLE_MASONRY_ORDER_DEFINITE_FIRST as u8;
+ }
+ result
+ }
+}
+
impl Parse for GridAutoFlow {
/// [ row | column ] || dense
fn parse<'i, 't>(