/* 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, NonNegativeNumber as ComputedNonNegativeNumber, ToComputedValue}; use values::computed::effects::BoxShadow as ComputedBoxShadow; use values::computed::effects::SimpleShadow as ComputedSimpleShadow; use values::generics::NonNegative; 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::RGBAColor; use values::specified::length::{Length, NonNegativeLength}; #[cfg(feature = "gecko")] use values::specified::url::SpecifiedUrl; /// A specified value for a single shadow of the `box-shadow` property. pub type BoxShadow = GenericBoxShadow, Length, Option, Option>; /// A specified value for a single `filter`. #[cfg(feature = "gecko")] pub type Filter = GenericFilter; /// A specified value for a single `filter`. #[cfg(not(feature = "gecko"))] pub type Filter = GenericFilter; /// A value for the `` parts in `Filter`. #[derive(Clone, Debug, 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> { NumberOrPercentage::parse_non_negative(context, input).map(Factor) } } impl ToComputedValue for Factor { type ComputedValue = ComputedNonNegativeNumber; #[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.into(), NumberOrPercentage::Percentage(p) => p.0.into(), } } #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { Factor(NumberOrPercentage::Number(ToComputedValue::from_computed_value(&computed.0))) } } /// A specified value for the `drop-shadow()` filter. pub type SimpleShadow = GenericSimpleShadow, Length, Option>; impl Parse for BoxShadow { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { 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.into()), 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| RGBAColor::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> { #[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)?).into())), "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> { let color = input.try(|i| RGBAColor::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| RGBAColor::parse(context, i)).ok()); Ok(SimpleShadow { color: color, horizontal: horizontal, vertical: vertical, blur: blur.map(NonNegative::), }) } } impl ToComputedValue for SimpleShadow { type ComputedValue = ComputedSimpleShadow; #[inline] fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { ComputedSimpleShadow { color: self.color.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(&NonNegativeLength::zero()).to_computed_value(context), } } #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { SimpleShadow { color: 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)), } } }