[librsvg] surface_utils: go back on set_pixel directly on the data slice



commit dea449a31975977ec6523909c582539cb2d8f932
Author: Paolo Borelli <pborelli gnome org>
Date:   Wed Jan 15 03:16:43 2020 +0100

    surface_utils: go back on set_pixel directly on the data slice
    
    It turns out that having set_pixel on the ExclusiveImageSurface
    caused a regression in the benchmarks. Instead add a modify()
    method taking a closure that gets passed data and stride and
    call set_pixel directly on the data slice.

 rsvg_internals/benches/srgb.rs                     |  26 ++---
 rsvg_internals/src/filters/color_matrix.rs         |  58 ++++++-----
 rsvg_internals/src/filters/component_transfer.rs   |  32 +++---
 rsvg_internals/src/filters/convolve_matrix.rs      | 110 +++++++++++----------
 rsvg_internals/src/filters/morphology.rs           |  74 +++++++-------
 rsvg_internals/src/filters/turbulence.rs           |  58 +++++------
 rsvg_internals/src/surface_utils/shared_surface.rs |  71 +++++++------
 rsvg_internals/src/surface_utils/srgb.rs           |  40 ++++----
 8 files changed, 247 insertions(+), 222 deletions(-)
---
diff --git a/rsvg_internals/benches/srgb.rs b/rsvg_internals/benches/srgb.rs
index 39cf9578..98427743 100644
--- a/rsvg_internals/benches/srgb.rs
+++ b/rsvg_internals/benches/srgb.rs
@@ -6,7 +6,7 @@ use rsvg_internals::rect::IRect;
 use rsvg_internals::surface_utils::{
     shared_surface::{ExclusiveImageSurface, SurfaceType},
     srgb::{linearize, map_unpremultiplied_components_loop},
-    Pixel,
+    ImageSurfaceDataExt, Pixel,
 };
 
 const SURFACE_SIDE: i32 = 512;
@@ -23,18 +23,20 @@ fn bench_srgb_linearization(c: &mut Criterion) {
             ExclusiveImageSurface::new(SURFACE_SIDE, SURFACE_SIDE, SurfaceType::LinearRgb).unwrap();
 
         // Fill the surface with non-zero alpha (otherwise linearization is a no-op).
-        for y in BOUNDS.y_range() {
-            for x in BOUNDS.x_range() {
-               let pixel = Pixel {
-                    r: 0,
-                    g: 0,
-                    b: 0,
-                    a: 127,
-                };
-
-                surface.set_pixel(pixel, x as u32, y as u32);
+        surface.modify(&mut |data, stride| {
+            for y in BOUNDS.y_range() {
+                for x in BOUNDS.x_range() {
+                    let pixel = Pixel {
+                        r: 0,
+                        g: 0,
+                        b: 0,
+                        a: 127,
+                    };
+
+                    data.set_pixel(stride, pixel, x as u32, y as u32);
+                }
             }
-        }
+        });
 
         let surface = surface.share().unwrap();
         let mut output_surface =
diff --git a/rsvg_internals/src/filters/color_matrix.rs b/rsvg_internals/src/filters/color_matrix.rs
index 230f200b..4db2d24c 100644
--- a/rsvg_internals/src/filters/color_matrix.rs
+++ b/rsvg_internals/src/filters/color_matrix.rs
@@ -8,7 +8,9 @@ use crate::node::{NodeResult, NodeTrait, RsvgNode};
 use crate::number_list::{NumberList, NumberListLength};
 use crate::parsers::{Parse, ParseValue};
 use crate::property_bag::PropertyBag;
-use crate::surface_utils::{iterators::Pixels, shared_surface::ExclusiveImageSurface, Pixel};
+use crate::surface_utils::{
+    iterators::Pixels, shared_surface::ExclusiveImageSurface, ImageSurfaceDataExt, Pixel,
+};
 use crate::util::clamp;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
@@ -170,36 +172,38 @@ impl FilterEffect for FeColorMatrix {
             input.surface().surface_type(),
         )?;
 
-        for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
-            let alpha = f64::from(pixel.a) / 255f64;
-
-            let pixel_vec = if alpha == 0.0 {
-                Vector5::new(0.0, 0.0, 0.0, 0.0, 1.0)
-            } else {
-                Vector5::new(
-                    f64::from(pixel.r) / 255f64 / alpha,
-                    f64::from(pixel.g) / 255f64 / alpha,
-                    f64::from(pixel.b) / 255f64 / alpha,
-                    alpha,
-                    1.0,
-                )
-            };
-            let mut new_pixel_vec = Vector5::zeros();
-            self.matrix.mul_to(&pixel_vec, &mut new_pixel_vec);
+        surface.modify(&mut |data, stride| {
+            for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
+                let alpha = f64::from(pixel.a) / 255f64;
+
+                let pixel_vec = if alpha == 0.0 {
+                    Vector5::new(0.0, 0.0, 0.0, 0.0, 1.0)
+                } else {
+                    Vector5::new(
+                        f64::from(pixel.r) / 255f64 / alpha,
+                        f64::from(pixel.g) / 255f64 / alpha,
+                        f64::from(pixel.b) / 255f64 / alpha,
+                        alpha,
+                        1.0,
+                    )
+                };
+                let mut new_pixel_vec = Vector5::zeros();
+                self.matrix.mul_to(&pixel_vec, &mut new_pixel_vec);
 
-            let new_alpha = clamp(new_pixel_vec[3], 0.0, 1.0);
+                let new_alpha = clamp(new_pixel_vec[3], 0.0, 1.0);
 
-            let premultiply = |x: f64| ((clamp(x, 0.0, 1.0) * new_alpha * 255f64) + 0.5) as u8;
+                let premultiply = |x: f64| ((clamp(x, 0.0, 1.0) * new_alpha * 255f64) + 0.5) as u8;
 
-            let output_pixel = Pixel {
-                r: premultiply(new_pixel_vec[0]),
-                g: premultiply(new_pixel_vec[1]),
-                b: premultiply(new_pixel_vec[2]),
-                a: ((new_alpha * 255f64) + 0.5) as u8,
-            };
+                let output_pixel = Pixel {
+                    r: premultiply(new_pixel_vec[0]),
+                    g: premultiply(new_pixel_vec[1]),
+                    b: premultiply(new_pixel_vec[2]),
+                    a: ((new_alpha * 255f64) + 0.5) as u8,
+                };
 
-            surface.set_pixel(output_pixel, x, y);
-        }
+                data.set_pixel(stride, output_pixel, x, y);
+            }
+        });
 
         Ok(FilterResult {
             name: self.base.result.clone(),
diff --git a/rsvg_internals/src/filters/component_transfer.rs 
b/rsvg_internals/src/filters/component_transfer.rs
index f433fe93..c5790ecb 100644
--- a/rsvg_internals/src/filters/component_transfer.rs
+++ b/rsvg_internals/src/filters/component_transfer.rs
@@ -9,7 +9,9 @@ use crate::node::{NodeResult, NodeTrait, NodeType, RsvgNode};
 use crate::number_list::{NumberList, NumberListLength};
 use crate::parsers::{Parse, ParseValue};
 use crate::property_bag::PropertyBag;
-use crate::surface_utils::{iterators::Pixels, shared_surface::ExclusiveImageSurface, Pixel};
+use crate::surface_utils::{
+    iterators::Pixels, shared_surface::ExclusiveImageSurface, ImageSurfaceDataExt, Pixel,
+};
 use crate::util::clamp;
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
@@ -355,19 +357,21 @@ impl FilterEffect for FeComponentTransfer {
         let compute_a = |alpha| compute_a(&params_a, alpha);
 
         // Do the actual processing.
-        for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
-            let alpha = f64::from(pixel.a) / 255f64;
-            let new_alpha = compute_a(alpha);
-
-            let output_pixel = Pixel {
-                r: compute_r(pixel.r, alpha, new_alpha),
-                g: compute_g(pixel.g, alpha, new_alpha),
-                b: compute_b(pixel.b, alpha, new_alpha),
-                a: ((new_alpha * 255f64) + 0.5) as u8,
-            };
-
-            surface.set_pixel(output_pixel, x, y);
-        }
+        surface.modify(&mut |data, stride| {
+            for (x, y, pixel) in Pixels::within(input.surface(), bounds) {
+                let alpha = f64::from(pixel.a) / 255f64;
+                let new_alpha = compute_a(alpha);
+
+                let output_pixel = Pixel {
+                    r: compute_r(pixel.r, alpha, new_alpha),
+                    g: compute_g(pixel.g, alpha, new_alpha),
+                    b: compute_b(pixel.b, alpha, new_alpha),
+                    a: ((new_alpha * 255f64) + 0.5) as u8,
+                };
+
+                data.set_pixel(stride, output_pixel, x, y);
+            }
+        });
 
         Ok(FilterResult {
             name: self.base.result.clone(),
diff --git a/rsvg_internals/src/filters/convolve_matrix.rs b/rsvg_internals/src/filters/convolve_matrix.rs
index 0d49ab80..de6c1ca8 100644
--- a/rsvg_internals/src/filters/convolve_matrix.rs
+++ b/rsvg_internals/src/filters/convolve_matrix.rs
@@ -12,7 +12,7 @@ use crate::rect::IRect;
 use crate::surface_utils::{
     iterators::{PixelRectangle, Pixels},
     shared_surface::ExclusiveImageSurface,
-    EdgeMode, Pixel,
+    EdgeMode, ImageSurfaceDataExt, Pixel,
 };
 use crate::util::clamp;
 
@@ -235,67 +235,69 @@ impl FilterEffect for FeConvolveMatrix {
             input.surface().surface_type(),
         )?;
 
-        for (x, y, pixel) in Pixels::within(&input_surface, bounds) {
-            // Compute the convolution rectangle bounds.
-            let kernel_bounds = IRect::new(
-                x as i32 - self.target_x.unwrap() as i32,
-                y as i32 - self.target_y.unwrap() as i32,
-                x as i32 - self.target_x.unwrap() as i32 + self.order.0 as i32,
-                y as i32 - self.target_y.unwrap() as i32 + self.order.1 as i32,
-            );
-
-            // Do the convolution.
-            let mut r = 0.0;
-            let mut g = 0.0;
-            let mut b = 0.0;
-            let mut a = 0.0;
-
-            for (x, y, pixel) in
-                PixelRectangle::within(&input_surface, bounds, kernel_bounds, self.edge_mode)
-            {
-                let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
-                let kernel_y = (kernel_bounds.y1 - y - 1) as usize;
-
-                r += f64::from(pixel.r) / 255.0 * matrix[(kernel_y, kernel_x)];
-                g += f64::from(pixel.g) / 255.0 * matrix[(kernel_y, kernel_x)];
-                b += f64::from(pixel.b) / 255.0 * matrix[(kernel_y, kernel_x)];
-
-                if !self.preserve_alpha {
-                    a += f64::from(pixel.a) / 255.0 * matrix[(kernel_y, kernel_x)];
+        surface.modify(&mut |data, stride| {
+            for (x, y, pixel) in Pixels::within(&input_surface, bounds) {
+                // Compute the convolution rectangle bounds.
+                let kernel_bounds = IRect::new(
+                    x as i32 - self.target_x.unwrap() as i32,
+                    y as i32 - self.target_y.unwrap() as i32,
+                    x as i32 - self.target_x.unwrap() as i32 + self.order.0 as i32,
+                    y as i32 - self.target_y.unwrap() as i32 + self.order.1 as i32,
+                );
+
+                // Do the convolution.
+                let mut r = 0.0;
+                let mut g = 0.0;
+                let mut b = 0.0;
+                let mut a = 0.0;
+
+                for (x, y, pixel) in
+                    PixelRectangle::within(&input_surface, bounds, kernel_bounds, self.edge_mode)
+                {
+                    let kernel_x = (kernel_bounds.x1 - x - 1) as usize;
+                    let kernel_y = (kernel_bounds.y1 - y - 1) as usize;
+
+                    r += f64::from(pixel.r) / 255.0 * matrix[(kernel_y, kernel_x)];
+                    g += f64::from(pixel.g) / 255.0 * matrix[(kernel_y, kernel_x)];
+                    b += f64::from(pixel.b) / 255.0 * matrix[(kernel_y, kernel_x)];
+
+                    if !self.preserve_alpha {
+                        a += f64::from(pixel.a) / 255.0 * matrix[(kernel_y, kernel_x)];
+                    }
                 }
-            }
 
-            // If preserve_alpha is true, set a to the source alpha value.
-            if self.preserve_alpha {
-                a = f64::from(pixel.a) / 255.0;
-            } else {
-                a = a / self.divisor.unwrap() + self.bias;
-            }
+                // If preserve_alpha is true, set a to the source alpha value.
+                if self.preserve_alpha {
+                    a = f64::from(pixel.a) / 255.0;
+                } else {
+                    a = a / self.divisor.unwrap() + self.bias;
+                }
 
-            let clamped_a = clamp(a, 0.0, 1.0);
+                let clamped_a = clamp(a, 0.0, 1.0);
 
-            let compute = |x| {
-                let x = x / self.divisor.unwrap() + self.bias * a;
+                let compute = |x| {
+                    let x = x / self.divisor.unwrap() + self.bias * a;
 
-                let x = if self.preserve_alpha {
-                    // Premultiply the output value.
-                    clamp(x, 0.0, 1.0) * clamped_a
-                } else {
-                    clamp(x, 0.0, clamped_a)
-                };
+                    let x = if self.preserve_alpha {
+                        // Premultiply the output value.
+                        clamp(x, 0.0, 1.0) * clamped_a
+                    } else {
+                        clamp(x, 0.0, clamped_a)
+                    };
 
-                ((x * 255.0) + 0.5) as u8
-            };
+                    ((x * 255.0) + 0.5) as u8
+                };
 
-            let output_pixel = Pixel {
-                r: compute(r),
-                g: compute(g),
-                b: compute(b),
-                a: ((clamped_a * 255.0) + 0.5) as u8,
-            };
+                let output_pixel = Pixel {
+                    r: compute(r),
+                    g: compute(g),
+                    b: compute(b),
+                    a: ((clamped_a * 255.0) + 0.5) as u8,
+                };
 
-            surface.set_pixel(output_pixel, x, y);
-        }
+                data.set_pixel(stride, output_pixel, x, y);
+            }
+        });
 
         let mut surface = surface.share()?;
 
diff --git a/rsvg_internals/src/filters/morphology.rs b/rsvg_internals/src/filters/morphology.rs
index a2ab7fa2..0fed43b7 100644
--- a/rsvg_internals/src/filters/morphology.rs
+++ b/rsvg_internals/src/filters/morphology.rs
@@ -12,7 +12,7 @@ use crate::rect::IRect;
 use crate::surface_utils::{
     iterators::{PixelRectangle, Pixels},
     shared_surface::ExclusiveImageSurface,
-    EdgeMode, Pixel,
+    EdgeMode, ImageSurfaceDataExt, Pixel,
 };
 
 use super::context::{FilterContext, FilterOutput, FilterResult};
@@ -98,44 +98,46 @@ impl FilterEffect for FeMorphology {
             input.surface().surface_type(),
         )?;
 
-        for (x, y, _pixel) in Pixels::within(input.surface(), bounds) {
-            // Compute the kernel rectangle bounds.
-            let kernel_bounds = IRect::new(
-                (f64::from(x) - rx).floor() as i32,
-                (f64::from(y) - ry).floor() as i32,
-                (f64::from(x) + rx).ceil() as i32 + 1,
-                (f64::from(y) + ry).ceil() as i32 + 1,
-            );
-
-            // Compute the new pixel values.
-            let initial = match self.operator {
-                Operator::Erode => u8::max_value(),
-                Operator::Dilate => u8::min_value(),
-            };
-
-            let mut output_pixel = Pixel {
-                r: initial,
-                g: initial,
-                b: initial,
-                a: initial,
-            };
-
-            for (_x, _y, pixel) in
-                PixelRectangle::within(&input.surface(), bounds, kernel_bounds, EdgeMode::None)
-            {
-                let op = match self.operator {
-                    Operator::Erode => min,
-                    Operator::Dilate => max,
+        surface.modify(&mut |data, stride| {
+            for (x, y, _pixel) in Pixels::within(input.surface(), bounds) {
+                // Compute the kernel rectangle bounds.
+                let kernel_bounds = IRect::new(
+                    (f64::from(x) - rx).floor() as i32,
+                    (f64::from(y) - ry).floor() as i32,
+                    (f64::from(x) + rx).ceil() as i32 + 1,
+                    (f64::from(y) + ry).ceil() as i32 + 1,
+                );
+
+                // Compute the new pixel values.
+                let initial = match self.operator {
+                    Operator::Erode => u8::max_value(),
+                    Operator::Dilate => u8::min_value(),
                 };
 
-                output_pixel.r = op(output_pixel.r, pixel.r);
-                output_pixel.g = op(output_pixel.g, pixel.g);
-                output_pixel.b = op(output_pixel.b, pixel.b);
-                output_pixel.a = op(output_pixel.a, pixel.a);
-            }
+                let mut output_pixel = Pixel {
+                    r: initial,
+                    g: initial,
+                    b: initial,
+                    a: initial,
+                };
 
-            surface.set_pixel(output_pixel, x, y);
-        }
+                for (_x, _y, pixel) in
+                    PixelRectangle::within(&input.surface(), bounds, kernel_bounds, EdgeMode::None)
+                {
+                    let op = match self.operator {
+                        Operator::Erode => min,
+                        Operator::Dilate => max,
+                    };
+
+                    output_pixel.r = op(output_pixel.r, pixel.r);
+                    output_pixel.g = op(output_pixel.g, pixel.g);
+                    output_pixel.b = op(output_pixel.b, pixel.b);
+                    output_pixel.a = op(output_pixel.a, pixel.a);
+                }
+
+                data.set_pixel(stride, output_pixel, x, y);
+            }
+        });
 
         Ok(FilterResult {
             name: self.base.result.clone(),
diff --git a/rsvg_internals/src/filters/turbulence.rs b/rsvg_internals/src/filters/turbulence.rs
index 26b3fc18..b8046a22 100644
--- a/rsvg_internals/src/filters/turbulence.rs
+++ b/rsvg_internals/src/filters/turbulence.rs
@@ -8,7 +8,7 @@ use crate::parsers::{NumberOptionalNumber, Parse, ParseValue};
 use crate::property_bag::PropertyBag;
 use crate::surface_utils::{
     shared_surface::{ExclusiveImageSurface, SurfaceType},
-    Pixel,
+    ImageSurfaceDataExt, Pixel,
 };
 use crate::util::clamp;
 
@@ -364,38 +364,40 @@ impl FilterEffect for FeTurbulence {
             surface_type,
         )?;
 
-        for y in bounds.y_range() {
-            for x in bounds.x_range() {
-                let point = affine.transform_point(f64::from(x), f64::from(y));
-                let point = [point.0, point.1];
-
-                let generate = |color_channel| {
-                    let v = noise_generator.turbulence(
-                        color_channel,
-                        point,
-                        f64::from(x - bounds.x0),
-                        f64::from(y - bounds.y0),
-                    );
-
-                    let v = match self.type_ {
-                        NoiseType::FractalNoise => (v * 255.0 + 255.0) / 2.0,
-                        NoiseType::Turbulence => v * 255.0,
+        surface.modify(&mut |data, stride| {
+            for y in bounds.y_range() {
+                for x in bounds.x_range() {
+                    let point = affine.transform_point(f64::from(x), f64::from(y));
+                    let point = [point.0, point.1];
+
+                    let generate = |color_channel| {
+                        let v = noise_generator.turbulence(
+                            color_channel,
+                            point,
+                            f64::from(x - bounds.x0),
+                            f64::from(y - bounds.y0),
+                        );
+
+                        let v = match self.type_ {
+                            NoiseType::FractalNoise => (v * 255.0 + 255.0) / 2.0,
+                            NoiseType::Turbulence => v * 255.0,
+                        };
+
+                        (clamp(v, 0.0, 255.0) + 0.5) as u8
                     };
 
-                    (clamp(v, 0.0, 255.0) + 0.5) as u8
-                };
+                    let pixel = Pixel {
+                        r: generate(0),
+                        g: generate(1),
+                        b: generate(2),
+                        a: generate(3),
+                    }
+                    .premultiply();
 
-                let pixel = Pixel {
-                    r: generate(0),
-                    g: generate(1),
-                    b: generate(2),
-                    a: generate(3),
+                    data.set_pixel(stride, pixel, x as u32, y as u32);
                 }
-                .premultiply();
-
-                surface.set_pixel(pixel, x as u32, y as u32);
             }
-        }
+        });
 
         Ok(FilterResult {
             name: self.base.result.clone(),
diff --git a/rsvg_internals/src/surface_utils/shared_surface.rs 
b/rsvg_internals/src/surface_utils/shared_surface.rs
index 292c0c76..ef7d089e 100644
--- a/rsvg_internals/src/surface_utils/shared_surface.rs
+++ b/rsvg_internals/src/surface_utils/shared_surface.rs
@@ -1159,37 +1159,39 @@ pub fn composite_arithmetic(
     k3: f64,
     k4: f64,
 ) {
-    for (x, y, pixel, pixel_2) in
-        Pixels::within(surface1, bounds).map(|(x, y, p)| (x, y, p, surface2.get_pixel(x, y)))
-    {
-        let i1a = f64::from(pixel.a) / 255f64;
-        let i2a = f64::from(pixel_2.a) / 255f64;
-        let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
-        let oa = clamp(oa, 0f64, 1f64);
-
-        // Contents of image surfaces are transparent by default, so if the resulting pixel is
-        // transparent there's no need to do anything.
-        if oa > 0f64 {
-            let compute = |i1, i2| {
-                let i1 = f64::from(i1) / 255f64;
-                let i2 = f64::from(i2) / 255f64;
-
-                let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
-                let o = clamp(o, 0f64, oa);
-
-                ((o * 255f64) + 0.5) as u8
-            };
+    output_surface.modify(&mut |data, stride| {
+        for (x, y, pixel, pixel_2) in
+            Pixels::within(surface1, bounds).map(|(x, y, p)| (x, y, p, surface2.get_pixel(x, y)))
+        {
+            let i1a = f64::from(pixel.a) / 255f64;
+            let i2a = f64::from(pixel_2.a) / 255f64;
+            let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
+            let oa = clamp(oa, 0f64, 1f64);
+
+            // Contents of image surfaces are transparent by default, so if the resulting pixel is
+            // transparent there's no need to do anything.
+            if oa > 0f64 {
+                let compute = |i1, i2| {
+                    let i1 = f64::from(i1) / 255f64;
+                    let i2 = f64::from(i2) / 255f64;
+
+                    let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
+                    let o = clamp(o, 0f64, oa);
+
+                    ((o * 255f64) + 0.5) as u8
+                };
 
-            let output_pixel = Pixel {
-                r: compute(pixel.r, pixel_2.r),
-                g: compute(pixel.g, pixel_2.g),
-                b: compute(pixel.b, pixel_2.b),
-                a: ((oa * 255f64) + 0.5) as u8,
-            };
+                let output_pixel = Pixel {
+                    r: compute(pixel.r, pixel_2.r),
+                    g: compute(pixel.g, pixel_2.g),
+                    b: compute(pixel.b, pixel_2.b),
+                    a: ((oa * 255f64) + 0.5) as u8,
+                };
 
-            output_surface.set_pixel(output_pixel, x, y);
+                data.set_pixel(stride, output_pixel, x, y);
+            }
         }
-    }
+    });
 }
 
 impl ImageSurface<Exclusive> {
@@ -1236,11 +1238,16 @@ impl ImageSurface<Exclusive> {
         self.surface.get_data().unwrap()
     }
 
-    /// Sets the pixel at the given coordinates. Assumes the `ARgb32` format.
+    /// Modify the image data
     #[inline]
-    pub fn set_pixel(&mut self, pixel: Pixel, x: u32, y: u32) {
-        let stride = self.stride as usize;
-        self.get_data().set_pixel(stride, pixel, x, y);
+    pub fn modify(
+        &mut self,
+        draw_fn: &mut dyn FnMut(&mut cairo::ImageSurfaceData, usize),
+    ) {
+        let stride = self.stride() as usize;
+        let mut data = self.get_data();
+
+        draw_fn(&mut data, stride)
     }
 
     /// Draw on the surface using cairo
diff --git a/rsvg_internals/src/surface_utils/srgb.rs b/rsvg_internals/src/surface_utils/srgb.rs
index 462fe94a..b88f486e 100644
--- a/rsvg_internals/src/surface_utils/srgb.rs
+++ b/rsvg_internals/src/surface_utils/srgb.rs
@@ -6,7 +6,7 @@ use crate::rect::IRect;
 use crate::surface_utils::{
     iterators::Pixels,
     shared_surface::{ExclusiveImageSurface, SharedImageSurface, SurfaceType},
-    Pixel,
+    ImageSurfaceDataExt, Pixel,
 };
 
 // Include the linearization and unlinearization tables.
@@ -32,28 +32,30 @@ pub fn map_unpremultiplied_components_loop<F: Fn(u8) -> u8>(
     bounds: IRect,
     f: F,
 ) {
-    for (x, y, pixel) in Pixels::within(surface, bounds) {
-        if pixel.a > 0 {
-            let alpha = f64::from(pixel.a) / 255f64;
+    output_surface.modify(&mut |data, stride| {
+        for (x, y, pixel) in Pixels::within(surface, bounds) {
+            if pixel.a > 0 {
+                let alpha = f64::from(pixel.a) / 255f64;
 
-            let compute = |x| {
-                let x = f64::from(x) / alpha; // Unpremultiply alpha.
-                let x = (x + 0.5) as u8; // Round to nearest u8.
-                let x = f(x);
-                let x = f64::from(x) * alpha; // Premultiply alpha again.
-                (x + 0.5) as u8
-            };
+                let compute = |x| {
+                    let x = f64::from(x) / alpha; // Unpremultiply alpha.
+                    let x = (x + 0.5) as u8; // Round to nearest u8.
+                    let x = f(x);
+                    let x = f64::from(x) * alpha; // Premultiply alpha again.
+                    (x + 0.5) as u8
+                };
 
-            let output_pixel = Pixel {
-                r: compute(pixel.r),
-                g: compute(pixel.g),
-                b: compute(pixel.b),
-                a: pixel.a,
-            };
+                let output_pixel = Pixel {
+                    r: compute(pixel.r),
+                    g: compute(pixel.g),
+                    b: compute(pixel.b),
+                    a: pixel.a,
+                };
 
-            output_surface.set_pixel(output_pixel, x, y);
+                data.set_pixel(stride, output_pixel, x, y);
+            }
         }
-    }
+    });
 }
 
 /// Applies the function to each pixel component after unpremultiplying.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]