Auto merge of #17071 - servo:derive-all-the-things, r=emilio

Reuse Rect<T> some more

<!-- 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/17071)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-05-30 05:11:28 -05:00 committed by GitHub
commit 433d68955b
24 changed files with 324 additions and 355 deletions

View file

@ -5,11 +5,10 @@
//! CSS handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape)
//! types that are generic over their `ToCss` implementations.
use euclid::size::Size2D;
use std::fmt;
use style_traits::{HasViewportPercentage, ToCss};
use values::computed::ComputedValueAsSpecified;
use values::generics::BorderRadiusSize;
use values::generics::border::BorderRadius;
use values::generics::position::Position;
use values::generics::rect::Rect;
use values::specified::url::SpecifiedUrl;
@ -71,22 +70,6 @@ pub struct InsetRect<LengthOrPercentage> {
pub round: Option<BorderRadius<LengthOrPercentage>>,
}
/// A generic type used for `border-radius`, `outline-radius` and `inset()` values.
///
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
pub struct BorderRadius<LengthOrPercentage> {
/// The top left radius.
pub top_left: BorderRadiusSize<LengthOrPercentage>,
/// The top right radius.
pub top_right: BorderRadiusSize<LengthOrPercentage>,
/// The bottom right radius.
pub bottom_right: BorderRadiusSize<LengthOrPercentage>,
/// The bottom left radius.
pub bottom_left: BorderRadiusSize<LengthOrPercentage>,
}
/// https://drafts.csswg.org/css-shapes/#funcdef-circle
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -201,33 +184,6 @@ impl<L> ToCss for InsetRect<L>
}
}
impl<L: ToCss + PartialEq> ToCss for BorderRadius<L> {
#[inline]
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
serialize_radius_values(dest, &self.top_left.0, &self.top_right.0,
&self.bottom_right.0, &self.bottom_left.0)
}
}
/// Serialization helper for types of longhands like `border-radius` and `outline-radius`
pub fn serialize_radius_values<L, W>(dest: &mut W, top_left: &Size2D<L>,
top_right: &Size2D<L>, bottom_right: &Size2D<L>,
bottom_left: &Size2D<L>) -> fmt::Result
where L: ToCss + PartialEq, W: fmt::Write
{
Rect::new(&top_left.width, &top_right.width, &bottom_right.width, &bottom_left.width).to_css(dest)?;
if
top_left.width != top_left.height ||
top_right.width != top_right.height ||
bottom_right.width != bottom_right.height ||
bottom_left.width != bottom_left.height
{
dest.write_str(" / ")?;
Rect::new(&top_left.height, &top_right.height, &bottom_right.height, &bottom_left.height).to_css(dest)?;
}
Ok(())
}
impl<L> Default for ShapeRadius<L> {
#[inline]
fn default() -> Self { ShapeRadius::ClosestSide }

View file

@ -4,6 +4,7 @@
//! Generic types for CSS values related to borders.
use euclid::Size2D;
use std::fmt;
use style_traits::ToCss;
use values::generics::rect::Rect;
@ -30,6 +31,27 @@ pub struct BorderImageSlice<NumberOrPercentage> {
pub fill: bool,
}
/// A generic value for `border-radius`, `outline-radius` and `inset()`.
///
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
pub struct BorderRadius<LengthOrPercentage> {
/// The top left radius.
pub top_left: BorderCornerRadius<LengthOrPercentage>,
/// The top right radius.
pub top_right: BorderCornerRadius<LengthOrPercentage>,
/// The bottom right radius.
pub bottom_right: BorderCornerRadius<LengthOrPercentage>,
/// The bottom left radius.
pub bottom_left: BorderCornerRadius<LengthOrPercentage>,
}
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
/// A generic value for `border-*-radius` longhand properties.
pub struct BorderCornerRadius<L>(pub Size2D<L>);
impl<L, N> ToCss for BorderImageWidthSide<L, N>
where L: ToCss, N: ToCss,
{
@ -69,3 +91,81 @@ impl<N> ToCss for BorderImageSlice<N>
Ok(())
}
}
impl<L> BorderRadius<L> {
/// Returns a new `BorderRadius<L>`.
#[inline]
pub fn new(tl: BorderCornerRadius<L>,
tr: BorderCornerRadius<L>,
br: BorderCornerRadius<L>,
bl: BorderCornerRadius<L>)
-> Self {
BorderRadius {
top_left: tl,
top_right: tr,
bottom_right: br,
bottom_left: bl,
}
}
}
impl<L> BorderRadius<L>
where L: PartialEq + ToCss
{
/// Serialises two given rects following the syntax of the `border-radius``
/// property.
pub fn serialize_rects<W>(widths: Rect<&L>, heights: Rect<&L>, dest: &mut W) -> fmt::Result
where W: fmt::Write,
{
widths.to_css(dest)?;
if widths.0 != heights.0 || widths.1 != heights.1 || widths.2 != heights.2 || widths.3 != heights.3 {
dest.write_str(" / ")?;
heights.to_css(dest)?;
}
Ok(())
}
}
impl<L> ToCss for BorderRadius<L>
where L: PartialEq + ToCss
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
let BorderRadius {
top_left: ref tl,
top_right: ref tr,
bottom_right: ref br,
bottom_left: ref bl,
} = *self;
let widths = Rect::new(&tl.0.width, &tr.0.width, &br.0.width, &bl.0.width);
let heights = Rect::new(&tl.0.height, &tr.0.height, &br.0.height, &bl.0.height);
Self::serialize_rects(widths, heights, dest)
}
}
impl<L> BorderCornerRadius<L> {
#[inline]
/// Create a new `BorderCornerRadius` for an area of given width and height.
pub fn new(width: L, height: L) -> BorderCornerRadius<L> {
BorderCornerRadius(Size2D::new(width, height))
}
}
impl<L: Clone> From<L> for BorderCornerRadius<L> {
fn from(radius: L) -> Self {
Self::new(radius.clone(), radius)
}
}
impl<L> ToCss for BorderCornerRadius<L>
where L: ToCss,
{
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where W: fmt::Write
{
self.0.width.to_css(dest)?;
dest.write_str(" ")?;
self.0.height.to_css(dest)
}
}

View file

@ -7,14 +7,11 @@
use counter_style::{Symbols, parse_counter_style_name};
use cssparser::Parser;
use euclid::size::Size2D;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::{HasViewportPercentage, OneOrMoreCommaSeparated, ToCss};
use style_traits::{OneOrMoreCommaSeparated, ToCss};
use super::CustomIdent;
pub use self::basic_shape::serialize_radius_values;
pub mod background;
pub mod basic_shape;
pub mod border;
@ -23,47 +20,6 @@ pub mod image;
pub mod position;
pub mod rect;
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A type for representing CSS `width` and `height` values.
pub struct BorderRadiusSize<L>(pub Size2D<L>);
impl<L> HasViewportPercentage for BorderRadiusSize<L> {
#[inline]
fn has_viewport_percentage(&self) -> bool { false }
}
impl<L: Clone> From<L> for BorderRadiusSize<L> {
fn from(other: L) -> Self {
Self::new(other.clone(), other)
}
}
impl<L> BorderRadiusSize<L> {
#[inline]
/// Create a new `BorderRadiusSize` for an area of given width and height.
pub fn new(width: L, height: L) -> BorderRadiusSize<L> {
BorderRadiusSize(Size2D::new(width, height))
}
}
impl<L: Clone> BorderRadiusSize<L> {
#[inline]
/// Create a new `BorderRadiusSize` for a circle of given radius.
pub fn circle(radius: L) -> BorderRadiusSize<L> {
BorderRadiusSize(Size2D::new(radius.clone(), radius))
}
}
impl<L: ToCss> ToCss for BorderRadiusSize<L> {
#[inline]
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.0.width.to_css(dest)?;
dest.write_str(" ")?;
self.0.height.to_css(dest)
}
}
// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
define_css_keyword_enum! { SymbolsType:
"cyclic" => Cyclic,

View file

@ -9,29 +9,16 @@ use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::ToCss;
/// A CSS value made of four sides: top, right, bottom, and left.
/// A CSS value made of four components, where its `ToCss` impl will try to
/// serialize as few components as possible, like for example in `border-width`.
#[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,
}
pub struct Rect<T>(pub T, pub T, pub T, pub 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,
}
pub fn new(first: T, second: T, third: T, fourth: T) -> Self {
Rect(first, second, third, fourth)
}
}
@ -46,21 +33,21 @@ impl<T> Rect<T>
-> 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 first = parse(context, input)?;
let second = if let Ok(second) = input.try(|i| parse(context, i)) { second } else {
// <first>
return Ok(Self::new(first.clone(), first.clone(), first.clone(), first));
};
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 third = if let Ok(third) = input.try(|i| parse(context, i)) { third } else {
// <first> <second>
return Ok(Self::new(first.clone(), second.clone(), first, second));
};
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));
let fourth = if let Ok(fourth) = input.try(|i| parse(context, i)) { fourth } else {
// <first> <second> <third>
return Ok(Self::new(first, second.clone(), third, second));
};
// <top> <right> <bottom> <left>
Ok(Self::new(top, right, bottom, left))
// <first> <second> <third> <fourth>
Ok(Self::new(first, second, third, fourth))
}
}
@ -88,23 +75,23 @@ impl<T> ToCss for Rect<T>
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 {
self.0.to_css(dest)?;
let same_vertical = self.0 == self.2;
let same_horizontal = self.1 == self.3;
if same_vertical && same_horizontal && self.0 == self.1 {
return Ok(());
}
dest.write_str(" ")?;
self.right.to_css(dest)?;
self.1.to_css(dest)?;
if same_vertical && same_horizontal {
return Ok(());
}
dest.write_str(" ")?;
self.bottom.to_css(dest)?;
self.2.to_css(dest)?;
if same_horizontal {
return Ok(());
}
dest.write_str(" ")?;
self.left.to_css(dest)
self.3.to_css(dest)
}
}