diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/layout/display_list_builder.rs | 25 | ||||
-rw-r--r-- | components/style/gecko/conversions.rs | 13 | ||||
-rw-r--r-- | components/style/values/computed/image.rs | 322 | ||||
-rw-r--r-- | components/style/values/generics/image.rs | 362 | ||||
-rw-r--r-- | components/style/values/generics/mod.rs | 1 | ||||
-rw-r--r-- | components/style/values/specified/image.rs | 162 |
6 files changed, 427 insertions, 458 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 5f9a783c896..5ecae6d66de 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -57,11 +57,12 @@ use style::properties::{self, ServoComputedValues}; use style::properties::longhands::border_image_repeat::computed_value::RepeatKeyword; use style::properties::style_structs; use style::servo::restyle_damage::REPAINT; -use style::values::{Either, RGBA, computed}; +use style::values::{Either, RGBA}; use style::values::computed::{AngleOrCorner, Gradient, GradientItem, GradientKind, LengthOrPercentage}; use style::values::computed::{LengthOrPercentageOrAuto, LengthOrKeyword, LengthOrPercentageOrKeyword}; use style::values::computed::{NumberOrPercentage, Position}; use style::values::computed::image::{EndingShape, SizeKeyword}; +use style::values::generics::image::{GradientItem as GenericGradientItem, Image}; use style::values::specified::{HorizontalDirection, VerticalDirection}; use style_traits::CSSPixel; use style_traits::cursor::Cursor; @@ -610,7 +611,7 @@ fn convert_gradient_stops(gradient_items: &[GradientItem], // Only keep the color stops, discard the color interpolation hints. let mut stop_items = gradient_items.iter().filter_map(|item| { match *item { - GradientItem::ColorStop(ref stop) => Some(*stop), + GenericGradientItem::ColorStop(ref stop) => Some(*stop), _ => None, } }).collect::<Vec<_>>(); @@ -855,7 +856,7 @@ impl FragmentDisplayListBuilding for Fragment { for (i, background_image) in background.background_image.0.iter().enumerate().rev() { match background_image.0 { None => {} - Some(computed::Image::Gradient(ref gradient)) => { + Some(Image::Gradient(ref gradient)) => { self.build_display_list_for_background_gradient(state, display_list_section, &absolute_bounds, @@ -864,7 +865,7 @@ impl FragmentDisplayListBuilding for Fragment { gradient, style); } - Some(computed::Image::Url(ref image_url)) => { + Some(Image::Url(ref image_url)) => { if let Some(url) = image_url.url() { self.build_display_list_for_background_image(state, style, @@ -875,10 +876,10 @@ impl FragmentDisplayListBuilding for Fragment { i); } } - Some(computed::Image::ImageRect(_)) => { + Some(Image::Rect(_)) => { // TODO: Implement `-moz-image-rect` } - Some(computed::Image::Element(_)) => { + Some(Image::Element(_)) => { // TODO: Implement `-moz-element` } } @@ -1221,7 +1222,7 @@ impl FragmentDisplayListBuilding for Fragment { style.get_cursor(Cursor::Default), display_list_section); - let display_item = match gradient.gradient_kind { + let display_item = match gradient.kind { GradientKind::Linear(ref angle_or_corner) => { let gradient = self.convert_linear_gradient(&bounds, &gradient.items[..], @@ -1357,8 +1358,8 @@ impl FragmentDisplayListBuilding for Fragment { }), })); } - Some(computed::Image::Gradient(ref gradient)) => { - match gradient.gradient_kind { + Some(Image::Gradient(ref gradient)) => { + match gradient.kind { GradientKind::Linear(angle_or_corner) => { let grad = self.convert_linear_gradient(&bounds, &gradient.items[..], @@ -1398,13 +1399,13 @@ impl FragmentDisplayListBuilding for Fragment { } } } - Some(computed::Image::ImageRect(..)) => { + Some(Image::Rect(..)) => { // TODO: Handle border-image with `-moz-image-rect`. } - Some(computed::Image::Element(..)) => { + Some(Image::Element(..)) => { // TODO: Handle border-image with `-moz-element`. } - Some(computed::Image::Url(ref image_url)) => { + Some(Image::Url(ref image_url)) => { if let Some(url) = image_url.url() { let webrender_image = state.layout_context .get_webrender_image_for_url(self.node, diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index bb299a74db1..d3d74234c35 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -16,8 +16,9 @@ use gecko_bindings::structs::{nsCSSUnit, nsStyleCoord_CalcValue, nsStyleImage}; use gecko_bindings::structs::{nsresult, SheetType}; use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut}; use stylesheets::{Origin, RulesMutateError}; -use values::computed::{Angle, CalcLengthOrPercentage, Gradient, GradientItem, Image}; +use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image}; use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto}; +use values::generics::image::{GradientItem, Image as GenericImage}; impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue { fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue { @@ -138,10 +139,10 @@ impl nsStyleImage { /// Set a given Servo `Image` value into this `nsStyleImage`. pub fn set(&mut self, image: Image, cacheable: &mut bool) { match image { - Image::Gradient(gradient) => { + GenericImage::Gradient(gradient) => { self.set_gradient(gradient) }, - Image::Url(ref url) => { + GenericImage::Url(ref url) => { unsafe { Gecko_SetUrlImageValue(self, url.for_ffi()); // We unfortunately must make any url() value uncacheable, since @@ -154,7 +155,7 @@ impl nsStyleImage { *cacheable = false; } }, - Image::ImageRect(ref image_rect) => { + GenericImage::Rect(ref image_rect) => { unsafe { Gecko_SetUrlImageValue(self, image_rect.url.for_ffi()); Gecko_InitializeImageCropRect(self); @@ -176,7 +177,7 @@ impl nsStyleImage { image_rect.left.to_gecko_style_coord(&mut rect.data_at_mut(3)); } } - Image::Element(ref element) => { + GenericImage::Element(ref element) => { unsafe { Gecko_SetImageElement(self, element.as_ptr()); } @@ -201,7 +202,7 @@ impl nsStyleImage { return; } - let gecko_gradient = match gradient.gradient_kind { + let gecko_gradient = match gradient.kind { GradientKind::Linear(angle_or_corner) => { let gecko_gradient = unsafe { Gecko_CreateGradient(NS_STYLE_GRADIENT_SHAPE_LINEAR as u8, diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index 01a6106f3d3..5140650d80e 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -7,128 +7,35 @@ //! //! [image]: https://drafts.csswg.org/css-images/#image-values -use Atom; -use cssparser::{Color as CSSColor, serialize_identifier}; +use cssparser::Color as CSSColor; use std::f32::consts::PI; use std::fmt; use style_traits::ToCss; +use values::generics::image::{CompatMode, ColorStop as GenericColorStop}; +use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem}; +use values::generics::image::{Image as GenericImage, ImageRect as GenericImageRect}; use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue}; use values::computed::position::Position; use values::specified::{self, HorizontalDirection, VerticalDirection}; -use values::specified::image::CompatMode; -use values::specified::url::SpecifiedUrl; pub use values::specified::SizeKeyword; -impl ToComputedValue for specified::Image { - type ComputedValue = Image; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Image { - match *self { - specified::Image::Url(ref url_value) => { - Image::Url(url_value.clone()) - }, - specified::Image::Gradient(ref gradient) => { - Image::Gradient(gradient.to_computed_value(context)) - }, - specified::Image::ImageRect(ref image_rect) => { - Image::ImageRect(image_rect.to_computed_value(context)) - }, - specified::Image::Element(ref selector) => { - Image::Element(selector.clone()) - } - } - } - - #[inline] - fn from_computed_value(computed: &Image) -> Self { - match *computed { - Image::Url(ref url_value) => { - specified::Image::Url(url_value.clone()) - }, - Image::Gradient(ref linear_gradient) => { - specified::Image::Gradient( - ToComputedValue::from_computed_value(linear_gradient) - ) - }, - Image::ImageRect(ref image_rect) => { - specified::Image::ImageRect( - ToComputedValue::from_computed_value(image_rect) - ) - }, - Image::Element(ref selector) => { - specified::Image::Element(selector.clone()) - }, - } - } -} - /// Computed values for an image according to CSS-IMAGES. /// https://drafts.csswg.org/css-images/#image-values -#[derive(Clone, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[allow(missing_docs)] -pub enum Image { - Url(SpecifiedUrl), - Gradient(Gradient), - ImageRect(ImageRect), - Element(Atom), -} - -impl fmt::Debug for Image { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Image::Url(ref url) => url.to_css(f), - Image::Gradient(ref grad) => { - if grad.repeating { - let _ = write!(f, "repeating-"); - } - match grad.gradient_kind { - GradientKind::Linear(_) => write!(f, "linear-gradient({:?})", grad), - GradientKind::Radial(_, _) => write!(f, "radial-gradient({:?})", grad), - } - }, - Image::ImageRect(ref image_rect) => write!(f, "{:?}", image_rect), - Image::Element(ref selector) => { - f.write_str("-moz-element(#")?; - serialize_identifier(&*selector.to_string(), f)?; - f.write_str(")") - }, - } - } -} - -impl ToCss for Image { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - Image::Url(ref url) => url.to_css(dest), - Image::Gradient(ref gradient) => gradient.to_css(dest), - Image::ImageRect(ref image_rect) => image_rect.to_css(dest), - Image::Element(ref selector) => { - dest.write_str("-moz-element(#")?; - // FIXME: We should get rid of these intermediate strings. - serialize_identifier(&*selector.to_string(), dest)?; - dest.write_str(")") - }, - } - } -} +pub type Image = GenericImage<Gradient, NumberOrPercentage>; /// Computed values for a CSS gradient. /// https://drafts.csswg.org/css-images/#gradients -#[derive(Clone, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub struct Gradient { - /// The color stops. - pub items: Vec<GradientItem>, - /// True if this is a repeating gradient. - pub repeating: bool, - /// Gradient kind can be linear or radial. - pub gradient_kind: GradientKind, - /// Compatibility mode. - pub compat_mode: CompatMode, -} +pub type Gradient = GenericGradient<GradientKind, CSSColor, LengthOrPercentage>; + +/// A computed gradient item. +pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>; + +/// A computed color stop. +pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>; + +/// Computed values for ImageRect. +pub type ImageRect = GenericImageRect<NumberOrPercentage>; impl ToCss for Gradient { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { @@ -138,7 +45,7 @@ impl ToCss for Gradient { if self.repeating { try!(dest.write_str("repeating-")); } - match self.gradient_kind { + match self.kind { GradientKind::Linear(angle_or_corner) => { try!(dest.write_str("linear-gradient(")); try!(angle_or_corner.to_css(dest, self.compat_mode)); @@ -161,7 +68,7 @@ impl ToCss for Gradient { impl fmt::Debug for Gradient { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.gradient_kind { + match self.kind { GradientKind::Linear(angle_or_corner) => { let _ = write!(f, "{:?}", angle_or_corner); }, @@ -177,42 +84,6 @@ impl fmt::Debug for Gradient { } } -impl ToComputedValue for specified::Gradient { - type ComputedValue = Gradient; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Gradient { - let specified::Gradient { - ref items, - repeating, - ref gradient_kind, - compat_mode, - } = *self; - Gradient { - items: items.iter().map(|s| s.to_computed_value(context)).collect(), - repeating: repeating, - gradient_kind: gradient_kind.to_computed_value(context), - compat_mode: compat_mode, - } - } - - #[inline] - fn from_computed_value(computed: &Gradient) -> Self { - let Gradient { - ref items, - repeating, - ref gradient_kind, - compat_mode, - } = *computed; - specified::Gradient { - items: items.iter().map(ToComputedValue::from_computed_value).collect(), - repeating: repeating, - gradient_kind: ToComputedValue::from_computed_value(gradient_kind), - compat_mode: compat_mode, - } - } -} - /// Computed values for CSS linear or radial gradients. /// https://drafts.csswg.org/css-images/#gradients #[derive(Clone, PartialEq)] @@ -252,112 +123,6 @@ impl ToComputedValue for specified::GradientKind { } } -/// Specified values for color stops and interpolation hints. -#[derive(Clone, PartialEq, Debug)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub enum GradientItem { - /// A color stop. - ColorStop(ColorStop), - /// An interpolation hint. - InterpolationHint(LengthOrPercentage), -} - -impl ToCss for GradientItem { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - GradientItem::ColorStop(stop) => stop.to_css(dest), - GradientItem::InterpolationHint(hint) => hint.to_css(dest), - } - } -} - -impl ToComputedValue for specified::GradientItem { - type ComputedValue = GradientItem; - - #[inline] - fn to_computed_value(&self, context: &Context) -> GradientItem { - match *self { - specified::GradientItem::ColorStop(ref stop) => { - GradientItem::ColorStop(stop.to_computed_value(context)) - }, - specified::GradientItem::InterpolationHint(ref hint) => { - GradientItem::InterpolationHint(hint.to_computed_value(context)) - }, - } - } - - #[inline] - fn from_computed_value(computed: &GradientItem) -> Self { - match *computed { - GradientItem::ColorStop(ref stop) => { - specified::GradientItem::ColorStop(ToComputedValue::from_computed_value(stop)) - }, - GradientItem::InterpolationHint(ref hint) => { - specified::GradientItem::InterpolationHint(ToComputedValue::from_computed_value(hint)) - }, - } - } -} - -/// Computed values for one color stop in a linear gradient. -/// https://drafts.csswg.org/css-images/#typedef-color-stop-list -#[derive(Clone, PartialEq, Copy)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub struct ColorStop { - /// The color of this stop. - pub color: CSSColor, - - /// The position of this stop. If not specified, this stop is placed halfway between the - /// point that precedes it and the point that follows it per CSS-IMAGES § 3.4. - pub position: Option<LengthOrPercentage>, -} - -impl ToCss for ColorStop { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.color.to_css(dest)); - if let Some(position) = self.position { - try!(dest.write_str(" ")); - try!(position.to_css(dest)); - } - Ok(()) - } -} - -impl fmt::Debug for ColorStop { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let _ = write!(f, "{:?}", self.color); - self.position.map(|pos| { - let _ = write!(f, " {:?}", pos); - }); - Ok(()) - } -} - -impl ToComputedValue for specified::ColorStop { - type ComputedValue = ColorStop; - - #[inline] - fn to_computed_value(&self, context: &Context) -> ColorStop { - ColorStop { - color: self.color.to_computed_value(context), - position: match self.position { - None => None, - Some(ref value) => Some(value.to_computed_value(context)), - }, - } - } - #[inline] - fn from_computed_value(computed: &ColorStop) -> Self { - specified::ColorStop { - color: ToComputedValue::from_computed_value(&computed.color), - position: match computed.position { - None => None, - Some(value) => Some(ToComputedValue::from_computed_value(&value)), - }, - } - } -} - /// Computed values for EndingShape /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape #[derive(Clone, PartialEq)] @@ -425,59 +190,6 @@ impl ToComputedValue for specified::GradientEndingShape { } } -/// Computed values for ImageRect -#[derive(Clone, PartialEq, Debug)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[allow(missing_docs)] -pub struct ImageRect { - pub url: SpecifiedUrl, - pub top: NumberOrPercentage, - pub bottom: NumberOrPercentage, - pub right: NumberOrPercentage, - pub left: NumberOrPercentage, -} - -impl ToCss for ImageRect { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - dest.write_str("-moz-image-rect(")?; - self.url.to_css(dest)?; - dest.write_str(", ")?; - self.top.to_css(dest)?; - dest.write_str(", ")?; - self.right.to_css(dest)?; - dest.write_str(", ")?; - self.bottom.to_css(dest)?; - dest.write_str(", ")?; - self.left.to_css(dest)?; - dest.write_str(")") - } -} - -impl ToComputedValue for specified::ImageRect { - type ComputedValue = ImageRect; - - #[inline] - fn to_computed_value(&self, context: &Context) -> ImageRect { - ImageRect { - url: self.url.to_computed_value(context), - top: self.top.to_computed_value(context), - right: self.right.to_computed_value(context), - bottom: self.bottom.to_computed_value(context), - left: self.left.to_computed_value(context), - } - } - #[inline] - fn from_computed_value(computed: &ImageRect) -> Self { - specified::ImageRect { - url: ToComputedValue::from_computed_value(&computed.url), - top: ToComputedValue::from_computed_value(&computed.top), - right: ToComputedValue::from_computed_value(&computed.right), - bottom: ToComputedValue::from_computed_value(&computed.bottom), - left: ToComputedValue::from_computed_value(&computed.left), - } - } -} - /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size #[derive(Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs new file mode 100644 index 00000000000..de644215acc --- /dev/null +++ b/components/style/values/generics/image.rs @@ -0,0 +1,362 @@ +/* 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 the handling of [images]. +//! +//! [images]: https://drafts.csswg.org/css-images/#image-values + +use Atom; +use cssparser::serialize_identifier; +use std::fmt; +use style_traits::ToCss; +use values::HasViewportPercentage; +use values::computed::{Context, ToComputedValue}; +use values::specified::url::SpecifiedUrl; + +/// An [image]. +/// +/// [image]: https://drafts.csswg.org/css-images/#image-values +#[derive(Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum Image<G, N> { + /// A `<url()>` image. + Url(SpecifiedUrl), + /// A `<gradient>` image. + Gradient(G), + /// A `-moz-image-rect` image + Rect(ImageRect<N>), + /// A `-moz-element(# <element-id>)` + Element(Atom), +} + +/// A CSS gradient. +/// https://drafts.csswg.org/css-images/#gradients +#[derive(Clone, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct Gradient<K, C, L> { + /// Gradients can be linear or radial. + pub kind: K, + /// The color stops and interpolation hints. + pub items: Vec<GradientItem<C, L>>, + /// True if this is a repeating gradient. + pub repeating: bool, + /// Compatibility mode. + pub compat_mode: CompatMode, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +/// Whether we used the modern notation or the compatibility `-webkit` prefix. +pub enum CompatMode { + /// Modern syntax. + Modern, + /// `-webkit` prefix. + WebKit, +} + +/// A gradient item. +/// https://drafts.csswg.org/css-images-4/#color-stop-syntax +#[derive(Clone, Copy, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum GradientItem<C, L> { + /// A color stop. + ColorStop(ColorStop<C, L>), + /// An interpolation hint. + InterpolationHint(L), +} + +/// A color stop. +/// https://drafts.csswg.org/css-images/#typedef-color-stop-list +#[derive(Clone, Copy, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct ColorStop<C, L> { + /// The color of this stop. + pub color: C, + /// The position of this stop. + pub position: Option<L>, +} + +/// Values for `moz-image-rect`. +/// +/// `-moz-image-rect(<uri>, top, right, bottom, left);` +#[derive(Clone, PartialEq, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[allow(missing_docs)] +pub struct ImageRect<C> { + pub url: SpecifiedUrl, + pub top: C, + pub bottom: C, + pub right: C, + pub left: C, +} + +impl<G, N> fmt::Debug for Image<G, N> + where G: fmt::Debug, N: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Image::Url(ref url) => url.to_css(f), + Image::Gradient(ref grad) => grad.fmt(f), + Image::Rect(ref rect) => rect.fmt(f), + Image::Element(ref selector) => { + f.write_str("-moz-element(#")?; + serialize_identifier(&selector.to_string(), f)?; + f.write_str(")") + }, + } + } +} + +impl<G, N> ToCss for Image<G, N> + where G: ToCss, N: ToCss, +{ + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + Image::Url(ref url) => url.to_css(dest), + Image::Gradient(ref gradient) => gradient.to_css(dest), + Image::Rect(ref rect) => rect.to_css(dest), + Image::Element(ref selector) => { + dest.write_str("-moz-element(#")?; + serialize_identifier(&selector.to_string(), dest)?; + dest.write_str(")") + }, + } + } +} + +impl<G, N> HasViewportPercentage for Image<G, N> + where G: HasViewportPercentage +{ + fn has_viewport_percentage(&self) -> bool { + match *self { + Image::Gradient(ref gradient) => gradient.has_viewport_percentage(), + _ => false, + } + } +} + +impl<G, N> ToComputedValue for Image<G, N> + where G: ToComputedValue, N: ToComputedValue, +{ + type ComputedValue = Image<<G as ToComputedValue>::ComputedValue, + <N as ToComputedValue>::ComputedValue>; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + match *self { + Image::Url(ref url) => { + Image::Url(url.clone()) + }, + Image::Gradient(ref gradient) => { + Image::Gradient(gradient.to_computed_value(context)) + }, + Image::Rect(ref rect) => { + Image::Rect(rect.to_computed_value(context)) + }, + Image::Element(ref selector) => { + Image::Element(selector.clone()) + } + } + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + match *computed { + Image::Url(ref url) => { + Image::Url(url.clone()) + }, + Image::Gradient(ref gradient) => { + Image::Gradient(ToComputedValue::from_computed_value(gradient)) + }, + Image::Rect(ref rect) => { + Image::Rect(ToComputedValue::from_computed_value(rect)) + }, + Image::Element(ref selector) => { + Image::Element(selector.clone()) + }, + } + } +} + +impl<K, C, L> HasViewportPercentage for Gradient<K, C, L> + where K: HasViewportPercentage, L: HasViewportPercentage, +{ + fn has_viewport_percentage(&self) -> bool { + self.kind.has_viewport_percentage() || + self.items.iter().any(|i| i.has_viewport_percentage()) + } +} + +impl<K, C, L> ToComputedValue for Gradient<K, C, L> + where K: ToComputedValue, C: ToComputedValue, L: ToComputedValue, +{ + type ComputedValue = Gradient<<K as ToComputedValue>::ComputedValue, + <C as ToComputedValue>::ComputedValue, + <L as ToComputedValue>::ComputedValue>; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + Gradient { + kind: self.kind.to_computed_value(context), + items: self.items.iter().map(|s| s.to_computed_value(context)).collect(), + repeating: self.repeating, + compat_mode: self.compat_mode, + } + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + Gradient { + kind: ToComputedValue::from_computed_value(&computed.kind), + items: computed.items.iter().map(ToComputedValue::from_computed_value).collect(), + repeating: computed.repeating, + compat_mode: computed.compat_mode, + } + } +} + +impl<C, L> ToCss for GradientItem<C, L> + where C: ToCss, L: ToCss, +{ + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + GradientItem::ColorStop(ref stop) => stop.to_css(dest), + GradientItem::InterpolationHint(ref hint) => hint.to_css(dest), + } + } +} + +impl<C, L> HasViewportPercentage for GradientItem<C, L> + where L: HasViewportPercentage, +{ + fn has_viewport_percentage(&self) -> bool { + match *self { + GradientItem::ColorStop(ref stop) => stop.has_viewport_percentage(), + GradientItem::InterpolationHint(ref hint) => hint.has_viewport_percentage(), + } + } +} + +impl<C, L> ToComputedValue for GradientItem<C, L> + where C: ToComputedValue, L: ToComputedValue, +{ + type ComputedValue = GradientItem<<C as ToComputedValue>::ComputedValue, + <L as ToComputedValue>::ComputedValue>; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + match *self { + GradientItem::ColorStop(ref stop) => { + GradientItem::ColorStop(stop.to_computed_value(context)) + }, + GradientItem::InterpolationHint(ref hint) => { + GradientItem::InterpolationHint(hint.to_computed_value(context)) + }, + } + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + match *computed { + GradientItem::ColorStop(ref stop) => { + GradientItem::ColorStop(ToComputedValue::from_computed_value(stop)) + }, + GradientItem::InterpolationHint(ref hint) => { + GradientItem::InterpolationHint(ToComputedValue::from_computed_value(hint)) + }, + } + } +} + +impl<C, L> fmt::Debug for ColorStop<C, L> + where C: fmt::Debug, L: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.color)?; + if let Some(ref pos) = self.position { + write!(f, " {:?}", pos)?; + } + Ok(()) + } +} + +impl<C, L> ToCss for ColorStop<C, L> + where C: ToCss, L: ToCss, +{ + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.color.to_css(dest)?; + if let Some(ref position) = self.position { + dest.write_str(" ")?; + position.to_css(dest)?; + } + Ok(()) + } +} + +impl<C, L> HasViewportPercentage for ColorStop<C, L> + where L: HasViewportPercentage, +{ + fn has_viewport_percentage(&self) -> bool { + self.position.as_ref().map_or(false, HasViewportPercentage::has_viewport_percentage) + } +} + +impl<C, L> ToComputedValue for ColorStop<C, L> + where C: ToComputedValue, L: ToComputedValue, +{ + type ComputedValue = ColorStop<<C as ToComputedValue>::ComputedValue, + <L as ToComputedValue>::ComputedValue>; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + ColorStop { + color: self.color.to_computed_value(context), + position: self.position.as_ref().map(|p| p.to_computed_value(context)), + } + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + ColorStop { + color: ToComputedValue::from_computed_value(&computed.color), + position: computed.position.as_ref().map(ToComputedValue::from_computed_value), + } + } +} + +impl<C> ToCss for ImageRect<C> + where C: ToCss, +{ + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + dest.write_str("-moz-image-rect(")?; + self.url.to_css(dest)?; + dest.write_str(", ")?; + self.top.to_css(dest)?; + dest.write_str(", ")?; + self.right.to_css(dest)?; + dest.write_str(", ")?; + self.bottom.to_css(dest)?; + dest.write_str(", ")?; + self.left.to_css(dest)?; + dest.write_str(")") + } +} + +impl<C> ToComputedValue for ImageRect<C> + where C: ToComputedValue, +{ + type ComputedValue = ImageRect<<C as ToComputedValue>::ComputedValue>; + + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + ImageRect { + url: self.url.clone(), + top: self.top.to_computed_value(context), + right: self.right.to_computed_value(context), + bottom: self.bottom.to_computed_value(context), + left: self.left.to_computed_value(context), + } + } + + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + ImageRect { + url: computed.url.clone(), + top: ToComputedValue::from_computed_value(&computed.top), + right: ToComputedValue::from_computed_value(&computed.right), + bottom: ToComputedValue::from_computed_value(&computed.bottom), + left: ToComputedValue::from_computed_value(&computed.left), + } + } +} diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 43cf722fb7e..604d6e21238 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -14,6 +14,7 @@ use super::computed::{Context, ToComputedValue}; pub use self::basic_shape::serialize_radius_values; pub mod basic_shape; +pub mod image; pub mod position; #[derive(Clone, PartialEq, Debug)] diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index 515082d2c11..62e971782f9 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -8,68 +8,58 @@ //! [image]: https://drafts.csswg.org/css-images/#image-values use Atom; -use cssparser::{Parser, Token, serialize_identifier}; +use cssparser::{Parser, Token}; use parser::{Parse, ParserContext}; #[cfg(feature = "servo")] use servo_url::ServoUrl; use std::fmt; use style_traits::ToCss; +use values::generics::image::{CompatMode, ColorStop as GenericColorStop}; +use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem}; +use values::generics::image::{Image as GenericImage, ImageRect as GenericImageRect}; use values::specified::{Angle, CSSColor, Length, LengthOrPercentage, NumberOrPercentage}; use values::specified::position::Position; use values::specified::url::SpecifiedUrl; /// Specified values for an image according to CSS-IMAGES. /// https://drafts.csswg.org/css-images/#image-values -#[derive(Clone, PartialEq, Debug)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub enum Image { - /// A `<url()>` image. - Url(SpecifiedUrl), - /// A `<gradient>` image. - Gradient(Gradient), - /// A `-moz-image-rect` image - ImageRect(ImageRect), - /// A `-moz-element(# <element-id>)` - Element(Atom), -} +pub type Image = GenericImage<Gradient, NumberOrPercentage>; -impl ToCss for Image { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - Image::Url(ref url_value) => url_value.to_css(dest), - Image::Gradient(ref gradient) => gradient.to_css(dest), - Image::ImageRect(ref image_rect) => image_rect.to_css(dest), - Image::Element(ref selector) => { - dest.write_str("-moz-element(#")?; - // FIXME: We should get rid of these intermediate strings. - serialize_identifier(&*selector.to_string(), dest)?; - dest.write_str(")") - }, - } - } -} +/// Specified values for a CSS gradient. +/// https://drafts.csswg.org/css-images/#gradients +pub type Gradient = GenericGradient<GradientKind, CSSColor, LengthOrPercentage>; + +/// A specified gradient item. +pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>; + +/// A computed color stop. +pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>; + +/// Specified values for `moz-image-rect` +/// -moz-image-rect(<uri>, top, right, bottom, left); +pub type ImageRect = GenericImageRect<NumberOrPercentage>; impl Image { #[allow(missing_docs)] pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<Image, ()> { if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) { - return Ok(Image::Url(url)); + return Ok(GenericImage::Url(url)); } if let Ok(gradient) = input.try(|input| Gradient::parse_function(context, input)) { - return Ok(Image::Gradient(gradient)); + return Ok(GenericImage::Gradient(gradient)); } if let Ok(image_rect) = input.try(|input| ImageRect::parse(context, input)) { - return Ok(Image::ImageRect(image_rect)); + return Ok(GenericImage::Rect(image_rect)); } - Ok(Image::Element(Image::parse_element(input)?)) + Ok(GenericImage::Element(Image::parse_element(input)?)) } /// Creates an already specified image value from an already resolved URL /// for insertion in the cascade. #[cfg(feature = "servo")] pub fn for_cascade(url: ServoUrl) -> Self { - Image::Url(SpecifiedUrl::for_cascade(url)) + GenericImage::Url(SpecifiedUrl::for_cascade(url)) } /// Parses a `-moz-element(# <element-id>)`. @@ -87,21 +77,6 @@ impl Image { } } -/// Specified values for a CSS gradient. -/// https://drafts.csswg.org/css-images/#gradients -#[derive(Clone, PartialEq, Debug)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub struct Gradient { - /// The color stops and interpolation hints. - pub items: Vec<GradientItem>, - /// True if this is a repeating gradient. - pub repeating: bool, - /// Gradients can be linear or radial. - pub gradient_kind: GradientKind, - /// Compatibility mode. - pub compat_mode: CompatMode, -} - impl ToCss for Gradient { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { if self.compat_mode == CompatMode::WebKit { @@ -111,7 +86,7 @@ impl ToCss for Gradient { try!(dest.write_str("repeating-")); } let mut skipcomma = false; - match self.gradient_kind { + match self.kind { GradientKind::Linear(angle_or_corner) => { try!(dest.write_str("linear-gradient(")); try!(angle_or_corner.to_css(dest, self.compat_mode)); @@ -198,7 +173,7 @@ impl Gradient { Ok(Gradient { items: items, repeating: repeating, - gradient_kind: gradient_kind, + kind: gradient_kind, compat_mode: compat_mode, }) } @@ -209,11 +184,11 @@ impl Gradient { if seen_stop { if let Ok(hint) = input.try(|i| LengthOrPercentage::parse(context, i)) { seen_stop = false; - return Ok(GradientItem::InterpolationHint(hint)); + return Ok(GenericGradientItem::InterpolationHint(hint)); } } seen_stop = true; - ColorStop::parse(context, input).map(GradientItem::ColorStop) + ColorStop::parse(context, input).map(GenericGradientItem::ColorStop) })); if !seen_stop || items.len() < 2 { return Err(()); @@ -238,16 +213,6 @@ pub enum GradientKind { Radial(EndingShape, Position), } -#[derive(Clone, Copy, PartialEq, Debug)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -/// Whether we used the modern notation or the compatibility `-webkit` prefix. -pub enum CompatMode { - /// Modern syntax. - Modern, - /// `-webkit` prefix. - WebKit, -} - impl GradientKind { /// Parses a linear gradient kind from the given arguments. fn parse_modern_linear(context: &ParserContext, input: &mut Parser) -> Result<GradientKind, ()> { @@ -396,35 +361,6 @@ impl GradientKind { } } -/// Specified values for `moz-image-rect` -/// -moz-image-rect(<uri>, top, right, bottom, left); -#[derive(Clone, PartialEq, Debug)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[allow(missing_docs)] -pub struct ImageRect { - pub url: SpecifiedUrl, - pub top: NumberOrPercentage, - pub bottom: NumberOrPercentage, - pub right: NumberOrPercentage, - pub left: NumberOrPercentage, -} - -impl ToCss for ImageRect { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - dest.write_str("-moz-image-rect(")?; - self.url.to_css(dest)?; - dest.write_str(", ")?; - self.top.to_css(dest)?; - dest.write_str(", ")?; - self.right.to_css(dest)?; - dest.write_str(", ")?; - self.bottom.to_css(dest)?; - dest.write_str(", ")?; - self.left.to_css(dest)?; - dest.write_str(")") - } -} - impl Parse for ImageRect { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { match_ignore_ascii_case! { &try!(input.expect_function()), @@ -502,50 +438,6 @@ impl AngleOrCorner { } } -/// Specified values for color stops and interpolation hints. -/// https://drafts.csswg.org/css-images-4/#color-stop-syntax -#[derive(Clone, PartialEq, Debug)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub enum GradientItem { - /// A color stop. - ColorStop(ColorStop), - /// An interpolation hint. - InterpolationHint(LengthOrPercentage), -} - -impl ToCss for GradientItem { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - GradientItem::ColorStop(ref stop) => stop.to_css(dest), - GradientItem::InterpolationHint(ref hint) => hint.to_css(dest), - } - } -} - -/// Specified values for one color stop in a gradient. -/// https://drafts.csswg.org/css-images/#typedef-color-stop-list -#[derive(Clone, PartialEq, Debug)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -pub struct ColorStop { - /// The color of this stop. - pub color: CSSColor, - - /// The position of this stop. If not specified, this stop is placed halfway between the - /// point that precedes it and the point that follows it. - pub position: Option<LengthOrPercentage>, -} - -impl ToCss for ColorStop { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.color.to_css(dest)); - if let Some(ref position) = self.position { - try!(dest.write_str(" ")); - try!(position.to_css(dest)); - } - Ok(()) - } -} - define_css_keyword_enum!(HorizontalDirection: "left" => Left, "right" => Right); define_css_keyword_enum!(VerticalDirection: "top" => Top, "bottom" => Bottom); |