☠☠ backed out by 27679131d486 ☠ ☠ | |
author | Connor Brewster <cbrewster@mozilla.com> |
Wed, 10 Jul 2019 02:17:25 +0000 | |
changeset 482261 | 7c43dc769da78fe45d9caf3d5dbd0205f33aa156 |
parent 482260 | b43e75b56fb86528f25ed074071bea5d877c2484 |
child 482262 | 134a51a0e03463d045ab71b79d251a91c70a8cd9 |
push id | 89660 |
push user | csabou@mozilla.com |
push date | Wed, 10 Jul 2019 19:47:03 +0000 |
treeherder | autoland@8149efc1f813 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | gw |
bugs | 1555483 |
milestone | 70.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/wr/examples/animation.rs +++ b/gfx/wr/examples/animation.rs @@ -66,16 +66,17 @@ impl App { ); builder.push_simple_stacking_context_with_filters( LayoutPoint::zero(), spatial_id, true, &filters, &[], + &[] ); let space_and_clip = SpaceAndClipInfo { spatial_id, clip_id: ClipId::root(pipeline_id), }; let clip_bounds = LayoutRect::new(LayoutPoint::zero(), bounds.size); let complex_clip = ComplexClipRegion {
--- a/gfx/wr/webrender/src/display_list_flattener.rs +++ b/gfx/wr/webrender/src/display_list_flattener.rs @@ -1,16 +1,16 @@ /* 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/. */ use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter}; use api::{ClipId, ColorF, CommonItemProperties, ComplexClipRegion, RasterSpace}; use api::{DisplayItem, DisplayItemRef, ExtendMode, ExternalScrollId}; -use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, GradientStop}; +use api::{FilterOp, FilterPrimitive, FontInstanceKey, GlyphInstance, GlyphOptions, GradientStop}; use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, ColorDepth}; use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId}; use api::{PropertyBinding, ReferenceFrame, ReferenceFrameKind, ScrollFrameDisplayItem, ScrollSensitivity}; use api::{Shadow, SpaceAndClipInfo, SpatialId, StackingContext, StickyFrameDisplayItem}; use api::{ClipMode, PrimitiveKeyKind, TransformStyle, YuvColorSpace, YuvData, TempFilterData}; use api::units::*; use crate::clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore}; use crate::clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex}; @@ -791,29 +791,31 @@ impl<'a> DisplayListFlattener<'a> { &mut self, traversal: &mut BuiltDisplayListIter<'a>, pipeline_id: PipelineId, stacking_context: &StackingContext, spatial_node_index: SpatialNodeIndex, origin: LayoutPoint, filters: ItemRange<FilterOp>, filter_datas: &[TempFilterData], + filter_primitives: ItemRange<FilterPrimitive>, is_backface_visible: bool, apply_pipeline_clip: bool, ) { // Avoid doing unnecessary work for empty stacking contexts. if traversal.current_stacking_context_empty() { traversal.skip_current_stacking_context(); return; } let composition_operations = { CompositeOps::new( stacking_context.filter_ops_for_compositing(filters), stacking_context.filter_datas_for_compositing(filter_datas), + stacking_context.filter_primitives_for_compositing(filter_primitives), stacking_context.mix_blend_mode_for_compositing(), ) }; let clip_chain_id = match stacking_context.clip_id { Some(clip_id) => self.id_to_index_mapper.get_clip_chain_id(clip_id), None => ClipChainId::NONE, }; @@ -1175,16 +1177,17 @@ impl<'a> DisplayListFlattener<'a> { self.flatten_stacking_context( &mut subtraversal, pipeline_id, &info.stacking_context, space, info.origin, item.filters(), item.filter_datas(), + item.filter_primitives(), info.is_backface_visible, apply_pipeline_clip, ); return Some(subtraversal); } DisplayItem::PushReferenceFrame(ref info) => { let parent_space = self.get_space(&info.parent_spatial_id); let mut subtraversal = item.sub_iter(); @@ -1304,19 +1307,20 @@ impl<'a> DisplayListFlattener<'a> { let parent_space = self.get_space(&info.parent_spatial_id); self.flatten_sticky_frame( info, parent_space, ); } // Do nothing; these are dummy items for the display list parser - DisplayItem::SetGradientStops => {} - DisplayItem::SetFilterOps => {} - DisplayItem::SetFilterData => {} + DisplayItem::SetGradientStops | + DisplayItem::SetFilterOps | + DisplayItem::SetFilterData | + DisplayItem::SetFilterPrimitives => {} DisplayItem::PopReferenceFrame | DisplayItem::PopStackingContext => { unreachable!("Should have returned in parent method.") } DisplayItem::PushShadow(info) => { let clip_and_scroll = self.get_clip_and_scroll( &info.space_and_clip.clip_id,
--- a/gfx/wr/webrender/src/scene.rs +++ b/gfx/wr/webrender/src/scene.rs @@ -1,14 +1,14 @@ /* 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/. */ use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch}; -use api::{FilterOp, TempFilterData, FilterData, ComponentTransferFuncType}; +use api::{FilterOp, TempFilterData, FilterData, FilterPrimitive, ComponentTransferFuncType}; use api::{PipelineId, PropertyBinding, PropertyBindingId, ItemRange, MixBlendMode, StackingContext}; use api::units::{LayoutSize, LayoutTransform}; use crate::internal_types::{FastHashMap, Filter}; use std::sync::Arc; /// Stores a map of the animated property bindings for the current display list. These /// can be used to animate the transform and/or opacity of a display list without /// re-submitting the display list itself. @@ -201,16 +201,20 @@ pub trait StackingContextHelpers { fn filter_ops_for_compositing( &self, input_filters: ItemRange<FilterOp>, ) -> Vec<Filter>; fn filter_datas_for_compositing( &self, input_filter_datas: &[TempFilterData], ) -> Vec<FilterData>; + fn filter_primitives_for_compositing( + &self, + input_filter_primitives: ItemRange<FilterPrimitive>, + ) -> Vec<FilterPrimitive>; } impl StackingContextHelpers for StackingContext { fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> { match self.mix_blend_mode { MixBlendMode::Normal => None, _ => Some(self.mix_blend_mode), } @@ -249,9 +253,20 @@ impl StackingContextHelpers for Stacking func_b_type: func_types[2], b_values: temp_filter_data.b_values.iter().collect(), func_a_type: func_types[3], a_values: temp_filter_data.a_values.iter().collect(), }); } filter_datas } + + fn filter_primitives_for_compositing( + &self, + input_filter_primitives: ItemRange<FilterPrimitive>, + ) -> Vec<FilterPrimitive> { + // Resolve these in the flattener? + // TODO(gw): Now that we resolve these later on, + // we could probably make it a bit + // more efficient than cloning these here. + input_filter_primitives.iter().map(|primitive| primitive.into()).collect() + } }
--- a/gfx/wr/webrender/src/tiling.rs +++ b/gfx/wr/webrender/src/tiling.rs @@ -1,14 +1,14 @@ /* 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/. */ use api::{ColorF, BorderStyle, MixBlendMode, PipelineId, PremultipliedColorF}; -use api::{DocumentLayer, FilterData, ImageFormat, LineOrientation}; +use api::{DocumentLayer, FilterData, FilterPrimitive, ImageFormat, LineOrientation}; use api::units::*; #[cfg(feature = "pathfinder")] use api::FontRenderMode; use crate::batch::{AlphaBatchBuilder, AlphaBatchContainer, ClipBatcher, resolve_image, BatchBuilder}; use crate::clip::ClipStore; use crate::clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX}; use crate::debug_render::DebugItem; use crate::device::{Texture}; @@ -1327,28 +1327,33 @@ impl RenderPass { } } #[derive(Debug, Clone, Default)] pub struct CompositeOps { // Requires only a single texture as input (e.g. most filters) pub filters: Vec<Filter>, pub filter_datas: Vec<FilterData>, + pub filter_primitives: Vec<FilterPrimitive>, // Requires two source textures (e.g. mix-blend-mode) pub mix_blend_mode: Option<MixBlendMode>, } impl CompositeOps { - pub fn new(filters: Vec<Filter>, - filter_datas: Vec<FilterData>, - mix_blend_mode: Option<MixBlendMode>) -> Self { + pub fn new( + filters: Vec<Filter>, + filter_datas: Vec<FilterData>, + filter_primitives: Vec<FilterPrimitive>, + mix_blend_mode: Option<MixBlendMode> + ) -> Self { CompositeOps { filters, filter_datas, + filter_primitives, mix_blend_mode, } } pub fn is_empty(&self) -> bool { self.filters.is_empty() && self.filter_datas.is_empty() && self.mix_blend_mode.is_none() } }
--- a/gfx/wr/webrender_api/src/display_item.rs +++ b/gfx/wr/webrender_api/src/display_item.rs @@ -116,16 +116,17 @@ pub enum DisplayItem { PushReferenceFrame(ReferenceFrameDisplayListItem), PushStackingContext(PushStackingContextDisplayItem), // These marker items indicate an array of data follows, to be used for the // next non-marker item. SetGradientStops, SetFilterOps, SetFilterData, + SetFilterPrimitives, // These marker items terminate a scope introduced by a previous item. PopReferenceFrame, PopStackingContext, PopAllShadows, } /// This is a "complete" version of the DisplayItem, with all implicit trailing @@ -154,16 +155,17 @@ pub enum DebugDisplayItem { StickyFrame(StickyFrameDisplayItem), Iframe(IframeDisplayItem), PushReferenceFrame(ReferenceFrameDisplayListItem), PushStackingContext(PushStackingContextDisplayItem), SetGradientStops(Vec<GradientStop>), SetFilterOps(Vec<FilterOp>), SetFilterData(FilterData), + SetFilterPrimitives(Vec<FilterPrimitive>), PopReferenceFrame, PopStackingContext, PopAllShadows, } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct ClipDisplayItem { @@ -633,17 +635,17 @@ pub struct PushStackingContextDisplayIte #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct StackingContext { pub transform_style: TransformStyle, pub mix_blend_mode: MixBlendMode, pub clip_id: Option<ClipId>, pub raster_space: RasterSpace, /// True if picture caching should be used on this stacking context. pub cache_tiles: bool, -} // IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData> +} // IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>, filter_primitives: Vec<FilterPrimitive> #[repr(u8)] #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] pub enum TransformStyle { Flat = 0, Preserve3D = 1, } @@ -692,16 +694,44 @@ pub enum MixBlendMode { Difference = 10, Exclusion = 11, Hue = 12, Saturation = 13, Color = 14, Luminosity = 15, } +/// An input to a SVG filter primitive. +#[repr(C)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub enum FilterPrimitiveInput { + /// The input is the original graphic that the filter is being applied to. + Original, + /// The input is the output of the previous filter primitive in the filter primitive chain. + Previous, + /// The input is the output of the filter primitive at the given index in the filter primitive chain. + OutputOfPrimitiveIndex(usize), +} + +#[repr(C)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub struct BlendPrimitive { + pub input1: FilterPrimitiveInput, + pub input2: FilterPrimitiveInput, + pub mode: MixBlendMode, +} + +/// SVG Filter Primitive. +#[repr(C)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] +pub enum FilterPrimitive { + Blend(BlendPrimitive), +} + +/// CSS filter. #[repr(C)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub enum FilterOp { /// Filter that does no transformation of the colors, needed for /// debug purposes only. Identity, Blur(f32), Brightness(f32), @@ -1157,16 +1187,17 @@ impl DisplayItem { DisplayItem::PopAllShadows => "pop_all_shadows", DisplayItem::PopReferenceFrame => "pop_reference_frame", DisplayItem::PopStackingContext => "pop_stacking_context", DisplayItem::PushShadow(..) => "push_shadow", DisplayItem::PushReferenceFrame(..) => "push_reference_frame", DisplayItem::PushStackingContext(..) => "push_stacking_context", DisplayItem::SetFilterOps => "set_filter_ops", DisplayItem::SetFilterData => "set_filter_data", + DisplayItem::SetFilterPrimitives => "set_filter_primitives", DisplayItem::RadialGradient(..) => "radial_gradient", DisplayItem::Rectangle(..) => "rectangle", DisplayItem::ScrollFrame(..) => "scroll_frame", DisplayItem::SetGradientStops => "set_gradient_stops", DisplayItem::StickyFrame(..) => "sticky_frame", DisplayItem::Text(..) => "text", DisplayItem::YuvImage(..) => "yuv_image", }
--- a/gfx/wr/webrender_api/src/display_list.rs +++ b/gfx/wr/webrender_api/src/display_list.rs @@ -126,16 +126,17 @@ pub struct BuiltDisplayListDescriptor { pub struct BuiltDisplayListIter<'a> { list: &'a BuiltDisplayList, data: &'a [u8], cur_item: di::DisplayItem, cur_stops: ItemRange<'a, di::GradientStop>, cur_glyphs: ItemRange<'a, GlyphInstance>, cur_filters: ItemRange<'a, di::FilterOp>, cur_filter_data: Vec<TempFilterData<'a>>, + cur_filter_primitives: ItemRange<'a, di::FilterPrimitive>, cur_clip_chain_items: ItemRange<'a, di::ClipId>, cur_complex_clip: ItemRange<'a, di::ComplexClipRegion>, peeking: Peek, /// Should just be initialized but never populated in release builds debug_stats: DebugStats, } /// Internal info used for more detailed analysis of serialized display lists @@ -292,16 +293,17 @@ impl<'a> BuiltDisplayListIter<'a> { BuiltDisplayListIter { list, data, cur_item: di::DisplayItem::PopStackingContext, cur_stops: ItemRange::default(), cur_glyphs: ItemRange::default(), cur_filters: ItemRange::default(), cur_filter_data: Vec::new(), + cur_filter_primitives: ItemRange::default(), cur_clip_chain_items: ItemRange::default(), cur_complex_clip: ItemRange::default(), peeking: Peek::NotPeeking, debug_stats: DebugStats { last_addr: data.as_ptr() as usize, stats: HashMap::default(), } } @@ -330,17 +332,18 @@ impl<'a> BuiltDisplayListIter<'a> { self.cur_complex_clip = ItemRange::default(); self.cur_clip_chain_items = ItemRange::default(); loop { self.next_raw()?; match self.cur_item { SetGradientStops | SetFilterOps | - SetFilterData => { + SetFilterData | + SetFilterPrimitives => { // These are marker items for populating other display items, don't yield them. continue; } _ => { break; } } } @@ -386,16 +389,20 @@ impl<'a> BuiltDisplayListIter<'a> { let data = *self.cur_filter_data.last().unwrap(); self.debug_stats.log_slice("set_filter_data.func_types", &data.func_types); self.debug_stats.log_slice("set_filter_data.r_values", &data.r_values); self.debug_stats.log_slice("set_filter_data.g_values", &data.g_values); self.debug_stats.log_slice("set_filter_data.b_values", &data.b_values); self.debug_stats.log_slice("set_filter_data.a_values", &data.a_values); } + SetFilterPrimitives => { + self.cur_filter_primitives = skip_slice::<di::FilterPrimitive>(&mut self.data); + self.debug_stats.log_slice("set_filter_primitives.primitives", &self.cur_filter_primitives); + } ClipChain(_) => { self.cur_clip_chain_items = skip_slice::<di::ClipId>(&mut self.data); self.debug_stats.log_slice("clip_chain.clip_ids", &self.cur_clip_chain_items); } Clip(_) | ScrollFrame(_) => { self.cur_complex_clip = skip_slice::<di::ComplexClipRegion>(&mut self.data); let name = if let Clip(_) = self.cur_item { "clip.complex_clips" @@ -497,16 +504,20 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> { pub fn filters(&self) -> ItemRange<di::FilterOp> { self.iter.cur_filters } pub fn filter_datas(&self) -> &Vec<TempFilterData> { &self.iter.cur_filter_data } + pub fn filter_primitives(&self) -> ItemRange<di::FilterPrimitive> { + self.iter.cur_filter_primitives + } + pub fn clip_chain_items(&self) -> ItemRange<di::ClipId> { self.iter.cur_clip_chain_items } pub fn display_list(&self) -> &BuiltDisplayList { self.iter.display_list() } @@ -597,16 +608,19 @@ impl Serialize for BuiltDisplayList { func_g_type: func_types[1], g_values: temp_filter_data.g_values.iter().collect(), func_b_type: func_types[2], b_values: temp_filter_data.b_values.iter().collect(), func_a_type: func_types[3], a_values: temp_filter_data.a_values.iter().collect(), }) }, + Real::SetFilterPrimitives => Debug::SetFilterPrimitives( + item.iter.cur_filter_primitives.iter().collect() + ), Real::SetGradientStops => Debug::SetGradientStops( item.iter.cur_stops.iter().collect() ), Real::StickyFrame(v) => Debug::StickyFrame(v), Real::Rectangle(v) => Debug::Rectangle(v), Real::ClearRectangle(v) => Debug::ClearRectangle(v), Real::HitTest(v) => Debug::HitTest(v), Real::Line(v) => Debug::Line(v), @@ -695,16 +709,20 @@ impl<'de> Deserialize<'de> for BuiltDisp filter_data.func_a_type].to_vec(); DisplayListBuilder::push_iter_impl(&mut temp, func_types); DisplayListBuilder::push_iter_impl(&mut temp, filter_data.r_values); DisplayListBuilder::push_iter_impl(&mut temp, filter_data.g_values); DisplayListBuilder::push_iter_impl(&mut temp, filter_data.b_values); DisplayListBuilder::push_iter_impl(&mut temp, filter_data.a_values); Real::SetFilterData }, + Debug::SetFilterPrimitives(filter_primitives) => { + DisplayListBuilder::push_iter_impl(&mut temp, filter_primitives); + Real::SetFilterPrimitives + } Debug::SetGradientStops(stops) => { DisplayListBuilder::push_iter_impl(&mut temp, stops); Real::SetGradientStops }, Debug::Rectangle(v) => Real::Rectangle(v), Debug::ClearRectangle(v) => Real::ClearRectangle(v), Debug::HitTest(v) => Real::HitTest(v), @@ -1420,16 +1438,17 @@ impl DisplayListBuilder { origin: LayoutPoint, spatial_id: di::SpatialId, is_backface_visible: bool, clip_id: Option<di::ClipId>, transform_style: di::TransformStyle, mix_blend_mode: di::MixBlendMode, filters: &[di::FilterOp], filter_datas: &[di::FilterData], + filter_primitives: &[di::FilterPrimitive], raster_space: di::RasterSpace, cache_tiles: bool, ) { if filters.len() > 0 { self.push_item(&di::DisplayItem::SetFilterOps); self.push_iter(filters); } @@ -1440,16 +1459,21 @@ impl DisplayListBuilder { self.push_item(&di::DisplayItem::SetFilterData); self.push_iter(&func_types); self.push_iter(&filter_data.r_values); self.push_iter(&filter_data.g_values); self.push_iter(&filter_data.b_values); self.push_iter(&filter_data.a_values); } + if !filter_primitives.is_empty() { + self.push_item(&di::DisplayItem::SetFilterPrimitives); + self.push_iter(filter_primitives); + } + let item = di::DisplayItem::PushStackingContext(di::PushStackingContextDisplayItem { origin, spatial_id, is_backface_visible, stacking_context: di::StackingContext { transform_style, mix_blend_mode, clip_id, @@ -1463,37 +1487,39 @@ impl DisplayListBuilder { /// Helper for examples/ code. pub fn push_simple_stacking_context( &mut self, origin: LayoutPoint, spatial_id: di::SpatialId, is_backface_visible: bool, ) { - self.push_simple_stacking_context_with_filters(origin, spatial_id, is_backface_visible, &[], &[]); + self.push_simple_stacking_context_with_filters(origin, spatial_id, is_backface_visible, &[], &[], &[]); } /// Helper for examples/ code. pub fn push_simple_stacking_context_with_filters( &mut self, origin: LayoutPoint, spatial_id: di::SpatialId, is_backface_visible: bool, filters: &[di::FilterOp], filter_datas: &[di::FilterData], + filter_primitives: &[di::FilterPrimitive], ) { self.push_stacking_context( origin, spatial_id, is_backface_visible, None, di::TransformStyle::Flat, di::MixBlendMode::Normal, filters, filter_datas, + filter_primitives, di::RasterSpace::Screen, /* cache_tiles = */ false, ); } pub fn pop_stacking_context(&mut self) { self.push_item(&di::DisplayItem::PopStackingContext); }
--- a/gfx/wr/wrench/src/yaml_frame_reader.rs +++ b/gfx/wr/wrench/src/yaml_frame_reader.rs @@ -1876,26 +1876,28 @@ impl YamlFrameReader { if let Some(size) = yaml["scroll-offset"].as_point() { let external_id = ExternalScrollId(0, dl.pipeline_id); self.scroll_offsets.insert(external_id, LayoutPoint::new(size.x, size.y)); } } let filters = yaml["filters"].as_vec_filter_op().unwrap_or(vec![]); let filter_datas = yaml["filter-datas"].as_vec_filter_data().unwrap_or(vec![]); + let filter_primitives = yaml["filter-primitives"].as_vec_filter_primitive().unwrap_or(vec![]); dl.push_stacking_context( bounds.origin, *self.spatial_id_stack.last().unwrap(), info.is_backface_visible, clip_node_id, transform_style, mix_blend_mode, &filters, &filter_datas, + &filter_primitives, raster_space, cache_tiles, ); if !yaml["items"].is_badvalue() { self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]); }
--- a/gfx/wr/wrench/src/yaml_frame_writer.rs +++ b/gfx/wr/wrench/src/yaml_frame_writer.rs @@ -67,16 +67,24 @@ fn color_to_string(value: ColorF) -> Str value.r * 255.0, value.g * 255.0, value.b * 255.0, value.a ) } } +fn filter_input_to_string(input: FilterPrimitiveInput) -> String { + match input { + FilterPrimitiveInput::Original => "original".into(), + FilterPrimitiveInput::Previous => "previous".into(), + FilterPrimitiveInput::OutputOfPrimitiveIndex(index) => index.to_string(), + } +} + fn color_node(parent: &mut Table, key: &str, value: ColorF) { yaml_node(parent, key, Yaml::String(color_to_string(value))); } fn point_node<U>(parent: &mut Table, key: &str, value: &TypedPoint2D<f32, U>) { f32_vec_node(parent, key, &[value.x, value.y]); } @@ -248,16 +256,17 @@ fn shadow_parameters(shadow: &Shadow) -> } fn write_stacking_context( parent: &mut Table, sc: &StackingContext, properties: &SceneProperties, filter_iter: impl IntoIterator<Item = FilterOp>, filter_data_iter: &[TempFilterData], + filter_primitive_iter: impl IntoIterator<Item = FilterPrimitive>, ) { enum_node(parent, "transform-style", sc.transform_style); let raster_space = match sc.raster_space { RasterSpace::Local(scale) => { format!("local({})", scale) } RasterSpace::Screen => { @@ -344,16 +353,33 @@ fn write_stacking_context( Yaml::Array(g_values), Yaml::Array(b_values), Yaml::Array(a_values), ].to_vec(); filter_datas.push(Yaml::Array(avec)); } yaml_node(parent, "filter-datas", Yaml::Array(filter_datas)); + + // filter primitives + let mut filter_primitives = vec![]; + for filter_primitive in filter_primitive_iter { + let mut table = new_table(); + match filter_primitive { + FilterPrimitive::Blend(blend_primitive) => { + yaml_node(&mut table, "type", Yaml::String("blend".into())); + yaml_node(&mut table, "in1", Yaml::String(filter_input_to_string(blend_primitive.input1))); + yaml_node(&mut table, "in2", Yaml::String(filter_input_to_string(blend_primitive.input2))); + enum_node(&mut table, "mode", blend_primitive.mode); + } + } + filter_primitives.push(Yaml::Hash(table)); + } + + yaml_node(parent, "filter-primitives", Yaml::Array(filter_primitives)); } #[cfg(target_os = "macos")] fn native_font_handle_to_yaml( rsrc: &mut ResourceGenerator, handle: &NativeFontHandle, parent: &mut yaml_rust::yaml::Hash, path_opt: &mut Option<PathBuf>, @@ -1160,16 +1186,17 @@ impl YamlFrameWriter { point_node(&mut v, "origin", &item.origin); bool_node(&mut v, "backface-visible", item.is_backface_visible); write_stacking_context( &mut v, &item.stacking_context, &scene.properties, base.filters(), base.filter_datas(), + base.filter_primitives(), ); let mut sub_iter = base.sub_iter(); self.write_display_list(&mut v, display_list, scene, &mut sub_iter, clip_id_mapper); continue_traversal = Some(sub_iter); } DisplayItem::PushReferenceFrame(item) => { str_node(&mut v, "type", "reference-frame"); @@ -1272,19 +1299,21 @@ impl YamlFrameWriter { Yaml::Real(item.previously_applied_offset.y.to_string()), ]; yaml_node(&mut v, "previously-applied-offset", Yaml::Array(applied)); } DisplayItem::PopReferenceFrame | DisplayItem::PopStackingContext => return, - DisplayItem::SetGradientStops => panic!("dummy item yielded?"), - DisplayItem::SetFilterOps => panic!("dummy item yielded?"), - DisplayItem::SetFilterData => panic!("dummy item yielded?"), + DisplayItem::SetGradientStops | + DisplayItem::SetFilterOps | + DisplayItem::SetFilterData | + DisplayItem::SetFilterPrimitives => panic!("dummy item yielded?"), + DisplayItem::PushShadow(item) => { str_node(&mut v, "type", "shadow"); vector_node(&mut v, "offset", &item.shadow.offset); color_node(&mut v, "color", item.shadow.color); f32_node(&mut v, "blur-radius", item.shadow.blur_radius); } DisplayItem::PopAllShadows => { str_node(&mut v, "type", "pop-all-shadows");
--- a/gfx/wr/wrench/src/yaml_helper.rs +++ b/gfx/wr/wrench/src/yaml_helper.rs @@ -33,16 +33,19 @@ pub trait YamlHelper { fn as_transform_style(&self) -> Option<TransformStyle>; fn as_raster_space(&self) -> Option<RasterSpace>; fn as_clip_mode(&self) -> Option<ClipMode>; fn as_mix_blend_mode(&self) -> Option<MixBlendMode>; fn as_filter_op(&self) -> Option<FilterOp>; fn as_vec_filter_op(&self) -> Option<Vec<FilterOp>>; fn as_filter_data(&self) -> Option<FilterData>; fn as_vec_filter_data(&self) -> Option<Vec<FilterData>>; + fn as_filter_input(&self) -> Option<FilterPrimitiveInput>; + fn as_filter_primitive(&self) -> Option<FilterPrimitive>; + fn as_vec_filter_primitive(&self) -> Option<Vec<FilterPrimitive>>; } fn string_to_color(color: &str) -> Option<ColorF> { match color { "red" => Some(ColorF::new(1.0, 0.0, 0.0, 1.0)), "green" => Some(ColorF::new(0.0, 1.0, 0.0, 1.0)), "blue" => Some(ColorF::new(0.0, 0.0, 1.0, 1.0)), "white" => Some(ColorF::new(1.0, 1.0, 1.0, 1.0)), @@ -669,16 +672,59 @@ impl YamlHelper for Yaml { } } } } } None } + fn as_filter_input(&self) -> Option<FilterPrimitiveInput> { + if let Some(input) = self.as_str() { + match input { + "original" => Some(FilterPrimitiveInput::Original), + "previous" => Some(FilterPrimitiveInput::Previous), + _ => None, + } + } else if let Some(index) = self.as_i64() { + if index >= 0 { + Some(FilterPrimitiveInput::OutputOfPrimitiveIndex(index as usize)) + } else { + panic!("Filter input index cannot be negative"); + } + } else { + panic!("Invalid filter input"); + } + } + fn as_vec_filter_data(&self) -> Option<Vec<FilterData>> { if let Some(v) = self.as_vec() { Some(v.iter().map(|x| x.as_filter_data().unwrap()).collect()) } else { self.as_filter_data().map(|data| vec![data]) } } + + fn as_filter_primitive(&self) -> Option<FilterPrimitive> { + if let Some(filter_type) = self["type"].as_str() { + match filter_type { + "blend" => { + Some(FilterPrimitive::Blend(BlendPrimitive { + input1: self["in1"].as_filter_input().unwrap(), + input2: self["in2"].as_filter_input().unwrap(), + mode: self["blend-mode"].as_mix_blend_mode().unwrap(), + })) + } + _ => None, + } + } else { + None + } + } + + fn as_vec_filter_primitive(&self) -> Option<Vec<FilterPrimitive>> { + if let Some(v) = self.as_vec() { + Some(v.iter().map(|x| x.as_filter_primitive().unwrap()).collect()) + } else { + self.as_filter_primitive().map(|data| vec![data]) + } + } }