Commit f93a2acc authored by Christian Persch's avatar Christian Persch

Use cairo_matrix_t

I've checked this quite carefully, but it still might contain
stupid typo bugs ;-)
parent 396efea7
......@@ -32,7 +32,6 @@ enum_sources = \
librsvg-enum-types.c
librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
rsvg-affine.c \
librsvg-features.c \
rsvg-bpath-util.c \
rsvg-bpath-util.h \
......
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 sts=4 ts=4 expandtab: */
/* Libart_LGPL - library of basic graphic primitives
* Copyright (C) 1998 Raph Levien
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* Simple manipulations with affine transformations */
#include "config.h"
#include "rsvg-private.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
/**
* _rsvg_affine_invert: Find the inverse of an affine transformation.
* @dst: Where the resulting affine is stored.
* @src: The original affine transformation.
*
* All non-degenerate affine transforms are invertible. If the original
* affine is degenerate or nearly so, expect numerical instability and
* very likely core dumps on Alpha and other fp-picky architectures.
* Otherwise, @dst multiplied with @src, or @src multiplied with @dst
* will be (to within roundoff error) the identity affine.
**/
void
_rsvg_affine_invert (double dst[6], const double src[6])
{
double r_det;
r_det = 1.0 / (src[0] * src[3] - src[1] * src[2]);
dst[0] = src[3] * r_det;
dst[1] = -src[1] * r_det;
dst[2] = -src[2] * r_det;
dst[3] = src[0] * r_det;
dst[4] = -src[4] * dst[0] - src[5] * dst[2];
dst[5] = -src[4] * dst[1] - src[5] * dst[3];
}
#define EPSILON 1e-6
/**
* _rsvg_affine_multiply: Multiply two affine transformation matrices.
* @dst: Where to store the result.
* @src1: The first affine transform to multiply.
* @src2: The second affine transform to multiply.
*
* Multiplies two affine transforms together, i.e. the resulting @dst
* is equivalent to doing first @src1 then @src2. Note that the
* PostScript concat operator multiplies on the left, i.e. "M concat"
* is equivalent to "CTM = multiply (M, CTM)";
*
* It is safe to call this function with @dst equal to @src1 or @src2.
**/
void
_rsvg_affine_multiply (double dst[6], const double src1[6], const double src2[6])
{
double d0, d1, d2, d3, d4, d5;
d0 = src1[0] * src2[0] + src1[1] * src2[2];
d1 = src1[0] * src2[1] + src1[1] * src2[3];
d2 = src1[2] * src2[0] + src1[3] * src2[2];
d3 = src1[2] * src2[1] + src1[3] * src2[3];
d4 = src1[4] * src2[0] + src1[5] * src2[2] + src2[4];
d5 = src1[4] * src2[1] + src1[5] * src2[3] + src2[5];
dst[0] = d0;
dst[1] = d1;
dst[2] = d2;
dst[3] = d3;
dst[4] = d4;
dst[5] = d5;
}
/**
* _rsvg_affine_identity: Set up the identity matrix.
* @dst: Where to store the resulting affine transform.
*
* Sets up an identity matrix.
**/
void
_rsvg_affine_identity (double dst[6])
{
dst[0] = 1;
dst[1] = 0;
dst[2] = 0;
dst[3] = 1;
dst[4] = 0;
dst[5] = 0;
}
/**
* _rsvg_affine_scale: Set up a scaling matrix.
* @dst: Where to store the resulting affine transform.
* @sx: X scale factor.
* @sy: Y scale factor.
*
* Sets up a scaling matrix.
**/
void
_rsvg_affine_scale (double dst[6], double sx, double sy)
{
dst[0] = sx;
dst[1] = 0;
dst[2] = 0;
dst[3] = sy;
dst[4] = 0;
dst[5] = 0;
}
/**
* _rsvg_affine_rotate: Set up a rotation affine transform.
* @dst: Where to store the resulting affine transform.
* @theta: Rotation angle in degrees.
*
* Sets up a rotation matrix. In the standard libart coordinate
* system, in which increasing y moves downward, this is a
* counterclockwise rotation. In the standard PostScript coordinate
* system, which is reversed in the y direction, it is a clockwise
* rotation.
**/
void
_rsvg_affine_rotate (double dst[6], double theta)
{
double s, c;
s = sin (theta * M_PI / 180.0);
c = cos (theta * M_PI / 180.0);
dst[0] = c;
dst[1] = s;
dst[2] = -s;
dst[3] = c;
dst[4] = 0;
dst[5] = 0;
}
/**
* _rsvg_affine_shear: Set up a shearing matrix.
* @dst: Where to store the resulting affine transform.
* @theta: Shear angle in degrees.
*
* Sets up a shearing matrix. In the standard libart coordinate system
* and a small value for theta, || becomes \\. Horizontal lines remain
* unchanged.
**/
void
_rsvg_affine_shear (double dst[6], double theta)
{
double t;
t = tan (theta * M_PI / 180.0);
dst[0] = 1;
dst[1] = 0;
dst[2] = t;
dst[3] = 1;
dst[4] = 0;
dst[5] = 0;
}
/**
* _rsvg_affine_translate: Set up a translation matrix.
* @dst: Where to store the resulting affine transform.
* @tx: X translation amount.
* @tx: Y translation amount.
*
* Sets up a translation matrix.
**/
void
_rsvg_affine_translate (double dst[6], double tx, double ty)
{
dst[0] = 1;
dst[1] = 0;
dst[2] = 0;
dst[3] = 1;
dst[4] = tx;
dst[5] = ty;
}
......@@ -2099,18 +2099,16 @@ rsvg_render_free (RsvgRender * render)
}
void
rsvg_bbox_init (RsvgBbox * self, double *affine)
rsvg_bbox_init (RsvgBbox * self, cairo_matrix_t *affine)
{
int i;
self->virgin = 1;
for (i = 0; i < 6; i++)
self->affine[i] = affine[i];
self->affine = *affine;
}
void
rsvg_bbox_insert (RsvgBbox * dst, RsvgBbox * src)
{
double affine[6];
cairo_matrix_t affine;
double xmin, ymin;
double xmax, ymax;
int i;
......@@ -2125,15 +2123,18 @@ rsvg_bbox_insert (RsvgBbox * dst, RsvgBbox * src)
xmin = ymin = xmax = ymax = 0;
}
_rsvg_affine_invert (affine, dst->affine);
_rsvg_affine_multiply (affine, src->affine, affine);
affine = dst->affine;
if (cairo_matrix_invert (&affine) != CAIRO_STATUS_SUCCESS)
return; //FIXMEchpe correct??
cairo_matrix_multiply (&affine, &src->affine, &affine);
for (i = 0; i < 4; i++) {
double rx, ry, x, y;
rx = src->rect.x + src->rect.width * (double) (i % 2);
ry = src->rect.y + src->rect.height * (double) (i / 2);
x = affine[0] * rx + affine[2] * ry + affine[4];
y = affine[1] * rx + affine[3] * ry + affine[5];
x = affine.xx * rx + affine.xy * ry + affine.x0;
y = affine.yx * rx + affine.yy * ry + affine.y0;
if (dst->virgin) {
xmin = xmax = x;
ymin = ymax = y;
......@@ -2158,7 +2159,7 @@ rsvg_bbox_insert (RsvgBbox * dst, RsvgBbox * src)
void
rsvg_bbox_clip (RsvgBbox * dst, RsvgBbox * src)
{
double affine[6];
cairo_matrix_t affine;
double xmin, ymin;
double xmax, ymax;
int i;
......@@ -2173,15 +2174,18 @@ rsvg_bbox_clip (RsvgBbox * dst, RsvgBbox * src)
xmin = ymin = xmax = ymax = 0;
}
_rsvg_affine_invert (affine, dst->affine);
_rsvg_affine_multiply (affine, src->affine, affine);
affine = dst->affine;
if (cairo_matrix_invert (&affine) != CAIRO_STATUS_SUCCESS)
return;
cairo_matrix_multiply (&affine, &src->affine, &affine);
for (i = 0; i < 4; i++) {
double rx, ry, x, y;
rx = src->rect.x + src->rect.width * (double) (i % 2);
ry = src->rect.y + src->rect.height * (double) (i / 2);
x = affine[0] * rx + affine[2] * ry + affine[4];
y = affine[1] * rx + affine[3] * ry + affine[5];
x = affine.xx * rx + affine.xy * ry + affine.x0;
y = affine.yx * rx + affine.yy * ry + affine.y0;
if (dst->virgin) {
xmin = xmax = x;
ymin = ymax = y;
......
......@@ -47,17 +47,17 @@ struct RsvgCairoClipRender {
#define RSVG_CAIRO_CLIP_RENDER(render) (_RSVG_RENDER_CIC ((render), RSVG_RENDER_TYPE_CAIRO_CLIP, RsvgCairoClipRender))
static void
rsvg_cairo_clip_apply_affine (RsvgCairoClipRender *render, const double affine[6])
rsvg_cairo_clip_apply_affine (RsvgCairoClipRender *render, cairo_matrix_t *affine)
{
RsvgCairoRender *cairo_render = &render->super;
cairo_matrix_t matrix;
gboolean nest = cairo_render->cr != cairo_render->initial_cr;
cairo_matrix_init (&matrix,
affine[0], affine[1],
affine[2], affine[3],
affine[4] + (nest ? 0 : render->parent->offset_x),
affine[5] + (nest ? 0 : render->parent->offset_y));
affine->xx, affine->yx,
affine->xy, affine->yy,
affine->x0 + (nest ? 0 : render->parent->offset_x),
affine->y0 + (nest ? 0 : render->parent->offset_y));
cairo_set_matrix (cairo_render->cr, &matrix);
}
......@@ -73,7 +73,7 @@ rsvg_cairo_clip_render_path (RsvgDrawingCtx * ctx, const RsvgBpathDef * bpath_de
cr = cairo_render->cr;
rsvg_cairo_clip_apply_affine (render, state->affine);
rsvg_cairo_clip_apply_affine (render, &state->affine);
cairo_set_fill_rule (cr, rsvg_current_state (ctx)->clip_rule);
......@@ -158,22 +158,22 @@ void
rsvg_cairo_clip (RsvgDrawingCtx * ctx, RsvgClipPath * clip, RsvgBbox * bbox)
{
RsvgCairoRender *save = RSVG_CAIRO_RENDER (ctx->render);
double affinesave[6];
int i;
cairo_matrix_t affinesave;
ctx->render = rsvg_cairo_clip_render_new (save->cr, save);
/* Horribly dirty hack to have the bbox premultiplied to everything */
if (clip->units == objectBoundingBox) {
double bbtransform[6];
bbtransform[0] = bbox->rect.width;
bbtransform[1] = 0.;
bbtransform[2] = 0.;
bbtransform[3] = bbox->rect.height;
bbtransform[4] = bbox->rect.x;
bbtransform[5] = bbox->rect.y;
for (i = 0; i < 6; i++)
affinesave[i] = clip->super.state->affine[i];
_rsvg_affine_multiply (clip->super.state->affine, bbtransform, clip->super.state->affine);
cairo_matrix_t bbtransform;
cairo_matrix_init (&bbtransform,
bbox->rect.width,
0,
0,
bbox->rect.height,
bbox->rect.x,
bbox->rect.y);
affinesave = clip->super.state->affine;
cairo_matrix_multiply (&clip->super.state->affine, &bbtransform, &clip->super.state->affine);
}
rsvg_state_push (ctx);
......@@ -181,8 +181,7 @@ rsvg_cairo_clip (RsvgDrawingCtx * ctx, RsvgClipPath * clip, RsvgBbox * bbox)
rsvg_state_pop (ctx);
if (clip->units == objectBoundingBox)
for (i = 0; i < 6; i++)
clip->super.state->affine[i] = affinesave[i];
clip->super.state->affine = affinesave;
g_free (ctx->render);
cairo_clip (save->cr);
......
......@@ -100,9 +100,7 @@ _set_source_rsvg_linear_gradient (RsvgDrawingCtx * ctx,
if (linear->obj_bbox)
_rsvg_pop_view_box (ctx);
cairo_matrix_init (&matrix,
linear->affine[0], linear->affine[1],
linear->affine[2], linear->affine[3], linear->affine[4], linear->affine[5]);
matrix = linear->affine;
if (linear->obj_bbox) {
cairo_matrix_t bboxmatrix;
cairo_matrix_init (&bboxmatrix, bbox.rect.width, 0, 0, bbox.rect.height,
......@@ -147,9 +145,7 @@ _set_source_rsvg_radial_gradient (RsvgDrawingCtx * ctx,
if (radial->obj_bbox)
_rsvg_pop_view_box (ctx);
cairo_matrix_init (&matrix,
radial->affine[0], radial->affine[1],
radial->affine[2], radial->affine[3], radial->affine[4], radial->affine[5]);
matrix = radial->affine;
if (radial->obj_bbox) {
cairo_matrix_t bboxmatrix;
cairo_matrix_init (&bboxmatrix, bbox.rect.width, 0, 0, bbox.rect.height,
......@@ -199,16 +195,14 @@ _set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
cairo_pattern_t *pattern;
cairo_surface_t *surface;
cairo_matrix_t matrix;
int i;
double affine[6], caffine[6], bbwscale, bbhscale, scwscale, schscale;
double taffine[6], patternw, patternh, patternx, patterny;
cairo_matrix_t affine, caffine, taffine;
double bbwscale, bbhscale, scwscale, schscale;
double patternw, patternh, patternx, patterny;
int pw, ph;
rsvg_pattern = &local_pattern;
rsvg_pattern_fix_fallback (rsvg_pattern);
cr_render = render->cr;
_rsvg_affine_identity (affine);
_rsvg_affine_identity (caffine);
if (rsvg_pattern->obj_bbox)
_rsvg_push_view_box (ctx, 1., 1.);
......@@ -233,10 +227,10 @@ _set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
bbhscale = 1.0;
}
_rsvg_affine_multiply (taffine, rsvg_pattern->affine, rsvg_current_state (ctx)->affine);
cairo_matrix_multiply (&taffine, &rsvg_pattern->affine, &rsvg_current_state (ctx)->affine);
scwscale = sqrt (taffine[0] * taffine[0] + taffine[2] * taffine[2]);
schscale = sqrt (taffine[1] * taffine[1] + taffine[3] * taffine[3]);
scwscale = sqrt (taffine.xx * taffine.xx + taffine.xy * taffine.xy);
schscale = sqrt (taffine.yx * taffine.yx + taffine.yy * taffine.yy);
pw = patternw * bbwscale * scwscale;
ph = patternh * bbhscale * schscale;
......@@ -251,15 +245,15 @@ _set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
/* Create the pattern coordinate system */
if (rsvg_pattern->obj_bbox) {
/* subtract the pattern origin */
affine[4] = bbox.rect.x + patternx * bbox.rect.width;
affine[5] = bbox.rect.y + patterny * bbox.rect.height;
cairo_matrix_init_translate (&affine,
bbox.rect.x + patternx * bbox.rect.width,
bbox.rect.y + patterny * bbox.rect.height);
} else {
/* subtract the pattern origin */
affine[4] = patternx;
affine[5] = patterny;
cairo_matrix_init_translate (&affine, patternx, patterny);
}
/* Apply the pattern transform */
_rsvg_affine_multiply (affine, affine, rsvg_pattern->affine);
cairo_matrix_multiply (&affine, &affine, &rsvg_pattern->affine);
/* Create the pattern contents coordinate system */
if (rsvg_pattern->vbox.active) {
......@@ -276,24 +270,27 @@ _set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
x -= rsvg_pattern->vbox.rect.x * w / rsvg_pattern->vbox.rect.width;
y -= rsvg_pattern->vbox.rect.y * h / rsvg_pattern->vbox.rect.height;
caffine[0] = w / rsvg_pattern->vbox.rect.width;
caffine[3] = h / rsvg_pattern->vbox.rect.height;
caffine[4] = x;
caffine[5] = y;
cairo_matrix_init (&caffine,
w / rsvg_pattern->vbox.rect.width,
0,
0,
h / rsvg_pattern->vbox.rect.height,
x,
y);
_rsvg_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 */
caffine[0] = bbox.rect.width;
caffine[3] = bbox.rect.height;
cairo_matrix_init_scale (&caffine, bbox.rect.width, bbox.rect.height);
_rsvg_push_view_box (ctx, 1., 1.);
}
if (scwscale != 1.0 || schscale != 1.0) {
double scalematrix[6];
_rsvg_affine_scale (scalematrix, scwscale, schscale);
_rsvg_affine_multiply (caffine, caffine, scalematrix);
_rsvg_affine_scale (scalematrix, 1. / scwscale, 1. / schscale);
_rsvg_affine_multiply (affine, scalematrix, affine);
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);
}
/* Draw to another surface */
......@@ -301,9 +298,8 @@ _set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
/* Set up transformations to be determined by the contents units */
rsvg_state_push (ctx);
for (i = 0; i < 6; i++)
rsvg_current_state (ctx)->personal_affine[i] =
rsvg_current_state (ctx)->affine[i] = caffine[i];
rsvg_current_state (ctx)->personal_affine =
rsvg_current_state (ctx)->affine = caffine;
/* Draw everything */
_rsvg_node_draw_children ((RsvgNode *) rsvg_pattern, ctx, 2);
......@@ -316,10 +312,10 @@ _set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
cairo_matrix_init (&matrix, affine[0], affine[1], affine[2], affine[3], affine[4], affine[5]);
matrix = affine;
if (cairo_matrix_invert (&matrix) != CAIRO_STATUS_SUCCESS)
goto out;
cairo_matrix_invert (&matrix);
cairo_pattern_set_matrix (pattern, &matrix);
cairo_pattern_set_filter (pattern, CAIRO_FILTER_BEST);
......@@ -328,6 +324,8 @@ _set_source_rsvg_pattern (RsvgDrawingCtx * ctx,
cairo_pattern_destroy (pattern);
cairo_destroy (cr_pattern);
cairo_surface_destroy (surface);
out:
if (rsvg_pattern->obj_cbbox || rsvg_pattern->vbox.active)
_rsvg_pop_view_box (ctx);
}
......@@ -356,17 +354,17 @@ _set_source_rsvg_paint_server (RsvgDrawingCtx * ctx,
}
static void
_set_rsvg_affine (RsvgCairoRender * render, const double affine[6])
_set_rsvg_affine (RsvgCairoRender * render, cairo_matrix_t *affine)
{
cairo_t * cr = render->cr;
cairo_matrix_t matrix;
gboolean nest = cr != render->initial_cr;
cairo_matrix_init (&matrix,
affine[0], affine[1],
affine[2], affine[3],
affine[4] + (nest ? 0 : render->offset_x),
affine[5] + (nest ? 0 : render->offset_y));
affine->xx, affine->yx,
affine->xy, affine->yy,
affine->x0 + (nest ? 0 : render->offset_x),
affine->y0 + (nest ? 0 : render->offset_y));
cairo_set_matrix (cr, &matrix);
}
......@@ -394,11 +392,11 @@ rsvg_cairo_render_pango_layout (RsvgDrawingCtx * ctx, PangoLayout * layout, doub
cairo_set_antialias (render->cr, state->text_rendering_type);
_set_rsvg_affine (render, state->affine);
_set_rsvg_affine (render, &state->affine);
pango_layout_get_extents (layout, &ink, NULL);
rsvg_bbox_init (&bbox, state->affine);
rsvg_bbox_init (&bbox, &state->affine);
bbox.rect.x = x + ink.x / (double)PANGO_SCALE;
bbox.rect.y = y + ink.y / (double)PANGO_SCALE;
bbox.rect.width = ink.width / (double)PANGO_SCALE;
......@@ -464,7 +462,7 @@ rsvg_cairo_render_path (RsvgDrawingCtx * ctx, const RsvgBpathDef * bpath_def)
cairo_set_antialias (cr, state->shape_rendering_type);
_set_rsvg_affine (render, state->affine);
_set_rsvg_affine (render, &state->affine);
cairo_set_line_width (cr, _rsvg_css_normalize_length (&state->stroke_width, ctx, 'h'));
cairo_set_miter_limit (cr, state->miter_limit);
......@@ -492,7 +490,7 @@ rsvg_cairo_render_path (RsvgDrawingCtx * ctx, const RsvgBpathDef * bpath_def)
}
}
rsvg_bbox_init (&bbox, state->affine);
rsvg_bbox_init (&bbox, &state->affine);
backup_tolerance = cairo_get_tolerance (cr);
cairo_set_tolerance (cr, 1.0);
......@@ -502,7 +500,7 @@ rsvg_cairo_render_path (RsvgDrawingCtx * ctx, const RsvgBpathDef * bpath_def)
if (state->fill != NULL) {
RsvgBbox fb;
rsvg_bbox_init (&fb, state->affine);
rsvg_bbox_init (&fb, &state->affine);
cairo_fill_extents (cr, &fb.rect.x, &fb.rect.y, &fb.rect.width, &fb.rect.height);
fb.rect.width -= fb.rect.x;
fb.rect.height -= fb.rect.y;
......@@ -511,7 +509,7 @@ rsvg_cairo_render_path (RsvgDrawingCtx * ctx, const RsvgBpathDef * bpath_def)
}
if (state->stroke != NULL) {
RsvgBbox sb;
rsvg_bbox_init (&sb, state->affine);
rsvg_bbox_init (&sb, &state->affine);
cairo_stroke_extents (cr, &sb.rect.x, &sb.rect.y, &sb.rect.width, &sb.rect.height);
sb.rect.width -= sb.rect.x;
sb.rect.height -= sb.rect.y;
......@@ -589,14 +587,14 @@ rsvg_cairo_render_image (RsvgDrawingCtx * ctx, const GdkPixbuf * pixbuf,
if (!cairo_pixels)
return;
rsvg_bbox_init (&bbox, state->affine);
rsvg_bbox_init (&bbox, &state->affine);
bbox.rect.x = pixbuf_x;
bbox.rect.y = pixbuf_y;
bbox.rect.width = w;
bbox.rect.height = h;
bbox.virgin = 0;
_set_rsvg_affine (render, state->affine);
_set_rsvg_affine (render, &state->affine);
cairo_scale (render->cr, w / dwidth, h / dheight);
pixbuf_x *= dwidth / w;
pixbuf_y *= dheight / h;
......@@ -696,7 +694,7 @@ rsvg_cairo_generate_mask (cairo_t * cr, RsvgMask * self, RsvgDrawingCtx * ctx, R
guint8 *pixels;
guint32 width = render->width, height = render->height;
guint32 rowstride = width * 4, row, i;
double affinesave[6];
cairo_matrix_t affinesave;
double sx, sy, sw, sh;
gboolean nest = cr != render->initial_cr;
......@@ -734,16 +732,16 @@ rsvg_cairo_generate_mask (cairo_t * cr, RsvgMask * self, RsvgDrawingCtx * ctx, R
/* Horribly dirty hack to have the bbox premultiplied to everything */
if (self->contentunits == objectBoundingBox) {
double bbtransform[6];
bbtransform[0] = bbox->rect.width;
bbtransform[1] = 0.;
bbtransform[2] = 0.;
bbtransform[3] = bbox->rect.height;
bbtransform[4] = bbox->rect.x;
bbtransform[5] = bbox->rect.y;
for (i = 0; i < 6; i++)
affinesave[i] = self->super.state->affine[i];
_rsvg_affine_multiply (self->super.state->affine, bbtransform, self->super.state->affine);
cairo_matrix_t bbtransform;
cairo_matrix_init (&bbtransform,
bbox->rect.width,
0,
0,
bbox->rect.height,
bbox->rect.x,
bbox->rect.y);
affinesave = self->super.state->affine;
cairo_matrix_multiply (&self->super.state->affine, &bbtransform, &self->super.state->affine);
_rsvg_push_view_box (ctx, 1, 1);
}
......@@ -753,8 +751,7 @@ rsvg_cairo_generate_mask (cairo_t * cr, RsvgMask * self, RsvgDrawingCtx * ctx, R
if (self->contentunits == objectBoundingBox) {
_rsvg_pop_view_box (ctx);
for (i = 0; i < 6; i++)
self->super.state->affine[i] = affinesave[i];
self->super.state->affine = affinesave;
}
render->cr = save_cr;
......@@ -852,7 +849,7 @@ rsvg_cairo_push_render_stack (RsvgDrawingCtx * ctx)
bbox = g_new (RsvgBbox, 1);
*bbox = render->bbox;
render->bb_stack = g_list_prepend (render->bb_stack, bbox);
rsvg_bbox_init (&render->bbox, state->affine);
rsvg_bbox_init (&render->bbox, &state->affine);
}
void
......@@ -953,7 +950,7 @@ rsvg_cairo_add_clipping_rect (RsvgDrawingCtx * ctx, double x, double y, double w
RsvgCairoRender *render = RSVG_CAIRO_RENDER (ctx->render);
cairo_t *cr = render->cr;
_set_rsvg_affine (render, rsvg_current_state (ctx)->affine);
_set_rsvg_affine (render, &rsvg_current_state (ctx)->affine);
cairo_rectangle (cr, x, y, w, h);
cairo_clip (cr);
......
......@@ -116,8 +116,8 @@ rsvg_cairo_new_drawing_ctx (cairo_t * cr, RsvgHandle * handle)
RsvgDrawingCtx *draw;
RsvgCairoRender *render;
RsvgState *state;
cairo_matrix_t cairo_transform;
double affine[6], bbx0, bby0, bbx1, bby1;
cairo_matrix_t affine;
double bbx0, bby0, bbx1, bby1;
rsvg_handle_get_dimensions (handle, &data);
if (data.width == 0 || data.height == 0)
......@@ -125,12 +125,12 @@ rsvg_cairo_new_drawing_ctx (cairo_t * cr, RsvgHandle * handle)
draw = g_new (RsvgDrawingCtx, 1);
cairo_get_matrix (cr, &cairo_transform);
cairo_get_matrix (cr, &affine);
/* find bounding box of image as transformed by the current cairo context
* The size of this bounding box determines the size of the intermediate
* surfaces allocated during drawing. */
rsvg_cairo_transformed_image_bounding_box (&cairo_transform,
rsvg_cairo_transformed_image_bounding_box (&affine,
data.width, data.height,
&bbx0, &bby0, &bbx1, &bby1);
......@@ -159,30 +159,19 @@ rsvg_cairo_new_drawing_ctx (cairo_t * cr, RsvgHandle * handle)
state = rsvg_current_state (draw);
/* apply cairo transformation to our affine transform */
affine[0] = cairo_transform.xx;
affine[1] = cairo_transform.yx;
affine[2] = cairo_transform.xy;
affine[3] = cairo_transform.yy;
affine[4] = cairo_transform.x0;
affine[5] = cairo_transform.y0;
_rsvg_affine_multiply (state->affine, affine, state->affine);
cairo_matrix_multiply (&state->affine, &affine, &state->affine);
/* scale according to size set by size_func callback */
affine[0] = data.width / data.em;
affine[1] = 0;
affine[2] = 0;
affine[3] = data.height / data.ex;
affine[4] = 0;
affine[5] = 0;
_rsvg_affine_multiply (state->affine, affine, state->affine);
cairo_matrix_init_scale (&affine, data.width / data.em, data.height / data.ex);
cairo_matrix_multiply (&state->affine, &affine, &state->affine);
/* adjust transform so that the corner of the bounding box above is
* at (0,0) - we compensate for this in _set_rsvg_affine() in
* rsvg-cairo-render.c and a few other places */
state->affine[4] -= render->offset_x;
state->affine[5] -= render->offset_y;
state->affine.x0 -= render->offset_x;
state->affine.y0 -= render->offset_y;