aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/display_list_builder.rs11
-rw-r--r--components/style/properties/gecko.mako.rs19
-rw-r--r--components/style/properties/longhand/border.mako.rs450
-rw-r--r--components/style/values/computed/border.rs28
-rw-r--r--components/style/values/computed/length.rs8
-rw-r--r--components/style/values/computed/mod.rs4
-rw-r--r--components/style/values/computed/rect.rs11
-rw-r--r--components/style/values/generics/border.rs71
-rw-r--r--components/style/values/generics/mod.rs2
-rw-r--r--components/style/values/generics/rect.rs110
-rw-r--r--components/style/values/specified/border.rs59
-rw-r--r--components/style/values/specified/length.rs6
-rw-r--r--components/style/values/specified/mod.rs4
-rw-r--r--components/style/values/specified/rect.rs21
14 files changed, 357 insertions, 447 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs
index 63ec70b7096..13829e8830d 100644
--- a/components/layout/display_list_builder.rs
+++ b/components/layout/display_list_builder.rs
@@ -1429,8 +1429,7 @@ impl FragmentDisplayListBuilding for Fragment {
url.clone(),
UsePlaceholder::No);
if let Some(webrender_image) = webrender_image {
- // The corners array is guaranteed to be len=4 by the css parser.
- let corners = &border_style_struct.border_image_slice.corners;
+ let corners = &border_style_struct.border_image_slice.offsets;
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
base: base,
@@ -1438,10 +1437,10 @@ impl FragmentDisplayListBuilding for Fragment {
details: BorderDetails::Image(ImageBorder {
image: webrender_image,
fill: border_style_struct.border_image_slice.fill,
- slice: SideOffsets2D::new(corners[0].resolve(webrender_image.height),
- corners[1].resolve(webrender_image.width),
- corners[2].resolve(webrender_image.height),
- corners[3].resolve(webrender_image.width)),
+ slice: SideOffsets2D::new(corners.top.resolve(webrender_image.height),
+ corners.right.resolve(webrender_image.width),
+ corners.bottom.resolve(webrender_image.height),
+ corners.left.resolve(webrender_image.width)),
// TODO(gw): Support border-image-outset
outset: SideOffsets2D::zero(),
repeat_horizontal: convert_repeat_mode(border_style_struct.border_image_repeat.0),
diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs
index 28ab764c463..bd390fc4273 100644
--- a/components/style/properties/gecko.mako.rs
+++ b/components/style/properties/gecko.mako.rs
@@ -959,8 +959,7 @@ fn static_assert() {
pub fn set_border_image_outset(&mut self, v: longhands::border_image_outset::computed_value::T) {
% for side in SIDES:
- v.${side.index}.to_gecko_style_coord(&mut self.gecko.mBorderImageOutset
- .data_at_mut(${side.index}));
+ v.${side.ident}.to_gecko_style_coord(&mut self.gecko.mBorderImageOutset.data_at_mut(${side.index}));
% endfor
}
@@ -994,17 +993,17 @@ fn static_assert() {
}
pub fn set_border_image_width(&mut self, v: longhands::border_image_width::computed_value::T) {
- use properties::longhands::border_image_width::computed_value::SingleComputedValue;
+ use values::generics::border::BorderImageWidthSide;
% for side in SIDES:
- match v.${side.index} {
- SingleComputedValue::Auto => {
+ match v.${side.ident} {
+ BorderImageWidthSide::Auto => {
self.gecko.mBorderImageWidth.data_at_mut(${side.index}).set_value(CoordDataValue::Auto)
},
- SingleComputedValue::LengthOrPercentage(l) => {
+ BorderImageWidthSide::Length(l) => {
l.to_gecko_style_coord(&mut self.gecko.mBorderImageWidth.data_at_mut(${side.index}))
},
- SingleComputedValue::Number(n) => {
+ BorderImageWidthSide::Number(n) => {
self.gecko.mBorderImageWidth.data_at_mut(${side.index}).set_value(CoordDataValue::Factor(n))
},
}
@@ -1021,9 +1020,9 @@ fn static_assert() {
pub fn set_border_image_slice(&mut self, v: longhands::border_image_slice::computed_value::T) {
use gecko_bindings::structs::{NS_STYLE_BORDER_IMAGE_SLICE_NOFILL, NS_STYLE_BORDER_IMAGE_SLICE_FILL};
- for (i, corner) in v.corners.iter().enumerate() {
- corner.to_gecko_style_coord(&mut self.gecko.mBorderImageSlice.data_at_mut(i));
- }
+ % for side in SIDES:
+ v.offsets.${side.ident}.to_gecko_style_coord(&mut self.gecko.mBorderImageSlice.data_at_mut(${side.index}));
+ % endfor
let fill = if v.fill {
NS_STYLE_BORDER_IMAGE_SLICE_FILL
diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs
index 8c775b682c0..bd6c6549f6d 100644
--- a/components/style/properties/longhand/border.mako.rs
+++ b/components/style/properties/longhand/border.mako.rs
@@ -200,109 +200,13 @@ ${helpers.predefined_type("border-image-source", "ImageLayer",
has_uncacheable_values=False,
boxed="True")}
-<%helpers:longhand name="border-image-outset" animation_value_type="none"
- spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset">
- use std::fmt;
- use style_traits::ToCss;
- use values::specified::{LengthOrNumber, Number};
-
- pub mod computed_value {
- use values::computed::LengthOrNumber;
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct T(pub LengthOrNumber, pub LengthOrNumber,
- pub LengthOrNumber, pub LengthOrNumber);
- }
-
- #[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct SpecifiedValue(pub Vec<LengthOrNumber>);
-
- impl ToCss for computed_value::T {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- try!(self.0.to_css(dest));
- try!(dest.write_str(" "));
- try!(self.1.to_css(dest));
- try!(dest.write_str(" "));
- try!(self.2.to_css(dest));
- try!(dest.write_str(" "));
- self.3.to_css(dest)
- }
- }
- impl ToCss for SpecifiedValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- try!(self.0[0].to_css(dest));
- for value in self.0.iter().skip(1) {
- try!(dest.write_str(" "));
- try!(value.to_css(dest));
- }
- Ok(())
- }
- }
-
- #[inline]
- pub fn get_initial_value() -> computed_value::T {
- computed_value::T(Either::Second(0.0), Either::Second(0.0),
- Either::Second(0.0), Either::Second(0.0))
- }
-
- #[inline]
- pub fn get_initial_specified_value() -> SpecifiedValue {
- SpecifiedValue(vec![Either::Second(Number::new(0.0))])
- }
-
- impl ToComputedValue for SpecifiedValue {
- type ComputedValue = computed_value::T;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> computed_value::T {
- let length = self.0.len();
- match length {
- 4 => computed_value::T(self.0[0].to_computed_value(context),
- self.0[1].to_computed_value(context),
- self.0[2].to_computed_value(context),
- self.0[3].to_computed_value(context)),
- 3 => computed_value::T(self.0[0].to_computed_value(context),
- self.0[1].to_computed_value(context),
- self.0[2].to_computed_value(context),
- self.0[1].to_computed_value(context)),
- 2 => computed_value::T(self.0[0].to_computed_value(context),
- self.0[1].to_computed_value(context),
- self.0[0].to_computed_value(context),
- self.0[1].to_computed_value(context)),
- 1 => computed_value::T(self.0[0].to_computed_value(context),
- self.0[0].to_computed_value(context),
- self.0[0].to_computed_value(context),
- self.0[0].to_computed_value(context)),
- _ => unreachable!(),
- }
- }
- #[inline]
- fn from_computed_value(computed: &computed_value::T) -> Self {
- SpecifiedValue(vec![ToComputedValue::from_computed_value(&computed.0),
- ToComputedValue::from_computed_value(&computed.1),
- ToComputedValue::from_computed_value(&computed.2),
- ToComputedValue::from_computed_value(&computed.3)])
- }
- }
-
- 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(context, input));
- match value {
- Ok(val) => values.push(val),
- Err(_) => break,
- }
- }
-
- if values.len() > 0 {
- Ok(SpecifiedValue(values))
- } else {
- Err(())
- }
- }
-</%helpers:longhand>
+${helpers.predefined_type("border-image-outset", "LengthOrNumberRect",
+ parse_method="parse_non_negative",
+ initial_value="computed::LengthOrNumber::zero().into()",
+ initial_specified_value="specified::LengthOrNumber::zero().into()",
+ spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
+ animation_value_type="none",
+ boxed=True)}
<%helpers:longhand name="border-image-repeat" animation_value_type="none"
spec="https://drafts.csswg.org/css-backgrounds/#border-image-repeat">
@@ -380,332 +284,16 @@ ${helpers.predefined_type("border-image-source", "ImageLayer",
}
</%helpers:longhand>
-<%helpers:longhand name="border-image-width" animation_value_type="none"
- spec="https://drafts.csswg.org/css-backgrounds/#border-image-width">
- use std::fmt;
- use style_traits::ToCss;
- use values::specified::{LengthOrPercentage, Number};
-
- pub mod computed_value {
- use values::computed::{LengthOrPercentage, Number};
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct T(pub SingleComputedValue, pub SingleComputedValue,
- pub SingleComputedValue, pub SingleComputedValue);
-
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub enum SingleComputedValue {
- LengthOrPercentage(LengthOrPercentage),
- Number(Number),
- Auto,
- }
- }
-
- #[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct SpecifiedValue(pub Vec<SingleSpecifiedValue>);
-
- impl ToCss for computed_value::T {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- try!(self.0.to_css(dest));
- try!(dest.write_str(" "));
- try!(self.1.to_css(dest));
- try!(dest.write_str(" "));
- try!(self.2.to_css(dest));
- try!(dest.write_str(" "));
- self.3.to_css(dest)
- }
- }
- impl ToCss for SpecifiedValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- try!(self.0[0].to_css(dest));
- for value in self.0.iter().skip(1) {
- try!(dest.write_str(" "));
- try!(value.to_css(dest));
- }
- Ok(())
- }
- }
-
- #[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub enum SingleSpecifiedValue {
- LengthOrPercentage(LengthOrPercentage),
- Number(Number),
- Auto,
- }
-
- impl ToCss for computed_value::SingleComputedValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- computed_value::SingleComputedValue::LengthOrPercentage(ref len) => len.to_css(dest),
- computed_value::SingleComputedValue::Number(number) => number.to_css(dest),
- computed_value::SingleComputedValue::Auto => dest.write_str("auto"),
- }
- }
- }
- impl ToCss for SingleSpecifiedValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- SingleSpecifiedValue::LengthOrPercentage(ref len) => len.to_css(dest),
- SingleSpecifiedValue::Number(number) => number.to_css(dest),
- SingleSpecifiedValue::Auto => dest.write_str("auto"),
- }
- }
- }
-
- impl ToComputedValue for SingleSpecifiedValue {
- type ComputedValue = computed_value::SingleComputedValue;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> computed_value::SingleComputedValue {
- match *self {
- SingleSpecifiedValue::LengthOrPercentage(ref len) => {
- computed_value::SingleComputedValue::LengthOrPercentage(
- len.to_computed_value(context))
- },
- SingleSpecifiedValue::Number(number) =>
- computed_value::SingleComputedValue::Number(number.to_computed_value(context)),
- SingleSpecifiedValue::Auto => computed_value::SingleComputedValue::Auto,
- }
- }
- #[inline]
- fn from_computed_value(computed: &computed_value::SingleComputedValue) -> Self {
- match *computed {
- computed_value::SingleComputedValue::LengthOrPercentage(len) => {
- SingleSpecifiedValue::LengthOrPercentage(
- ToComputedValue::from_computed_value(&len))
- },
- computed_value::SingleComputedValue::Number(number) =>
- SingleSpecifiedValue::Number(ToComputedValue::from_computed_value(&number)),
- computed_value::SingleComputedValue::Auto => SingleSpecifiedValue::Auto,
- }
- }
- }
-
- #[inline]
- pub fn get_initial_value() -> computed_value::T {
- computed_value::T(computed_value::SingleComputedValue::Number(1.0),
- computed_value::SingleComputedValue::Number(1.0),
- computed_value::SingleComputedValue::Number(1.0),
- computed_value::SingleComputedValue::Number(1.0))
- }
-
- #[inline]
- pub fn get_initial_specified_value() -> SpecifiedValue {
- SpecifiedValue(vec![SingleSpecifiedValue::Number(Number::new(1.0))])
- }
-
- impl ToComputedValue for SpecifiedValue {
- type ComputedValue = computed_value::T;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> computed_value::T {
- let length = self.0.len();
- match length {
- 4 => computed_value::T(self.0[0].to_computed_value(context),
- self.0[1].to_computed_value(context),
- self.0[2].to_computed_value(context),
- self.0[3].to_computed_value(context)),
- 3 => computed_value::T(self.0[0].to_computed_value(context),
- self.0[1].to_computed_value(context),
- self.0[2].to_computed_value(context),
- self.0[1].to_computed_value(context)),
- 2 => computed_value::T(self.0[0].to_computed_value(context),
- self.0[1].to_computed_value(context),
- self.0[0].to_computed_value(context),
- self.0[1].to_computed_value(context)),
- 1 => computed_value::T(self.0[0].to_computed_value(context),
- self.0[0].to_computed_value(context),
- self.0[0].to_computed_value(context),
- self.0[0].to_computed_value(context)),
- _ => unreachable!(),
- }
- }
- #[inline]
- fn from_computed_value(computed: &computed_value::T) -> Self {
- SpecifiedValue(vec![ToComputedValue::from_computed_value(&computed.0),
- ToComputedValue::from_computed_value(&computed.1),
- ToComputedValue::from_computed_value(&computed.2),
- ToComputedValue::from_computed_value(&computed.3)])
- }
- }
-
- impl Parse for SingleSpecifiedValue {
- fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
- if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
- return Ok(SingleSpecifiedValue::Auto);
- }
-
- if let Ok(len) = input.try(|input| LengthOrPercentage::parse_non_negative(context, input)) {
- return Ok(SingleSpecifiedValue::LengthOrPercentage(len));
- }
-
- let num = try!(Number::parse_non_negative(context, input));
- Ok(SingleSpecifiedValue::Number(num))
- }
- }
-
- pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
- let mut values = vec![];
- for _ in 0..4 {
- let value = input.try(|input| SingleSpecifiedValue::parse(context, input));
- match value {
- Ok(val) => values.push(val),
- Err(_) => break,
- }
- }
-
- if values.len() > 0 {
- Ok(SpecifiedValue(values))
- } else {
- Err(())
- }
- }
-</%helpers:longhand>
-
-<%helpers:longhand name="border-image-slice" boxed="True" animation_value_type="none"
- spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice">
- use std::fmt;
- use style_traits::ToCss;
- use values::computed::NumberOrPercentage as ComputedNumberOrPercentage;
- use values::specified::{NumberOrPercentage, Percentage};
-
- no_viewport_percentage!(SpecifiedValue);
-
- pub mod computed_value {
- use values::computed::NumberOrPercentage;
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct T {
- pub corners: [NumberOrPercentage; 4],
- pub fill: bool,
- }
- }
-
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct SpecifiedValue {
- pub corners: Vec<NumberOrPercentage>,
- pub fill: bool,
- }
-
- impl ToCss for computed_value::T {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- try!(self.corners[0].to_css(dest));
- try!(dest.write_str(" "));
- try!(self.corners[1].to_css(dest));
- try!(dest.write_str(" "));
- try!(self.corners[2].to_css(dest));
- try!(dest.write_str(" "));
- try!(self.corners[3].to_css(dest));
-
- if self.fill {
- try!(dest.write_str(" fill"));
- }
- Ok(())
- }
- }
- impl ToCss for SpecifiedValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- try!(self.corners[0].to_css(dest));
- for value in self.corners.iter().skip(1) {
- try!(dest.write_str(" "));
- try!(value.to_css(dest));
- }
-
- if self.fill {
- try!(dest.write_str(" fill"));
- }
- Ok(())
- }
- }
-
- #[inline]
- pub fn get_initial_value() -> computed_value::T {
- computed_value::T {
- corners: [ComputedNumberOrPercentage::Percentage(Percentage(1.0)),
- ComputedNumberOrPercentage::Percentage(Percentage(1.0)),
- ComputedNumberOrPercentage::Percentage(Percentage(1.0)),
- ComputedNumberOrPercentage::Percentage(Percentage(1.0))],
- fill: false,
- }
- }
-
- #[inline]
- pub fn get_initial_specified_value() -> SpecifiedValue {
- SpecifiedValue {
- corners: vec![NumberOrPercentage::Percentage(Percentage(1.0))],
- fill: false,
- }
- }
-
- impl ToComputedValue for SpecifiedValue {
- type ComputedValue = computed_value::T;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> computed_value::T {
- let length = self.corners.len();
- let corners = match length {
- 4 => [self.corners[0].to_computed_value(context),
- self.corners[1].to_computed_value(context),
- self.corners[2].to_computed_value(context),
- self.corners[3].to_computed_value(context)],
- 3 => [self.corners[0].to_computed_value(context),
- self.corners[1].to_computed_value(context),
- self.corners[2].to_computed_value(context),
- self.corners[1].to_computed_value(context)],
- 2 => [self.corners[0].to_computed_value(context),
- self.corners[1].to_computed_value(context),
- self.corners[0].to_computed_value(context),
- self.corners[1].to_computed_value(context)],
- 1 => [self.corners[0].to_computed_value(context),
- self.corners[0].to_computed_value(context),
- self.corners[0].to_computed_value(context),
- self.corners[0].to_computed_value(context)],
- _ => unreachable!(),
- };
- computed_value::T {
- corners: corners,
- fill: self.fill,
- }
- }
- #[inline]
- fn from_computed_value(computed: &computed_value::T) -> Self {
- SpecifiedValue {
- corners: vec![ToComputedValue::from_computed_value(&computed.corners[0]),
- ToComputedValue::from_computed_value(&computed.corners[1]),
- ToComputedValue::from_computed_value(&computed.corners[2]),
- ToComputedValue::from_computed_value(&computed.corners[3])],
- fill: computed.fill,
- }
- }
- }
-
- pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
- let mut fill = input.try(|input| input.expect_ident_matching("fill")).is_ok();
-
- let mut values = vec![];
- for _ in 0..4 {
- let value = input.try(|input| NumberOrPercentage::parse_non_negative(context, input));
- match value {
- Ok(val) => values.push(val),
- Err(_) => break,
- }
- }
-
- if !fill {
- fill = input.try(|input| input.expect_ident_matching("fill")).is_ok();
- }
+${helpers.predefined_type("border-image-width", "BorderImageWidth",
+ initial_value="computed::BorderImageWidthSide::one().into()",
+ initial_specified_value="specified::BorderImageWidthSide::one().into()",
+ spec="https://drafts.csswg.org/css-backgrounds/#border-image-width",
+ animation_value_type="none",
+ boxed=True)}
- if !values.is_empty() {
- Ok(SpecifiedValue {
- corners: values,
- fill: fill
- })
- } else {
- Err(())
- }
- }
-</%helpers:longhand>
+${helpers.predefined_type("border-image-slice", "BorderImageSlice",
+ initial_value="computed::NumberOrPercentage::Percentage(computed::Percentage(1.)).into()",
+ initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage(1.)).into()",
+ spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice",
+ animation_value_type="none",
+ boxed=True)}
diff --git a/components/style/values/computed/border.rs b/components/style/values/computed/border.rs
new file mode 100644
index 00000000000..e247f9a9cf4
--- /dev/null
+++ b/components/style/values/computed/border.rs
@@ -0,0 +1,28 @@
+/* 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/. */
+
+//! Computed types for CSS values related to borders.
+
+use values::computed::{Number, NumberOrPercentage};
+use values::computed::length::LengthOrPercentage;
+use values::generics::border::BorderImageSlice as GenericBorderImageSlice;
+use values::generics::border::BorderImageWidthSide as GenericBorderImageWidthSide;
+use values::generics::rect::Rect;
+
+/// A computed value for the `border-image-width` property.
+pub type BorderImageWidth = Rect<BorderImageWidthSide>;
+
+/// A computed value for a single side of a `border-image-width` property.
+pub type BorderImageWidthSide = GenericBorderImageWidthSide<LengthOrPercentage, Number>;
+
+/// A computed value for the `border-image-slice` property.
+pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>;
+
+impl BorderImageWidthSide {
+ /// Returns `1`.
+ #[inline]
+ pub fn one() -> Self {
+ GenericBorderImageWidthSide::Number(1.)
+ }
+}
diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs
index e2dac197652..1ed038941a7 100644
--- a/components/style/values/computed/length.rs
+++ b/components/style/values/computed/length.rs
@@ -603,6 +603,14 @@ pub type LengthOrAuto = Either<Length, Auto>;
/// Either a computed `<length>` or a `<number>` value.
pub type LengthOrNumber = Either<Length, Number>;
+impl LengthOrNumber {
+ /// Returns `0`.
+ #[inline]
+ pub fn zero() -> Self {
+ Either::Second(0.)
+ }
+}
+
/// Either a computed `<length>` or the `normal` keyword.
pub type LengthOrNormal = Either<Length, Normal>;
diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs
index 7251b315796..10b5014483b 100644
--- a/components/style/values/computed/mod.rs
+++ b/components/style/values/computed/mod.rs
@@ -24,7 +24,9 @@ use super::specified;
pub use app_units::Au;
pub use cssparser::Color as CSSColor;
+pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageWidthSide};
pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
+pub use self::rect::LengthOrNumberRect;
pub use super::{Auto, Either, None_};
#[cfg(feature = "gecko")]
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
@@ -37,9 +39,11 @@ pub use self::length::{MaxLength, MozLength};
pub use self::position::Position;
pub mod basic_shape;
+pub mod border;
pub mod image;
pub mod length;
pub mod position;
+pub mod rect;
/// A `Context` is all the data a specified value could ever need to compute
/// itself and be transformed to a computed value.
diff --git a/components/style/values/computed/rect.rs b/components/style/values/computed/rect.rs
new file mode 100644
index 00000000000..46fcdc65583
--- /dev/null
+++ b/components/style/values/computed/rect.rs
@@ -0,0 +1,11 @@
+/* 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/. */
+
+//! Computed types for CSS borders.
+
+use values::computed::length::LengthOrNumber;
+use values::generics::rect::Rect;
+
+/// A specified rectangle made of four `<length-or-number>` values.
+pub type LengthOrNumberRect = Rect<LengthOrNumber>;
diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs
new file mode 100644
index 00000000000..70e5812b401
--- /dev/null
+++ b/components/style/values/generics/border.rs
@@ -0,0 +1,71 @@
+/* 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/. */
+
+//! Generic types for CSS values related to borders.
+
+use std::fmt;
+use style_traits::ToCss;
+use values::generics::rect::Rect;
+
+/// A generic value for a single side of a `border-image-width` property.
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
+pub enum BorderImageWidthSide<LengthOrPercentage, Number> {
+ /// `<length-or-percentage>`
+ Length(LengthOrPercentage),
+ /// `<number>`
+ Number(Number),
+ /// `auto`
+ Auto,
+}
+
+/// A generic value for the `border-image-slice` property.
+#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct BorderImageSlice<NumberOrPercentage> {
+ /// The offsets.
+ pub offsets: Rect<NumberOrPercentage>,
+ /// Whether to fill the middle part.
+ pub fill: bool,
+}
+
+impl<L, N> ToCss for BorderImageWidthSide<L, N>
+ where L: ToCss, N: ToCss,
+{
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+ where W: fmt::Write
+ {
+ match *self {
+ BorderImageWidthSide::Length(ref length) => length.to_css(dest),
+ BorderImageWidthSide::Number(ref number) => number.to_css(dest),
+ BorderImageWidthSide::Auto => dest.write_str("auto"),
+ }
+ }
+}
+
+impl<N> From<N> for BorderImageSlice<N>
+ where N: Clone,
+{
+ #[inline]
+ fn from(value: N) -> Self {
+ Self {
+ offsets: value.into(),
+ fill: false,
+ }
+ }
+}
+
+impl<N> ToCss for BorderImageSlice<N>
+ where N: PartialEq + ToCss,
+{
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+ where W: fmt::Write
+ {
+ self.offsets.to_css(dest)?;
+ if self.fill {
+ dest.write_str(" fill")?;
+ }
+ Ok(())
+ }
+}
diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs
index 65fca55feb6..1efc617b0b0 100644
--- a/components/style/values/generics/mod.rs
+++ b/components/style/values/generics/mod.rs
@@ -16,9 +16,11 @@ use super::CustomIdent;
pub use self::basic_shape::serialize_radius_values;
pub mod basic_shape;
+pub mod border;
pub mod grid;
pub mod image;
pub mod position;
+pub mod rect;
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
diff --git a/components/style/values/generics/rect.rs b/components/style/values/generics/rect.rs
new file mode 100644
index 00000000000..767ce2223e4
--- /dev/null
+++ b/components/style/values/generics/rect.rs
@@ -0,0 +1,110 @@
+/* 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/. */
+
+//! Generic types for CSS values that are composed of four sides.
+
+use cssparser::Parser;
+use parser::{Parse, ParserContext};
+use std::fmt;
+use style_traits::ToCss;
+
+/// A CSS value made of four sides: top, right, bottom, and left.
+#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct Rect<T> {
+ /// Top
+ pub top: T,
+ /// Right.
+ pub right: T,
+ /// Bottom.
+ pub bottom: T,
+ /// Left.
+ pub left: T,
+}
+
+impl<T> Rect<T> {
+ /// Returns a new `Rect<T>` value.
+ pub fn new(top: T, right: T, bottom: T, left: T) -> Self {
+ Rect {
+ top: top,
+ right: right,
+ bottom: bottom,
+ left: left,
+ }
+ }
+}
+
+impl<T> Rect<T>
+ where T: Clone
+{
+ /// Parses a new `Rect<T>` value with the given parse function.
+ pub fn parse_with<Parse>(
+ context: &ParserContext,
+ input: &mut Parser,
+ parse: Parse)
+ -> Result<Self, ()>
+ where Parse: Fn(&ParserContext, &mut Parser) -> Result<T, ()>
+ {
+ let top = parse(context, input)?;
+ let right = if let Ok(right) = input.try(|i| parse(context, i)) { right } else {
+ // <top>
+ return Ok(Self::new(top.clone(), top.clone(), top.clone(), top));
+ };
+ let bottom = if let Ok(bottom) = input.try(|i| parse(context, i)) { bottom } else {
+ // <top> <right>
+ return Ok(Self::new(top.clone(), right.clone(), top, right));
+ };
+ let left = if let Ok(left) = input.try(|i| parse(context, i)) { left } else {
+ // <top> <right> <bottom>
+ return Ok(Self::new(top, right.clone(), bottom, right));
+ };
+ // <top> <right> <bottom> <left>
+ Ok(Self::new(top, right, bottom, left))
+ }
+}
+
+impl<T> From<T> for Rect<T>
+ where T: Clone
+{
+ #[inline]
+ fn from(value: T) -> Self {
+ Self::new(value.clone(), value.clone(), value.clone(), value)
+ }
+}
+
+impl<T> Parse for Rect<T>
+ where T: Clone + Parse
+{
+ #[inline]
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ Self::parse_with(context, input, T::parse)
+ }
+}
+
+impl<T> ToCss for Rect<T>
+ where T: PartialEq + ToCss
+{
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result
+ where W: fmt::Write,
+ {
+ self.top.to_css(dest)?;
+ let same_vertical = self.top == self.bottom;
+ let same_horizontal = self.right == self.left;
+ if same_vertical && same_horizontal && self.top == self.right {
+ return Ok(());
+ }
+ dest.write_str(" ")?;
+ self.right.to_css(dest)?;
+ if same_vertical && same_horizontal {
+ return Ok(());
+ }
+ dest.write_str(" ")?;
+ self.bottom.to_css(dest)?;
+ if same_horizontal {
+ return Ok(());
+ }
+ dest.write_str(" ")?;
+ self.left.to_css(dest)
+ }
+}
diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs
new file mode 100644
index 00000000000..c4b95c86865
--- /dev/null
+++ b/components/style/values/specified/border.rs
@@ -0,0 +1,59 @@
+/* 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 cssparser::Parser;
+use parser::{Parse, ParserContext};
+use values::generics::border::BorderImageSlice as GenericBorderImageSlice;
+use values::generics::border::BorderImageWidthSide as GenericBorderImageWidthSide;
+use values::generics::rect::Rect;
+use values::specified::{Number, NumberOrPercentage};
+use values::specified::length::LengthOrPercentage;
+
+/// A specified value for the `border-image-width` property.
+pub type BorderImageWidth = Rect<BorderImageWidthSide>;
+
+/// A specified value for a single side of a `border-image-width` property.
+pub type BorderImageWidthSide = GenericBorderImageWidthSide<LengthOrPercentage, Number>;
+
+/// A specified value for the `border-image-slice` property.
+pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>;
+
+impl BorderImageWidthSide {
+ /// Returns `1`.
+ #[inline]
+ pub fn one() -> Self {
+ GenericBorderImageWidthSide::Number(Number::new(1.))
+ }
+}
+
+impl Parse for BorderImageWidthSide {
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
+ return Ok(GenericBorderImageWidthSide::Auto);
+ }
+
+ if let Ok(len) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
+ return Ok(GenericBorderImageWidthSide::Length(len));
+ }
+
+ let num = Number::parse_non_negative(context, input)?;
+ Ok(GenericBorderImageWidthSide::Number(num))
+ }
+}
+
+impl Parse for BorderImageSlice {
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
+ let offsets = Rect::parse_with(context, input, NumberOrPercentage::parse_non_negative)?;
+ if !fill {
+ fill = input.try(|i| i.expect_ident_matching("fill")).is_ok();
+ }
+ Ok(GenericBorderImageSlice {
+ offsets: offsets,
+ fill: fill,
+ })
+ }
+}
diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs
index e37aad81f0e..ef4083544ae 100644
--- a/components/style/values/specified/length.rs
+++ b/components/style/values/specified/length.rs
@@ -1180,6 +1180,12 @@ impl LengthOrNumber {
Length::parse_non_negative(context, input).map(Either::First)
}
+
+ /// Returns `0`.
+ #[inline]
+ pub fn zero() -> Self {
+ Either::Second(Number::new(0.))
+ }
}
/// A value suitable for a `min-width` or `min-height` property.
diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs
index 8d75e0c4a07..ec0ac648d87 100644
--- a/components/style/values/specified/mod.rs
+++ b/components/style/values/specified/mod.rs
@@ -30,6 +30,8 @@ use values::specified::calc::CalcNode;
#[cfg(feature = "gecko")]
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
+pub use self::rect::LengthOrNumberRect;
+pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageWidthSide};
pub use self::color::Color;
pub use super::generics::grid::GridLine;
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
@@ -44,12 +46,14 @@ pub use self::position::{Position, PositionComponent};
#[cfg(feature = "gecko")]
pub mod align;
pub mod basic_shape;
+pub mod border;
pub mod calc;
pub mod color;
pub mod grid;
pub mod image;
pub mod length;
pub mod position;
+pub mod rect;
/// Common handling for the specified value CSS url() values.
pub mod url {
diff --git a/components/style/values/specified/rect.rs b/components/style/values/specified/rect.rs
new file mode 100644
index 00000000000..11c03e57f7b
--- /dev/null
+++ b/components/style/values/specified/rect.rs
@@ -0,0 +1,21 @@
+/* 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/. */
+
+//! Computed types for CSS borders.
+
+use cssparser::Parser;
+use parser::ParserContext;
+use values::generics::rect::Rect;
+use values::specified::length::LengthOrNumber;
+
+/// A specified rectangle made of four `<length-or-number>` values.
+pub type LengthOrNumberRect = Rect<LengthOrNumber>;
+
+impl LengthOrNumberRect {
+ /// Parses a `LengthOrNumberRect`, rejecting negative values.
+ #[inline]
+ pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ Rect::parse_with(context, input, LengthOrNumber::parse_non_negative)
+ }
+}