mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Implement parsing of all gradients
This commit is contained in:
parent
522734de22
commit
26c98edd68
8 changed files with 962 additions and 393 deletions
460
components/style/values/computed/image.rs
Normal file
460
components/style/values/computed/image.rs
Normal file
|
@ -0,0 +1,460 @@
|
|||
/* 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<W>(&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<ColorStop>,
|
||||
/// 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<W>(&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<LengthOrPercentage>,
|
||||
}
|
||||
|
||||
impl ::cssparser::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.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<W>(&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<W>(&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<W>(&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)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue