--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -648,25 +648,26 @@ def set_gecko_property(ffi_name, expr):
};
SVGPaint {
kind: kind,
fallback: fallback,
}
}
</%def>
-<%def name="impl_app_units(ident, gecko_ffi_name, need_clone, inherit_from=None, round_to_pixels=False)">
+<%def name="impl_non_negative_app_units(ident, gecko_ffi_name, need_clone, inherit_from=None,
+ round_to_pixels=False)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
let value = {
% if round_to_pixels:
let au_per_device_px = Au(self.gecko.mTwipsPerPixel);
- round_border_to_device_pixels(v, au_per_device_px).0
+ round_border_to_device_pixels(v.0, au_per_device_px).0
% else:
- v.0
+ v.value()
% endif
};
% if inherit_from:
self.gecko.${inherit_from} = value;
% endif
self.gecko.${gecko_ffi_name} = value;
}
@@ -684,17 +685,18 @@ def set_gecko_property(ffi_name, expr):
% else:
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
% endif
}
%if need_clone:
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
- Au(self.gecko.${gecko_ffi_name})
+ use values::computed::NonNegativeAu;
+ NonNegativeAu(Au(self.gecko.${gecko_ffi_name}))
}
% endif
</%def>
<%def name="impl_split_style_coord(ident, gecko_ffi_name, index, need_clone=False)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
v.to_gecko_style_coord(&mut self.gecko.${gecko_ffi_name}.data_at_mut(${index}));
@@ -1122,21 +1124,21 @@ fn static_assert() {
// just copy the specified border here, we'll adjust it if it's incorrect
// later.
fn update_border_${side.ident}(&mut self) {
self.gecko.mComputedBorder.${side.ident} = self.gecko.mBorder.${side.ident};
}
<% impl_color("border_%s_color" % side.ident, "(mBorderColor)[%s]" % side.index, need_clone=True) %>
- <% impl_app_units("border_%s_width" % side.ident,
- "mComputedBorder.%s" % side.ident,
- inherit_from="mBorder.%s" % side.ident,
- need_clone=True,
- round_to_pixels=True) %>
+ <% impl_non_negative_app_units("border_%s_width" % side.ident,
+ "mComputedBorder.%s" % side.ident,
+ inherit_from="mBorder.%s" % side.ident,
+ need_clone=True,
+ round_to_pixels=True) %>
pub fn border_${side.ident}_has_nonzero_width(&self) -> bool {
self.gecko.mComputedBorder.${side.ident} != 0
}
#[allow(non_snake_case)]
pub fn set__moz_border_${side.ident}_colors(&mut self,
v: longhands::_moz_border_${side.ident}_colors::computed_value::T) {
@@ -1665,19 +1667,19 @@ fn static_assert() {
% endfor
structs::${border_style_keyword.gecko_constant('auto')} => Either::First(Auto),
% if border_style_keyword.gecko_inexhaustive:
x => panic!("Found unexpected value in style struct for outline_style property: {:?}", x),
% endif
}
}
- <% impl_app_units("outline_width", "mActualOutlineWidth",
- inherit_from="mOutlineWidth",
- need_clone=True, round_to_pixels=True) %>
+ <% impl_non_negative_app_units("outline_width", "mActualOutlineWidth",
+ inherit_from="mOutlineWidth",
+ need_clone=True, round_to_pixels=True) %>
% for corner in CORNERS:
<% impl_corner_style_coord("_moz_outline_radius_%s" % corner.ident.replace("_", ""),
"mOutlineRadius",
corner.x_index,
corner.y_index,
need_clone=True) %>
% endfor
@@ -4186,17 +4188,19 @@ fn static_assert() {
};
T::Keyword(KeywordValue {
fill: fill,
shape: shape
})
}
- <%call expr="impl_app_units('_webkit_text_stroke_width', 'mWebkitTextStrokeWidth', need_clone=True)"></%call>
+ <%call expr="impl_non_negative_app_units('_webkit_text_stroke_width',
+ 'mWebkitTextStrokeWidth',
+ need_clone=True)"></%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));
@@ -4807,18 +4811,18 @@ clip-path
debug_assert!((self.gecko.mColumnCount as i32) >= 0 &&
(self.gecko.mColumnCount as i32) < i32::max_value());
Either::First(self.gecko.mColumnCount as i32)
} else {
Either::Second(Auto)
}
}
- <% impl_app_units("column_rule_width", "mColumnRuleWidth", need_clone=True,
- round_to_pixels=True) %>
+ <% impl_non_negative_app_units("column_rule_width", "mColumnRuleWidth", need_clone=True,
+ round_to_pixels=True) %>
</%self:impl_trait>
<%self:impl_trait style_struct_name="Counters"
skip_longhands="content counter-increment counter-reset">
pub fn ineffective_content_property(&self) -> bool {
self.gecko.mContents.is_empty()
}
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -38,17 +38,17 @@ use values::animated::{ToAnimatedValue,
use values::animated::effects::BoxShadowList as AnimatedBoxShadowList;
use values::animated::effects::Filter as AnimatedFilter;
use values::animated::effects::FilterList as AnimatedFilterList;
use values::animated::effects::TextShadowList as AnimatedTextShadowList;
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
use values::computed::{BorderCornerRadius, ClipRect};
use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
use values::computed::{LengthOrPercentage, MaxLength, MozLength, Percentage, ToComputedValue};
-use values::computed::{GreaterThanOrEqualToOneNumber, NonNegativeNumber};
+use values::computed::{GreaterThanOrEqualToOneNumber, NonNegativeAu, NonNegativeNumber};
use values::generics::{SVGPaint, SVGPaintKind};
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::effects::Filter;
use values::generics::position as generic_position;
/// A trait used to implement various procedures used during animation.
pub trait Animatable: Sized {
/// Performs a weighted sum of this value and |other|. This is used for
@@ -903,16 +903,29 @@ impl Animatable for i32 {
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
Ok((*self - *other).abs() as f64)
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-number
+impl Animatable for NonNegativeAu {
+ #[inline]
+ fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
+ self.0.add_weighted(&other.0, self_portion, other_portion).map(NonNegativeAu)
+ }
+
+ #[inline]
+ fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
+ self.0.compute_distance(&other.0)
+ }
+}
+
+/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animatable for NonNegativeNumber {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
self.0.add_weighted(&other.0, self_portion, other_portion).map(NonNegativeNumber)
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
--- a/servo/components/style/properties/longhand/border.mako.rs
+++ b/servo/components/style/properties/longhand/border.mako.rs
@@ -35,21 +35,21 @@
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
spec=maybe_logical_spec(side, "style"),
flags="APPLIES_TO_FIRST_LETTER",
animation_value_type="discrete" if not is_logical else "none",
logical=is_logical)}
${helpers.predefined_type("border-%s-width" % side_name,
"BorderSideWidth",
- "Au::from_px(3)",
- computed_type="::app_units::Au",
+ "::values::computed::NonNegativeAu::from_px(3)",
+ computed_type="::values::computed::NonNegativeAu",
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
spec=maybe_logical_spec(side, "width"),
- animation_value_type="ComputedValue",
+ animation_value_type="NonNegativeAu",
logical=is_logical,
flags="APPLIES_TO_FIRST_LETTER",
allow_quirks=not is_logical)}
% endfor
${helpers.gecko_keyword_conversion(Keyword('border-style',
"none solid double dotted dashed hidden groove ridge inset outset"),
type="::values::specified::BorderStyle")}
--- a/servo/components/style/properties/longhand/column.mako.rs
+++ b/servo/components/style/properties/longhand/column.mako.rs
@@ -37,22 +37,22 @@
spec="https://drafts.csswg.org/css-multicol/#propdef-column-gap")}
${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
products="gecko", animation_value_type="discrete",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill")}
${helpers.predefined_type("column-rule-width",
"BorderSideWidth",
- "Au::from_px(3)",
+ "::values::computed::NonNegativeAu::from_px(3)",
initial_specified_value="specified::BorderSideWidth::Medium",
- computed_type="::app_units::Au",
+ computed_type="::values::computed::NonNegativeAu",
products="gecko",
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width",
- animation_value_type="ComputedValue",
+ animation_value_type="NonNegativeAu",
extra_prefixes="moz")}
// https://drafts.csswg.org/css-multicol-1/#crc
${helpers.predefined_type("column-rule-color", "Color",
"computed_value::T::currentcolor()",
initial_specified_value="specified::Color::currentcolor()",
products="gecko", animation_value_type="IntermediateColor", extra_prefixes="moz",
need_clone=True, ignored_when_colors_disabled=True,
--- a/servo/components/style/properties/longhand/inherited_text.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_text.mako.rs
@@ -737,19 +737,19 @@
initial_specified_value="specified::Color::currentcolor()",
products="gecko", animation_value_type="IntermediateColor",
need_clone=True, ignored_when_colors_disabled=True,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color")}
${helpers.predefined_type("-webkit-text-stroke-width",
"BorderSideWidth",
- "Au::from_px(0)",
+ "::values::computed::NonNegativeAu::from_px(0)",
initial_specified_value="specified::BorderSideWidth::Length(specified::Length::zero())",
- computed_type="::app_units::Au",
+ computed_type="::values::computed::NonNegativeAu",
products="gecko",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
animation_value_type="none")}
// CSS Ruby Layout Module Level 1
// https://drafts.csswg.org/css-ruby/
${helpers.single_keyword("ruby-align", "space-around start center space-between",
--- a/servo/components/style/properties/longhand/outline.mako.rs
+++ b/servo/components/style/properties/longhand/outline.mako.rs
@@ -59,20 +59,20 @@
Ok(result)
}
})
}
</%helpers:longhand>
${helpers.predefined_type("outline-width",
"BorderSideWidth",
- "Au::from_px(3)",
+ "::values::computed::NonNegativeAu::from_px(3)",
initial_specified_value="specified::BorderSideWidth::Medium",
- computed_type="::app_units::Au",
- animation_value_type="ComputedValue",
+ computed_type="::values::computed::NonNegativeAu",
+ animation_value_type="NonNegativeAu",
spec="https://drafts.csswg.org/css-ui/#propdef-outline-width")}
// The -moz-outline-radius-* properties are non-standard and not on a standards track.
% for corner in ["topleft", "topright", "bottomright", "bottomleft"]:
${helpers.predefined_type("-moz-outline-radius-" + corner, "BorderCornerRadius",
"computed::LengthOrPercentage::zero().into()",
products="gecko",
boxed=True,
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -3238,17 +3238,17 @@ where
}
/// See StyleAdjuster::adjust_for_border_width.
pub fn adjust_border_width(style: &mut StyleBuilder) {
% for side in ["top", "right", "bottom", "left"]:
// Like calling to_computed_value, which wouldn't type check.
if style.get_border().clone_border_${side}_style().none_or_hidden() &&
style.get_border().border_${side}_has_nonzero_width() {
- style.set_border_${side}_width(Au(0));
+ style.set_border_${side}_width(computed::NonNegativeAu(Au(0)));
}
% endfor
}
/// Adjusts borders as appropriate to account for a fragment's status as the
/// first or last fragment within the range of an element.
///
/// Specifically, this function sets border widths to zero on the sides for
--- a/servo/components/style/style_adjuster.rs
+++ b/servo/components/style/style_adjuster.rs
@@ -7,16 +7,17 @@
use app_units::Au;
use properties::{self, CascadeFlags, ComputedValues};
use properties::{IS_ROOT_ELEMENT, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, StyleBuilder};
use properties::longhands::display::computed_value::T as display;
use properties::longhands::float::computed_value::T as float;
use properties::longhands::overflow_x::computed_value::T as overflow;
use properties::longhands::position::computed_value::T as position;
+use values::computed::NonNegativeAu;
/// An unsized struct that implements all the adjustment methods.
pub struct StyleAdjuster<'a, 'b: 'a> {
style: &'a mut StyleBuilder<'b>,
}
impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
/// Trivially constructs a new StyleAdjuster.
@@ -220,17 +221,17 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
fn adjust_for_border_width(&mut self) {
properties::adjust_border_width(self.style);
}
/// The initial value of outline-width may be changed at computed value time.
fn adjust_for_outline(&mut self) {
if self.style.get_outline().clone_outline_style().none_or_hidden() &&
self.style.get_outline().outline_has_nonzero_width() {
- self.style.mutate_outline().set_outline_width(Au(0));
+ self.style.mutate_outline().set_outline_width(NonNegativeAu(Au(0)));
}
}
/// CSS3 overflow-x and overflow-y require some fixup as well in some
/// cases.
///
/// overflow: clip and overflow: visible are meaningful only when used in
/// both dimensions.
--- a/servo/components/style/values/animated/mod.rs
+++ b/servo/components/style/values/animated/mod.rs
@@ -5,16 +5,17 @@
//! Animated values.
//!
//! Some values, notably colors, cannot be interpolated directly with their
//! computed values and need yet another intermediate representation. This
//! module's raison d'ĂȘtre is to ultimately contain all these types.
use app_units::Au;
use values::computed::Angle as ComputedAngle;
+use values::computed::NonNegativeAu;
use values::computed::NonNegativeNumber as ComputedNonNegativeNumber;
use values::computed::GreaterThanOrEqualToOneNumber as ComputedGreaterThanOrEqualToOneNumber;
use values::specified::url::SpecifiedUrl;
pub mod effects;
/// Conversion between computed values and intermediate values for animations.
///
@@ -113,16 +114,30 @@ impl ToAnimatedValue for ComputedGreater
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
ComputedGreaterThanOrEqualToOneNumber(animated.0.max(1.))
}
}
+impl ToAnimatedValue for NonNegativeAu {
+ type AnimatedValue = Self;
+
+ #[inline]
+ fn to_animated_value(self) -> Self {
+ self
+ }
+
+ #[inline]
+ fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+ animated.max(NonNegativeAu(Au(0)))
+ }
+}
+
/// Returns a value similar to `self` that represents zero.
pub trait ToAnimatedZero: Sized {
/// Returns a value that, when added with an underlying value, will produce the underlying
/// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
/// the zero value to the 'by' value, and then adds the result to the underlying value.
///
/// This is not the necessarily the same as the initial value of a property. For example, the
/// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the
@@ -154,8 +169,13 @@ impl ToAnimatedZero for ComputedNonNegat
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Ok(ComputedNonNegativeNumber(0.)) }
}
impl ToAnimatedZero for ComputedGreaterThanOrEqualToOneNumber {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Ok(ComputedGreaterThanOrEqualToOneNumber(0.)) }
}
+
+impl ToAnimatedZero for NonNegativeAu {
+ #[inline]
+ fn to_animated_zero(&self) -> Result<Self, ()> { Ok(NonNegativeAu(Au(0))) }
+}
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -589,8 +589,32 @@ impl ClipRectOrAuto {
Either::Second(_) => true,
_ => false
}
}
}
/// <color> | auto
pub type ColorOrAuto = Either<Color, Auto>;
+
+/// A wrapper of Au, but only accept a value >= 0.
+#[derive(Clone, PartialEq, PartialOrd, Copy, Debug, ToCss)]
+pub struct NonNegativeAu(pub Au);
+
+impl NonNegativeAu {
+ /// Return a NonNegativeAu from pixel.
+ #[inline]
+ pub fn from_px(px: i32) -> Self {
+ NonNegativeAu(Au::from_px(::std::cmp::max(px, 0)))
+ }
+
+ /// Get the inner value of |NonNegativeAu.0|.
+ #[inline]
+ pub fn value(self) -> i32 {
+ (self.0).0
+ }
+
+ /// Returns the maximum of |self| and |other|.
+ #[inline]
+ pub fn max(self, other: Self) -> Self {
+ NonNegativeAu(Au(::std::cmp::max(self.value(), other.value())))
+ }
+}
--- a/servo/components/style/values/specified/border.rs
+++ b/servo/components/style/values/specified/border.rs
@@ -1,19 +1,18 @@
/* 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/. */
//! Specified types for CSS values related to borders.
-use app_units::Au;
use cssparser::Parser;
use parser::{Parse, ParserContext};
use style_traits::ParseError;
-use values::computed::{Context, ToComputedValue};
+use values::computed::{Context, NonNegativeAu, ToComputedValue};
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth;
use values::generics::border::BorderImageSlice as GenericBorderImageSlice;
use values::generics::border::BorderRadius as GenericBorderRadius;
use values::generics::rect::Rect;
use values::specified::{AllowQuirks, Number, NumberOrPercentage};
use values::specified::length::{Length, LengthOrPercentage};
@@ -67,34 +66,34 @@ impl BorderSideWidth {
impl Parse for BorderSideWidth {
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
Self::parse_quirky(context, input, AllowQuirks::No)
}
}
impl ToComputedValue for BorderSideWidth {
- type ComputedValue = Au;
+ type ComputedValue = NonNegativeAu;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
// We choose the pixel length of the keyword values the same as both spec and gecko.
// Spec: https://drafts.csswg.org/css-backgrounds-3/#line-width
// Gecko: https://bugzilla.mozilla.org/show_bug.cgi?id=1312155#c0
- match *self {
+ NonNegativeAu(match *self {
BorderSideWidth::Thin => Length::from_px(1.).to_computed_value(context),
BorderSideWidth::Medium => Length::from_px(3.).to_computed_value(context),
BorderSideWidth::Thick => Length::from_px(5.).to_computed_value(context),
BorderSideWidth::Length(ref length) => length.to_computed_value(context)
- }
+ })
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
- BorderSideWidth::Length(ToComputedValue::from_computed_value(computed))
+ BorderSideWidth::Length(ToComputedValue::from_computed_value(&computed.0))
}
}
impl BorderImageSideWidth {
/// Returns `1`.
#[inline]
pub fn one() -> Self {
GenericBorderImageSideWidth::Number(Number::new(1.))