[librsvg] pattern.rs: New file; resolution of pattern fallbacks is now done in Rust
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] pattern.rs: New file; resolution of pattern fallbacks is now done in Rust
- Date: Wed, 8 Feb 2017 19:13:01 +0000 (UTC)
commit 198103a59c208a1562e101d89d90e7068d0018dd
Author: Federico Mena Quintero <federico gnome org>
Date: Wed Feb 8 08:22:38 2017 -0600
pattern.rs: New file; resolution of pattern fallbacks is now done in Rust
rsvg-cairo-draw.c | 178 +++++++++--------------------------------------
rsvg-cairo-draw.h | 2 +
rsvg-paint-server.c | 140 +++++++++----------------------------
rsvg-paint-server.h | 40 ++++++++++-
rust/Cargo.toml | 2 +
rust/src/drawing_ctx.rs | 32 +++++++++
rust/src/lib.rs | 7 ++
rust/src/pattern.rs | 178 +++++++++++++++++++++++++++++++++++++----------
8 files changed, 286 insertions(+), 293 deletions(-)
---
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index 0b51c39..3cc2f8c 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -169,155 +169,15 @@ _set_source_rsvg_solid_color (RsvgDrawingCtx * ctx,
static void
_set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
- RsvgPattern * rsvg_pattern, guint8 opacity, RsvgBbox bbox)
+ RsvgPattern * rsvg_pattern, RsvgBbox bbox)
{
- RsvgCairoRender *render = RSVG_CAIRO_RENDER (ctx->render);
- RsvgPattern local_pattern = *rsvg_pattern;
- cairo_t *cr_render, *cr_pattern;
- cairo_pattern_t *pattern;
- cairo_surface_t *surface;
- cairo_matrix_t matrix;
- cairo_matrix_t affine, caffine, taffine;
- double bbwscale, bbhscale, scwscale, schscale;
- double patternw, patternh, patternx, patterny;
- double scaled_width, scaled_height;
- int pw, ph;
-
- rsvg_pattern = &local_pattern;
- rsvg_pattern_fix_fallback (ctx, rsvg_pattern);
- cr_render = render->cr;
-
- if (rsvg_pattern->obj_bbox)
- rsvg_drawing_ctx_push_view_box (ctx, 1., 1.);
-
- patternx = rsvg_length_normalize (&rsvg_pattern->x, ctx);
- patterny = rsvg_length_normalize (&rsvg_pattern->y, ctx);
- patternw = rsvg_length_normalize (&rsvg_pattern->width, ctx);
- patternh = rsvg_length_normalize (&rsvg_pattern->height, ctx);
-
- if (rsvg_pattern->obj_bbox)
- rsvg_drawing_ctx_pop_view_box (ctx);
-
- /* Work out the size of the rectangle so it takes into account the object bounding box */
-
- if (rsvg_pattern->obj_bbox) {
- bbwscale = bbox.rect.width;
- bbhscale = bbox.rect.height;
- } else {
- bbwscale = 1.0;
- bbhscale = 1.0;
- }
-
- cairo_matrix_multiply (&taffine, &rsvg_pattern->affine, &rsvg_current_state (ctx)->affine);
-
- scwscale = sqrt (taffine.xx * taffine.xx + taffine.xy * taffine.xy);
- schscale = sqrt (taffine.yx * taffine.yx + taffine.yy * taffine.yy);
+ Pattern *pattern;
- pw = patternw * bbwscale * scwscale;
- ph = patternh * bbhscale * schscale;
+ pattern = rsvg_pattern_node_to_rust_pattern ((RsvgNode *) rsvg_pattern);
- scaled_width = patternw * bbwscale;
- scaled_height = patternh * bbhscale;
-
- if (fabs (scaled_width) < DBL_EPSILON || fabs (scaled_height) < DBL_EPSILON)
- return;
-
- scwscale = pw / scaled_width;
- schscale = ph / scaled_height;
-
- surface = cairo_surface_create_similar (cairo_get_target (cr_render),
- CAIRO_CONTENT_COLOR_ALPHA, pw, ph);
- cr_pattern = cairo_create (surface);
-
- /* Create the pattern coordinate system */
- if (rsvg_pattern->obj_bbox) {
- /* subtract the pattern origin */
- cairo_matrix_init_translate (&affine,
- bbox.rect.x + patternx * bbox.rect.width,
- bbox.rect.y + patterny * bbox.rect.height);
- } else {
- /* subtract the pattern origin */
- cairo_matrix_init_translate (&affine, patternx, patterny);
- }
- /* Apply the pattern transform */
- cairo_matrix_multiply (&affine, &affine, &rsvg_pattern->affine);
-
- /* Create the pattern contents coordinate system */
- if (rsvg_pattern->vbox.active) {
- /* If there is a vbox, use that */
- double w, h, x, y;
- w = patternw * bbwscale;
- h = patternh * bbhscale;
- x = 0;
- y = 0;
- rsvg_aspect_ratio_compute (rsvg_pattern->preserve_aspect_ratio,
- rsvg_pattern->vbox.rect.width,
- rsvg_pattern->vbox.rect.height,
- &x, &y, &w, &h);
-
- x -= rsvg_pattern->vbox.rect.x * w / rsvg_pattern->vbox.rect.width;
- y -= rsvg_pattern->vbox.rect.y * h / rsvg_pattern->vbox.rect.height;
-
- cairo_matrix_init (&caffine,
- w / rsvg_pattern->vbox.rect.width,
- 0,
- 0,
- h / rsvg_pattern->vbox.rect.height,
- x,
- y);
- rsvg_drawing_ctx_push_view_box (ctx, rsvg_pattern->vbox.rect.width, rsvg_pattern->vbox.rect.height);
- } else if (rsvg_pattern->obj_cbbox) {
- /* If coords are in terms of the bounding box, use them */
- cairo_matrix_init_scale (&caffine, bbox.rect.width, bbox.rect.height);
- rsvg_drawing_ctx_push_view_box (ctx, 1., 1.);
- } else {
- cairo_matrix_init_identity (&caffine);
- }
-
- if (scwscale != 1.0 || schscale != 1.0) {
- cairo_matrix_t scalematrix;
-
- cairo_matrix_init_scale (&scalematrix, scwscale, schscale);
- cairo_matrix_multiply (&caffine, &caffine, &scalematrix);
- cairo_matrix_init_scale (&scalematrix, 1. / scwscale, 1. / schscale);
- cairo_matrix_multiply (&affine, &scalematrix, &affine);
- }
+ pattern_resolve_fallbacks_and_set_pattern (pattern, ctx, bbox);
- /* Draw to another surface */
- render->cr = cr_pattern;
-
- /* Set up transformations to be determined by the contents units */
- rsvg_state_push (ctx);
- rsvg_current_state (ctx)->personal_affine =
- rsvg_current_state (ctx)->affine = caffine;
-
- /* Draw everything */
- _rsvg_node_draw_children ((RsvgNode *) rsvg_pattern, ctx, 2);
- /* Return to the original coordinate system */
- rsvg_state_pop (ctx);
-
- /* Set the render to draw where it used to */
- render->cr = cr_render;
-
- pattern = cairo_pattern_create_for_surface (surface);
- cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
-
- matrix = affine;
- if (cairo_matrix_invert (&matrix) != CAIRO_STATUS_SUCCESS)
- goto out;
-
- cairo_pattern_set_matrix (pattern, &matrix);
- cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);
-
- cairo_set_source (cr_render, pattern);
-
- cairo_pattern_destroy (pattern);
- cairo_destroy (cr_pattern);
- cairo_surface_destroy (surface);
-
- out:
- if (rsvg_pattern->obj_cbbox || rsvg_pattern->vbox.active)
- rsvg_drawing_ctx_pop_view_box (ctx);
+ pattern_destroy (pattern);
}
/* note: _set_source_rsvg_paint_server does not change cairo's CTM */
@@ -339,7 +199,7 @@ _set_source_rsvg_paint_server (RsvgDrawingCtx * ctx,
else if (rsvg_node_type (node) == RSVG_NODE_TYPE_RADIAL_GRADIENT)
_set_source_rsvg_radial_gradient (ctx, (RsvgRadialGradient *) node, opacity, bbox);
else if (rsvg_node_type (node) == RSVG_NODE_TYPE_PATTERN)
- _set_source_rsvg_pattern (ctx, (RsvgPattern *) node, opacity, bbox);
+ _set_source_rsvg_pattern (ctx, (RsvgPattern *) node, bbox);
rsvg_drawing_ctx_release_node (ctx, node);
break;
@@ -690,6 +550,32 @@ rsvg_cairo_get_cairo_context (RsvgDrawingCtx *ctx)
return render->cr;
}
+/* FIXME: Usage of this function is more less a hack. Some code does this:
+ *
+ * save_cr = rsvg_cairo_get_cairo_context (ctx);
+ *
+ * some_surface = create_surface ();
+ *
+ * cr = cairo_create (some_surface);
+ *
+ * rsvg_cairo_set_cairo_context (ctx, cr);
+ *
+ * ... draw with ctx but to that temporary surface
+ *
+ * rsvg_cairo_set_cairo_context (ctx, save_cr);
+ *
+ * It would be better to have an explicit push/pop for the cairo_t, or
+ * pushing a temporary surface, or something that does not involve
+ * monkeypatching the cr directly.
+ */
+void
+rsvg_cairo_set_cairo_context (RsvgDrawingCtx *ctx, cairo_t *cr)
+{
+ RsvgCairoRender *render = RSVG_CAIRO_RENDER (ctx->render);
+
+ render->cr = cr;
+}
+
static void
rsvg_cairo_generate_mask (cairo_t * cr, RsvgMask * self, RsvgDrawingCtx * ctx, RsvgBbox * bbox)
{
diff --git a/rsvg-cairo-draw.h b/rsvg-cairo-draw.h
index aff07c6..9cac30d 100644
--- a/rsvg-cairo-draw.h
+++ b/rsvg-cairo-draw.h
@@ -46,6 +46,8 @@ void rsvg_cairo_render_surface (RsvgDrawingCtx *ctx, cairo_surf
double x, double y, double w, double h);
G_GNUC_INTERNAL
cairo_t *rsvg_cairo_get_cairo_context (RsvgDrawingCtx *ctx);
+G_GNUC_INTERNAL
+void rsvg_cairo_set_cairo_context (RsvgDrawingCtx *ctx, cairo_t *cr);
G_GNUC_INTERNAL
void rsvg_cairo_push_discrete_layer (RsvgDrawingCtx *ctx);
diff --git a/rsvg-paint-server.c b/rsvg-paint-server.c
index 0977be6..981c2de 100644
--- a/rsvg-paint-server.c
+++ b/rsvg-paint-server.c
@@ -502,127 +502,55 @@ rsvg_new_pattern (const char *element_name)
return &pattern->super;
}
-typedef const char * (* GetFallbackFn) (RsvgNode *node);
-typedef void (* ApplyFallbackFn) (RsvgNode *node, RsvgNode *fallback_node);
-
-/* Some SVG paint servers can reference a "parent" or "fallback" paint server
- * through the xlink:href attribute (for example,
- * http://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementHrefAttribute )
- * This is used to define a chain of properties to be resolved from each
- * fallback.
- */
-static void
-resolve_fallbacks (RsvgDrawingCtx *ctx,
- RsvgNode *data,
- RsvgNode *last_fallback,
- GetFallbackFn get_fallback,
- ApplyFallbackFn apply_fallback)
+Pattern *
+rsvg_pattern_node_to_rust_pattern (RsvgNode *node)
{
- RsvgNode *fallback;
- const char *fallback_id;
-
- fallback_id = get_fallback (last_fallback);
- if (fallback_id == NULL)
- return;
- fallback = rsvg_drawing_ctx_acquire_node (ctx, fallback_id);
- if (fallback == NULL)
- return;
+ RsvgPattern *pnode;
+ Pattern *pattern;
- apply_fallback (data, fallback);
- resolve_fallbacks (ctx, data, fallback, get_fallback, apply_fallback);
-
- rsvg_drawing_ctx_release_node (ctx, fallback);
-}
-
-static const char *
-pattern_get_fallback (RsvgNode *node)
-{
- if (rsvg_node_type (node) == RSVG_NODE_TYPE_PATTERN) {
- RsvgPattern *pattern = (RsvgPattern *) node;
-
- return pattern->fallback;
- } else
+ if (rsvg_node_type (node) != RSVG_NODE_TYPE_PATTERN)
return NULL;
+
+ pnode = (RsvgPattern *) node;
+
+ pattern = pattern_new (pnode->hasx ? &pnode->x : NULL,
+ pnode->hasy ? &pnode->y : NULL,
+ pnode->haswidth ? &pnode->width : NULL,
+ pnode->hasheight ? &pnode->height : NULL,
+ pnode->hasbbox ? &pnode->obj_bbox : NULL,
+ pnode->hascbox ? &pnode->obj_cbbox : NULL,
+ pnode->hasvbox ? &pnode->vbox : NULL,
+ pnode->hastransform ? &pnode->affine : NULL,
+ pnode->hasaspect ? &pnode->preserve_aspect_ratio : NULL,
+ pnode->fallback,
+ node);
+
+ return pattern;
}
static gboolean
-has_children_foreach (RsvgNode *node, gpointer data)
+count_one_child_fn (RsvgNode *child, gpointer data)
{
- gboolean *has_child = data;
+ gboolean *has_children = data;
- *has_child = TRUE;
- return FALSE; /* stop since we found a child */
+ *has_children = TRUE;
+ return FALSE;
}
static gboolean
-has_children (RsvgNode *node)
+node_has_at_least_one_child (RsvgNode *node)
{
- gboolean has_child = FALSE;
+ gboolean has_children = FALSE;
- rsvg_node_foreach_child (node, has_children_foreach, &has_child);
- return has_child;
+ rsvg_node_foreach_child (node, count_one_child_fn, &has_children);
+ return has_children;
}
-static void
-pattern_apply_fallback (RsvgNode *pattern_node, RsvgNode *fallback_node)
+gboolean
+rsvg_pattern_node_has_children (RsvgNode *node)
{
- RsvgPattern *pattern;
- RsvgPattern *fallback;
-
- g_assert (rsvg_node_type (pattern_node) == RSVG_NODE_TYPE_PATTERN);
-
- if (rsvg_node_type (fallback_node) != RSVG_NODE_TYPE_PATTERN)
- return;
-
- pattern = (RsvgPattern *) pattern_node;
- fallback = (RsvgPattern *) fallback_node;
-
- if (!pattern->hasx && fallback->hasx) {
- pattern->hasx = TRUE;
- pattern->x = fallback->x;
- }
- if (!pattern->hasy && fallback->hasy) {
- pattern->hasy = TRUE;
- pattern->y = fallback->y;
- }
- if (!pattern->haswidth && fallback->haswidth) {
- pattern->haswidth = TRUE;
- pattern->width = fallback->width;
- }
- if (!pattern->hasheight && fallback->hasheight) {
- pattern->hasheight = TRUE;
- pattern->height = fallback->height;
- }
- if (!pattern->hastransform && fallback->hastransform) {
- pattern->hastransform = TRUE;
- pattern->affine = fallback->affine;
- }
- if (!pattern->hasvbox && fallback->hasvbox) {
- pattern->vbox = fallback->vbox;
- }
- if (!pattern->hasaspect && fallback->hasaspect) {
- pattern->hasaspect = TRUE;
- pattern->preserve_aspect_ratio = fallback->preserve_aspect_ratio;
- }
- if (!pattern->hasbbox && fallback->hasbbox) {
- pattern->hasbbox = TRUE;
- pattern->obj_bbox = fallback->obj_bbox;
- }
- if (!pattern->hascbox && fallback->hascbox) {
- pattern->hascbox = TRUE;
- pattern->obj_cbbox = fallback->obj_cbbox;
- }
- if (!has_children (pattern_node) && has_children (fallback_node)) {
- pattern->super.children = fallback->super.children;
- }
-}
+ if (rsvg_node_type (node) != RSVG_NODE_TYPE_PATTERN)
+ return FALSE;
-void
-rsvg_pattern_fix_fallback (RsvgDrawingCtx *ctx, RsvgPattern * pattern)
-{
- resolve_fallbacks (ctx,
- (RsvgNode *) pattern,
- (RsvgNode *) pattern,
- pattern_get_fallback,
- pattern_apply_fallback);
+ return node_has_at_least_one_child (node);
}
diff --git a/rsvg-paint-server.h b/rsvg-paint-server.h
index 6d5ad2b..e260fba 100644
--- a/rsvg-paint-server.h
+++ b/rsvg-paint-server.h
@@ -83,6 +83,7 @@ struct _RsvgRadialGradient {
char *fallback;
};
+/* This is a Rust gradient from rust/src/gradient.rs */
typedef struct _Gradient Gradient;
/* Implemented in rust/src/gradient.rs */
@@ -148,6 +149,41 @@ struct _RsvgPattern {
char *fallback;
};
+/* This is a Rust pattern from rust/src/pattern.rs */
+typedef struct _Pattern Pattern;
+
+/* Implemented in rust/src/pattern.rs */
+G_GNUC_INTERNAL
+Pattern *
+pattern_new (RsvgLength *x,
+ RsvgLength *y,
+ RsvgLength *width,
+ RsvgLength *height,
+ gboolean *obj_bbox,
+ gboolean *obj_cbbox,
+ RsvgViewBox *vbox,
+ cairo_matrix_t *affine,
+ guint32 *preserve_aspect_ratio,
+ const char *fallback_name,
+ RsvgNode *node);
+
+/* Implemented in rust/src/pattern.rs */
+G_GNUC_INTERNAL
+void pattern_destroy (Pattern *pattern);
+
+/* Implemented in rust/src/pattern.rs */
+G_GNUC_INTERNAL
+void pattern_resolve_fallbacks_and_set_pattern (Pattern *pattern,
+ RsvgDrawingCtx *draw_ctx,
+ RsvgBbox bbox);
+
+G_GNUC_INTERNAL
+Pattern *rsvg_pattern_node_to_rust_pattern (RsvgNode *node);
+
+G_GNUC_INTERNAL
+gboolean rsvg_pattern_node_has_children (RsvgNode *node);
+
+
struct _RsvgSolidColor {
gboolean currentcolor;
guint32 argb;
@@ -189,9 +225,7 @@ G_GNUC_INTERNAL
RsvgNode *rsvg_new_stop (const char *element_name);
G_GNUC_INTERNAL
RsvgNode *rsvg_new_pattern (const char *element_name);
-G_GNUC_INTERNAL
-void rsvg_pattern_fix_fallback (RsvgDrawingCtx * ctx,
- RsvgPattern * pattern);
+
G_END_DECLS
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index 6579336..4dc2d97 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -11,11 +11,13 @@ bitflags = ""
#git = "https://github.com/gtk-rs/cairo.git"
git = "https://github.com/federicomenaquintero/cairo.git"
#git = "file:///home/federico/src/gtk-rs/cairo"
+#features = ["png"]
[dependencies.cairo-rs]
#git = "https://github.com/gtk-rs/cairo.git"
git = "https://github.com/federicomenaquintero/cairo.git"
#git = "file:///home/federico/src/gtk-rs/cairo"
+#features = ["png"]
[dependencies.glib]
git = "https://github.com/gtk-rs/glib"
diff --git a/rust/src/drawing_ctx.rs b/rust/src/drawing_ctx.rs
index 60d2900..d166cd6 100644
--- a/rust/src/drawing_ctx.rs
+++ b/rust/src/drawing_ctx.rs
@@ -40,6 +40,9 @@ extern "C" {
fn rsvg_drawing_ctx_set_current_state_affine (draw_ctx: *const RsvgDrawingCtx,
affine: *const cairo::Matrix);
+ fn rsvg_state_push (draw_ctx: *const RsvgDrawingCtx);
+ fn rsvg_state_pop (draw_ctx: *const RsvgDrawingCtx);
+
fn rsvg_state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
state: *mut RsvgState,
dominate: libc::c_int);
@@ -48,6 +51,9 @@ extern "C" {
builder: *const RsvgPathBuilder);
fn rsvg_cairo_get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
+ fn rsvg_cairo_set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
+
+ fn _rsvg_node_draw_children (node: *const RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate:
libc::c_int);
}
pub fn get_dpi (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
@@ -115,6 +121,14 @@ pub fn get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
}
}
+pub fn set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
+ unsafe {
+ let raw_cr = cr.to_glib_none ().0;
+
+ rsvg_cairo_set_cairo_context (draw_ctx, raw_cr);
+ }
+}
+
pub fn get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix {
unsafe {
rsvg_drawing_ctx_get_current_state_affine (draw_ctx)
@@ -126,3 +140,21 @@ pub fn set_current_state_affine (draw_ctx: *const RsvgDrawingCtx, affine: cairo:
rsvg_drawing_ctx_set_current_state_affine (draw_ctx, &affine);
}
}
+
+pub fn state_push (draw_ctx: *const RsvgDrawingCtx) {
+ unsafe {
+ rsvg_state_push (draw_ctx);
+ }
+}
+
+pub fn state_pop (draw_ctx: *const RsvgDrawingCtx) {
+ unsafe {
+ rsvg_state_pop (draw_ctx);
+ }
+}
+
+pub fn node_draw_children (draw_ctx: *const RsvgDrawingCtx, c_node: *const RsvgNode, dominate: libc::c_int) {
+ unsafe {
+ _rsvg_node_draw_children (c_node, draw_ctx, dominate);
+ }
+}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 37b787a..ef5012c 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -58,6 +58,12 @@ pub use viewbox::{
RsvgViewBox
};
+pub use pattern::{
+ pattern_new,
+ pattern_destroy,
+ pattern_resolve_fallbacks_and_set_pattern,
+};
+
mod aspect_ratio;
mod bbox;
@@ -69,6 +75,7 @@ mod marker;
mod node;
mod path_builder;
mod path_parser;
+mod pattern;
mod property_bag;
mod state;
mod shapes;
diff --git a/rust/src/pattern.rs b/rust/src/pattern.rs
index 0073671..e0fc383 100644
--- a/rust/src/pattern.rs
+++ b/rust/src/pattern.rs
@@ -3,8 +3,13 @@ extern crate cairo;
extern crate cairo_sys;
extern crate glib;
+use std::io;
+use std::io::prelude::*;
+use std::fs::File;
+
use self::glib::translate::*;
+use aspect_ratio::*;
use length::*;
use drawing_ctx;
@@ -16,19 +21,33 @@ use util::*;
use viewbox::*;
use self::cairo::MatrixTrait;
-use self::cairo::enums::Content;
+use self::cairo::enums::*;
+use self::cairo::SurfacePattern;
+use self::cairo::Pattern as CairoPattern;
pub struct Pattern {
pub obj_bbox: Option<bool>,
pub obj_cbbox: Option<bool>,
pub vbox: Option<RsvgViewBox>,
- pub preserve_aspect_ratio: Option<u32>,
+ pub preserve_aspect_ratio: Option<AspectRatio>,
pub affine: Option<cairo::Matrix>,
pub fallback: Option<String>,
pub x: Option<RsvgLength>,
pub y: Option<RsvgLength>,
pub width: Option<RsvgLength>,
- pub height: Option<RsvgLength>
+ pub height: Option<RsvgLength>,
+
+ // We just use c_node to see if the C implementation has children
+ pub c_node: *const RsvgNode
+}
+
+extern "C" {
+ fn rsvg_pattern_node_to_rust_pattern (node: *const RsvgNode) -> *mut Pattern;
+ fn rsvg_pattern_node_has_children (node: *const RsvgNode) -> bool;
+}
+
+fn pattern_node_has_children (c_node: *const RsvgNode) -> bool {
+ unsafe { rsvg_pattern_node_has_children (c_node) }
}
impl Pattern {
@@ -41,20 +60,21 @@ impl Pattern {
self.x.is_some () &&
self.y.is_some () &&
self.width.is_some () &&
- self.height.is_some ()
- // FIXME: which fallback contains the children?
+ self.height.is_some () &&
+ pattern_node_has_children (self.c_node)
}
fn resolve_from_defaults (&mut self) {
- /* FIXME: check the spec */
/* These are per the spec */
if self.obj_bbox.is_none () { self.obj_bbox = Some (true); }
if self.obj_cbbox.is_none () { self.obj_cbbox = Some (false); }
if self.vbox.is_none () { self.vbox = Some (RsvgViewBox::new_inactive ()); }
- // FIXME: this is RSVG_ASPECT_RATIO_XMID_YMID; use a constant, not a number. Spec says "xMidYMid
meet"
- if self.preserve_aspect_ratio.is_none () { self.preserve_aspect_ratio = Some (1 << 4); }
+ if self.preserve_aspect_ratio.is_none () {
+ let aspect: AspectRatio = Default::default ();
+ self.preserve_aspect_ratio = Some (aspect);
+ }
if self.affine.is_none () { self.affine = Some (cairo::Matrix::identity ()); }
@@ -64,6 +84,9 @@ impl Pattern {
if self.y.is_none () { self.y = Some (RsvgLength::parse ("0",
LengthDir::Horizontal)); }
if self.width.is_none () { self.width = Some (RsvgLength::parse ("0",
LengthDir::Horizontal)); }
if self.height.is_none () { self.height = Some (RsvgLength::parse ("0",
LengthDir::Horizontal)); }
+
+ // We don't resolve the children here - instead, we'll just
+ // NOP if there are no children at drawing time.
}
fn resolve_from_fallback (&mut self, fallback: &Pattern) {
@@ -83,6 +106,10 @@ impl Pattern {
if self.fallback.is_none () {
self.fallback = clone_fallback_name (&fallback.fallback);
}
+
+ if !pattern_node_has_children (self.c_node) {
+ self.c_node = fallback.c_node;
+ }
}
}
@@ -99,6 +126,7 @@ impl Clone for Pattern {
y: self.y,
width: self.width,
height: self.height,
+ c_node: self.c_node
}
}
}
@@ -150,10 +178,6 @@ impl Drop for NodeFallbackSource {
}
}
-extern "C" {
- fn rsvg_pattern_node_to_rust_pattern (node: *const RsvgNode) -> *mut Pattern;
-}
-
impl FallbackSource for NodeFallbackSource {
fn get_fallback (&mut self, name: &str) -> Option<Box<Pattern>> {
let fallback_node = drawing_ctx::acquire_node (self.draw_ctx, name);
@@ -178,11 +202,14 @@ impl FallbackSource for NodeFallbackSource {
fn set_pattern_on_draw_context (pattern: &Pattern,
draw_ctx: *mut RsvgDrawingCtx,
- opacity: u8,
bbox: &RsvgBbox) {
assert! (pattern.is_resolved ());
- let obj_bbox = pattern.obj_bbox.unwrap ();
+ let obj_bbox = pattern.obj_bbox.unwrap ();
+ let obj_cbbox = pattern.obj_cbbox.unwrap ();
+ let pattern_affine = pattern.affine.unwrap ();
+ let vbox = pattern.vbox.unwrap ();
+ let preserve_aspect_ratio = pattern.preserve_aspect_ratio.unwrap ();
if obj_bbox {
drawing_ctx::push_view_box (draw_ctx, 1.0, 1.0);
@@ -210,13 +237,13 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
bbhscale = 1.0;
}
- let taffine = cairo::Matrix::multiply (&pattern.affine.unwrap (), &drawing_ctx::get_current_state_affine
(draw_ctx));
+ let taffine = cairo::Matrix::multiply (&pattern_affine, &drawing_ctx::get_current_state_affine
(draw_ctx));
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 = pattern_width * bbwscale * scwscale;
- let ph = pattern_height * bbhscale * schscale;
+ 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;
@@ -225,14 +252,8 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
return
}
- scwscale = pw / scaled_width;
- schscale = ph / scaled_height;
-
- let cr = drawing_ctx::get_cairo_context (draw_ctx);
-
- let surface = cr.get_target ().create_similar (Content::ColorAlpha, pw as i32, ph as i32);
-
- let cr_pattern = cairo::Context::new (&surface);
+ scwscale = pw as f64 / scaled_width;
+ schscale = ph as f64 / scaled_height;
let mut affine: cairo::Matrix = cairo::Matrix::identity ();
@@ -245,17 +266,96 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
}
// Apply the pattern transform
- affine = cairo::Matrix::multiply (&affine, pattern.affine.as_ref ().unwrap ());
+ affine = cairo::Matrix::multiply (&affine, &pattern_affine);
+
+ let mut caffine: cairo::Matrix;
- // Create the pattern contents coordinate system
- if pattern.vbox.unwrap ().active {
+ let pushed_view_box: bool;
+
+ // Create the pattern contents coordinate system
+ if vbox.active {
// If there is a vbox, use that
- let w = pattern_width * bbwscale;
- let h = pattern_height * bbhscale;
- let mut x: f64 = 0.0;
- let mut y: f64 = 0.0;
+ let (mut x, mut y, w, h) = preserve_aspect_ratio.compute (vbox.rect.width,
+ vbox.rect.height,
+ 0.0,
+ 0.0,
+ pattern_width * bbwscale,
+ pattern_height * bbhscale);
+
+ x -= vbox.rect.x * w / vbox.rect.width;
+ y -= vbox.rect.y * h / vbox.rect.height;
+
+ caffine = cairo::Matrix::new (w / vbox.rect.width,
+ 0.0,
+ 0.0,
+ h / vbox.rect.height,
+ x,
+ y);
+
+ drawing_ctx::push_view_box (draw_ctx, vbox.rect.width, vbox.rect.height);
+ pushed_view_box = true;
+ } else if obj_cbbox {
+ // If coords are in terms of the bounding box, use them
+
+ caffine = cairo::Matrix::identity ();
+ caffine.scale (bbox.rect.width, bbox.rect.height);
+
+ drawing_ctx::push_view_box (draw_ctx, 1.0, 1.0);
+ pushed_view_box = true;
+ } else {
+ caffine = cairo::Matrix::identity ();
+ pushed_view_box = false;
+ }
+
+ if scwscale != 1.0 || schscale != 1.0 {
+ let mut scalematrix = cairo::Matrix::identity ();
+ scalematrix.scale (scwscale, schscale);
+ caffine = cairo::Matrix::multiply (&caffine, &scalematrix);
+
+ scalematrix = cairo::Matrix::identity ();
+ scalematrix.scale (1.0 / scwscale, 1.0 / schscale);
+
+ affine = cairo::Matrix::multiply (&scalematrix, &affine);
+ }
+
+ // Draw to another surface
+
+ let cr_save = drawing_ctx::get_cairo_context (draw_ctx);
+ drawing_ctx::state_push (draw_ctx);
+
+ let surface = cr_save.get_target ().create_similar (Content::ColorAlpha, pw, ph);
+
+ let cr_pattern = cairo::Context::new (&surface);
+
+ drawing_ctx::set_cairo_context (draw_ctx, &cr_pattern);
+
+ // Set up transformations to be determined by the contents units
+ drawing_ctx::set_current_state_affine (draw_ctx, caffine);
+
+ // Draw everything
+ drawing_ctx::node_draw_children (draw_ctx, pattern.c_node, 2);
+
+ // Return to the original coordinate system and rendering context
+
+ drawing_ctx::state_pop (draw_ctx);
+ drawing_ctx::set_cairo_context (draw_ctx, &cr_save);
+
+ if pushed_view_box {
+ drawing_ctx::pop_view_box (draw_ctx);
}
-
+
+ // Set the final surface as a Cairo pattern into the Cairo context
+
+ let surface_pattern = SurfacePattern::create (&surface);
+ surface_pattern.set_extend (Extend::Repeat);
+
+ let mut matrix = affine;
+ matrix.invert ();
+
+ surface_pattern.set_matrix (matrix);
+ surface_pattern.set_filter (Filter::Best);
+
+ cr_save.set_source (&surface_pattern);
}
#[no_mangle]
@@ -268,7 +368,10 @@ pub unsafe extern fn pattern_new (x: *const RsvgLength,
vbox: *const RsvgViewBox,
affine: *const cairo::Matrix,
preserve_aspect_ratio: *const u32,
- fallback_name: *const libc::c_char) -> *mut Pattern {
+ fallback_name: *const libc::c_char,
+ c_node: *const RsvgNode) -> *mut Pattern {
+ assert! (!c_node.is_null ());
+
let my_x = { if x.is_null () { None } else { Some (*x) } };
let my_y = { if y.is_null () { None } else { Some (*y) } };
let my_width = { if width.is_null () { None } else { Some (*width) } };
@@ -280,7 +383,7 @@ pub unsafe extern fn pattern_new (x: *const RsvgLength,
let my_affine = { if affine.is_null () { None } else { Some (*affine) } };
- let my_preserve_aspect_ratio = { if preserve_aspect_ratio.is_null () { None } else { Some
(*preserve_aspect_ratio) } };
+ let my_preserve_aspect_ratio = { if preserve_aspect_ratio.is_null () { None } else { Some
(AspectRatio::from_u32 (*preserve_aspect_ratio)) } };
let my_fallback_name = { if fallback_name.is_null () { None } else { Some (String::from_glib_none
(fallback_name)) } };
@@ -294,7 +397,8 @@ pub unsafe extern fn pattern_new (x: *const RsvgLength,
x: my_x,
y: my_y,
width: my_width,
- height: my_height
+ height: my_height,
+ c_node: c_node
};
let boxed_pattern = Box::new (pattern);
@@ -312,7 +416,6 @@ pub unsafe extern fn pattern_destroy (raw_pattern: *mut Pattern) {
#[no_mangle]
pub extern fn pattern_resolve_fallbacks_and_set_pattern (raw_pattern: *mut Pattern,
draw_ctx: *mut RsvgDrawingCtx,
- opacity: u8,
bbox: RsvgBbox) {
assert! (!raw_pattern.is_null ());
let pattern: &mut Pattern = unsafe { &mut (*raw_pattern) };
@@ -323,6 +426,5 @@ pub extern fn pattern_resolve_fallbacks_and_set_pattern (raw_pattern: *mut Patte
set_pattern_on_draw_context (&resolved,
draw_ctx,
- opacity,
&bbox);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]