mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-21 14:28:10 +02:00
This is a step toward allowing device scaling in addition to device offsets. So far, the scale values are still always 1.0 so only the translation is actually being used. But most of the code is in place for doing scaling as well and it just needs to be hooked up. There are some fragile parts in this code, all of which involve using the translation without the scale, (so grep for device_transform.x0 or device_transform->x0). Some of these are likely bugs that will hopefully be obvious once we start using the scale. Others are OK if only because we 'know' that we aren't ever setting device scaling on a surface that has a device offset (we only set device scaling on surfaces we create internally and we don't export device scaling to the user). All of these fragile parts in the code have been marked with comments of the form: XXX: FRAGILE.
632 lines
15 KiB
C
632 lines
15 KiB
C
/* cairo - a vector graphics library with display and print output
|
|
*
|
|
* Copyright © 2002 University of Southern California
|
|
* Copyright © 2005 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it either under the terms of the GNU Lesser General Public
|
|
* License version 2.1 as published by the Free Software Foundation
|
|
* (the "LGPL") or, at your option, under the terms of the Mozilla
|
|
* Public License Version 1.1 (the "MPL"). If you do not alter this
|
|
* notice, a recipient may use your version of this file under either
|
|
* the MPL or the LGPL.
|
|
*
|
|
* You should have received a copy of the LGPL along with this library
|
|
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
* You should have received a copy of the MPL along with this library
|
|
* in the file COPYING-MPL-1.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
* Version 1.1 (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
|
|
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
|
|
* the specific language governing rights and limitations.
|
|
*
|
|
* The Original Code is the cairo graphics library.
|
|
*
|
|
* The Initial Developer of the Original Code is University of Southern
|
|
* California.
|
|
*
|
|
* Contributor(s):
|
|
* Carl D. Worth <cworth@cworth.org>
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include "cairoint.h"
|
|
|
|
#include "cairo-path-fixed-private.h"
|
|
|
|
/* private functions */
|
|
static cairo_status_t
|
|
_cairo_path_fixed_add (cairo_path_fixed_t *path,
|
|
cairo_path_op_t op,
|
|
cairo_point_t *points,
|
|
int num_points);
|
|
|
|
static void
|
|
_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path,
|
|
cairo_path_op_buf_t *op_buf);
|
|
|
|
static void
|
|
_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path,
|
|
cairo_path_arg_buf_t *arg_buf);
|
|
|
|
static cairo_path_op_buf_t *
|
|
_cairo_path_op_buf_create (void);
|
|
|
|
static void
|
|
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf);
|
|
|
|
static void
|
|
_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
|
|
cairo_path_op_t op);
|
|
|
|
static cairo_path_arg_buf_t *
|
|
_cairo_path_arg_buf_create (void);
|
|
|
|
static void
|
|
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf);
|
|
|
|
static void
|
|
_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
|
|
cairo_point_t *points,
|
|
int num_points);
|
|
|
|
void
|
|
_cairo_path_fixed_init (cairo_path_fixed_t *path)
|
|
{
|
|
path->op_buf_head = NULL;
|
|
path->op_buf_tail = NULL;
|
|
|
|
path->arg_buf_head = NULL;
|
|
path->arg_buf_tail = NULL;
|
|
|
|
path->current_point.x = 0;
|
|
path->current_point.y = 0;
|
|
path->has_current_point = FALSE;
|
|
path->last_move_point = path->current_point;
|
|
}
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
|
|
cairo_path_fixed_t *other)
|
|
{
|
|
cairo_path_op_buf_t *op_buf, *other_op_buf;
|
|
cairo_path_arg_buf_t *arg_buf, *other_arg_buf;
|
|
|
|
_cairo_path_fixed_init (path);
|
|
path->current_point = other->current_point;
|
|
path->has_current_point = other->has_current_point;
|
|
path->last_move_point = other->last_move_point;
|
|
|
|
for (other_op_buf = other->op_buf_head;
|
|
other_op_buf;
|
|
other_op_buf = other_op_buf->next)
|
|
{
|
|
op_buf = _cairo_path_op_buf_create ();
|
|
if (op_buf == NULL) {
|
|
_cairo_path_fixed_fini (path);
|
|
return CAIRO_STATUS_NO_MEMORY;
|
|
}
|
|
memcpy (op_buf, other_op_buf, sizeof (cairo_path_op_buf_t));
|
|
_cairo_path_fixed_add_op_buf (path, op_buf);
|
|
}
|
|
|
|
for (other_arg_buf = other->arg_buf_head;
|
|
other_arg_buf;
|
|
other_arg_buf = other_arg_buf->next)
|
|
{
|
|
arg_buf = _cairo_path_arg_buf_create ();
|
|
if (arg_buf == NULL) {
|
|
_cairo_path_fixed_fini (path);
|
|
return CAIRO_STATUS_NO_MEMORY;
|
|
}
|
|
memcpy (arg_buf, other_arg_buf, sizeof (cairo_path_arg_buf_t));
|
|
_cairo_path_fixed_add_arg_buf (path, arg_buf);
|
|
}
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
cairo_path_fixed_t *
|
|
_cairo_path_fixed_create (void)
|
|
{
|
|
cairo_path_fixed_t *path = malloc (sizeof (cairo_path_fixed_t));
|
|
|
|
if (!path)
|
|
return NULL;
|
|
_cairo_path_fixed_init (path);
|
|
return path;
|
|
}
|
|
|
|
void
|
|
_cairo_path_fixed_fini (cairo_path_fixed_t *path)
|
|
{
|
|
cairo_path_op_buf_t *op_buf;
|
|
cairo_path_arg_buf_t *arg_buf;
|
|
|
|
while (path->op_buf_head) {
|
|
op_buf = path->op_buf_head;
|
|
path->op_buf_head = op_buf->next;
|
|
_cairo_path_op_buf_destroy (op_buf);
|
|
}
|
|
path->op_buf_tail = NULL;
|
|
|
|
while (path->arg_buf_head) {
|
|
arg_buf = path->arg_buf_head;
|
|
path->arg_buf_head = arg_buf->next;
|
|
_cairo_path_arg_buf_destroy (arg_buf);
|
|
}
|
|
path->arg_buf_tail = NULL;
|
|
|
|
path->has_current_point = FALSE;
|
|
}
|
|
|
|
void
|
|
_cairo_path_fixed_destroy (cairo_path_fixed_t *path)
|
|
{
|
|
_cairo_path_fixed_fini (path);
|
|
free (path);
|
|
}
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
|
|
cairo_fixed_t x,
|
|
cairo_fixed_t y)
|
|
{
|
|
cairo_status_t status;
|
|
cairo_point_t point;
|
|
|
|
point.x = x;
|
|
point.y = y;
|
|
|
|
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
|
|
if (status)
|
|
return status;
|
|
|
|
path->current_point = point;
|
|
path->has_current_point = TRUE;
|
|
path->last_move_point = path->current_point;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
void
|
|
_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path)
|
|
{
|
|
path->has_current_point = FALSE;
|
|
}
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
|
|
cairo_fixed_t dx,
|
|
cairo_fixed_t dy)
|
|
{
|
|
cairo_fixed_t x, y;
|
|
|
|
if (! path->has_current_point)
|
|
return CAIRO_STATUS_NO_CURRENT_POINT;
|
|
|
|
x = path->current_point.x + dx;
|
|
y = path->current_point.y + dy;
|
|
|
|
return _cairo_path_fixed_move_to (path, x, y);
|
|
}
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
|
|
cairo_fixed_t x,
|
|
cairo_fixed_t y)
|
|
{
|
|
cairo_status_t status;
|
|
cairo_point_t point;
|
|
|
|
point.x = x;
|
|
point.y = y;
|
|
|
|
if (! path->has_current_point)
|
|
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
|
|
else
|
|
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
|
|
|
|
if (status)
|
|
return status;
|
|
|
|
path->current_point = point;
|
|
path->has_current_point = TRUE;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
|
|
cairo_fixed_t dx,
|
|
cairo_fixed_t dy)
|
|
{
|
|
cairo_fixed_t x, y;
|
|
|
|
if (! path->has_current_point)
|
|
return CAIRO_STATUS_NO_CURRENT_POINT;
|
|
|
|
x = path->current_point.x + dx;
|
|
y = path->current_point.y + dy;
|
|
|
|
return _cairo_path_fixed_line_to (path, x, y);
|
|
}
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
|
|
cairo_fixed_t x0, cairo_fixed_t y0,
|
|
cairo_fixed_t x1, cairo_fixed_t y1,
|
|
cairo_fixed_t x2, cairo_fixed_t y2)
|
|
{
|
|
cairo_status_t status;
|
|
cairo_point_t point[3];
|
|
|
|
point[0].x = x0; point[0].y = y0;
|
|
point[1].x = x1; point[1].y = y1;
|
|
point[2].x = x2; point[2].y = y2;
|
|
|
|
if (! path->has_current_point) {
|
|
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO,
|
|
&point[0], 1);
|
|
if (status)
|
|
return status;
|
|
}
|
|
|
|
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
|
|
if (status)
|
|
return status;
|
|
|
|
path->current_point = point[2];
|
|
path->has_current_point = TRUE;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
|
|
cairo_fixed_t dx0, cairo_fixed_t dy0,
|
|
cairo_fixed_t dx1, cairo_fixed_t dy1,
|
|
cairo_fixed_t dx2, cairo_fixed_t dy2)
|
|
{
|
|
cairo_fixed_t x0, y0;
|
|
cairo_fixed_t x1, y1;
|
|
cairo_fixed_t x2, y2;
|
|
|
|
if (! path->has_current_point)
|
|
return CAIRO_STATUS_NO_CURRENT_POINT;
|
|
|
|
x0 = path->current_point.x + dx0;
|
|
y0 = path->current_point.y + dy0;
|
|
|
|
x1 = path->current_point.x + dx1;
|
|
y1 = path->current_point.y + dy1;
|
|
|
|
x2 = path->current_point.x + dx2;
|
|
y2 = path->current_point.y + dy2;
|
|
|
|
return _cairo_path_fixed_curve_to (path,
|
|
x0, y0,
|
|
x1, y1,
|
|
x2, y2);
|
|
}
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_close_path (cairo_path_fixed_t *path)
|
|
{
|
|
cairo_status_t status;
|
|
|
|
if (! path->has_current_point)
|
|
return CAIRO_STATUS_SUCCESS;
|
|
|
|
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
|
|
if (status)
|
|
return status;
|
|
|
|
path->current_point.x = path->last_move_point.x;
|
|
path->current_point.y = path->last_move_point.y;
|
|
path->has_current_point = TRUE;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
|
|
cairo_fixed_t *x,
|
|
cairo_fixed_t *y)
|
|
{
|
|
if (! path->has_current_point)
|
|
return CAIRO_STATUS_NO_CURRENT_POINT;
|
|
|
|
*x = path->current_point.x;
|
|
*y = path->current_point.y;
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static cairo_status_t
|
|
_cairo_path_fixed_add (cairo_path_fixed_t *path,
|
|
cairo_path_op_t op,
|
|
cairo_point_t *points,
|
|
int num_points)
|
|
{
|
|
if (path->op_buf_tail == NULL ||
|
|
path->op_buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE)
|
|
{
|
|
cairo_path_op_buf_t *op_buf;
|
|
|
|
op_buf = _cairo_path_op_buf_create ();
|
|
if (op_buf == NULL)
|
|
return CAIRO_STATUS_NO_MEMORY;
|
|
|
|
_cairo_path_fixed_add_op_buf (path, op_buf);
|
|
}
|
|
|
|
_cairo_path_op_buf_add_op (path->op_buf_tail, op);
|
|
|
|
if (path->arg_buf_tail == NULL ||
|
|
path->arg_buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE)
|
|
{
|
|
cairo_path_arg_buf_t *arg_buf;
|
|
|
|
arg_buf = _cairo_path_arg_buf_create ();
|
|
|
|
if (arg_buf == NULL)
|
|
return CAIRO_STATUS_NO_MEMORY;
|
|
|
|
_cairo_path_fixed_add_arg_buf (path, arg_buf);
|
|
}
|
|
|
|
_cairo_path_arg_buf_add_points (path->arg_buf_tail, points, num_points);
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
_cairo_path_fixed_add_op_buf (cairo_path_fixed_t *path,
|
|
cairo_path_op_buf_t *op_buf)
|
|
{
|
|
op_buf->next = NULL;
|
|
op_buf->prev = path->op_buf_tail;
|
|
|
|
if (path->op_buf_tail) {
|
|
path->op_buf_tail->next = op_buf;
|
|
} else {
|
|
path->op_buf_head = op_buf;
|
|
}
|
|
|
|
path->op_buf_tail = op_buf;
|
|
}
|
|
|
|
static void
|
|
_cairo_path_fixed_add_arg_buf (cairo_path_fixed_t *path,
|
|
cairo_path_arg_buf_t *arg_buf)
|
|
{
|
|
arg_buf->next = NULL;
|
|
arg_buf->prev = path->arg_buf_tail;
|
|
|
|
if (path->arg_buf_tail) {
|
|
path->arg_buf_tail->next = arg_buf;
|
|
} else {
|
|
path->arg_buf_head = arg_buf;
|
|
}
|
|
|
|
path->arg_buf_tail = arg_buf;
|
|
}
|
|
|
|
static cairo_path_op_buf_t *
|
|
_cairo_path_op_buf_create (void)
|
|
{
|
|
cairo_path_op_buf_t *op_buf;
|
|
|
|
op_buf = malloc (sizeof (cairo_path_op_buf_t));
|
|
|
|
if (op_buf) {
|
|
op_buf->num_ops = 0;
|
|
op_buf->next = NULL;
|
|
}
|
|
|
|
return op_buf;
|
|
}
|
|
|
|
static void
|
|
_cairo_path_op_buf_destroy (cairo_path_op_buf_t *op_buf)
|
|
{
|
|
free (op_buf);
|
|
}
|
|
|
|
static void
|
|
_cairo_path_op_buf_add_op (cairo_path_op_buf_t *op_buf,
|
|
cairo_path_op_t op)
|
|
{
|
|
op_buf->op[op_buf->num_ops++] = op;
|
|
}
|
|
|
|
static cairo_path_arg_buf_t *
|
|
_cairo_path_arg_buf_create (void)
|
|
{
|
|
cairo_path_arg_buf_t *arg_buf;
|
|
|
|
arg_buf = malloc (sizeof (cairo_path_arg_buf_t));
|
|
|
|
if (arg_buf) {
|
|
arg_buf->num_points = 0;
|
|
arg_buf->next = NULL;
|
|
}
|
|
|
|
return arg_buf;
|
|
}
|
|
|
|
static void
|
|
_cairo_path_arg_buf_destroy (cairo_path_arg_buf_t *arg_buf)
|
|
{
|
|
free (arg_buf);
|
|
}
|
|
|
|
static void
|
|
_cairo_path_arg_buf_add_points (cairo_path_arg_buf_t *arg_buf,
|
|
cairo_point_t *points,
|
|
int num_points)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i < num_points; i++) {
|
|
arg_buf->points[arg_buf->num_points++] = points[i];
|
|
}
|
|
}
|
|
|
|
#define CAIRO_PATH_OP_MAX_ARGS 3
|
|
|
|
static int const num_args[] =
|
|
{
|
|
1, /* cairo_path_move_to */
|
|
1, /* cairo_path_op_line_to */
|
|
3, /* cairo_path_op_curve_to */
|
|
0, /* cairo_path_op_close_path */
|
|
};
|
|
|
|
cairo_status_t
|
|
_cairo_path_fixed_interpret (cairo_path_fixed_t *path,
|
|
cairo_direction_t dir,
|
|
cairo_path_fixed_move_to_func_t *move_to,
|
|
cairo_path_fixed_line_to_func_t *line_to,
|
|
cairo_path_fixed_curve_to_func_t *curve_to,
|
|
cairo_path_fixed_close_path_func_t *close_path,
|
|
void *closure)
|
|
{
|
|
cairo_status_t status;
|
|
int i, arg;
|
|
cairo_path_op_buf_t *op_buf;
|
|
cairo_path_op_t op;
|
|
cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
|
|
int buf_i = 0;
|
|
cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS];
|
|
cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
|
|
int step = forward ? 1 : -1;
|
|
|
|
for (op_buf = forward ? path->op_buf_head : path->op_buf_tail;
|
|
op_buf;
|
|
op_buf = forward ? op_buf->next : op_buf->prev)
|
|
{
|
|
int start, stop;
|
|
if (forward) {
|
|
start = 0;
|
|
stop = op_buf->num_ops;
|
|
} else {
|
|
start = op_buf->num_ops - 1;
|
|
stop = -1;
|
|
}
|
|
|
|
for (i=start; i != stop; i += step) {
|
|
op = op_buf->op[i];
|
|
|
|
if (! forward) {
|
|
if (buf_i == 0) {
|
|
arg_buf = arg_buf->prev;
|
|
buf_i = arg_buf->num_points;
|
|
}
|
|
buf_i -= num_args[op];
|
|
}
|
|
|
|
for (arg = 0; arg < num_args[op]; arg++) {
|
|
point[arg] = arg_buf->points[buf_i];
|
|
buf_i++;
|
|
if (buf_i >= arg_buf->num_points) {
|
|
arg_buf = arg_buf->next;
|
|
buf_i = 0;
|
|
}
|
|
}
|
|
|
|
if (! forward) {
|
|
buf_i -= num_args[op];
|
|
}
|
|
|
|
switch (op) {
|
|
case CAIRO_PATH_OP_MOVE_TO:
|
|
status = (*move_to) (closure, &point[0]);
|
|
break;
|
|
case CAIRO_PATH_OP_LINE_TO:
|
|
status = (*line_to) (closure, &point[0]);
|
|
break;
|
|
case CAIRO_PATH_OP_CURVE_TO:
|
|
status = (*curve_to) (closure, &point[0], &point[1], &point[2]);
|
|
break;
|
|
case CAIRO_PATH_OP_CLOSE_PATH:
|
|
default:
|
|
status = (*close_path) (closure);
|
|
break;
|
|
}
|
|
if (status)
|
|
return status;
|
|
}
|
|
}
|
|
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
|
|
cairo_fixed_t offx,
|
|
cairo_fixed_t offy,
|
|
cairo_fixed_t scalex,
|
|
cairo_fixed_t scaley)
|
|
{
|
|
cairo_path_arg_buf_t *arg_buf = path->arg_buf_head;
|
|
int i;
|
|
cairo_int64_t i64temp;
|
|
cairo_fixed_t fixedtemp;
|
|
|
|
while (arg_buf) {
|
|
for (i = 0; i < arg_buf->num_points; i++) {
|
|
if (scalex == CAIRO_FIXED_ONE) {
|
|
arg_buf->points[i].x += offx;
|
|
} else {
|
|
fixedtemp = arg_buf->points[i].x + offx;
|
|
i64temp = _cairo_int32x32_64_mul (fixedtemp, scalex);
|
|
arg_buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
|
|
}
|
|
|
|
if (scaley == CAIRO_FIXED_ONE) {
|
|
arg_buf->points[i].y += offy;
|
|
} else {
|
|
fixedtemp = arg_buf->points[i].y + offy;
|
|
i64temp = _cairo_int32x32_64_mul (fixedtemp, scaley);
|
|
arg_buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
|
|
}
|
|
}
|
|
|
|
arg_buf = arg_buf->next;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* _cairo_path_fixed_device_transform:
|
|
* @path: a #cairo_path_fixed_t to be transformed
|
|
* @device_transform: a matrix with only scaling/translation (no rotation or shear)
|
|
*
|
|
* Transform the fixed-point path according to the scaling and
|
|
* translation of the given matrix. This function assert()s that the
|
|
* given matrix has no rotation or shear elements, (that is, xy and yx
|
|
* are 0.0).
|
|
**/
|
|
void
|
|
_cairo_path_fixed_device_transform (cairo_path_fixed_t *path,
|
|
cairo_matrix_t *device_transform)
|
|
{
|
|
assert (device_transform->yx == 0.0 && device_transform->xy == 0.0);
|
|
/* XXX: FRAGILE: I'm not really sure whether we're doing the
|
|
* "right" thing here if there is both scaling and translation in
|
|
* the matrix. But for now, the internals guarantee that we won't
|
|
* really ever have both going on. */
|
|
_cairo_path_fixed_offset_and_scale (path,
|
|
_cairo_fixed_from_double (device_transform->x0),
|
|
_cairo_fixed_from_double (device_transform->y0),
|
|
_cairo_fixed_from_double (device_transform->xx),
|
|
_cairo_fixed_from_double (device_transform->yy));
|
|
}
|