servo/components/style/values/specified/effects.rs

224 lines
8.2 KiB
Rust

/* 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 effects.
use cssparser::Parser;
use parser::{Parse, ParserContext};
use style_traits::{ParseError, StyleParseError};
#[cfg(not(feature = "gecko"))]
use values::Impossible;
use values::computed::{Context, Number as ComputedNumber, ToComputedValue};
use values::computed::effects::BoxShadow as ComputedBoxShadow;
use values::computed::effects::SimpleShadow as ComputedSimpleShadow;
use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow;
use values::specified::{Angle, NumberOrPercentage};
use values::specified::color::Color;
use values::specified::length::Length;
#[cfg(feature = "gecko")]
use values::specified::url::SpecifiedUrl;
/// A specified value for a single shadow of the `box-shadow` property.
pub type BoxShadow = GenericBoxShadow<Option<Color>, Length, Option<Length>>;
/// A specified value for a single `filter`.
#[cfg(feature = "gecko")]
pub type Filter = GenericFilter<Angle, Factor, Length, SimpleShadow>;
/// A specified value for a single `filter`.
#[cfg(not(feature = "gecko"))]
pub type Filter = GenericFilter<Angle, Factor, Length, Impossible>;
/// A value for the `<factor>` parts in `Filter`.
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Factor(NumberOrPercentage);
impl Parse for Factor {
#[inline]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
NumberOrPercentage::parse_non_negative(context, input).map(Factor)
}
}
impl ToComputedValue for Factor {
type ComputedValue = ComputedNumber;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
use values::computed::NumberOrPercentage;
match self.0.to_computed_value(context) {
NumberOrPercentage::Number(n) => n,
NumberOrPercentage::Percentage(p) => p.0,
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Factor(NumberOrPercentage::Number(ToComputedValue::from_computed_value(computed)))
}
}
/// A specified value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<Option<Color>, Length, Option<Length>>;
impl Parse for BoxShadow {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let mut lengths = None;
let mut color = None;
let mut inset = false;
loop {
if !inset {
if input.try(|input| input.expect_ident_matching("inset")).is_ok() {
inset = true;
continue;
}
}
if lengths.is_none() {
let value = input.try::<_, _, ParseError>(|i| {
let horizontal = Length::parse(context, i)?;
let vertical = Length::parse(context, i)?;
let (blur, spread) = match i.try::<_, _, ParseError>(|i| Length::parse_non_negative(context, i)) {
Ok(blur) => {
let spread = i.try(|i| Length::parse(context, i)).ok();
(Some(blur), spread)
},
Err(_) => (None, None),
};
Ok((horizontal, vertical, blur, spread))
});
if let Ok(value) = value {
lengths = Some(value);
continue;
}
}
if color.is_none() {
if let Ok(value) = input.try(|i| Color::parse(context, i)) {
color = Some(value);
continue;
}
}
break;
}
let lengths = lengths.ok_or(StyleParseError::UnspecifiedError)?;
Ok(BoxShadow {
base: SimpleShadow {
color: color,
horizontal: lengths.0,
vertical: lengths.1,
blur: lengths.2,
},
spread: lengths.3,
inset: inset,
})
}
}
impl ToComputedValue for BoxShadow {
type ComputedValue = ComputedBoxShadow;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
ComputedBoxShadow {
base: self.base.to_computed_value(context),
spread: self.spread.as_ref().unwrap_or(&Length::zero()).to_computed_value(context),
inset: self.inset,
}
}
#[inline]
fn from_computed_value(computed: &ComputedBoxShadow) -> Self {
BoxShadow {
base: ToComputedValue::from_computed_value(&computed.base),
spread: Some(ToComputedValue::from_computed_value(&computed.spread)),
inset: computed.inset,
}
}
}
impl Parse for Filter {
#[inline]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
#[cfg(feature = "gecko")]
{
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
return Ok(GenericFilter::Url(url));
}
}
let function = input.expect_function()?.clone();
input.parse_nested_block(|i| {
try_match_ident_ignore_ascii_case! { function,
"blur" => Ok(GenericFilter::Blur(Length::parse_non_negative(context, i)?)),
"brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)),
"contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)),
"grayscale" => Ok(GenericFilter::Grayscale(Factor::parse(context, i)?)),
"hue-rotate" => Ok(GenericFilter::HueRotate(Angle::parse(context, i)?)),
"invert" => Ok(GenericFilter::Invert(Factor::parse(context, i)?)),
"opacity" => Ok(GenericFilter::Opacity(Factor::parse(context, i)?)),
"saturate" => Ok(GenericFilter::Saturate(Factor::parse(context, i)?)),
"sepia" => Ok(GenericFilter::Sepia(Factor::parse(context, i)?)),
"drop-shadow" => Ok(GenericFilter::DropShadow(Parse::parse(context, i)?)),
}
})
}
}
impl Parse for SimpleShadow {
#[inline]
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<Self, ParseError<'i>> {
let color = input.try(|i| Color::parse(context, i)).ok();
let horizontal = Length::parse(context, input)?;
let vertical = Length::parse(context, input)?;
let blur = input.try(|i| Length::parse_non_negative(context, i)).ok();
let color = color.or_else(|| input.try(|i| Color::parse(context, i)).ok());
Ok(SimpleShadow {
color: color,
horizontal: horizontal,
vertical: vertical,
blur: blur,
})
}
}
impl ToComputedValue for SimpleShadow {
type ComputedValue = ComputedSimpleShadow;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
ComputedSimpleShadow {
color:
self.color.as_ref().unwrap_or(&Color::CurrentColor).to_computed_value(context),
horizontal: self.horizontal.to_computed_value(context),
vertical: self.vertical.to_computed_value(context),
blur:
self.blur.as_ref().unwrap_or(&Length::zero()).to_computed_value(context),
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
SimpleShadow {
color: Some(ToComputedValue::from_computed_value(&computed.color)),
horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
vertical: ToComputedValue::from_computed_value(&computed.vertical),
blur: Some(ToComputedValue::from_computed_value(&computed.blur)),
}
}
}