[librsvg: 1/2] paint_server: introduce PaintSource trait



commit a8894e63e0826f4fe22935ef684c5bb4f6dddb70
Author: Paolo Borelli <pborelli gnome org>
Date:   Sun Nov 18 00:10:44 2018 +0100

    paint_server: introduce PaintSource trait
    
    Gradient and Pattern have a similar structure, so we make them
    implement a common PaintSource trait

 rsvg_internals/src/gradient.rs     | 184 +++++++++----------
 rsvg_internals/src/paint_server.rs |  52 +++++-
 rsvg_internals/src/pattern.rs      | 352 +++++++++++++++++++------------------
 3 files changed, 308 insertions(+), 280 deletions(-)
---
diff --git a/rsvg_internals/src/gradient.rs b/rsvg_internals/src/gradient.rs
index 22bf54c5..31738fd4 100644
--- a/rsvg_internals/src/gradient.rs
+++ b/rsvg_internals/src/gradient.rs
@@ -11,6 +11,7 @@ use error::*;
 use handle::RsvgHandle;
 use length::*;
 use node::*;
+use paint_server::PaintSource;
 use parsers::{parse, Parse, ParseError};
 use property_bag::PropertyBag;
 use rect::RectangleExt;
@@ -20,7 +21,7 @@ use unitinterval::UnitInterval;
 use util::clone_fallback_name;
 
 #[derive(Copy, Clone)]
-struct ColorStop {
+pub struct ColorStop {
     pub offset: f64,
     pub rgba: cssparser::RGBA,
     pub opacity: UnitInterval,
@@ -80,7 +81,7 @@ impl From<SpreadMethod> for cairo::enums::Extend {
 // ones can be inherited from the gradient referenced by its "fallback" IRI.  We
 // represent these possibly-missing attributes as Option<foo>.
 #[derive(Clone)]
-struct GradientCommon {
+pub struct GradientCommon {
     pub units: Option<GradientUnits>,
     pub affine: Option<cairo::Matrix>,
     pub spread: Option<SpreadMethod>,
@@ -89,7 +90,7 @@ struct GradientCommon {
 }
 
 #[derive(Copy, Clone)]
-enum GradientVariant {
+pub enum GradientVariant {
     Linear {
         x1: Option<Length>,
         y1: Option<Length>,
@@ -107,7 +108,7 @@ enum GradientVariant {
 }
 
 #[derive(Clone)]
-struct Gradient {
+pub struct Gradient {
     pub common: GradientCommon,
     pub variant: GradientVariant,
 }
@@ -443,33 +444,6 @@ fn acquire_gradient<'a>(draw_ctx: &'a mut DrawingCtx<'_>, name: &str) -> Option<
     None
 }
 
-fn resolve_gradient(gradient: &Gradient, draw_ctx: &mut DrawingCtx<'_>) -> Gradient {
-    let mut result = gradient.clone();
-
-    while !result.is_resolved() {
-        result
-            .common
-            .fallback
-            .as_ref()
-            .and_then(|fallback_name| acquire_gradient(draw_ctx, fallback_name))
-            .and_then(|acquired| {
-                let fallback_node = acquired.get();
-
-                fallback_node.with_impl(|i: &NodeGradient| {
-                    let fallback_grad = i.get_gradient_with_color_stops_from_node(&fallback_node);
-                    result.resolve_from_fallback(&fallback_grad)
-                });
-                Some(())
-            })
-            .or_else(|| {
-                result.resolve_from_defaults();
-                Some(())
-            });
-    }
-
-    result
-}
-
 fn set_common_on_pattern<P: cairo::PatternTrait + cairo::Gradient>(
     gradient: &Gradient,
     pattern: &mut P,
@@ -541,50 +515,94 @@ fn fix_focus_point(fx: f64, fy: f64, cx: f64, cy: f64, radius: f64) -> (f64, f64
     (cx + dx, cy + dy)
 }
 
-fn set_pattern_on_draw_context(
-    gradient: &Gradient,
-    values: &ComputedValues,
-    draw_ctx: &mut DrawingCtx<'_>,
-    opacity: &UnitInterval,
-    bbox: &BoundingBox,
-) {
-    assert!(gradient.is_resolved());
+impl PaintSource<Gradient> for NodeGradient {
+    fn resolve(
+        &self,
+        node: &RsvgNode,
+        draw_ctx: &mut DrawingCtx<'_>,
+        bbox: &BoundingBox,
+    ) -> Option<Gradient> {
+        let gradient =
+            node.with_impl(|i: &NodeGradient| i.get_gradient_with_color_stops_from_node(node));
+        let mut result = gradient.clone();
+
+        while !result.is_resolved() {
+            result
+                .common
+                .fallback
+                .as_ref()
+                .and_then(|fallback_name| acquire_gradient(draw_ctx, fallback_name))
+                .and_then(|acquired| {
+                    let fallback_node = acquired.get();
+
+                    fallback_node.with_impl(|i: &NodeGradient| {
+                        let fallback_grad =
+                            i.get_gradient_with_color_stops_from_node(&fallback_node);
+                        result.resolve_from_fallback(&fallback_grad)
+                    });
+                    Some(())
+                })
+                .or_else(|| {
+                    result.resolve_from_defaults();
+                    Some(())
+                });
+        }
 
-    let units = gradient.common.units.unwrap();
-    let params = if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
-        draw_ctx.push_view_box(1.0, 1.0)
-    } else {
-        draw_ctx.get_view_params()
-    };
-
-    match gradient.variant {
-        GradientVariant::Linear { x1, y1, x2, y2 } => {
-            let mut pattern = cairo::LinearGradient::new(
-                x1.as_ref().unwrap().normalize(values, &params),
-                y1.as_ref().unwrap().normalize(values, &params),
-                x2.as_ref().unwrap().normalize(values, &params),
-                y2.as_ref().unwrap().normalize(values, &params),
-            );
-
-            let cr = draw_ctx.get_cairo_context();
-            set_common_on_pattern(gradient, &mut pattern, bbox, opacity);
-            cr.set_source(&cairo::Pattern::LinearGradient(pattern));
+        if result.bounds_are_valid(bbox) {
+            Some(result)
+        } else {
+            None
         }
+    }
+
+    fn set_pattern_on_draw_context(
+        &self,
+        gradient: &Gradient,
+        values: &ComputedValues,
+        draw_ctx: &mut DrawingCtx<'_>,
+        opacity: &UnitInterval,
+        bbox: &BoundingBox,
+    ) -> Result<bool, RenderingError> {
+        assert!(gradient.is_resolved());
 
-        GradientVariant::Radial { cx, cy, r, fx, fy } => {
-            let n_cx = cx.as_ref().unwrap().normalize(values, &params);
-            let n_cy = cy.as_ref().unwrap().normalize(values, &params);
-            let n_r = r.as_ref().unwrap().normalize(values, &params);
-            let n_fx = fx.as_ref().unwrap().normalize(values, &params);
-            let n_fy = fy.as_ref().unwrap().normalize(values, &params);
+        let units = gradient.common.units.unwrap();
+        let params = if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
+            draw_ctx.push_view_box(1.0, 1.0)
+        } else {
+            draw_ctx.get_view_params()
+        };
 
-            let (new_fx, new_fy) = fix_focus_point(n_fx, n_fy, n_cx, n_cy, n_r);
-            let mut pattern = cairo::RadialGradient::new(new_fx, new_fy, 0.0, n_cx, n_cy, n_r);
+        match gradient.variant {
+            GradientVariant::Linear { x1, y1, x2, y2 } => {
+                let mut pattern = cairo::LinearGradient::new(
+                    x1.as_ref().unwrap().normalize(values, &params),
+                    y1.as_ref().unwrap().normalize(values, &params),
+                    x2.as_ref().unwrap().normalize(values, &params),
+                    y2.as_ref().unwrap().normalize(values, &params),
+                );
 
-            let cr = draw_ctx.get_cairo_context();
-            set_common_on_pattern(gradient, &mut pattern, bbox, opacity);
-            cr.set_source(&cairo::Pattern::RadialGradient(pattern));
+                let cr = draw_ctx.get_cairo_context();
+                set_common_on_pattern(gradient, &mut pattern, bbox, opacity);
+                cr.set_source(&cairo::Pattern::LinearGradient(pattern));
+            }
+
+            GradientVariant::Radial { cx, cy, r, fx, fy } => {
+                let n_cx = cx.as_ref().unwrap().normalize(values, &params);
+                let n_cy = cy.as_ref().unwrap().normalize(values, &params);
+                let n_r = r.as_ref().unwrap().normalize(values, &params);
+                let n_fx = fx.as_ref().unwrap().normalize(values, &params);
+                let n_fy = fy.as_ref().unwrap().normalize(values, &params);
+
+                let (new_fx, new_fy) = fix_focus_point(n_fx, n_fy, n_cx, n_cy, n_r);
+                let mut pattern = cairo::RadialGradient::new(new_fx, new_fy, 0.0, n_cx, n_cy, n_r);
+
+                let cr = draw_ctx.get_cairo_context();
+                set_common_on_pattern(gradient, &mut pattern, bbox, opacity);
+                cr.set_source(&cairo::Pattern::RadialGradient(pattern));
+            }
         }
+
+        Ok(true)
     }
 }
 
@@ -688,34 +706,6 @@ impl NodeTrait for NodeGradient {
     }
 }
 
-pub fn gradient_resolve_fallbacks_and_set_pattern(
-    node: &RsvgNode,
-    draw_ctx: &mut DrawingCtx<'_>,
-    opacity: &UnitInterval,
-    bbox: &BoundingBox,
-) -> bool {
-    assert!(
-        node.get_type() == NodeType::LinearGradient || node.get_type() == NodeType::RadialGradient
-    );
-
-    let mut did_set_gradient = false;
-
-    node.with_impl(|node_gradient: &NodeGradient| {
-        let gradient = node_gradient.get_gradient_with_color_stops_from_node(node);
-        let resolved = resolve_gradient(&gradient, draw_ctx);
-
-        if resolved.bounds_are_valid(bbox) {
-            let cascaded = node.get_cascaded_values();
-            let values = cascaded.get();
-            set_pattern_on_draw_context(&resolved, values, draw_ctx, opacity, bbox);
-        }
-
-        did_set_gradient = true;
-    });
-
-    did_set_gradient
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/rsvg_internals/src/paint_server.rs b/rsvg_internals/src/paint_server.rs
index 83c531d7..7919c1f7 100644
--- a/rsvg_internals/src/paint_server.rs
+++ b/rsvg_internals/src/paint_server.rs
@@ -3,10 +3,11 @@ use cssparser::{self, Parser};
 use bbox::BoundingBox;
 use drawing_ctx::DrawingCtx;
 use error::*;
-use gradient;
-use node::NodeType;
+use gradient::NodeGradient;
+use node::{NodeType, RsvgNode};
 use parsers::Parse;
-use pattern;
+use pattern::NodePattern;
+use state::ComputedValues;
 use unitinterval::UnitInterval;
 
 #[derive(Debug, Clone, PartialEq)]
@@ -69,6 +70,40 @@ fn set_color(
     );
 }
 
+pub trait PaintSource<T> {
+    fn resolve(
+        &self,
+        node: &RsvgNode,
+        draw_ctx: &mut DrawingCtx<'_>,
+        bbox: &BoundingBox,
+    ) -> Option<T>;
+
+    fn set_pattern_on_draw_context(
+        &self,
+        pattern: &T,
+        values: &ComputedValues,
+        draw_ctx: &mut DrawingCtx<'_>,
+        opacity: &UnitInterval,
+        bbox: &BoundingBox,
+    ) -> Result<bool, RenderingError>;
+
+    fn resolve_fallbacks_and_set_pattern(
+        &self,
+        node: &RsvgNode,
+        draw_ctx: &mut DrawingCtx<'_>,
+        opacity: &UnitInterval,
+        bbox: &BoundingBox,
+    ) -> Result<bool, RenderingError> {
+        if let Some(resolved) = self.resolve(&node, draw_ctx, bbox) {
+            let cascaded = node.get_cascaded_values();
+            let values = cascaded.get();
+            self.set_pattern_on_draw_context(&resolved, values, draw_ctx, opacity, bbox)
+        } else {
+            Ok(false)
+        }
+    }
+}
+
 pub fn set_source_paint_server(
     draw_ctx: &mut DrawingCtx<'_>,
     ps: &PaintServer,
@@ -91,12 +126,13 @@ pub fn set_source_paint_server(
                 if node.get_type() == NodeType::LinearGradient
                     || node.get_type() == NodeType::RadialGradient
                 {
-                    had_paint_server = gradient::gradient_resolve_fallbacks_and_set_pattern(
-                        &node, draw_ctx, opacity, bbox,
-                    );
+                    had_paint_server = node.with_impl(|n: &NodeGradient| {
+                        n.resolve_fallbacks_and_set_pattern(&node, draw_ctx, opacity, bbox)
+                    })?;
                 } else if node.get_type() == NodeType::Pattern {
-                    had_paint_server =
-                        pattern::pattern_resolve_fallbacks_and_set_pattern(&node, draw_ctx, bbox)?;
+                    had_paint_server = node.with_impl(|n: &NodePattern| {
+                        n.resolve_fallbacks_and_set_pattern(&node, draw_ctx, opacity, bbox)
+                    })?;
                 }
             }
 
diff --git a/rsvg_internals/src/pattern.rs b/rsvg_internals/src/pattern.rs
index 17a8088e..bf562cd4 100644
--- a/rsvg_internals/src/pattern.rs
+++ b/rsvg_internals/src/pattern.rs
@@ -15,16 +15,18 @@ use float_eq_cairo::ApproxEqCairo;
 use handle::RsvgHandle;
 use length::*;
 use node::*;
+use paint_server::PaintSource;
 use parsers::{parse, parse_and_validate};
 use property_bag::PropertyBag;
 use state::ComputedValues;
+use unitinterval::UnitInterval;
 use viewbox::*;
 
 coord_units!(PatternUnits, CoordUnits::ObjectBoundingBox);
 coord_units!(PatternContentUnits, CoordUnits::UserSpaceOnUse);
 
 #[derive(Clone)]
-struct Pattern {
+pub struct Pattern {
     pub units: Option<PatternUnits>,
     pub content_units: Option<PatternContentUnits>,
     // This Option<Option<ViewBox>> is a bit strange.  We want a field
@@ -234,233 +236,233 @@ impl NodeTrait for NodePattern {
     }
 }
 
-fn resolve_pattern(pattern: &Pattern, draw_ctx: &mut DrawingCtx<'_>) -> Pattern {
-    let mut result = pattern.clone();
-
-    let mut stack = NodeStack::new();
+impl PaintSource<Pattern> for NodePattern {
+    fn resolve(
+        &self,
+        node: &RsvgNode,
+        draw_ctx: &mut DrawingCtx<'_>,
+        _bbox: &BoundingBox,
+    ) -> Option<Pattern> {
+        let node_pattern = node.get_impl::<NodePattern>().unwrap();
+        let pattern = &*node_pattern.pattern.borrow();
+        let mut result = pattern.clone();
+        let mut stack = NodeStack::new();
+
+        while !result.is_resolved() {
+            if let Some(acquired) = draw_ctx.get_acquired_node_of_type(
+                result.fallback.as_ref().map(String::as_ref),
+                NodeType::Pattern,
+            ) {
+                let node = acquired.get();
+
+                if stack.contains(node) {
+                    // FIXME: return a Result here with RenderingError::CircularReference
+                    // FIXME: print the pattern's name
+                    rsvg_log!("circular reference in pattern");
+                    result.resolve_from_defaults();
+                    break;
+                }
 
-    while !result.is_resolved() {
-        if let Some(acquired) = draw_ctx.get_acquired_node_of_type(
-            result.fallback.as_ref().map(String::as_ref),
-            NodeType::Pattern,
-        ) {
-            let node = acquired.get();
+                node.with_impl(|i: &NodePattern| {
+                    result.resolve_from_fallback(&*i.pattern.borrow())
+                });
 
-            if stack.contains(node) {
-                // FIXME: return a Result here with RenderingError::CircularReference
-                // FIXME: print the pattern's name
-                rsvg_log!("circular reference in pattern");
+                stack.push(node);
+            } else {
                 result.resolve_from_defaults();
-                break;
             }
+        }
 
-            node.with_impl(|i: &NodePattern| result.resolve_from_fallback(&*i.pattern.borrow()));
+        Some(result)
+    }
 
-            stack.push(node);
-        } else {
-            result.resolve_from_defaults();
+    fn set_pattern_on_draw_context(
+        &self,
+        pattern: &Pattern,
+        values: &ComputedValues,
+        draw_ctx: &mut DrawingCtx<'_>,
+        _opacity: &UnitInterval,
+        bbox: &BoundingBox,
+    ) -> Result<bool, RenderingError> {
+        assert!(pattern.is_resolved());
+
+        if pattern.node.is_none() {
+            // This means we didn't find any children among the fallbacks,
+            // so there is nothing to render.
+            return Ok(false);
         }
-    }
 
-    result
-}
+        let units = pattern.units.unwrap();
+        let content_units = pattern.content_units.unwrap();
+        let pattern_affine = pattern.affine.unwrap();
+        let vbox = pattern.vbox.unwrap();
+        let preserve_aspect_ratio = pattern.preserve_aspect_ratio.unwrap();
 
-fn set_pattern_on_draw_context(
-    pattern: &Pattern,
-    values: &ComputedValues,
-    draw_ctx: &mut DrawingCtx<'_>,
-    bbox: &BoundingBox,
-) -> Result<bool, RenderingError> {
-    assert!(pattern.is_resolved());
-
-    if pattern.node.is_none() {
-        // This means we didn't find any children among the fallbacks,
-        // so there is nothing to render.
-        return Ok(false);
-    }
+        let (pattern_x, pattern_y, pattern_width, pattern_height) = {
+            let params = if units == PatternUnits(CoordUnits::ObjectBoundingBox) {
+                draw_ctx.push_view_box(1.0, 1.0)
+            } else {
+                draw_ctx.get_view_params()
+            };
 
-    let units = pattern.units.unwrap();
-    let content_units = pattern.content_units.unwrap();
-    let pattern_affine = pattern.affine.unwrap();
-    let vbox = pattern.vbox.unwrap();
-    let preserve_aspect_ratio = pattern.preserve_aspect_ratio.unwrap();
+            let pattern_x = pattern.x.unwrap().normalize(values, &params);
+            let pattern_y = pattern.y.unwrap().normalize(values, &params);
+            let pattern_width = pattern.width.unwrap().normalize(values, &params);
+            let pattern_height = pattern.height.unwrap().normalize(values, &params);
 
-    let (pattern_x, pattern_y, pattern_width, pattern_height) = {
-        let params = if units == PatternUnits(CoordUnits::ObjectBoundingBox) {
-            draw_ctx.push_view_box(1.0, 1.0)
-        } else {
-            draw_ctx.get_view_params()
+            (pattern_x, pattern_y, pattern_width, pattern_height)
         };
 
-        let pattern_x = pattern.x.unwrap().normalize(values, &params);
-        let pattern_y = pattern.y.unwrap().normalize(values, &params);
-        let pattern_width = pattern.width.unwrap().normalize(values, &params);
-        let pattern_height = pattern.height.unwrap().normalize(values, &params);
-
-        (pattern_x, pattern_y, pattern_width, pattern_height)
-    };
+        // Work out the size of the rectangle so it takes into account the object bounding box
 
-    // Work out the size of the rectangle so it takes into account the object bounding box
+        let bbwscale: f64;
+        let bbhscale: f64;
 
-    let bbwscale: f64;
-    let bbhscale: f64;
-
-    match units {
-        PatternUnits(CoordUnits::ObjectBoundingBox) => {
-            let bbrect = bbox.rect.unwrap();
-            bbwscale = bbrect.width;
-            bbhscale = bbrect.height;
-        }
+        match units {
+            PatternUnits(CoordUnits::ObjectBoundingBox) => {
+                let bbrect = bbox.rect.unwrap();
+                bbwscale = bbrect.width;
+                bbhscale = bbrect.height;
+            }
 
-        PatternUnits(CoordUnits::UserSpaceOnUse) => {
-            bbwscale = 1.0;
-            bbhscale = 1.0;
+            PatternUnits(CoordUnits::UserSpaceOnUse) => {
+                bbwscale = 1.0;
+                bbhscale = 1.0;
+            }
         }
-    }
 
-    let cr = draw_ctx.get_cairo_context();
-    let affine = cr.get_matrix();
-    let taffine = cairo::Matrix::multiply(&pattern_affine, &affine);
+        let cr = draw_ctx.get_cairo_context();
+        let affine = cr.get_matrix();
+        let taffine = cairo::Matrix::multiply(&pattern_affine, &affine);
 
-    let mut scwscale = (taffine.xx * taffine.xx + taffine.xy * taffine.xy).sqrt();
-    let mut schscale = (taffine.yx * taffine.yx + taffine.yy * taffine.yy).sqrt();
+        let mut scwscale = (taffine.xx * taffine.xx + taffine.xy * taffine.xy).sqrt();
+        let mut schscale = (taffine.yx * taffine.yx + taffine.yy * taffine.yy).sqrt();
 
-    let pw: i32 = (pattern_width * bbwscale * scwscale) as i32;
-    let ph: i32 = (pattern_height * bbhscale * schscale) as i32;
+        let pw: i32 = (pattern_width * bbwscale * scwscale) as i32;
+        let ph: i32 = (pattern_height * bbhscale * schscale) as i32;
 
-    let scaled_width = pattern_width * bbwscale;
-    let scaled_height = pattern_height * bbhscale;
+        let scaled_width = pattern_width * bbwscale;
+        let scaled_height = pattern_height * bbhscale;
 
-    if scaled_width.abs() < f64::EPSILON || scaled_height.abs() < f64::EPSILON || pw < 1 || ph < 1 {
-        return Ok(false);
-    }
-
-    scwscale = f64::from(pw) / scaled_width;
-    schscale = f64::from(ph) / scaled_height;
-
-    let mut affine: cairo::Matrix = cairo::Matrix::identity();
-
-    // Create the pattern coordinate system
-    match units {
-        PatternUnits(CoordUnits::ObjectBoundingBox) => {
-            let bbrect = bbox.rect.unwrap();
-            affine.translate(
-                bbrect.x + pattern_x * bbrect.width,
-                bbrect.y + pattern_y * bbrect.height,
-            );
+        if scaled_width.abs() < f64::EPSILON
+            || scaled_height.abs() < f64::EPSILON
+            || pw < 1
+            || ph < 1
+        {
+            return Ok(false);
         }
 
-        PatternUnits(CoordUnits::UserSpaceOnUse) => {
-            affine.translate(pattern_x, pattern_y);
-        }
-    }
-
-    // Apply the pattern transform
-    affine = cairo::Matrix::multiply(&affine, &pattern_affine);
+        scwscale = f64::from(pw) / scaled_width;
+        schscale = f64::from(ph) / scaled_height;
 
-    let mut caffine: cairo::Matrix;
+        let mut affine: cairo::Matrix = cairo::Matrix::identity();
 
-    // Create the pattern contents coordinate system
-    let _params = if let Some(vbox) = vbox {
-        // If there is a vbox, use that
-        let (mut x, mut y, w, h) = preserve_aspect_ratio.compute(
-            vbox.0.width,
-            vbox.0.height,
-            0.0,
-            0.0,
-            pattern_width * bbwscale,
-            pattern_height * bbhscale,
-        );
+        // Create the pattern coordinate system
+        match units {
+            PatternUnits(CoordUnits::ObjectBoundingBox) => {
+                let bbrect = bbox.rect.unwrap();
+                affine.translate(
+                    bbrect.x + pattern_x * bbrect.width,
+                    bbrect.y + pattern_y * bbrect.height,
+                );
+            }
 
-        x -= vbox.0.x * w / vbox.0.width;
-        y -= vbox.0.y * h / vbox.0.height;
+            PatternUnits(CoordUnits::UserSpaceOnUse) => {
+                affine.translate(pattern_x, pattern_y);
+            }
+        }
 
-        caffine = cairo::Matrix::new(w / vbox.0.width, 0.0, 0.0, h / vbox.0.height, x, y);
+        // Apply the pattern transform
+        affine = cairo::Matrix::multiply(&affine, &pattern_affine);
+
+        let mut caffine: cairo::Matrix;
+
+        // Create the pattern contents coordinate system
+        let _params = if let Some(vbox) = vbox {
+            // If there is a vbox, use that
+            let (mut x, mut y, w, h) = preserve_aspect_ratio.compute(
+                vbox.0.width,
+                vbox.0.height,
+                0.0,
+                0.0,
+                pattern_width * bbwscale,
+                pattern_height * bbhscale,
+            );
 
-        draw_ctx.push_view_box(vbox.0.width, vbox.0.height)
-    } else if content_units == PatternContentUnits(CoordUnits::ObjectBoundingBox) {
-        // If coords are in terms of the bounding box, use them
-        let bbrect = bbox.rect.unwrap();
+            x -= vbox.0.x * w / vbox.0.width;
+            y -= vbox.0.y * h / vbox.0.height;
 
-        caffine = cairo::Matrix::identity();
-        caffine.scale(bbrect.width, bbrect.height);
+            caffine = cairo::Matrix::new(w / vbox.0.width, 0.0, 0.0, h / vbox.0.height, x, y);
 
-        draw_ctx.push_view_box(1.0, 1.0)
-    } else {
-        caffine = cairo::Matrix::identity();
-        draw_ctx.get_view_params()
-    };
+            draw_ctx.push_view_box(vbox.0.width, vbox.0.height)
+        } else if content_units == PatternContentUnits(CoordUnits::ObjectBoundingBox) {
+            // If coords are in terms of the bounding box, use them
+            let bbrect = bbox.rect.unwrap();
 
-    if !scwscale.approx_eq_cairo(&1.0) || !schscale.approx_eq_cairo(&1.0) {
-        let mut scalematrix = cairo::Matrix::identity();
-        scalematrix.scale(scwscale, schscale);
-        caffine = cairo::Matrix::multiply(&caffine, &scalematrix);
+            caffine = cairo::Matrix::identity();
+            caffine.scale(bbrect.width, bbrect.height);
 
-        scalematrix = cairo::Matrix::identity();
-        scalematrix.scale(1.0 / scwscale, 1.0 / schscale);
+            draw_ctx.push_view_box(1.0, 1.0)
+        } else {
+            caffine = cairo::Matrix::identity();
+            draw_ctx.get_view_params()
+        };
 
-        affine = cairo::Matrix::multiply(&scalematrix, &affine);
-    }
+        if !scwscale.approx_eq_cairo(&1.0) || !schscale.approx_eq_cairo(&1.0) {
+            let mut scalematrix = cairo::Matrix::identity();
+            scalematrix.scale(scwscale, schscale);
+            caffine = cairo::Matrix::multiply(&caffine, &scalematrix);
 
-    // Draw to another surface
+            scalematrix = cairo::Matrix::identity();
+            scalematrix.scale(1.0 / scwscale, 1.0 / schscale);
 
-    let cr_save = draw_ctx.get_cairo_context();
+            affine = cairo::Matrix::multiply(&scalematrix, &affine);
+        }
 
-    let surface = cr_save
-        .get_target()
-        .create_similar(cairo::Content::ColorAlpha, pw, ph);
+        // Draw to another surface
 
-    let cr_pattern = cairo::Context::new(&surface);
+        let cr_save = draw_ctx.get_cairo_context();
 
-    draw_ctx.set_cairo_context(&cr_pattern);
+        let surface = cr_save
+            .get_target()
+            .create_similar(cairo::Content::ColorAlpha, pw, ph);
 
-    // Set up transformations to be determined by the contents units
+        let cr_pattern = cairo::Context::new(&surface);
 
-    // Draw everything
-    let pattern_node = pattern.node.clone().unwrap().upgrade().unwrap();
-    let pattern_cascaded = pattern_node.get_cascaded_values();
-    let pattern_values = pattern_cascaded.get();
+        draw_ctx.set_cairo_context(&cr_pattern);
 
-    cr_pattern.set_matrix(caffine);
+        // Set up transformations to be determined by the contents units
 
-    let res = draw_ctx.with_discrete_layer(&pattern_node, pattern_values, false, &mut |dc| {
-        pattern_node.draw_children(&pattern_cascaded, dc, false)
-    });
+        // Draw everything
+        let pattern_node = pattern.node.clone().unwrap().upgrade().unwrap();
+        let pattern_cascaded = pattern_node.get_cascaded_values();
+        let pattern_values = pattern_cascaded.get();
 
-    // Return to the original coordinate system and rendering context
+        cr_pattern.set_matrix(caffine);
 
-    draw_ctx.set_cairo_context(&cr_save);
+        let res = draw_ctx.with_discrete_layer(&pattern_node, pattern_values, false, &mut |dc| {
+            pattern_node.draw_children(&pattern_cascaded, dc, false)
+        });
 
-    // Set the final surface as a Cairo pattern into the Cairo context
+        // Return to the original coordinate system and rendering context
 
-    let surface_pattern = cairo::SurfacePattern::create(&surface);
-    surface_pattern.set_extend(cairo::Extend::Repeat);
+        draw_ctx.set_cairo_context(&cr_save);
 
-    let mut matrix = affine;
-    matrix.invert();
+        // Set the final surface as a Cairo pattern into the Cairo context
 
-    surface_pattern.set_matrix(matrix);
-    surface_pattern.set_filter(cairo::Filter::Best);
+        let surface_pattern = cairo::SurfacePattern::create(&surface);
+        surface_pattern.set_extend(cairo::Extend::Repeat);
 
-    cr_save.set_source(&cairo::Pattern::SurfacePattern(surface_pattern));
+        let mut matrix = affine;
+        matrix.invert();
 
-    res.and_then(|_| Ok(true))
-}
+        surface_pattern.set_matrix(matrix);
+        surface_pattern.set_filter(cairo::Filter::Best);
 
-pub fn pattern_resolve_fallbacks_and_set_pattern(
-    node: &RsvgNode,
-    draw_ctx: &mut DrawingCtx<'_>,
-    bbox: &BoundingBox,
-) -> Result<bool, RenderingError> {
-    assert!(node.get_type() == NodeType::Pattern);
+        cr_save.set_source(&cairo::Pattern::SurfacePattern(surface_pattern));
 
-    node.with_impl(|node_pattern: &NodePattern| {
-        let pattern = &*node_pattern.pattern.borrow();
-        let resolved = resolve_pattern(pattern, draw_ctx);
-        let cascaded = node.get_cascaded_values();
-        let values = cascaded.get();
-        set_pattern_on_draw_context(&resolved, values, draw_ctx, bbox)
-    })
+        res.and_then(|_| Ok(true))
+    }
 }
 
 #[cfg(test)]


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