pattern.rs: New file; resolution of pattern fallbacks is now done in Rust

parent e4a637ae
......@@ -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)
{
......
......@@ -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);
......
......@@ -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);
}
......@@ -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
......
......@@ -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"
......
......@@ -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);
}
}
......@@ -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;
......
......@@ -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 ();