diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-02-09 15:51:29 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-09 15:51:29 -0800 |
commit | e985ad54229083e5e76b2862cec57ce4fef4433c (patch) | |
tree | 151eeb17007f252c278aaa13e38deba3af5bee9d | |
parent | ce7827eadfcceb37e779846926c2b2f72c08dd72 (diff) | |
parent | 779d93669855c787bde3a66e0bdf06aec27a9004 (diff) | |
download | servo-e985ad54229083e5e76b2862cec57ce4fef4433c.tar.gz servo-e985ad54229083e5e76b2862cec57ce4fef4433c.zip |
Auto merge of #15463 - Manishearth:buncha-props, r=mbrubeck
stylo: Implement a bunch of properties
r? @mbrubeck or @heycam
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15463)
<!-- Reviewable:end -->
20 files changed, 451 insertions, 246 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 1285d5cef7a..4dc72f20301 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -1176,10 +1176,11 @@ impl FragmentDisplayListBuilding for Fragment { fn adjust_clip_for_style(&self, parent_clip: &mut ClippingRegion, stacking_relative_border_box: &Rect<Au>) { + use style::values::Either; // Account for `clip` per CSS 2.1 § 11.1.2. let style_clip_rect = match (self.style().get_box().position, - self.style().get_effects().clip.0) { - (position::T::absolute, Some(style_clip_rect)) => style_clip_rect, + self.style().get_effects().clip) { + (position::T::absolute, Either::First(style_clip_rect)) => style_clip_rect, _ => return, }; diff --git a/components/style/gecko_bindings/sugar/ns_t_array.rs b/components/style/gecko_bindings/sugar/ns_t_array.rs index 5d9c005f0e3..6bc389702f5 100644 --- a/components/style/gecko_bindings/sugar/ns_t_array.rs +++ b/components/style/gecko_bindings/sugar/ns_t_array.rs @@ -93,4 +93,13 @@ impl<T> nsTArray<T> { let mut header = self.header_mut(); header.mLength = len; } + + /// Resizes an array containing only POD elements + /// + /// This will not leak since it only works on POD types (and thus doesn't assert) + pub unsafe fn set_len_pod(&mut self, len: u32) where T: Copy { + self.ensure_capacity(len as usize); + let mut header = unsafe { self.header_mut() }; + header.mLength = len; + } } diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 70363eba25c..5d79857be93 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -328,6 +328,39 @@ def set_gecko_property(ffi_name, expr): % endif </%def> +<%def name="impl_absolute_length(ident, gecko_ffi_name, need_clone=False)"> + #[allow(non_snake_case)] + pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { + ${set_gecko_property(gecko_ffi_name, "v.0")} + } + <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call> + % if need_clone: + #[allow(non_snake_case)] + pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { + Au(self.gecko.${gecko_ffi_name}) + } + % endif +</%def> + +<%def name="impl_position(ident, gecko_ffi_name, need_clone=False)"> + #[allow(non_snake_case)] + pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { + ${set_gecko_property("%s.mXPosition" % gecko_ffi_name, "v.horizontal.into()")} + ${set_gecko_property("%s.mYPosition" % gecko_ffi_name, "v.vertical.into()")} + } + <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call> + % if need_clone: + #[allow(non_snake_case)] + pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { + use values::computed::Position; + Position { + horizontal: self.gecko.${gecko_ffi_name}.mXPosition.into(), + vertical: self.gecko.${gecko_ffi_name}.mYPosition.into(), + } + } + % endif +</%def> + <%def name="impl_color(ident, gecko_ffi_name, need_clone=False, complex_color=True)"> <%call expr="impl_color_setter(ident, gecko_ffi_name, complex_color)"></%call> <%call expr="impl_color_copy(ident, gecko_ffi_name, complex_color)"></%call> @@ -501,7 +534,8 @@ impl Debug for ${style_struct.gecko_struct_name} { # Types used with predefined_type()-defined properties that we can auto-generate. predefined_types = { "length::LengthOrAuto": impl_style_coord, - "Length": impl_style_coord, + "Length": impl_absolute_length, + "Position": impl_position, "LengthOrPercentage": impl_style_coord, "LengthOrPercentageOrAuto": impl_style_coord, "LengthOrPercentageOrNone": impl_style_coord, @@ -1169,7 +1203,8 @@ fn static_assert() { animation-iteration-count animation-timing-function -moz-binding page-break-before page-break-after scroll-snap-points-x scroll-snap-points-y transform - scroll-snap-type-y perspective-origin transform-origin""" %> + scroll-snap-type-y scroll-snap-coordinate + perspective-origin transform-origin""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> // We manually-implement the |display| property until we get general @@ -1340,6 +1375,34 @@ fn static_assert() { ${impl_coord_copy('scroll_snap_points_y', 'mScrollSnapPointsY')} + pub fn set_scroll_snap_coordinate(&mut self, v: longhands::scroll_snap_coordinate::computed_value::T) { + unsafe { self.gecko.mScrollSnapCoordinate.set_len_pod(v.0.len() as u32); } + for (gecko, servo) in self.gecko.mScrollSnapCoordinate + .iter_mut() + .zip(v.0.iter()) { + gecko.mXPosition = servo.horizontal.into(); + gecko.mYPosition = servo.vertical.into(); + } + } + + pub fn copy_scroll_snap_coordinate_from(&mut self, other: &Self) { + unsafe { + self.gecko.mScrollSnapCoordinate + .set_len_pod(other.gecko.mScrollSnapCoordinate.len() as u32); + } + + for (this, that) in self.gecko.mScrollSnapCoordinate + .iter_mut() + .zip(other.gecko.mScrollSnapCoordinate.iter()) { + *this = *that; + } + } + + pub fn clone_scroll_snap_coordinate(&self) -> longhands::scroll_snap_coordinate::computed_value::T { + let vec = self.gecko.mScrollSnapCoordinate.iter().map(|f| f.into()).collect(); + longhands::scroll_snap_coordinate::computed_value::T(vec) + } + <%def name="transform_function_arm(name, keyword, items)"> <% pattern = None @@ -1971,7 +2034,7 @@ fn static_assert() { </%self:impl_trait> <%self:impl_trait style_struct_name="List" - skip_longhands="list-style-image list-style-type quotes" + skip_longhands="list-style-image list-style-type quotes -moz-image-region" skip_additionals="*"> pub fn set_list_style_image(&mut self, image: longhands::list_style_image::computed_value::T) { @@ -2037,6 +2100,28 @@ fn static_assert() { unsafe { self.gecko.mQuotes.set(&other.gecko.mQuotes); } } + #[allow(non_snake_case)] + pub fn set__moz_image_region(&mut self, v: longhands::_moz_image_region::computed_value::T) { + use values::Either; + + match v { + Either::Second(_auto) => { + self.gecko.mImageRegion.x = 0; + self.gecko.mImageRegion.y = 0; + self.gecko.mImageRegion.width = 0; + self.gecko.mImageRegion.height = 0; + } + Either::First(rect) => { + self.gecko.mImageRegion.x = rect.left.0; + self.gecko.mImageRegion.y = rect.top.0; + self.gecko.mImageRegion.height = rect.bottom.unwrap_or(Au(0)).0 - self.gecko.mImageRegion.y; + self.gecko.mImageRegion.width = rect.right.unwrap_or(Au(0)).0 - self.gecko.mImageRegion.x; + } + } + } + + ${impl_simple_copy('_moz_image_region', 'mImageRegion')} + </%self:impl_trait> <%self:impl_trait style_struct_name="Effects" @@ -2204,7 +2289,7 @@ fn static_assert() { <%self:impl_trait style_struct_name="InheritedText" skip_longhands="text-align text-emphasis-style text-shadow line-height letter-spacing word-spacing - -webkit-text-stroke-width"> + -webkit-text-stroke-width text-emphasis-position -moz-tab-size"> <% text_align_keyword = Keyword("text-align", "start end left right center justify -moz-center -moz-left " + "-moz-right match-parent") %> @@ -2310,6 +2395,26 @@ fn static_assert() { } } + pub fn set_text_emphasis_position(&mut self, v: longhands::text_emphasis_position::computed_value::T) { + use properties::longhands::text_emphasis_position::*; + + let mut result = match v.0 { + HorizontalWritingModeValue::Over => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER as u8, + HorizontalWritingModeValue::Under => structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER as u8, + }; + match v.1 { + VerticalWritingModeValue::Right => { + result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT as u8; + } + VerticalWritingModeValue::Left => { + result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT as u8; + } + } + self.gecko.mTextEmphasisPosition = result; + } + + <%call expr="impl_simple_copy('text_emphasis_position', 'mTextEmphasisPosition')"></%call> + pub fn set_text_emphasis_style(&mut self, v: longhands::text_emphasis_style::computed_value::T) { use nsstring::nsCString; use properties::longhands::text_emphasis_style::computed_value::T; @@ -2353,6 +2458,22 @@ fn static_assert() { <%call expr="impl_app_units('_webkit_text_stroke_width', 'mWebkitTextStrokeWidth', need_clone=False)"></%call> + #[allow(non_snake_case)] + pub fn set__moz_tab_size(&mut self, v: longhands::_moz_tab_size::computed_value::T) { + use values::Either; + + match v { + Either::Second(number) => { + self.gecko.mTabSize.set_value(CoordDataValue::Factor(number)); + } + Either::First(au) => { + self.gecko.mTabSize.set(au); + } + } + } + + <%call expr="impl_coord_copy('_moz_tab_size', 'mTabSize')"></%call> + </%self:impl_trait> <%self:impl_trait style_struct_name="Text" @@ -2815,6 +2936,18 @@ clip-path } </%self:impl_trait> +<%self:impl_trait style_struct_name="XUL" + skip_longhands="-moz-stack-sizing"> + + #[allow(non_snake_case)] + pub fn set__moz_stack_sizing(&mut self, v: longhands::_moz_stack_sizing::computed_value::T) { + use properties::longhands::_moz_stack_sizing::computed_value::T; + self.gecko.mStretchStack = v == T::stretch_to_fit; + } + + ${impl_simple_copy('_moz_stack_sizing', 'mStretchStack')} +</%self:impl_trait> + <%def name="define_ffi_struct_accessor(style_struct)"> #[no_mangle] #[allow(non_snake_case, unused_variables)] diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 30c6873a8a2..3d84c4a8190 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -21,8 +21,9 @@ </%call> </%def> -<%def name="predefined_type(name, type, initial_value, parse_method='parse', needs_context=True, **kwargs)"> - <%call expr="longhand(name, predefined_type=type, **kwargs)"> +<%def name="predefined_type(name, type, initial_value, parse_method='parse', + needs_context=True, vector=False, **kwargs)"> + <%def name="predefined_type_inner(name, type, initial_value, parse_method)"> #[allow(unused_imports)] use app_units::Au; use cssparser::{Color as CSSParserColor, RGBA}; @@ -40,7 +41,16 @@ specified::${type}::${parse_method}(input) % endif } - </%call> + </%def> + % if vector: + <%call expr="vector_longhand(name, predefined_type=type, **kwargs)"> + ${predefined_type_inner(name, type, initial_value, parse_method)} + </%call> + % else: + <%call expr="longhand(name, predefined_type=type, **kwargs)"> + ${predefined_type_inner(name, type, initial_value, parse_method)} + </%call> + % endif </%def> // FIXME (Manishearth): Add computed_value_as_specified argument @@ -56,7 +66,7 @@ We assume that the default/initial value is an empty vector for these. `initial_value` need not be defined for these. </%doc> -<%def name="vector_longhand(name, gecko_only=False, allow_empty=False, **kwargs)"> +<%def name="vector_longhand(name, gecko_only=False, allow_empty=False, delegate_animate=False, **kwargs)"> <%call expr="longhand(name, **kwargs)"> % if not gecko_only: use std::fmt; @@ -87,6 +97,15 @@ #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct T(pub Vec<single_value::T>); + + % if delegate_animate: + use properties::animated_properties::Interpolate; + impl Interpolate for T { + fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { + self.0.interpolate(&other.0, progress).map(T) + } + } + % endif } impl ToCss for computed_value::T { diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 35fb529c851..fae2c82e54d 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -10,8 +10,6 @@ use euclid::{Point2D, Size2D}; #[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID; use properties::{DeclaredValue, PropertyDeclaration}; use properties::longhands; -use properties::longhands::background_position_x::computed_value::T as BackgroundPositionX; -use properties::longhands::background_position_y::computed_value::T as BackgroundPositionY; use properties::longhands::background_size::computed_value::T as BackgroundSize; use properties::longhands::font_weight::computed_value::T as FontWeight; use properties::longhands::line_height::computed_value::T as LineHeight; @@ -33,7 +31,7 @@ use super::ComputedValues; use values::CSSFloat; use values::Either; use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone}; -use values::computed::{BorderRadiusSize, LengthOrNone}; +use values::computed::{BorderRadiusSize, ClipRect, LengthOrNone}; use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage}; use values::computed::position::{HorizontalPosition, Position, VerticalPosition}; use values::computed::ToComputedValue; @@ -724,17 +722,16 @@ impl Interpolate for VerticalPosition { impl RepeatableListInterpolate for VerticalPosition {} -impl Interpolate for BackgroundPositionX { +/// https://drafts.csswg.org/css-transitions/#animtype-rect +impl Interpolate for ClipRect { #[inline] - fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { - Ok(BackgroundPositionX(try!(self.0.interpolate(&other.0, progress)))) - } -} - -impl Interpolate for BackgroundPositionY { - #[inline] - fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { - Ok(BackgroundPositionY(try!(self.0.interpolate(&other.0, progress)))) + fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> { + Ok(ClipRect { + top: try!(self.top.interpolate(&other.top, time)), + right: try!(self.right.interpolate(&other.right, time)), + bottom: try!(self.bottom.interpolate(&other.bottom, time)), + left: try!(self.left.interpolate(&other.left, time)), + }) } } diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index b4b0686e542..f8622e75d29 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -89,7 +89,8 @@ ${helpers.predefined_type("background-color", "CSSColor", </%helpers:vector_longhand> <%helpers:vector_longhand name="background-position-x" animatable="True" - spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x"> + spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x" + delegate_animate="True"> use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; @@ -139,7 +140,8 @@ ${helpers.predefined_type("background-color", "CSSColor", </%helpers:vector_longhand> <%helpers:vector_longhand name="background-position-y" animatable="True" - spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y"> + spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y" + delegate_animate="True"> use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index 624e8ac7926..8a85377febb 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -257,10 +257,10 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box", } } - pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { let mut values = vec![]; for _ in 0..4 { - let value = input.try(|input| LengthOrNumber::parse_non_negative(input)); + let value = input.try(|input| LengthOrNumber::parse_non_negative(context, input)); match value { Ok(val) => values.push(val), Err(_) => break, diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 95d23dbf0e4..9fbe615fea0 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -1049,6 +1049,25 @@ ${helpers.single_keyword("animation-fill-mode", </%helpers:longhand> +${helpers.predefined_type("scroll-snap-destination", + "Position", + "computed::Position::zero()", + products="gecko", + boxed="True", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)", + animatable=True)} + +${helpers.predefined_type("scroll-snap-coordinate", + "Position", + "computed::Position::zero()", + vector=True, + products="gecko", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-snap-destination)", + animatable=True, + allow_empty=True, + delegate_animate=True)} + + <%helpers:longhand name="transform" products="gecko servo" extra_prefixes="webkit" animatable="True" diff --git a/components/style/properties/longhand/effects.mako.rs b/components/style/properties/longhand/effects.mako.rs index b01874e8095..eb4879f7afb 100644 --- a/components/style/properties/longhand/effects.mako.rs +++ b/components/style/properties/longhand/effects.mako.rs @@ -77,217 +77,13 @@ ${helpers.predefined_type("opacity", </%helpers:vector_longhand> // FIXME: This prop should be animatable -<%helpers:longhand name="clip" products="servo" animatable="False" boxed="True" - spec="https://drafts.fxtf.org/css-masking/#clip-property"> - use std::fmt; - use style_traits::ToCss; - use values::HasViewportPercentage; - - // NB: `top` and `left` are 0 if `auto` per CSS 2.1 11.1.2. - - pub mod computed_value { - use app_units::Au; - use properties::animated_properties::Interpolate; - - #[derive(Clone, PartialEq, Eq, Copy, Debug)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct ClipRect { - pub top: Au, - pub right: Option<Au>, - pub bottom: Option<Au>, - pub left: Au, - } - - #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct T(pub Option<ClipRect>); - - - /// https://drafts.csswg.org/css-transitions/#animtype-rect - impl Interpolate for ClipRect { - #[inline] - fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> { - Ok(ClipRect { - top: try!(self.top.interpolate(&other.top, time)), - right: try!(self.right.interpolate(&other.right, time)), - bottom: try!(self.bottom.interpolate(&other.bottom, time)), - left: try!(self.left.interpolate(&other.left, time)), - }) - } - } - } - - impl ToCss for computed_value::T { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match self.0 { - None => dest.write_str("auto"), - Some(rect) => { - try!(dest.write_str("rect(")); - try!(rect.top.to_css(dest)); - try!(dest.write_str(", ")); - if let Some(right) = rect.right { - try!(right.to_css(dest)); - try!(dest.write_str(", ")); - } else { - try!(dest.write_str("auto, ")); - } - - if let Some(bottom) = rect.bottom { - try!(bottom.to_css(dest)); - try!(dest.write_str(", ")); - } else { - try!(dest.write_str("auto, ")); - } - - try!(rect.left.to_css(dest)); - try!(dest.write_str(")")); - Ok(()) - } - } - } - } - - impl HasViewportPercentage for SpecifiedClipRect { - fn has_viewport_percentage(&self) -> bool { - self.top.has_viewport_percentage() || - self.right.as_ref().map_or(false, |x| x.has_viewport_percentage()) || - self.bottom.as_ref().map_or(false, |x| x.has_viewport_percentage()) || - self.left.has_viewport_percentage() - } - } - - #[derive(Clone, Debug, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct SpecifiedClipRect { - pub top: specified::Length, - pub right: Option<specified::Length>, - pub bottom: Option<specified::Length>, - pub left: specified::Length, - } - - impl HasViewportPercentage for SpecifiedValue { - fn has_viewport_percentage(&self) -> bool { - self.0.as_ref().map_or(false, |x| x.has_viewport_percentage()) - } - } - - #[derive(Clone, Debug, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct SpecifiedValue(Option<SpecifiedClipRect>); - - impl ToCss for SpecifiedClipRect { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(dest.write_str("rect(")); - - try!(self.top.to_css(dest)); - try!(dest.write_str(", ")); - - if let Some(ref right) = self.right { - try!(right.to_css(dest)); - try!(dest.write_str(", ")); - } else { - try!(dest.write_str("auto, ")); - } - - if let Some(ref bottom) = self.bottom { - try!(bottom.to_css(dest)); - try!(dest.write_str(", ")); - } else { - try!(dest.write_str("auto, ")); - } - - try!(self.left.to_css(dest)); - - try!(dest.write_str(")")); - Ok(()) - } - } - - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if let Some(ref rect) = self.0 { - rect.to_css(dest) - } else { - dest.write_str("auto") - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(None) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::T { - computed_value::T(self.0.as_ref().map(|value| computed_value::ClipRect { - top: value.top.to_computed_value(context), - right: value.right.as_ref().map(|right| right.to_computed_value(context)), - bottom: value.bottom.as_ref().map(|bottom| bottom.to_computed_value(context)), - left: value.left.to_computed_value(context), - })) - } - - #[inline] - fn from_computed_value(computed: &computed_value::T) -> Self { - SpecifiedValue(computed.0.map(|value| SpecifiedClipRect { - top: ToComputedValue::from_computed_value(&value.top), - right: value.right.map(|right| ToComputedValue::from_computed_value(&right)), - bottom: value.bottom.map(|bottom| ToComputedValue::from_computed_value(&bottom)), - left: ToComputedValue::from_computed_value(&value.left), - })) - } - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - use app_units::Au; - use std::ascii::AsciiExt; - use values::specified::Length; - - fn parse_argument(context: &ParserContext, input: &mut Parser) -> Result<Option<Length>, ()> { - if input.try(|input| input.expect_ident_matching("auto")).is_ok() { - Ok(None) - } else { - Length::parse(context, input).map(Some) - } - } - - if input.try(|input| input.expect_ident_matching("auto")).is_ok() { - return Ok(SpecifiedValue(None)) - } - if !try!(input.expect_function()).eq_ignore_ascii_case("rect") { - return Err(()) - } - - input.parse_nested_block(|input| { - let top = try!(parse_argument(context, input)); - let right; - let bottom; - let left; - - if input.try(|input| input.expect_comma()).is_ok() { - right = try!(parse_argument(context, input)); - try!(input.expect_comma()); - bottom = try!(parse_argument(context, input)); - try!(input.expect_comma()); - left = try!(parse_argument(context, input)); - } else { - right = try!(parse_argument(context, input)); - bottom = try!(parse_argument(context, input)); - left = try!(parse_argument(context, input)); - } - Ok(SpecifiedValue(Some(SpecifiedClipRect { - top: top.unwrap_or(Length::zero()), - right: right, - bottom: bottom, - left: left.unwrap_or(Length::zero()), - }))) - }) - } -</%helpers:longhand> +${helpers.predefined_type("clip", + "ClipRectOrAuto", + "computed::ClipRectOrAuto::auto()", + animatable=False, + products="servo", + boxed="True", + spec="https://drafts.fxtf.org/css-masking/#clip-property")} // FIXME: This prop should be animatable <%helpers:longhand name="filter" animatable="False" extra_prefixes="webkit" diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 335ad1f1ca1..dc3e32f99b3 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -973,7 +973,7 @@ ${helpers.single_keyword("text-align-last", } </%helpers:longhand> -<%helpers:longhand name="text-emphasis-position" animatable="False" products="none" +<%helpers:longhand name="text-emphasis-position" animatable="False" products="gecko" spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position"> use std::fmt; use values::computed::ComputedValueAsSpecified; @@ -1030,6 +1030,15 @@ ${helpers.predefined_type("text-emphasis-color", "CSSColor", boxed=True, spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-color")} + +${helpers.predefined_type( + "-moz-tab-size", "LengthOrNumber", + "::values::Either::Second(8.0)", + "parse_non_negative", + products="gecko", animatable=False, + spec="https://drafts.csswg.org/css-text-3/#tab-size-property")} + + // CSS Compatibility // https://compat.spec.whatwg.org ${helpers.predefined_type( @@ -1070,6 +1079,7 @@ ${helpers.predefined_type( } </%helpers:longhand> + // CSS Ruby Layout Module Level 1 // https://drafts.csswg.org/css-ruby/ ${helpers.single_keyword("ruby-align", "start center space-between space-around", diff --git a/components/style/properties/longhand/list.mako.rs b/components/style/properties/longhand/list.mako.rs index f4f84f9e884..91e003d2575 100644 --- a/components/style/properties/longhand/list.mako.rs +++ b/components/style/properties/longhand/list.mako.rs @@ -101,3 +101,11 @@ ${helpers.predefined_type("list-style-image", "UrlOrNone", "Either::Second(None_ } } </%helpers:longhand> + +${helpers.predefined_type("-moz-image-region", + "ClipRectOrAuto", + "computed::ClipRectOrAuto::auto()", + animatable=False, + products="gecko", + boxed="True", + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-image-region)")} diff --git a/components/style/properties/longhand/outline.mako.rs b/components/style/properties/longhand/outline.mako.rs index b47f45d7a68..cd242797f0d 100644 --- a/components/style/properties/longhand/outline.mako.rs +++ b/components/style/properties/longhand/outline.mako.rs @@ -114,5 +114,5 @@ ${helpers.predefined_type("outline-color", "CSSColor", "::cssparser::Color::Curr spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)")} % endfor -${helpers.predefined_type("outline-offset", "Length", "Au(0)", products="servo", animatable=True, +${helpers.predefined_type("outline-offset", "Length", "Au(0)", products="servo gecko", animatable=True, spec="https://drafts.csswg.org/css-ui/#propdef-outline-offset")} diff --git a/components/style/properties/longhand/position.mako.rs b/components/style/properties/longhand/position.mako.rs index 3e55cb2bd3b..9c801358988 100644 --- a/components/style/properties/longhand/position.mako.rs +++ b/components/style/properties/longhand/position.mako.rs @@ -210,6 +210,14 @@ ${helpers.single_keyword("object-fit", "fill contain cover none scale-down", products="gecko", animatable=False, spec="https://drafts.csswg.org/css-images/#propdef-object-fit")} +${helpers.predefined_type("object-position", + "Position", + "computed::Position::zero()", + products="gecko", + boxed="True", + spec="https://drafts.csswg.org/css-images-3/#the-object-position", + animatable=True)} + <% grid_longhands = ["grid-row-start", "grid-row-end", "grid-column-start", "grid-column-end"] %> % for longhand in grid_longhands: diff --git a/components/style/properties/longhand/ui.mako.rs b/components/style/properties/longhand/ui.mako.rs index 62948316e70..79d25467df6 100644 --- a/components/style/properties/longhand/ui.mako.rs +++ b/components/style/properties/longhand/ui.mako.rs @@ -23,3 +23,9 @@ ${helpers.single_keyword("-moz-user-select", "auto text none all", products="gec gecko_inexhaustive=True, animatable=False, spec="https://drafts.csswg.org/css-ui-4/#propdef-user-select")} + +${helpers.single_keyword("-moz-window-dragging", "default drag no-drag", products="gecko", + gecko_ffi_name="mWindowDragging", + gecko_enum_prefix="StyleWindowDragging", + animatable=False, + spec="None (Nonstandard Firefox-only property)")} diff --git a/components/style/properties/longhand/xul.mako.rs b/components/style/properties/longhand/xul.mako.rs index 7862b1d9177..6cf61f3948a 100644 --- a/components/style/properties/longhand/xul.mako.rs +++ b/components/style/properties/longhand/xul.mako.rs @@ -22,3 +22,10 @@ ${helpers.predefined_type("-moz-box-flex", "Number", "0.0", "parse_non_negative" animatable=False, alias="-webkit-box-flex", spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/box-flex)")} + + +${helpers.single_keyword("-moz-stack-sizing", "stretch-to-fit ignore", + products="gecko", gecko_ffi_name="mStretchStack", + gecko_constant_prefix="NS_STYLE_STACK_SIZING", + animatable=False, + spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-stack-sizing)")} diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 3f014d3368f..02cbcbf1150 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -1589,7 +1589,7 @@ impl ComputedValues { // TODO(gw): Add clip-path, isolation, mask-image, mask-border-source when supported. if effects.opacity < 1.0 || !effects.filter.is_empty() || - effects.clip.0.is_some() { + !effects.clip.is_auto() { effects.mix_blend_mode != mix_blend_mode::T::normal || return transform_style::T::flat; } @@ -2290,10 +2290,10 @@ pub fn modify_style_for_text(style: &mut Arc<ComputedValues>) { /// doesn't clip its children. #[cfg(feature = "servo")] pub fn modify_style_for_inline_absolute_hypothetical_fragment(style: &mut Arc<ComputedValues>) { - if style.get_effects().clip.0.is_some() { + if !style.get_effects().clip.is_auto() { let mut style = Arc::make_mut(style); let effects_style = Arc::make_mut(&mut style.effects); - effects_style.clip.0 = None + effects_style.clip = Either::auto() } } diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index a653d18918c..36b3b2dc6ac 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -15,11 +15,12 @@ use super::{CSSFloat, specified}; pub use cssparser::Color as CSSColor; pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image}; pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword}; -pub use super::{Either, None_}; +pub use super::{Auto, Either, None_}; pub use super::specified::{Angle, BorderStyle, GridLine, Time, UrlOrNone}; pub use super::specified::url::UrlExtraData; pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto}; pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone}; +pub use self::position::Position; pub mod basic_shape; pub mod image; @@ -176,3 +177,57 @@ pub type Number = CSSFloat; /// A type used for opacity. pub type Opacity = CSSFloat; + + +#[derive(Clone, PartialEq, Eq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[allow(missing_docs)] +/// A computed cliprect for clip and image-region +pub struct ClipRect { + pub top: Au, + pub right: Option<Au>, + pub bottom: Option<Au>, + pub left: Au, +} + +impl ToCss for ClipRect { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(dest.write_str("rect(")); + try!(self.top.to_css(dest)); + try!(dest.write_str(", ")); + if let Some(right) = self.right { + try!(right.to_css(dest)); + try!(dest.write_str(", ")); + } else { + try!(dest.write_str("auto, ")); + } + + if let Some(bottom) = self.bottom { + try!(bottom.to_css(dest)); + try!(dest.write_str(", ")); + } else { + try!(dest.write_str("auto, ")); + } + + try!(self.left.to_css(dest)); + dest.write_str(")") + } +} + +/// rect(...) | auto +pub type ClipRectOrAuto = Either<ClipRect, Auto>; + +impl ClipRectOrAuto { + /// Return an auto (default for clip-rect and image-region) value + pub fn auto() -> Self { + Either::Second(Auto) + } + + /// Check if it is auto + pub fn is_auto(&self) -> bool { + match *self { + Either::Second(_) => true, + _ => false + } + } +} diff --git a/components/style/values/computed/position.rs b/components/style/values/computed/position.rs index a9b51953810..d2cc4b1e48f 100644 --- a/components/style/values/computed/position.rs +++ b/components/style/values/computed/position.rs @@ -19,6 +19,16 @@ pub struct Position { pub vertical: LengthOrPercentage, } +impl Position { + /// Construct a position at (0, 0) + pub fn zero() -> Self { + Position { + horizontal: LengthOrPercentage::zero(), + vertical: LengthOrPercentage::zero(), + } + } +} + impl ToCss for Position { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { try!(self.horizontal.to_css(dest)); diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 99c4a09abf1..fb4ac9c0b60 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -1215,7 +1215,7 @@ pub type LengthOrNumber = Either<Length, Number>; impl LengthOrNumber { /// Parse a non-negative LengthOrNumber. - pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> { + pub fn parse_non_negative(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { // We try to parse as a Number first because, for cases like LengthOrNumber, // we want "0" to be parsed as a plain Number rather than a Length (0px); this // matches the behaviour of all major browsers diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index dac10f661f7..8e3315f0ea6 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -16,7 +16,7 @@ use std::f32::consts::PI; use std::fmt; use std::ops::Mul; use style_traits::ToCss; -use super::{CSSFloat, HasViewportPercentage, Either, None_}; +use super::{Auto, CSSFloat, HasViewportPercentage, Either, None_}; use super::computed::{ComputedValueAsSpecified, Context, ToComputedValue}; use super::computed::Shadow as ComputedShadow; @@ -27,6 +27,7 @@ pub use self::image::{SizeKeyword, VerticalDirection}; pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage}; pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto}; pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength, CalcUnit}; +pub use self::position::{HorizontalPosition, Position, VerticalPosition}; pub mod basic_shape; pub mod grid; @@ -664,3 +665,127 @@ impl Shadow { }) } } + + +impl HasViewportPercentage for ClipRect { + fn has_viewport_percentage(&self) -> bool { + self.top.has_viewport_percentage() || + self.right.as_ref().map_or(false, |x| x.has_viewport_percentage()) || + self.bottom.as_ref().map_or(false, |x| x.has_viewport_percentage()) || + self.left.has_viewport_percentage() + } +} + +#[derive(Clone, Debug, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +/// rect(<top>, <left>, <bottom>, <right>) used by clip and image-region +pub struct ClipRect { + /// <top> (<length> | <auto>). Auto maps to 0 + pub top: Length, + /// <right> (<length> | <auto>) + pub right: Option<Length>, + /// <bottom> (<length> | <auto>) + pub bottom: Option<Length>, + /// <left> (<length> | <auto>). Auto maps to 0 + pub left: Length, +} + + +impl ToCss for ClipRect { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(dest.write_str("rect(")); + + try!(self.top.to_css(dest)); + try!(dest.write_str(", ")); + + if let Some(ref right) = self.right { + try!(right.to_css(dest)); + try!(dest.write_str(", ")); + } else { + try!(dest.write_str("auto, ")); + } + + if let Some(ref bottom) = self.bottom { + try!(bottom.to_css(dest)); + try!(dest.write_str(", ")); + } else { + try!(dest.write_str("auto, ")); + } + + try!(self.left.to_css(dest)); + + try!(dest.write_str(")")); + Ok(()) + } +} + +impl ToComputedValue for ClipRect { + type ComputedValue = super::computed::ClipRect; + + #[inline] + fn to_computed_value(&self, context: &Context) -> super::computed::ClipRect { + super::computed::ClipRect { + top: self.top.to_computed_value(context), + right: self.right.as_ref().map(|right| right.to_computed_value(context)), + bottom: self.bottom.as_ref().map(|bottom| bottom.to_computed_value(context)), + left: self.left.to_computed_value(context), + } + } + + #[inline] + fn from_computed_value(computed: &super::computed::ClipRect) -> Self { + ClipRect { + top: ToComputedValue::from_computed_value(&computed.top), + right: computed.right.map(|right| ToComputedValue::from_computed_value(&right)), + bottom: computed.bottom.map(|bottom| ToComputedValue::from_computed_value(&bottom)), + left: ToComputedValue::from_computed_value(&computed.left), + } + } +} + +impl Parse for ClipRect { + fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + use values::specified::Length; + + fn parse_argument(context: &ParserContext, input: &mut Parser) -> Result<Option<Length>, ()> { + if input.try(|input| input.expect_ident_matching("auto")).is_ok() { + Ok(None) + } else { + Length::parse(context, input).map(Some) + } + } + + if !try!(input.expect_function()).eq_ignore_ascii_case("rect") { + return Err(()) + } + + // NB: `top` and `left` are 0 if `auto` per CSS 2.1 11.1.2. + input.parse_nested_block(|input| { + let top = try!(parse_argument(context, input)); + let right; + let bottom; + let left; + + if input.try(|input| input.expect_comma()).is_ok() { + right = try!(parse_argument(context, input)); + try!(input.expect_comma()); + bottom = try!(parse_argument(context, input)); + try!(input.expect_comma()); + left = try!(parse_argument(context, input)); + } else { + right = try!(parse_argument(context, input)); + bottom = try!(parse_argument(context, input)); + left = try!(parse_argument(context, input)); + } + Ok(ClipRect { + top: top.unwrap_or(Length::zero()), + right: right, + bottom: bottom, + left: left.unwrap_or(Length::zero()), + }) + }) + } +} + +/// rect(...) | auto +pub type ClipRectOrAuto = Either<ClipRect, Auto>; |