[librsvg: 3/11] Normalize gradients before setting them on the cr




commit 068aa558f0b2eab3e45bfe2b858169a0de533389
Author: Federico Mena Quintero <federico gnome org>
Date:   Mon Nov 30 21:01:47 2020 -0600

    Normalize gradients before setting them on the cr
    
    This introduces a Gradient struct again, which is in user-space
    units.  It gets constructed from ResolvedGradient.to_user_space().

 src/drawing_ctx.rs | 61 ++++++++-------------------------------
 src/gradient.rs    | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 49 deletions(-)
---
diff --git a/src/drawing_ctx.rs b/src/drawing_ctx.rs
index 9fe4175d..19e2dc6d 100644
--- a/src/drawing_ctx.rs
+++ b/src/drawing_ctx.rs
@@ -20,7 +20,7 @@ use crate::error::{AcquireError, RenderingError};
 use crate::filter::FilterValue;
 use crate::filters;
 use crate::float_eq_cairo::ApproxEqCairo;
-use crate::gradient::{GradientUnits, ResolvedGradient, ResolvedGradientVariant, SpreadMethod};
+use crate::gradient::{Gradient, GradientVariant, SpreadMethod};
 use crate::marker;
 use crate::node::{CascadedValues, Node, NodeBorrow, NodeDraw};
 use crate::paint_server::{PaintServer, PaintSource};
@@ -933,62 +933,26 @@ impl DrawingCtx {
         Ok(child_surface)
     }
 
-    fn set_gradient(
-        self: &mut DrawingCtx,
-        gradient: &ResolvedGradient,
-        _acquired_nodes: &mut AcquiredNodes<'_>,
-        opacity: UnitInterval,
-        values: &ComputedValues,
-        bbox: &BoundingBox,
-    ) -> Result<bool, RenderingError> {
-        let GradientUnits(units) = gradient.get_units();
-        let transform = if let Ok(t) = bbox.rect_to_transform(units) {
-            t
-        } else {
-            return Ok(false);
-        };
-
-        let params = self.push_coord_units(units);
-
-        let g = match gradient.get_variant() {
-            ResolvedGradientVariant::Linear { x1, y1, x2, y2 } => {
-                cairo::Gradient::clone(&cairo::LinearGradient::new(
-                    x1.normalize(values, &params),
-                    y1.normalize(values, &params),
-                    x2.normalize(values, &params),
-                    y2.normalize(values, &params),
-                ))
+    fn set_gradient(self: &mut DrawingCtx, gradient: &Gradient, opacity: UnitInterval) {
+        let g = match gradient.variant {
+            GradientVariant::Linear { x1, y1, x2, y2 } => {
+                cairo::Gradient::clone(&cairo::LinearGradient::new(x1, y1, x2, y2))
             }
 
-            ResolvedGradientVariant::Radial {
+            GradientVariant::Radial {
                 cx,
                 cy,
                 r,
                 fx,
                 fy,
                 fr,
-            } => {
-                let n_cx = cx.normalize(values, &params);
-                let n_cy = cy.normalize(values, &params);
-                let n_r = r.normalize(values, &params);
-                let n_fx = fx.normalize(values, &params);
-                let n_fy = fy.normalize(values, &params);
-                let n_fr = fr.normalize(values, &params);
-
-                cairo::Gradient::clone(&cairo::RadialGradient::new(
-                    n_fx, n_fy, n_fr, n_cx, n_cy, n_r,
-                ))
-            }
+            } => cairo::Gradient::clone(&cairo::RadialGradient::new(fx, fy, fr, cx, cy, r)),
         };
 
-        let transform = transform.pre_transform(&gradient.get_transform());
-        if let Some(m) = transform.invert() {
-            g.set_matrix(m.into())
-        }
+        g.set_matrix(gradient.transform.into());
+        g.set_extend(cairo::Extend::from(gradient.spread));
 
-        g.set_extend(cairo::Extend::from(gradient.get_spread()));
-
-        for stop in gradient.get_stops() {
+        for stop in &gradient.stops {
             let UnitInterval(stop_offset) = stop.offset;
             let UnitInterval(o) = opacity;
             let UnitInterval(stop_opacity) = stop.opacity;
@@ -1004,8 +968,6 @@ impl DrawingCtx {
 
         let cr = self.cr.clone();
         cr.set_source(&g);
-
-        Ok(true)
     }
 
     fn set_pattern(
@@ -1193,7 +1155,8 @@ impl DrawingCtx {
 
         match paint_source {
             PaintSource::Gradient(g, c) => {
-                if self.set_gradient(&g, acquired_nodes, opacity, values, bbox)? {
+                if let Some(gradient) = g.to_user_space(bbox, self, values) {
+                    self.set_gradient(&gradient, opacity);
                     Ok(true)
                 } else if let Some(c) = c {
                     self.set_color(c, opacity, current_color)
diff --git a/src/gradient.rs b/src/gradient.rs
index e0f28931..3cbca442 100644
--- a/src/gradient.rs
+++ b/src/gradient.rs
@@ -7,14 +7,17 @@ use markup5ever::{
 use std::cell::RefCell;
 
 use crate::attributes::Attributes;
+use crate::bbox::BoundingBox;
 use crate::coord_units::CoordUnits;
 use crate::document::{AcquiredNodes, NodeStack};
+use crate::drawing_ctx::DrawingCtx;
 use crate::element::{Draw, Element, ElementResult, SetAttributes};
 use crate::error::*;
 use crate::href::{is_href, set_href};
 use crate::length::*;
 use crate::node::{CascadedValues, Node, NodeBorrow};
 use crate::parsers::{Parse, ParseValue};
+use crate::properties::ComputedValues;
 use crate::property_defs::StopColor;
 use crate::transform::Transform;
 use crate::unit_interval::UnitInterval;
@@ -139,6 +142,25 @@ pub enum ResolvedGradientVariant {
     },
 }
 
+/// Parameters specific to each gradient type, after normalizing to user-space units.
+pub enum GradientVariant {
+    Linear {
+        x1: f64,
+        y1: f64,
+        x2: f64,
+        y2: f64,
+    },
+
+    Radial {
+        cx: f64,
+        cy: f64,
+        r: f64,
+        fx: f64,
+        fy: f64,
+        fr: f64,
+    },
+}
+
 impl UnresolvedVariant {
     fn into_resolved(self) -> ResolvedGradientVariant {
         assert!(self.is_resolved());
@@ -341,6 +363,15 @@ pub struct ResolvedGradient {
     variant: ResolvedGradientVariant,
 }
 
+/// Gradient normalized to user-space units.
+pub struct Gradient {
+    pub transform: Transform,
+    pub spread: SpreadMethod,
+    pub stops: Vec<ColorStop>,
+
+    pub variant: GradientVariant,
+}
+
 impl UnresolvedGradient {
     fn into_resolved(self) -> ResolvedGradient {
         assert!(self.is_resolved());
@@ -683,6 +714,60 @@ impl ResolvedGradient {
     pub fn get_variant(&self) -> &ResolvedGradientVariant {
         &self.variant
     }
+
+    pub fn to_user_space(
+        &self,
+        bbox: &BoundingBox,
+        draw_ctx: &DrawingCtx,
+        values: &ComputedValues,
+    ) -> Option<Gradient> {
+        let units = self.units.0;
+        let transform = if let Ok(t) = bbox.rect_to_transform(units) {
+            t
+        } else {
+            return None;
+        };
+
+        let params = draw_ctx.push_coord_units(units);
+
+        let transform = if let Some(m) = transform.pre_transform(&self.transform).invert() {
+            m
+        } else {
+            return None;
+        };
+
+        let variant = match self.variant {
+            ResolvedGradientVariant::Linear { x1, y1, x2, y2 } => GradientVariant::Linear {
+                x1: x1.normalize(values, &params),
+                y1: y1.normalize(values, &params),
+                x2: x2.normalize(values, &params),
+                y2: y2.normalize(values, &params),
+            },
+
+            ResolvedGradientVariant::Radial {
+                cx,
+                cy,
+                r,
+                fx,
+                fy,
+                fr,
+            } => GradientVariant::Radial {
+                cx: cx.normalize(values, &params),
+                cy: cy.normalize(values, &params),
+                r: r.normalize(values, &params),
+                fx: fx.normalize(values, &params),
+                fy: fy.normalize(values, &params),
+                fr: fr.normalize(values, &params),
+            },
+        };
+
+        Some(Gradient {
+            transform,
+            spread: self.spread,
+            stops: self.stops.clone(),
+            variant,
+        })
+    }
 }
 
 #[cfg(test)]


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