Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make filter property animatable. #17288

Merged
merged 5 commits into from Jun 19, 2017

Make filter property animatable.

  • Loading branch information
mantaroh committed Jun 19, 2017
commit 87e580a33d91947553fd071cb989be55f39a870f
@@ -3434,6 +3434,15 @@ fn static_assert() {
}
}

<%
# This array is several filter function which has percentage or
# number value for function of clone / set.
# The setting / cloning process of other function(e.g. Blur / HueRotate) is
# different from these function. So this array don't include such function.
FILTER_FUNCTIONS = [ 'Brightness', 'Contrast', 'Grayscale', 'Invert',
'Opacity', 'Saturate', 'Sepia' ]
%>

pub fn set_filter(&mut self, v: longhands::filter::computed_value::T) {
use properties::longhands::filter::computed_value::Filter::*;
use gecko_bindings::structs::nsCSSShadowArray;
@@ -3460,35 +3469,20 @@ fn static_assert() {
debug_assert!(v.filters.len() == self.gecko.mFilters.len());

for (servo, gecko_filter) in v.filters.into_iter().zip(self.gecko.mFilters.iter_mut()) {
//TODO: URL, drop-shadow
match servo {
Blur(len) => fill_filter(NS_STYLE_FILTER_BLUR,
CoordDataValue::Coord(len.0),
gecko_filter),
Brightness(factor) => fill_filter(NS_STYLE_FILTER_BRIGHTNESS,
CoordDataValue::Factor(factor),
gecko_filter),
Contrast(factor) => fill_filter(NS_STYLE_FILTER_CONTRAST,
CoordDataValue::Factor(factor),
gecko_filter),
Grayscale(factor) => fill_filter(NS_STYLE_FILTER_GRAYSCALE,
CoordDataValue::Factor(factor),
gecko_filter),
HueRotate(angle) => fill_filter(NS_STYLE_FILTER_HUE_ROTATE,
CoordDataValue::from(angle),
gecko_filter),
Invert(factor) => fill_filter(NS_STYLE_FILTER_INVERT,
CoordDataValue::Factor(factor),
gecko_filter),
Opacity(factor) => fill_filter(NS_STYLE_FILTER_OPACITY,
CoordDataValue::Factor(factor),
gecko_filter),
Saturate(factor) => fill_filter(NS_STYLE_FILTER_SATURATE,
CoordDataValue::Factor(factor),
gecko_filter),
Sepia(factor) => fill_filter(NS_STYLE_FILTER_SEPIA,
CoordDataValue::Factor(factor),
gecko_filter),
% for func in FILTER_FUNCTIONS:
${func}(factor) => fill_filter(NS_STYLE_FILTER_${func.upper()},
CoordDataValue::Factor(factor),
gecko_filter),
% endfor
Blur(length) => fill_filter(NS_STYLE_FILTER_BLUR,
CoordDataValue::Coord(length.0),
gecko_filter),

HueRotate(angle) => fill_filter(NS_STYLE_FILTER_HUE_ROTATE,
CoordDataValue::from(angle),
gecko_filter),

DropShadow(shadow) => {
gecko_filter.mType = NS_STYLE_FILTER_DROP_SHADOW;

@@ -3504,12 +3498,12 @@ fn static_assert() {

let mut gecko_shadow = init_shadow(gecko_filter);
gecko_shadow.mArray[0].set_from_shadow(shadow);
}
},
Url(ref url) => {
unsafe {
bindings::Gecko_nsStyleFilter_SetURLValue(gecko_filter, url.for_ffi());
}
}
},
}
}
}
@@ -3519,6 +3513,58 @@ fn static_assert() {
Gecko_CopyFiltersFrom(&other.gecko as *const _ as *mut _, &mut self.gecko);
}
}

pub fn clone_filter(&self) -> longhands::filter::computed_value::T {
use properties::longhands::filter::computed_value::Filter::*;
use values::specified::url::SpecifiedUrl;
use gecko_bindings::structs::NS_STYLE_FILTER_BLUR;
use gecko_bindings::structs::NS_STYLE_FILTER_BRIGHTNESS;
use gecko_bindings::structs::NS_STYLE_FILTER_CONTRAST;
use gecko_bindings::structs::NS_STYLE_FILTER_GRAYSCALE;
use gecko_bindings::structs::NS_STYLE_FILTER_INVERT;
use gecko_bindings::structs::NS_STYLE_FILTER_OPACITY;
use gecko_bindings::structs::NS_STYLE_FILTER_SATURATE;
use gecko_bindings::structs::NS_STYLE_FILTER_SEPIA;
use gecko_bindings::structs::NS_STYLE_FILTER_HUE_ROTATE;
use gecko_bindings::structs::NS_STYLE_FILTER_DROP_SHADOW;
use gecko_bindings::structs::NS_STYLE_FILTER_URL;

let mut filters = Vec::new();
for filter in self.gecko.mFilters.iter(){
match filter.mType {
% for func in FILTER_FUNCTIONS:
NS_STYLE_FILTER_${func.upper()} => {
filters.push(${func}(
GeckoStyleCoordConvertible::from_gecko_style_coord(
&filter.mFilterParameter).unwrap()));
},
% endfor
NS_STYLE_FILTER_BLUR => {
filters.push(Blur(Au::from_gecko_style_coord(
&filter.mFilterParameter).unwrap()));
},
NS_STYLE_FILTER_HUE_ROTATE => {
filters.push(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())
});
},
NS_STYLE_FILTER_URL => {
filters.push(unsafe {
(Url(SpecifiedUrl::from_url_value_data(
&(**filter.__bindgen_anon_1.mURL.as_ref())._base).unwrap()))
});
}
_ => {},
}
}
longhands::filter::computed_value::T::new(filters)
}

</%self:impl_trait>

<%self:impl_trait style_struct_name="InheritedBox"
@@ -14,9 +14,12 @@ 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;
@@ -3016,7 +3019,7 @@ impl Animatable for IntermediateSVGPaintKind {
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
/// Intermediate type for box-shadow and text-shadow.
/// The difference between normal shadow type is that this type uses
/// The difference from normal shadow type is that this type uses
/// IntermediateColor instead of ParserColor.
pub struct IntermediateShadow {
pub offset_x: Au,
@@ -3192,3 +3195,196 @@ impl Animatable for IntermediateShadowList {
Ok(IntermediateShadowList(result))
}
}

/// 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,
self_portion: f64,
other_portion: f64)
-> Result<IntermediateFilter, ()> {
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))))
},
% 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))))
},
% 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))))
},
% 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(())
},
% endif
_ => {
// If specified the different filter functions,
// we will need to interpolate as discreate.
Err(())
},
}
}

/// https://drafts.fxtf.org/filters/#animation-of-filters
fn add_weighted_filter_function(from: Option<<&IntermediateFilter>,
to: Option<<&IntermediateFilter>,
self_portion: f64,
other_portion: f64) -> Result<IntermediateFilter, ()> {
match (from, to) {
(Some(f), Some(t)) => {
add_weighted_filter_function_impl(f, t, self_portion, other_portion)
},
(Some(f), None) => {
add_weighted_filter_function_impl(f, f, self_portion, 0.0)
},
(None, Some(t)) => {
add_weighted_filter_function_impl(t, t, other_portion, 0.0)
},
_ => { Err(()) }
}
}


impl Animatable for IntermediateFilters {
#[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 from = from_iter.next();
let mut to = to_iter.next();
while (from,to) != (None, None) {
filters.push(try!(add_weighted_filter_function(from,
to,
self_portion,
other_portion)));
if from != None {
from = from_iter.next();
}
if to != None {
to = to_iter.next();
}
}

Ok(filters)
}

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)
}
}
@@ -41,8 +41,7 @@ ${helpers.predefined_type("clip",
allow_quirks=True,
spec="https://drafts.fxtf.org/css-masking/#clip-property")}

// FIXME: This prop should be animatable
<%helpers:longhand name="filter" animation_value_type="none" extra_prefixes="webkit"
<%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;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.