--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -3429,16 +3429,25 @@ fn static_assert() {
} else {
Some(Au(self.gecko.mClip.x + self.gecko.mClip.width))
};
Either::First(ClipRect { top: top, right: right, bottom: bottom, left: left, })
}
}
+ <%
+ # 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;
use gecko_bindings::structs::nsStyleFilter;
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;
@@ -3455,75 +3464,112 @@ fn static_assert() {
}
unsafe {
Gecko_ResetFilters(&mut self.gecko, v.filters.len());
}
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;
fn init_shadow(filter: &mut nsStyleFilter) -> &mut nsCSSShadowArray {
unsafe {
let ref mut union = filter.__bindgen_anon_1;
let mut shadow_array: &mut *mut nsCSSShadowArray = union.mDropShadow.as_mut();
*shadow_array = Gecko_NewCSSShadowArray(1);
&mut **shadow_array
}
}
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());
}
- }
+ },
}
}
}
pub fn copy_filter_from(&mut self, other: &Self) {
unsafe {
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"
skip_longhands="image-orientation">
// FIXME: Gecko uses a tricky way to store computed value of image-orientation
// within an u8. We could inline following glue codes by implementing all
// those tricky parts for Servo as well. But, it's not done yet just for
// convenience.
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -9,19 +9,22 @@
use app_units::Au;
use cssparser::{Parser, RGBA};
use euclid::{Point2D, Size2D};
#[cfg(feature = "gecko")] use gecko_bindings::bindings::RawServoAnimationValueMap;
#[cfg(feature = "gecko")] use gecko_bindings::structs::RawGeckoGfxMatrix4x4;
#[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;
use properties::longhands::box_shadow::computed_value::T as BoxShadowList;
use properties::longhands::transform::computed_value::ComputedMatrix;
use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
use properties::longhands::transform::computed_value::T as TransformList;
use properties::longhands::vertical_align::computed_value::T as VerticalAlign;
@@ -931,19 +934,30 @@ impl Animatable for i32 {
Ok((*self - *other).abs() as f64)
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animatable for Angle {
#[inline]
fn add_weighted(&self, other: &Angle, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
- self.radians()
- .add_weighted(&other.radians(), self_portion, other_portion)
- .map(Angle::from_radians)
+ match (*self, *other) {
+ % for angle_type in [ 'Degree', 'Gradian', 'Turn' ]:
+ (Angle::${angle_type}(val1), Angle::${angle_type}(val2)) => {
+ Ok(Angle::${angle_type}(
+ try!(val1.add_weighted(&val2, self_portion, other_portion))
+ ))
+ }
+ % endfor
+ _ => {
+ self.radians()
+ .add_weighted(&other.radians(), self_portion, other_portion)
+ .map(Angle::from_radians)
+ }
+ }
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-percentage
impl Animatable for Percentage {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(Percentage((self.0 as f64 * self_portion + other.0 as f64 * other_portion) as f32))
@@ -3000,17 +3014,17 @@ impl Animatable for IntermediateSVGPaint
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[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,
pub offset_y: Au,
pub blur_radius: Au,
pub spread_radius: Au,
pub color: IntermediateColor,
pub inset: bool,
@@ -3176,8 +3190,262 @@ impl Animatable for IntermediateShadowLi
};
result.extend(self.0.iter().cloned());
result.extend(other.0.iter().cloned());
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(()) }
+ }
+}
+
+fn compute_filter_square_distance(from: &IntermediateFilter,
+ to: &IntermediateFilter)
+ -> Result<f64, ()> {
+ match (from, to) {
+ % for func in FILTER_FUNCTIONS :
+ (&IntermediateFilter::${func}(f),
+ &IntermediateFilter::${func}(t)) => {
+ Ok(try!(f.compute_squared_distance(&t)))
+ },
+ % endfor
+ % if product == "gecko":
+ (&IntermediateFilter::DropShadow(f),
+ &IntermediateFilter::DropShadow(t)) => {
+ Ok(try!(f.compute_squared_distance(&t)))
+ },
+ % endif
+ _ => {
+ 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)
+ }
+
+ #[inline]
+ fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
+ self.compute_squared_distance(other).map(|sd| sd.sqrt())
+ }
+
+ #[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 = from_iter.next();
+ let mut to = to_iter.next();
+ while (from,to) != (None, None) {
+ let current_square_distance: f64 ;
+ if from == 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 {
+ let none = try!(add_weighted_filter_function(from, from, 0.0, 0.0));
+ current_square_distance =
+ compute_filter_square_distance(&none, &(from.unwrap())).unwrap();
+
+ from = from_iter.next();
+ } else {
+ current_square_distance =
+ compute_filter_square_distance(&(from.unwrap()),
+ &(to.unwrap())).unwrap();
+
+ from = from_iter.next();
+ to = to_iter.next();
+ }
+ square_distance += current_square_distance;
+ }
+ Ok(square_distance.sqrt())
+ }
+}