[librsvg: 1/2] paint_server: introduce PaintSource trait
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/2] paint_server: introduce PaintSource trait
- Date: Sun, 18 Nov 2018 09:22:36 +0000 (UTC)
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, ¶ms),
- y1.as_ref().unwrap().normalize(values, ¶ms),
- x2.as_ref().unwrap().normalize(values, ¶ms),
- y2.as_ref().unwrap().normalize(values, ¶ms),
- );
-
- 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, ¶ms);
- let n_cy = cy.as_ref().unwrap().normalize(values, ¶ms);
- let n_r = r.as_ref().unwrap().normalize(values, ¶ms);
- let n_fx = fx.as_ref().unwrap().normalize(values, ¶ms);
- let n_fy = fy.as_ref().unwrap().normalize(values, ¶ms);
+ 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, ¶ms),
+ y1.as_ref().unwrap().normalize(values, ¶ms),
+ x2.as_ref().unwrap().normalize(values, ¶ms),
+ y2.as_ref().unwrap().normalize(values, ¶ms),
+ );
- 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, ¶ms);
+ let n_cy = cy.as_ref().unwrap().normalize(values, ¶ms);
+ let n_r = r.as_ref().unwrap().normalize(values, ¶ms);
+ let n_fx = fx.as_ref().unwrap().normalize(values, ¶ms);
+ let n_fy = fy.as_ref().unwrap().normalize(values, ¶ms);
+
+ 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, ¶ms);
+ let pattern_y = pattern.y.unwrap().normalize(values, ¶ms);
+ let pattern_width = pattern.width.unwrap().normalize(values, ¶ms);
+ let pattern_height = pattern.height.unwrap().normalize(values, ¶ms);
- 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, ¶ms);
- let pattern_y = pattern.y.unwrap().normalize(values, ¶ms);
- let pattern_width = pattern.width.unwrap().normalize(values, ¶ms);
- let pattern_height = pattern.height.unwrap().normalize(values, ¶ms);
-
- (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]