/* 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/. */ //! CSS handling for the computed value of //! [`image`][image]s //! //! [image]: https://drafts.csswg.org/css-images/#image-values use cssparser::Color as CSSColor; use std::fmt; use url::Url; use values::LocalToCss; use values::computed::{Context, Length, LengthOrPercentage, ToComputedValue}; use values::computed::position::Position; use values::specified; use values::specified::{AngleOrCorner, SizeKeyword, UrlExtraData}; impl ToComputedValue for specified::Image { type ComputedValue = Image; #[inline] fn to_computed_value(&self, context: &Context) -> Image { match *self { specified::Image::Url(ref url, ref extra_data) => { Image::Url(url.clone(), extra_data.clone()) }, specified::Image::Gradient(ref gradient) => { Image::Gradient(gradient.to_computed_value(context)) } } } #[inline] fn from_computed_value(computed: &Image) -> Self { match *computed { Image::Url(ref url, ref extra_data) => { specified::Image::Url(url.clone(), extra_data.clone()) }, Image::Gradient(ref linear_gradient) => { specified::Image::Gradient( ToComputedValue::from_computed_value(linear_gradient) ) } } } } /// 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))] pub enum Image { Url(Url, UrlExtraData), Gradient(Gradient), } impl fmt::Debug for Image { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Image::Url(ref url, ref _extra_data) => write!(f, "url(\"{}\")", url), 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), } }, } } } impl ::cssparser::ToCss for Image { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { use values::LocalToCss; match *self { Image::Url(ref url, _) => { url.to_css(dest) } Image::Gradient(ref gradient) => gradient.to_css(dest) } } } /// 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 stops: Vec, /// True if this is a repeating gradient. pub repeating: bool, /// Gradient kind can be linear or radial. pub gradient_kind: GradientKind, } impl ::cssparser::ToCss for Gradient { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { if self.repeating { try!(dest.write_str("repeating-")); } match self.gradient_kind { GradientKind::Linear(angle_or_corner) => { try!(dest.write_str("linear-gradient(")); try!(angle_or_corner.to_css(dest)); }, GradientKind::Radial(ref shape, position) => { try!(dest.write_str("radial-gradient(")); try!(shape.to_css(dest)); try!(dest.write_str(" at ")); try!(position.to_css(dest)); }, } for stop in &self.stops { try!(dest.write_str(", ")); try!(stop.to_css(dest)); } try!(dest.write_str(")")); Ok(()) } } impl fmt::Debug for Gradient { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.gradient_kind { GradientKind::Linear(angle_or_corner) => { let _ = write!(f, "{:?}", angle_or_corner); }, GradientKind::Radial(ref shape, position) => { let _ = write!(f, "{:?} at {:?}", shape, position); }, } for stop in &self.stops { let _ = write!(f, ", {:?}", stop); } Ok(()) } } impl ToComputedValue for specified::Gradient { type ComputedValue = Gradient; #[inline] fn to_computed_value(&self, context: &Context) -> Gradient { let specified::Gradient { ref stops, repeating, ref gradient_kind } = *self; Gradient { stops: stops.iter().map(|s| s.to_computed_value(context)).collect(), repeating: repeating, gradient_kind: gradient_kind.to_computed_value(context), } } #[inline] fn from_computed_value(computed: &Gradient) -> Self { let Gradient { ref stops, repeating, ref gradient_kind } = *computed; specified::Gradient { stops: stops.iter().map(ToComputedValue::from_computed_value).collect(), repeating: repeating, gradient_kind: ToComputedValue::from_computed_value(gradient_kind), } } } /// Computed values for CSS linear or radial gradients. /// https://drafts.csswg.org/css-images/#gradients #[derive(Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum GradientKind { Linear(AngleOrCorner), Radial(EndingShape, Position), } impl ToComputedValue for specified::GradientKind { type ComputedValue = GradientKind; #[inline] fn to_computed_value(&self, context: &Context) -> GradientKind { match *self { specified::GradientKind::Linear(angle_or_corner) => { GradientKind::Linear(angle_or_corner) }, specified::GradientKind::Radial(ref shape, position) => { GradientKind::Radial(shape.to_computed_value(context), position.to_computed_value(context)) }, } } #[inline] fn from_computed_value(computed: &GradientKind) -> Self { match *computed { GradientKind::Linear(angle_or_corner) => { specified::GradientKind::Linear(ToComputedValue::from_computed_value(&angle_or_corner)) }, GradientKind::Radial(ref shape, position) => { specified::GradientKind::Radial(ToComputedValue::from_computed_value(shape), ToComputedValue::from_computed_value(&position)) }, } } } /// 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, } impl ::cssparser::ToCss for ColorStop { fn to_css(&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.parsed, position: match self.position { None => None, Some(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)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum EndingShape { Circle(LengthOrKeyword), Ellipse(LengthOrPercentageOrKeyword), } impl ::cssparser::ToCss for EndingShape { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { EndingShape::Circle(ref length) => { try!(dest.write_str("circle ")); try!(length.to_css(dest)); }, EndingShape::Ellipse(ref length) => { try!(dest.write_str("ellipse ")); try!(length.to_css(dest)); }, } Ok(()) } } impl fmt::Debug for EndingShape { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { EndingShape::Circle(ref length) => { let _ = write!(f, "circle {:?}", length); }, EndingShape::Ellipse(ref length) => { let _ = write!(f, "ellipse {:?}", length); } } Ok(()) } } impl ToComputedValue for specified::GradientEndingShape { type ComputedValue = EndingShape; #[inline] fn to_computed_value(&self, context: &Context) -> EndingShape { match *self { specified::GradientEndingShape::Circle(ref length) => { EndingShape::Circle(length.to_computed_value(context)) }, specified::GradientEndingShape::Ellipse(ref length) => { EndingShape::Ellipse(length.to_computed_value(context)) }, } } #[inline] fn from_computed_value(computed: &EndingShape) -> Self { match *computed { EndingShape::Circle(ref length) => { specified::GradientEndingShape::Circle(ToComputedValue::from_computed_value(length)) }, EndingShape::Ellipse(ref length) => { specified::GradientEndingShape::Ellipse(ToComputedValue::from_computed_value(length)) }, } } } /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size #[derive(Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum LengthOrKeyword { Length(Length), Keyword(SizeKeyword), } impl ::cssparser::ToCss for LengthOrKeyword { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { LengthOrKeyword::Length(ref length) => length.to_css(dest), LengthOrKeyword::Keyword(keyword) => keyword.to_css(dest), } } } impl fmt::Debug for LengthOrKeyword { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { LengthOrKeyword::Length(ref length) => { let _ = write!(f, "{:?}", length); }, LengthOrKeyword::Keyword(keyword) => { let _ = write!(f, "{:?}", keyword); }, } Ok(()) } } impl ToComputedValue for specified::LengthOrKeyword { type ComputedValue = LengthOrKeyword; #[inline] fn to_computed_value(&self, context: &Context) -> LengthOrKeyword { match *self { specified::LengthOrKeyword::Length(length) => { LengthOrKeyword::Length(length.to_computed_value(context)) }, specified::LengthOrKeyword::Keyword(keyword) => { LengthOrKeyword::Keyword(keyword) }, } } #[inline] fn from_computed_value(computed: &LengthOrKeyword) -> Self { match *computed { LengthOrKeyword::Length(length) => { specified::LengthOrKeyword::Length(ToComputedValue::from_computed_value(&length)) }, LengthOrKeyword::Keyword(keyword) => { specified::LengthOrKeyword::Keyword(keyword) }, } } } /// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size #[derive(Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum LengthOrPercentageOrKeyword { LengthOrPercentage(LengthOrPercentage, LengthOrPercentage), Keyword(SizeKeyword), } impl ::cssparser::ToCss for LengthOrPercentageOrKeyword { fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match *self { LengthOrPercentageOrKeyword::LengthOrPercentage(ref first_len, second_len) => { try!(first_len.to_css(dest)); try!(dest.write_str(" ")); second_len.to_css(dest) }, LengthOrPercentageOrKeyword::Keyword(keyword) => keyword.to_css(dest), } } } impl fmt::Debug for LengthOrPercentageOrKeyword { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { LengthOrPercentageOrKeyword::LengthOrPercentage(ref first_len, second_len) => { let _ = write!(f, "{:?} {:?}", first_len, second_len); }, LengthOrPercentageOrKeyword::Keyword(keyword) => { let _ = write!(f, "{:?}", keyword); }, } Ok(()) } } impl ToComputedValue for specified::LengthOrPercentageOrKeyword { type ComputedValue = LengthOrPercentageOrKeyword; #[inline] fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrKeyword { match *self { specified::LengthOrPercentageOrKeyword::LengthOrPercentage(first_len, second_len) => { LengthOrPercentageOrKeyword::LengthOrPercentage(first_len.to_computed_value(context), second_len.to_computed_value(context)) }, specified::LengthOrPercentageOrKeyword::Keyword(keyword) => { LengthOrPercentageOrKeyword::Keyword(keyword) }, } } #[inline] fn from_computed_value(computed: &LengthOrPercentageOrKeyword) -> Self { match *computed { LengthOrPercentageOrKeyword::LengthOrPercentage(first_len, second_len) => { specified::LengthOrPercentageOrKeyword::LengthOrPercentage( ToComputedValue::from_computed_value(&first_len), ToComputedValue::from_computed_value(&second_len)) }, LengthOrPercentageOrKeyword::Keyword(keyword) => { specified::LengthOrPercentageOrKeyword::Keyword(keyword) }, } } }