mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Use generics for the filter property
This introduces an additional shadow type for drop-shadow().
This commit is contained in:
parent
e41b7d06b4
commit
6f4061d4ad
21 changed files with 822 additions and 496 deletions
|
@ -3444,7 +3444,7 @@ fn static_assert() {
|
|||
%>
|
||||
|
||||
pub fn set_filter(&mut self, v: longhands::filter::computed_value::T) {
|
||||
use properties::longhands::filter::computed_value::Filter::*;
|
||||
use values::generics::effects::Filter::*;
|
||||
use gecko_bindings::structs::nsCSSShadowArray;
|
||||
use gecko_bindings::structs::nsStyleFilter;
|
||||
use gecko_bindings::structs::NS_STYLE_FILTER_BLUR;
|
||||
|
@ -3464,11 +3464,11 @@ fn static_assert() {
|
|||
}
|
||||
|
||||
unsafe {
|
||||
Gecko_ResetFilters(&mut self.gecko, v.filters.len());
|
||||
Gecko_ResetFilters(&mut self.gecko, v.0.len());
|
||||
}
|
||||
debug_assert!(v.filters.len() == self.gecko.mFilters.len());
|
||||
debug_assert!(v.0.len() == self.gecko.mFilters.len());
|
||||
|
||||
for (servo, gecko_filter) in v.filters.into_iter().zip(self.gecko.mFilters.iter_mut()) {
|
||||
for (servo, gecko_filter) in v.0.into_vec().into_iter().zip(self.gecko.mFilters.iter_mut()) {
|
||||
match servo {
|
||||
% for func in FILTER_FUNCTIONS:
|
||||
${func}(factor) => fill_filter(NS_STYLE_FILTER_${func.upper()},
|
||||
|
@ -3497,7 +3497,7 @@ fn static_assert() {
|
|||
}
|
||||
|
||||
let mut gecko_shadow = init_shadow(gecko_filter);
|
||||
gecko_shadow.mArray[0].set_from_shadow(shadow);
|
||||
gecko_shadow.mArray[0].set_from_drop_shadow(shadow);
|
||||
},
|
||||
Url(ref url) => {
|
||||
unsafe {
|
||||
|
@ -3515,7 +3515,7 @@ fn static_assert() {
|
|||
}
|
||||
|
||||
pub fn clone_filter(&self) -> longhands::filter::computed_value::T {
|
||||
use properties::longhands::filter::computed_value::Filter::*;
|
||||
use values::generics::effects::{Filter, FilterList};
|
||||
use values::specified::url::SpecifiedUrl;
|
||||
use gecko_bindings::structs::NS_STYLE_FILTER_BLUR;
|
||||
use gecko_bindings::structs::NS_STYLE_FILTER_BRIGHTNESS;
|
||||
|
@ -3534,35 +3534,36 @@ fn static_assert() {
|
|||
match filter.mType {
|
||||
% for func in FILTER_FUNCTIONS:
|
||||
NS_STYLE_FILTER_${func.upper()} => {
|
||||
filters.push(${func}(
|
||||
filters.push(Filter::${func}(
|
||||
GeckoStyleCoordConvertible::from_gecko_style_coord(
|
||||
&filter.mFilterParameter).unwrap()));
|
||||
},
|
||||
% endfor
|
||||
NS_STYLE_FILTER_BLUR => {
|
||||
filters.push(Blur(Au::from_gecko_style_coord(
|
||||
filters.push(Filter::Blur(Au::from_gecko_style_coord(
|
||||
&filter.mFilterParameter).unwrap()));
|
||||
},
|
||||
NS_STYLE_FILTER_HUE_ROTATE => {
|
||||
filters.push(HueRotate(
|
||||
filters.push(Filter::HueRotate(
|
||||
GeckoStyleCoordConvertible::from_gecko_style_coord(
|
||||
&filter.mFilterParameter).unwrap()));
|
||||
},
|
||||
NS_STYLE_FILTER_DROP_SHADOW => {
|
||||
filters.push(unsafe {
|
||||
DropShadow((**filter.__bindgen_anon_1.mDropShadow.as_ref()).mArray[0].to_shadow())
|
||||
Filter::DropShadow((**filter.__bindgen_anon_1.mDropShadow.as_ref()).mArray[0].to_drop_shadow())
|
||||
});
|
||||
},
|
||||
NS_STYLE_FILTER_URL => {
|
||||
filters.push(unsafe {
|
||||
(Url(SpecifiedUrl::from_url_value_data(
|
||||
&(**filter.__bindgen_anon_1.mURL.as_ref())._base).unwrap()))
|
||||
Filter::Url(
|
||||
SpecifiedUrl::from_url_value_data(&(**filter.__bindgen_anon_1.mURL.as_ref())._base).unwrap()
|
||||
)
|
||||
});
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
longhands::filter::computed_value::T::new(filters)
|
||||
FilterList(filters.into_boxed_slice())
|
||||
}
|
||||
|
||||
</%self:impl_trait>
|
||||
|
|
|
@ -14,12 +14,9 @@ use euclid::{Point2D, Size2D};
|
|||
#[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID;
|
||||
#[cfg(feature = "gecko")] use gecko_bindings::sugar::ownership::{HasFFI, HasSimpleFFI};
|
||||
#[cfg(feature = "gecko")] use gecko_string_cache::Atom;
|
||||
#[cfg(feature = "gecko")] use gecko::url::SpecifiedUrl;
|
||||
use properties::{CSSWideKeyword, PropertyDeclaration};
|
||||
use properties::longhands;
|
||||
use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
|
||||
use properties::longhands::filter::computed_value::Filter;
|
||||
use properties::longhands::filter::computed_value::T as Filters;
|
||||
use properties::longhands::font_weight::computed_value::T as FontWeight;
|
||||
use properties::longhands::font_stretch::computed_value::T as FontStretch;
|
||||
use properties::longhands::text_shadow::computed_value::T as TextShadowList;
|
||||
|
@ -37,12 +34,14 @@ use std::cmp;
|
|||
use style_traits::ParseError;
|
||||
use super::ComputedValues;
|
||||
use values::{Auto, CSSFloat, CustomIdent, Either};
|
||||
use values::animated::effects::{Filter as AnimatedFilter, FilterList as AnimatedFilterList};
|
||||
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
||||
use values::computed::{BorderCornerRadius, ClipRect};
|
||||
use values::computed::{CalcLengthOrPercentage, Color, Context, ComputedValueAsSpecified};
|
||||
use values::computed::{LengthOrPercentage, MaxLength, MozLength, Shadow, ToComputedValue};
|
||||
use values::generics::{SVGPaint, SVGPaintKind};
|
||||
use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
|
||||
use values::generics::effects::Filter;
|
||||
use values::generics::position as generic_position;
|
||||
use values::specified::length::Percentage;
|
||||
|
||||
|
@ -3196,135 +3195,61 @@ impl Animatable for IntermediateShadowList {
|
|||
}
|
||||
}
|
||||
|
||||
/// Intermediate type for filter property.
|
||||
/// The difference from normal filter type is that this structure uses
|
||||
/// IntermediateColor into DropShadow's value.
|
||||
pub type IntermediateFilters = Vec<IntermediateFilter>;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
#[allow(missing_docs)]
|
||||
pub enum IntermediateFilter {
|
||||
Blur(Au),
|
||||
Brightness(CSSFloat),
|
||||
Contrast(CSSFloat),
|
||||
Grayscale(CSSFloat),
|
||||
HueRotate(Angle),
|
||||
Invert(CSSFloat),
|
||||
Opacity(CSSFloat),
|
||||
Saturate(CSSFloat),
|
||||
Sepia(CSSFloat),
|
||||
% if product == "gecko":
|
||||
DropShadow(IntermediateShadow),
|
||||
Url(SpecifiedUrl),
|
||||
% endif
|
||||
}
|
||||
|
||||
impl From<Filters> for IntermediateFilters {
|
||||
fn from(filters: Filters) -> IntermediateFilters {
|
||||
filters.filters.into_iter().map(|f| f.into()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IntermediateFilters> for Filters {
|
||||
fn from(filters: IntermediateFilters) -> Filters {
|
||||
Filters::new(filters.into_iter().map(|f| f.into()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
<%
|
||||
FILTER_FUNCTIONS = [ 'Blur', 'Brightness', 'Contrast', 'Grayscale',
|
||||
'HueRotate', 'Invert', 'Opacity', 'Saturate',
|
||||
'Sepia' ]
|
||||
%>
|
||||
|
||||
impl From<Filter> for IntermediateFilter {
|
||||
fn from(filter: Filter) -> IntermediateFilter {
|
||||
use properties::longhands::filter::computed_value::Filter::*;
|
||||
match filter {
|
||||
% for func in FILTER_FUNCTIONS:
|
||||
${func}(val) => IntermediateFilter::${func}(val),
|
||||
% endfor
|
||||
% if product == "gecko":
|
||||
DropShadow(shadow) => {
|
||||
IntermediateFilter::DropShadow(shadow.into())
|
||||
},
|
||||
Url(ref url) => {
|
||||
IntermediateFilter::Url(url.clone())
|
||||
},
|
||||
% endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IntermediateFilter> for Filter {
|
||||
fn from(filter: IntermediateFilter) -> Filter {
|
||||
match filter {
|
||||
% for func in FILTER_FUNCTIONS:
|
||||
IntermediateFilter::${func}(val) => Filter::${func}(val),
|
||||
% endfor
|
||||
% if product == "gecko":
|
||||
IntermediateFilter::DropShadow(shadow) => {
|
||||
Filter::DropShadow(shadow.into())
|
||||
},
|
||||
IntermediateFilter::Url(ref url) => {
|
||||
Filter::Url(url.clone())
|
||||
},
|
||||
% endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// https://drafts.fxtf.org/filters/#animation-of-filters
|
||||
fn add_weighted_filter_function_impl(from: &IntermediateFilter,
|
||||
to: &IntermediateFilter,
|
||||
fn add_weighted_filter_function_impl(from: &AnimatedFilter,
|
||||
to: &AnimatedFilter,
|
||||
self_portion: f64,
|
||||
other_portion: f64)
|
||||
-> Result<IntermediateFilter, ()> {
|
||||
-> Result<AnimatedFilter, ()> {
|
||||
match (from, to) {
|
||||
% for func in [ 'Blur', 'HueRotate' ]:
|
||||
(&IntermediateFilter::${func}(from_value),
|
||||
&IntermediateFilter::${func}(to_value)) => {
|
||||
Ok(IntermediateFilter::${func}(
|
||||
try!(from_value.add_weighted(&to_value,
|
||||
self_portion,
|
||||
other_portion))))
|
||||
(&Filter::${func}(from_value), &Filter::${func}(to_value)) => {
|
||||
Ok(Filter::${func}(from_value.add_weighted(
|
||||
&to_value,
|
||||
self_portion,
|
||||
other_portion,
|
||||
)?))
|
||||
},
|
||||
% endfor
|
||||
% for func in [ 'Grayscale', 'Invert', 'Sepia' ]:
|
||||
(&IntermediateFilter::${func}(from_value),
|
||||
&IntermediateFilter::${func}(to_value)) => {
|
||||
Ok(IntermediateFilter::${func}(try!(
|
||||
add_weighted_with_initial_val(&from_value,
|
||||
&to_value,
|
||||
self_portion,
|
||||
other_portion,
|
||||
&0.0))))
|
||||
(&Filter::${func}(from_value), &Filter::${func}(to_value)) => {
|
||||
Ok(Filter::${func}(add_weighted_with_initial_val(
|
||||
&from_value,
|
||||
&to_value,
|
||||
self_portion,
|
||||
other_portion,
|
||||
&0.0,
|
||||
)?))
|
||||
},
|
||||
% endfor
|
||||
% for func in [ 'Brightness', 'Contrast', 'Opacity', 'Saturate' ]:
|
||||
(&IntermediateFilter::${func}(from_value),
|
||||
&IntermediateFilter::${func}(to_value)) => {
|
||||
Ok(IntermediateFilter::${func}(try!(
|
||||
add_weighted_with_initial_val(&from_value,
|
||||
&to_value,
|
||||
self_portion,
|
||||
other_portion,
|
||||
&1.0))))
|
||||
(&Filter::${func}(from_value), &Filter::${func}(to_value)) => {
|
||||
Ok(Filter::${func}(add_weighted_with_initial_val(
|
||||
&from_value,
|
||||
&to_value,
|
||||
self_portion,
|
||||
other_portion,
|
||||
&1.0,
|
||||
)?))
|
||||
},
|
||||
% endfor
|
||||
% if product == "gecko":
|
||||
(&IntermediateFilter::DropShadow(from_value),
|
||||
&IntermediateFilter::DropShadow(to_value)) => {
|
||||
Ok(IntermediateFilter::DropShadow(try!(
|
||||
from_value.add_weighted(&to_value,
|
||||
self_portion,
|
||||
other_portion))))
|
||||
},
|
||||
(&IntermediateFilter::Url(_),
|
||||
&IntermediateFilter::Url(_)) => {
|
||||
Err(())
|
||||
},
|
||||
(&Filter::DropShadow(ref from_value), &Filter::DropShadow(ref to_value)) => {
|
||||
Ok(Filter::DropShadow(from_value.add_weighted(
|
||||
&to_value,
|
||||
self_portion,
|
||||
other_portion,
|
||||
)?))
|
||||
},
|
||||
(&Filter::Url(_), &Filter::Url(_)) => {
|
||||
Err(())
|
||||
},
|
||||
% endif
|
||||
_ => {
|
||||
// If specified the different filter functions,
|
||||
|
@ -3335,10 +3260,10 @@ fn add_weighted_filter_function_impl(from: &IntermediateFilter,
|
|||
}
|
||||
|
||||
/// https://drafts.fxtf.org/filters/#animation-of-filters
|
||||
fn add_weighted_filter_function(from: Option<<&IntermediateFilter>,
|
||||
to: Option<<&IntermediateFilter>,
|
||||
fn add_weighted_filter_function(from: Option<<&AnimatedFilter>,
|
||||
to: Option<<&AnimatedFilter>,
|
||||
self_portion: f64,
|
||||
other_portion: f64) -> Result<IntermediateFilter, ()> {
|
||||
other_portion: f64) -> Result<AnimatedFilter, ()> {
|
||||
match (from, to) {
|
||||
(Some(f), Some(t)) => {
|
||||
add_weighted_filter_function_impl(f, t, self_portion, other_portion)
|
||||
|
@ -3353,19 +3278,18 @@ fn add_weighted_filter_function(from: Option<<&IntermediateFilter>,
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_filter_square_distance(from: &IntermediateFilter,
|
||||
to: &IntermediateFilter)
|
||||
fn compute_filter_square_distance(from: &AnimatedFilter,
|
||||
to: &AnimatedFilter)
|
||||
-> Result<f64, ()> {
|
||||
match (from, to) {
|
||||
% for func in FILTER_FUNCTIONS :
|
||||
(&IntermediateFilter::${func}(f),
|
||||
&IntermediateFilter::${func}(t)) => {
|
||||
(&Filter::${func}(f),
|
||||
&Filter::${func}(t)) => {
|
||||
Ok(try!(f.compute_squared_distance(&t)))
|
||||
},
|
||||
% endfor
|
||||
% if product == "gecko":
|
||||
(&IntermediateFilter::DropShadow(f),
|
||||
&IntermediateFilter::DropShadow(t)) => {
|
||||
(&Filter::DropShadow(ref f), &Filter::DropShadow(ref t)) => {
|
||||
Ok(try!(f.compute_squared_distance(&t)))
|
||||
},
|
||||
% endif
|
||||
|
@ -3375,38 +3299,34 @@ fn compute_filter_square_distance(from: &IntermediateFilter,
|
|||
}
|
||||
}
|
||||
|
||||
impl Animatable for IntermediateFilters {
|
||||
impl Animatable for AnimatedFilterList {
|
||||
#[inline]
|
||||
fn add_weighted(&self, other: &Self,
|
||||
self_portion: f64, other_portion: f64) -> Result<Self, ()> {
|
||||
let mut filters: IntermediateFilters = Vec::new();
|
||||
let mut from_iter = self.iter();
|
||||
let mut to_iter = (&other).iter();
|
||||
let mut filters = vec![];
|
||||
let mut from_iter = self.0.iter();
|
||||
let mut to_iter = other.0.iter();
|
||||
|
||||
let mut from = from_iter.next();
|
||||
let mut to = to_iter.next();
|
||||
while (from,to) != (None, None) {
|
||||
while from.is_some() || to.is_some() {
|
||||
filters.push(try!(add_weighted_filter_function(from,
|
||||
to,
|
||||
self_portion,
|
||||
other_portion)));
|
||||
if from != None {
|
||||
if from.is_some() {
|
||||
from = from_iter.next();
|
||||
}
|
||||
if to != None {
|
||||
if to.is_some() {
|
||||
to = to_iter.next();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(filters)
|
||||
Ok(filters.into())
|
||||
}
|
||||
|
||||
fn add(&self, other: &Self) -> Result<Self, ()> {
|
||||
let from_list = &self;
|
||||
let to_list = &other;
|
||||
let filters: IntermediateFilters =
|
||||
vec![&from_list[..], &to_list[..]].concat();
|
||||
Ok(filters)
|
||||
Ok(self.0.iter().chain(other.0.iter()).cloned().collect::<Vec<_>>().into())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -3417,20 +3337,20 @@ impl Animatable for IntermediateFilters {
|
|||
#[inline]
|
||||
fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||
let mut square_distance: f64 = 0.0;
|
||||
let mut from_iter = self.iter();
|
||||
let mut to_iter = (&other).iter();
|
||||
let mut from_iter = self.0.iter();
|
||||
let mut to_iter = other.0.iter();
|
||||
|
||||
let mut from = from_iter.next();
|
||||
let mut to = to_iter.next();
|
||||
while (from,to) != (None, None) {
|
||||
while from.is_some() || to.is_some() {
|
||||
let current_square_distance: f64 ;
|
||||
if from == None {
|
||||
if from.is_none() {
|
||||
let none = try!(add_weighted_filter_function(to, to, 0.0, 0.0));
|
||||
current_square_distance =
|
||||
compute_filter_square_distance(&none, &(to.unwrap())).unwrap();
|
||||
|
||||
to = to_iter.next();
|
||||
} else if to == None {
|
||||
} else if to.is_none() {
|
||||
let none = try!(add_weighted_filter_function(from, from, 0.0, 0.0));
|
||||
current_square_distance =
|
||||
compute_filter_square_distance(&none, &(from.unwrap())).unwrap();
|
||||
|
|
|
@ -41,339 +41,15 @@ ${helpers.predefined_type("clip",
|
|||
allow_quirks=True,
|
||||
spec="https://drafts.fxtf.org/css-masking/#clip-property")}
|
||||
|
||||
<%helpers:longhand name="filter" animation_value_type="IntermediateFilters" extra_prefixes="webkit"
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB"
|
||||
spec="https://drafts.fxtf.org/filters/#propdef-filter">
|
||||
//pub use self::computed_value::T as SpecifiedValue;
|
||||
use std::fmt;
|
||||
use style_traits::{HasViewportPercentage, ToCss};
|
||||
use values::CSSFloat;
|
||||
use values::specified::{Angle, Length};
|
||||
#[cfg(feature = "gecko")]
|
||||
use values::specified::Shadow;
|
||||
#[cfg(feature = "gecko")]
|
||||
use values::specified::url::SpecifiedUrl;
|
||||
|
||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub struct SpecifiedValue(pub Vec<SpecifiedFilter>);
|
||||
|
||||
impl HasViewportPercentage for SpecifiedFilter {
|
||||
fn has_viewport_percentage(&self) -> bool {
|
||||
match *self {
|
||||
SpecifiedFilter::Blur(ref length) => length.has_viewport_percentage(),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(pcwalton): `drop-shadow`
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||
pub enum SpecifiedFilter {
|
||||
Blur(Length),
|
||||
Brightness(CSSFloat),
|
||||
Contrast(CSSFloat),
|
||||
Grayscale(CSSFloat),
|
||||
HueRotate(Angle),
|
||||
Invert(CSSFloat),
|
||||
Opacity(CSSFloat),
|
||||
Saturate(CSSFloat),
|
||||
Sepia(CSSFloat),
|
||||
% if product == "gecko":
|
||||
DropShadow(Shadow),
|
||||
Url(SpecifiedUrl),
|
||||
% endif
|
||||
}
|
||||
|
||||
pub mod computed_value {
|
||||
use app_units::Au;
|
||||
use values::CSSFloat;
|
||||
#[cfg(feature = "gecko")]
|
||||
use values::computed::Shadow;
|
||||
use values::computed::Angle;
|
||||
#[cfg(feature = "gecko")]
|
||||
use values::specified::url::SpecifiedUrl;
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
||||
pub enum Filter {
|
||||
Blur(Au),
|
||||
Brightness(CSSFloat),
|
||||
Contrast(CSSFloat),
|
||||
Grayscale(CSSFloat),
|
||||
HueRotate(Angle),
|
||||
Invert(CSSFloat),
|
||||
Opacity(CSSFloat),
|
||||
Saturate(CSSFloat),
|
||||
Sepia(CSSFloat),
|
||||
% if product == "gecko":
|
||||
DropShadow(Shadow),
|
||||
Url(SpecifiedUrl),
|
||||
% endif
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
||||
pub struct T { pub filters: Vec<Filter> }
|
||||
|
||||
impl T {
|
||||
/// Creates a new filter pipeline.
|
||||
#[inline]
|
||||
pub fn new(filters: Vec<Filter>) -> T {
|
||||
T
|
||||
{
|
||||
filters: filters,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a new filter to the filter pipeline.
|
||||
#[inline]
|
||||
pub fn push(&mut self, filter: Filter) {
|
||||
self.filters.push(filter)
|
||||
}
|
||||
|
||||
/// Returns true if this filter pipeline is empty and false otherwise.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.filters.is_empty()
|
||||
}
|
||||
|
||||
/// Returns the resulting opacity of this filter pipeline.
|
||||
#[inline]
|
||||
pub fn opacity(&self) -> CSSFloat {
|
||||
let mut opacity = 1.0;
|
||||
|
||||
for filter in &self.filters {
|
||||
if let Filter::Opacity(ref opacity_value) = *filter {
|
||||
opacity *= *opacity_value
|
||||
}
|
||||
}
|
||||
opacity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for computed_value::T {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
let mut iter = self.filters.iter();
|
||||
if let Some(filter) = iter.next() {
|
||||
filter.to_css(dest)?;
|
||||
} else {
|
||||
dest.write_str("none")?;
|
||||
return Ok(())
|
||||
}
|
||||
for filter in iter {
|
||||
dest.write_str(" ")?;
|
||||
filter.to_css(dest)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for SpecifiedValue {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
let mut iter = self.0.iter();
|
||||
if let Some(filter) = iter.next() {
|
||||
filter.to_css(dest)?;
|
||||
} else {
|
||||
dest.write_str("none")?;
|
||||
return Ok(())
|
||||
}
|
||||
for filter in iter {
|
||||
dest.write_str(" ")?;
|
||||
filter.to_css(dest)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for computed_value::Filter {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
match *self {
|
||||
computed_value::Filter::Blur(ref value) => {
|
||||
dest.write_str("blur(")?;
|
||||
value.to_css(dest)?;
|
||||
dest.write_str(")")?;
|
||||
}
|
||||
computed_value::Filter::Brightness(value) => write!(dest, "brightness({})", value)?,
|
||||
computed_value::Filter::Contrast(value) => write!(dest, "contrast({})", value)?,
|
||||
computed_value::Filter::Grayscale(value) => write!(dest, "grayscale({})", value)?,
|
||||
computed_value::Filter::HueRotate(value) => {
|
||||
dest.write_str("hue-rotate(")?;
|
||||
value.to_css(dest)?;
|
||||
dest.write_str(")")?;
|
||||
}
|
||||
computed_value::Filter::Invert(value) => write!(dest, "invert({})", value)?,
|
||||
computed_value::Filter::Opacity(value) => write!(dest, "opacity({})", value)?,
|
||||
computed_value::Filter::Saturate(value) => write!(dest, "saturate({})", value)?,
|
||||
computed_value::Filter::Sepia(value) => write!(dest, "sepia({})", value)?,
|
||||
% if product == "gecko":
|
||||
computed_value::Filter::DropShadow(shadow) => {
|
||||
dest.write_str("drop-shadow(")?;
|
||||
shadow.to_css(dest)?;
|
||||
dest.write_str(")")?;
|
||||
}
|
||||
computed_value::Filter::Url(ref url) => {
|
||||
url.to_css(dest)?;
|
||||
}
|
||||
% endif
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for SpecifiedFilter {
|
||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||
match *self {
|
||||
SpecifiedFilter::Blur(ref value) => {
|
||||
dest.write_str("blur(")?;
|
||||
value.to_css(dest)?;
|
||||
dest.write_str(")")?;
|
||||
}
|
||||
SpecifiedFilter::Brightness(value) => write!(dest, "brightness({})", value)?,
|
||||
SpecifiedFilter::Contrast(value) => write!(dest, "contrast({})", value)?,
|
||||
SpecifiedFilter::Grayscale(value) => write!(dest, "grayscale({})", value)?,
|
||||
SpecifiedFilter::HueRotate(value) => {
|
||||
dest.write_str("hue-rotate(")?;
|
||||
value.to_css(dest)?;
|
||||
dest.write_str(")")?;
|
||||
}
|
||||
SpecifiedFilter::Invert(value) => write!(dest, "invert({})", value)?,
|
||||
SpecifiedFilter::Opacity(value) => write!(dest, "opacity({})", value)?,
|
||||
SpecifiedFilter::Saturate(value) => write!(dest, "saturate({})", value)?,
|
||||
SpecifiedFilter::Sepia(value) => write!(dest, "sepia({})", value)?,
|
||||
% if product == "gecko":
|
||||
SpecifiedFilter::DropShadow(ref shadow) => {
|
||||
dest.write_str("drop-shadow(")?;
|
||||
shadow.to_css(dest)?;
|
||||
dest.write_str(")")?;
|
||||
}
|
||||
SpecifiedFilter::Url(ref url) => {
|
||||
url.to_css(dest)?;
|
||||
}
|
||||
% endif
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
computed_value::T::new(Vec::new())
|
||||
}
|
||||
|
||||
pub fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
|
||||
-> Result<SpecifiedValue, ParseError<'i>> {
|
||||
let mut filters = Vec::new();
|
||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
||||
return Ok(SpecifiedValue(filters))
|
||||
}
|
||||
loop {
|
||||
% if product == "gecko":
|
||||
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
|
||||
filters.push(SpecifiedFilter::Url(url));
|
||||
} else
|
||||
% endif
|
||||
if let Ok(function_name) = input.try(|input| input.expect_function()) {
|
||||
filters.push(input.parse_nested_block(|input| {
|
||||
match_ignore_ascii_case! { &function_name,
|
||||
"blur" => specified::Length::parse_non_negative(context, input).map(SpecifiedFilter::Blur),
|
||||
"brightness" => parse_factor(input).map(SpecifiedFilter::Brightness),
|
||||
"contrast" => parse_factor(input).map(SpecifiedFilter::Contrast),
|
||||
"grayscale" => parse_factor(input).map(SpecifiedFilter::Grayscale),
|
||||
"hue-rotate" => Angle::parse(context, input).map(SpecifiedFilter::HueRotate),
|
||||
"invert" => parse_factor(input).map(SpecifiedFilter::Invert),
|
||||
"opacity" => parse_factor(input).map(SpecifiedFilter::Opacity),
|
||||
"saturate" => parse_factor(input).map(SpecifiedFilter::Saturate),
|
||||
"sepia" => parse_factor(input).map(SpecifiedFilter::Sepia),
|
||||
% if product == "gecko":
|
||||
"drop-shadow" => specified::Shadow::parse(context, input, true)
|
||||
.map(SpecifiedFilter::DropShadow),
|
||||
% endif
|
||||
_ => Err(StyleParseError::UnexpectedFunction(function_name.clone()).into())
|
||||
}
|
||||
})?);
|
||||
} else if filters.is_empty() {
|
||||
return Err(StyleParseError::UnspecifiedError.into())
|
||||
} else {
|
||||
return Ok(SpecifiedValue(filters))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_factor<'i, 't>(input: &mut Parser<'i, 't>) -> Result<::values::CSSFloat, ParseError<'i>> {
|
||||
use cssparser::Token;
|
||||
match input.next() {
|
||||
Ok(Token::Number { value, .. }) if value.is_sign_positive() => Ok(value),
|
||||
Ok(Token::Percentage { unit_value, .. }) if unit_value.is_sign_positive() => Ok(unit_value),
|
||||
Ok(t) => Err(BasicParseError::UnexpectedToken(t).into()),
|
||||
Err(e) => Err(e.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for SpecifiedValue {
|
||||
type ComputedValue = computed_value::T;
|
||||
|
||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||
computed_value::T{ filters: self.0.iter().map(|value| {
|
||||
match *value {
|
||||
SpecifiedFilter::Blur(ref factor) =>
|
||||
computed_value::Filter::Blur(factor.to_computed_value(context)),
|
||||
SpecifiedFilter::Brightness(factor) => computed_value::Filter::Brightness(factor),
|
||||
SpecifiedFilter::Contrast(factor) => computed_value::Filter::Contrast(factor),
|
||||
SpecifiedFilter::Grayscale(factor) => computed_value::Filter::Grayscale(factor),
|
||||
SpecifiedFilter::HueRotate(ref factor) => {
|
||||
computed_value::Filter::HueRotate(factor.to_computed_value(context))
|
||||
},
|
||||
SpecifiedFilter::Invert(factor) => computed_value::Filter::Invert(factor),
|
||||
SpecifiedFilter::Opacity(factor) => computed_value::Filter::Opacity(factor),
|
||||
SpecifiedFilter::Saturate(factor) => computed_value::Filter::Saturate(factor),
|
||||
SpecifiedFilter::Sepia(factor) => computed_value::Filter::Sepia(factor),
|
||||
% if product == "gecko":
|
||||
SpecifiedFilter::DropShadow(ref shadow) => {
|
||||
computed_value::Filter::DropShadow(shadow.to_computed_value(context))
|
||||
},
|
||||
SpecifiedFilter::Url(ref url) => {
|
||||
computed_value::Filter::Url(url.to_computed_value(context))
|
||||
}
|
||||
% endif
|
||||
}
|
||||
}).collect() }
|
||||
}
|
||||
|
||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
||||
SpecifiedValue(computed.filters.iter().map(|value| {
|
||||
match *value {
|
||||
computed_value::Filter::Blur(factor) =>
|
||||
SpecifiedFilter::Blur(ToComputedValue::from_computed_value(&factor)),
|
||||
computed_value::Filter::Brightness(factor) => SpecifiedFilter::Brightness(factor),
|
||||
computed_value::Filter::Contrast(factor) => SpecifiedFilter::Contrast(factor),
|
||||
computed_value::Filter::Grayscale(factor) => SpecifiedFilter::Grayscale(factor),
|
||||
computed_value::Filter::HueRotate(ref factor) => {
|
||||
SpecifiedFilter::HueRotate(ToComputedValue::from_computed_value(factor))
|
||||
},
|
||||
computed_value::Filter::Invert(factor) => SpecifiedFilter::Invert(factor),
|
||||
computed_value::Filter::Opacity(factor) => SpecifiedFilter::Opacity(factor),
|
||||
computed_value::Filter::Saturate(factor) => SpecifiedFilter::Saturate(factor),
|
||||
computed_value::Filter::Sepia(factor) => SpecifiedFilter::Sepia(factor),
|
||||
% if product == "gecko":
|
||||
computed_value::Filter::DropShadow(ref shadow) => {
|
||||
SpecifiedFilter::DropShadow(
|
||||
ToComputedValue::from_computed_value(shadow),
|
||||
)
|
||||
}
|
||||
computed_value::Filter::Url(ref url) => {
|
||||
SpecifiedFilter::Url(
|
||||
ToComputedValue::from_computed_value(url),
|
||||
)
|
||||
}
|
||||
% endif
|
||||
}
|
||||
}).collect())
|
||||
}
|
||||
}
|
||||
</%helpers:longhand>
|
||||
${helpers.predefined_type(
|
||||
"filter",
|
||||
"FilterList",
|
||||
"computed::FilterList::none()",
|
||||
animation_value_type="AnimatedFilterList",
|
||||
extra_prefixes="webkit",
|
||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
||||
spec="https://drafts.fxtf.org/filters/#propdef-filter",
|
||||
)}
|
||||
|
||||
${helpers.single_keyword("mix-blend-mode",
|
||||
"""normal multiply screen overlay darken lighten color-dodge
|
||||
|
|
|
@ -2064,7 +2064,7 @@ impl ComputedValues {
|
|||
let effects = self.get_effects();
|
||||
// TODO(gw): Add clip-path, isolation, mask-image, mask-border-source when supported.
|
||||
effects.opacity < 1.0 ||
|
||||
!effects.filter.is_empty() ||
|
||||
!effects.filter.0.is_empty() ||
|
||||
!effects.clip.is_auto() ||
|
||||
effects.mix_blend_mode != mix_blend_mode::T::normal
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue