Bug 1505871. Implement yaml reader/writer for component transfer. r=jrmuizel
authorTimothy Nikkel <tnikkel@gmail.com>
Tue, 26 Feb 2019 00:16:36 -0600
changeset 519008 bc60982f282807b43fe8e1d4f200433e3352cba4
parent 519007 f499cb201bd6afae94acabdf5ca5fb1afa998a91
child 519009 30cb5423d03f4375ab7ba9e08906295d8864c17b
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1505871
milestone67.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
Bug 1505871. Implement yaml reader/writer for component transfer. r=jrmuizel
gfx/wr/wrench/src/yaml_frame_reader.rs
gfx/wr/wrench/src/yaml_frame_writer.rs
gfx/wr/wrench/src/yaml_helper.rs
--- a/gfx/wr/wrench/src/yaml_frame_reader.rs
+++ b/gfx/wr/wrench/src/yaml_frame_reader.rs
@@ -1820,27 +1820,29 @@ impl YamlFrameReader {
         if is_root {
             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![]);
 
         info.rect = bounds;
         info.clip_rect = bounds;
 
         dl.push_stacking_context(
             &info,
             *self.spatial_id_stack.last().unwrap(),
             clip_node_id,
             transform_style,
             mix_blend_mode,
             &filters,
+            &filter_datas,
             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
@@ -212,16 +212,18 @@ fn write_reference_frame(
     usize_node(parent, "id", clip_id_mapper.add_spatial_id(reference_frame.id));
 }
 
 fn write_stacking_context(
     parent: &mut Table,
     sc: &StackingContext,
     properties: &SceneProperties,
     filter_iter: AuxIter<FilterOp>,
+    filter_data_iter: &[TempFilterData],
+    display_list: &BuiltDisplayList,
 ) {
     enum_node(parent, "transform-style", sc.transform_style);
 
     let raster_space = match sc.raster_space {
         RasterSpace::Local(scale) => {
             format!("local({})", scale)
         }
         RasterSpace::Screen => {
@@ -261,20 +263,60 @@ fn write_stacking_context(
                 filters.push(Yaml::String(format!("color-matrix({:?})", matrix)))
             }
             FilterOp::SrgbToLinear => {
                 filters.push(Yaml::String("srgb-to-linear".to_string()))
             }
             FilterOp::LinearToSrgb => {
                 filters.push(Yaml::String("linear-to-srgb".to_string()))
             }
+            FilterOp::ComponentTransfer => {
+                filters.push(Yaml::String("component-transfer".to_string()))
+            }
         }
     }
 
     yaml_node(parent, "filters", Yaml::Array(filters));
+
+    // filter datas
+    let mut filter_datas = vec![];
+    for filter_data in filter_data_iter {
+        let func_types = display_list.get(filter_data.func_types).map(|func_type| {
+            match func_type {
+                ComponentTransferFuncType::Identity => { Yaml::String("Identity".to_string()) }
+                ComponentTransferFuncType::Table => { Yaml::String("Table".to_string()) }
+                ComponentTransferFuncType::Discrete => { Yaml::String("Discrete".to_string()) }
+                ComponentTransferFuncType::Linear => { Yaml::String("Linear".to_string()) }
+                ComponentTransferFuncType::Gamma => { Yaml::String("Gamma".to_string()) }
+            }
+        }).collect();
+        let r_values = display_list.get(filter_data.r_values).map(|value| {
+            Yaml::String(format!("{}", value))
+        }).collect();
+        let g_values = display_list.get(filter_data.g_values).map(|value| {
+            Yaml::String(format!("{}", value))
+        }).collect();
+        let b_values = display_list.get(filter_data.b_values).map(|value| {
+            Yaml::String(format!("{}", value))
+        }).collect();
+        let a_values = display_list.get(filter_data.a_values).map(|value| {
+            Yaml::String(format!("{}", value))
+        }).collect();
+
+        let avec: Vec<Yaml> = [
+            Yaml::Array(func_types),
+            Yaml::Array(r_values),
+            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));
 }
 
 #[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>,
@@ -1029,16 +1071,18 @@ impl YamlFrameWriter {
                 Sdi::PushStackingContext(item) => {
                     str_node(&mut v, "type", "stacking-context");
                     let filters = display_list.get(base.filters());
                     write_stacking_context(
                         &mut v,
                         &item.stacking_context,
                         &scene.properties,
                         filters,
+                        base.filter_datas(),
+                        display_list,
                     );
 
                     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);
                 }
                 Sdi::PushReferenceFrame(item) => {
                     str_node(&mut v, "type", "reference-frame");
@@ -1147,16 +1191,18 @@ impl YamlFrameWriter {
                 Sdi::PopStackingContext => return,
 
                 Sdi::PopCacheMarker => return,
                 Sdi::PushCacheMarker(_) => {
                     str_node(&mut v, "type", "cache-marker");
                 }
 
                 Sdi::SetGradientStops => panic!("dummy item yielded?"),
+                Sdi::SetFilterOps => panic!("dummy item yielded?"),
+                Sdi::SetFilterData => panic!("dummy item yielded?"),
                 Sdi::PushShadow(shadow) => {
                     str_node(&mut v, "type", "shadow");
                     vector_node(&mut v, "offset", &shadow.offset);
                     color_node(&mut v, "color", shadow.color);
                     f32_node(&mut v, "blur-radius", shadow.blur_radius);
                 }
                 Sdi::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
@@ -31,16 +31,18 @@ pub trait YamlHelper {
     fn as_border_radius_component(&self) -> LayoutSize;
     fn as_border_radius(&self) -> Option<BorderRadius>;
     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 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)),
@@ -134,16 +136,27 @@ define_string_enum!(
         Dotted = "dotted",
         Dashed = "dashed",
         Wavy = "wavy"
     ]
 );
 
 define_string_enum!(ClipMode, [Clip = "clip", ClipOut = "clip-out"]);
 
+define_string_enum!(
+    ComponentTransferFuncType,
+    [
+        Identity = "Identity",
+        Table = "Table",
+        Discrete = "Discrete",
+        Linear = "Linear",
+        Gamma = "Gamma"
+    ]
+);
+
 // Rotate around `axis` by `degrees` angle
 fn make_rotation(
     origin: &LayoutPoint,
     degrees: f32,
     axis_x: f32,
     axis_y: f32,
     axis_z: f32,
 ) -> LayoutTransform {
@@ -543,16 +556,19 @@ impl YamlHelper for Yaml {
     }
 
     fn as_filter_op(&self) -> Option<FilterOp> {
         if let Some(s) = self.as_str() {
             match parse_function(s) {
                 ("identity", _, _) => {
                     Some(FilterOp::Identity)
                 }
+                ("component-transfer", _, _) => {
+                    Some(FilterOp::ComponentTransfer)
+                }
                 ("blur", ref args, _) if args.len() == 1 => {
                     Some(FilterOp::Blur(args[0].parse().unwrap()))
                 }
                 ("brightness", ref args, _) if args.len() == 1 => {
                     Some(FilterOp::Brightness(args[0].parse().unwrap()))
                 }
                 ("contrast", ref args, _) if args.len() == 1 => {
                     Some(FilterOp::Contrast(args[0].parse().unwrap()))
@@ -601,9 +617,57 @@ impl YamlHelper for Yaml {
 
     fn as_vec_filter_op(&self) -> Option<Vec<FilterOp>> {
         if let Some(v) = self.as_vec() {
             Some(v.iter().map(|x| x.as_filter_op().unwrap()).collect())
         } else {
             self.as_filter_op().map(|op| vec![op])
         }
     }
+
+    fn as_filter_data(&self) -> Option<FilterData> {
+        // Parse an array with five entries. First entry is an array of func types (4).
+        // The remaining entries are arrays of floats.
+        if let Yaml::Array(ref array) = *self {
+            if array.len() != 5 {
+                panic!("Invalid filter data specified, base array doesn't have five entries: {:?}", self);
+            }
+            if let Some(func_types_p) = array[0].as_vec_string() {
+                if func_types_p.len() != 4 {
+                    panic!("Invalid filter data specified, func type array doesn't have five entries: {:?}", self);
+                }
+                let func_types: Vec<ComponentTransferFuncType> =
+                    func_types_p.into_iter().map(|x| { match StringEnum::from_str(&x) {
+                        Some(y) => y,
+                        None => panic!("Invalid filter data specified, invalid func type name: {:?}", self),
+                    }}).collect();
+                if let Some(r_values_p) = array[1].as_vec_f32() {
+                    if let Some(g_values_p) = array[2].as_vec_f32() {
+                        if let Some(b_values_p) = array[3].as_vec_f32() {
+                            if let Some(a_values_p) = array[4].as_vec_f32() {
+                                let filter_data = FilterData {
+                                    func_r_type: func_types[0],
+                                    r_values: r_values_p,
+                                    func_g_type: func_types[1],
+                                    g_values: g_values_p,
+                                    func_b_type: func_types[2],
+                                    b_values: b_values_p,
+                                    func_a_type: func_types[3],
+                                    a_values: a_values_p,
+                                };
+                                return Some(filter_data)
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        None
+    }
+
+    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])
+        }
+    }
 }