1
/* cairo - a vector graphics library with display and print output
3
* Copyright © 2002 University of Southern California
4
* Copyright © 2005 Red Hat, Inc.
6
* This library is free software; you can redistribute it and/or
7
* modify it either under the terms of the GNU Lesser General Public
8
* License version 2.1 as published by the Free Software Foundation
9
* (the "LGPL") or, at your option, under the terms of the Mozilla
10
* Public License Version 1.1 (the "MPL"). If you do not alter this
11
* notice, a recipient may use your version of this file under either
12
* the MPL or the LGPL.
14
* You should have received a copy of the LGPL along with this library
15
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
* You should have received a copy of the MPL along with this library
18
* in the file COPYING-MPL-1.1
20
* The contents of this file are subject to the Mozilla Public License
21
* Version 1.1 (the "License"); you may not use this file except in
22
* compliance with the License. You may obtain a copy of the License at
23
* http://www.mozilla.org/MPL/
25
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
* the specific language governing rights and limitations.
29
* The Original Code is the cairo graphics library.
31
* The Initial Developer of the Original Code is University of Southern
35
* Carl D. Worth <cworth@cworth.org>
40
#include "cairo-path-fixed-private.h"
42
/* private functions */
44
_cairo_path_fixed_add (cairo_path_fixed_t *path,
46
cairo_point_t *points,
50
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
51
cairo_path_buf_t *buf);
53
static cairo_path_buf_t *
54
_cairo_path_buf_create (void);
57
_cairo_path_buf_destroy (cairo_path_buf_t *buf);
60
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
64
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
65
cairo_point_t *points,
69
_cairo_path_fixed_init (cairo_path_fixed_t *path)
71
path->buf_head->next = NULL;
72
path->buf_head->prev = NULL;
73
path->buf_tail = path->buf_head;
75
path->buf_head->num_ops = 0;
76
path->buf_head->num_points = 0;
78
path->current_point.x = 0;
79
path->current_point.y = 0;
80
path->has_current_point = FALSE;
81
path->has_curve_to = FALSE;
82
path->last_move_point = path->current_point;
86
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
87
cairo_path_fixed_t *other)
89
cairo_path_buf_t *buf, *other_buf;
91
_cairo_path_fixed_init (path);
92
path->current_point = other->current_point;
93
path->has_current_point = other->has_current_point;
94
path->has_curve_to = other->has_curve_to;
95
path->last_move_point = other->last_move_point;
97
path->buf_head->num_ops = other->buf_head->num_ops;
98
path->buf_head->num_points = other->buf_head->num_points;
99
memcpy (path->buf_head->op, other->buf_head->op,
100
other->buf_head->num_ops * sizeof (other->buf_head->op[0]));
101
memcpy (path->buf_head->points, other->buf_head->points,
102
other->buf_head->num_points * sizeof (other->buf_head->points[0]));
103
for (other_buf = other->buf_head->next;
105
other_buf = other_buf->next)
107
buf = _cairo_path_buf_create ();
109
_cairo_path_fixed_fini (path);
110
return CAIRO_STATUS_NO_MEMORY;
112
memcpy (buf, other_buf, sizeof (cairo_path_buf_t));
113
_cairo_path_fixed_add_buf (path, buf);
116
return CAIRO_STATUS_SUCCESS;
120
_cairo_path_fixed_create (void)
122
cairo_path_fixed_t *path = malloc (sizeof (cairo_path_fixed_t));
126
_cairo_path_fixed_init (path);
131
_cairo_path_fixed_fini (cairo_path_fixed_t *path)
133
cairo_path_buf_t *buf;
135
buf = path->buf_head->next;
137
cairo_path_buf_t *this = buf;
139
_cairo_path_buf_destroy (this);
141
path->buf_head->next = NULL;
142
path->buf_head->prev = NULL;
143
path->buf_tail = path->buf_head;
144
path->buf_head->num_ops = 0;
145
path->buf_head->num_points = 0;
147
path->has_current_point = FALSE;
148
path->has_curve_to = FALSE;
152
_cairo_path_fixed_destroy (cairo_path_fixed_t *path)
154
_cairo_path_fixed_fini (path);
159
_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
163
cairo_status_t status;
169
/* If the previous op was also a MOVE_TO, then just change its
170
* point rather than adding a new op. */
171
if (path->buf_tail && path->buf_tail->num_ops &&
172
path->buf_tail->op[path->buf_tail->num_ops - 1] == CAIRO_PATH_OP_MOVE_TO)
174
cairo_point_t *last_move_to_point;
175
last_move_to_point = &path->buf_tail->points[path->buf_tail->num_points - 1];
176
*last_move_to_point = point;
178
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
183
path->current_point = point;
184
path->has_current_point = TRUE;
185
path->last_move_point = path->current_point;
187
return CAIRO_STATUS_SUCCESS;
191
_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path)
193
path->has_current_point = FALSE;
197
_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
203
if (! path->has_current_point)
204
return CAIRO_STATUS_NO_CURRENT_POINT;
206
x = path->current_point.x + dx;
207
y = path->current_point.y + dy;
209
return _cairo_path_fixed_move_to (path, x, y);
213
_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
217
cairo_status_t status;
223
/* When there is not yet a current point, the line_to operation
224
* becomes a move_to instead. Note: We have to do this by
225
* explicitly calling into _cairo_path_fixed_line_to to ensure
226
* that the last_move_point state is updated properly.
228
if (! path->has_current_point)
229
status = _cairo_path_fixed_move_to (path, point.x, point.y);
231
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
236
path->current_point = point;
237
path->has_current_point = TRUE;
239
return CAIRO_STATUS_SUCCESS;
243
_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
249
if (! path->has_current_point)
250
return CAIRO_STATUS_NO_CURRENT_POINT;
252
x = path->current_point.x + dx;
253
y = path->current_point.y + dy;
255
return _cairo_path_fixed_line_to (path, x, y);
259
_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
260
cairo_fixed_t x0, cairo_fixed_t y0,
261
cairo_fixed_t x1, cairo_fixed_t y1,
262
cairo_fixed_t x2, cairo_fixed_t y2)
264
cairo_status_t status;
265
cairo_point_t point[3];
267
point[0].x = x0; point[0].y = y0;
268
point[1].x = x1; point[1].y = y1;
269
point[2].x = x2; point[2].y = y2;
271
if (! path->has_current_point) {
272
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO,
278
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
282
path->current_point = point[2];
283
path->has_current_point = TRUE;
284
path->has_curve_to = TRUE;
286
return CAIRO_STATUS_SUCCESS;
290
_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
291
cairo_fixed_t dx0, cairo_fixed_t dy0,
292
cairo_fixed_t dx1, cairo_fixed_t dy1,
293
cairo_fixed_t dx2, cairo_fixed_t dy2)
295
cairo_fixed_t x0, y0;
296
cairo_fixed_t x1, y1;
297
cairo_fixed_t x2, y2;
299
if (! path->has_current_point)
300
return CAIRO_STATUS_NO_CURRENT_POINT;
302
x0 = path->current_point.x + dx0;
303
y0 = path->current_point.y + dy0;
305
x1 = path->current_point.x + dx1;
306
y1 = path->current_point.y + dy1;
308
x2 = path->current_point.x + dx2;
309
y2 = path->current_point.y + dy2;
311
return _cairo_path_fixed_curve_to (path,
318
_cairo_path_fixed_close_path (cairo_path_fixed_t *path)
320
cairo_status_t status;
322
if (! path->has_current_point)
323
return CAIRO_STATUS_SUCCESS;
325
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
329
status = _cairo_path_fixed_move_to (path,
330
path->last_move_point.x,
331
path->last_move_point.y);
335
return CAIRO_STATUS_SUCCESS;
339
_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
343
if (! path->has_current_point)
344
return CAIRO_STATUS_NO_CURRENT_POINT;
346
*x = path->current_point.x;
347
*y = path->current_point.y;
349
return CAIRO_STATUS_SUCCESS;
352
static cairo_status_t
353
_cairo_path_fixed_add (cairo_path_fixed_t *path,
355
cairo_point_t *points,
358
if ((unsigned int) path->buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE ||
359
(unsigned int) path->buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE)
361
cairo_path_buf_t *buf;
363
buf = _cairo_path_buf_create ();
365
return CAIRO_STATUS_NO_MEMORY;
367
_cairo_path_fixed_add_buf (path, buf);
370
_cairo_path_buf_add_op (path->buf_tail, op);
371
_cairo_path_buf_add_points (path->buf_tail, points, num_points);
373
return CAIRO_STATUS_SUCCESS;
377
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
378
cairo_path_buf_t *buf)
381
buf->prev = path->buf_tail;
383
path->buf_tail->next = buf;
384
path->buf_tail = buf;
387
static cairo_path_buf_t *
388
_cairo_path_buf_create (void)
390
cairo_path_buf_t *buf;
392
buf = malloc (sizeof (cairo_path_buf_t));
405
_cairo_path_buf_destroy (cairo_path_buf_t *buf)
411
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
414
buf->op[buf->num_ops++] = op;
418
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
419
cairo_point_t *points,
424
for (i=0; i < num_points; i++) {
425
buf->points[buf->num_points++] = points[i];
429
static int const num_args[] =
431
1, /* cairo_path_move_to */
432
1, /* cairo_path_op_line_to */
433
3, /* cairo_path_op_curve_to */
434
0, /* cairo_path_op_close_path */
438
_cairo_path_fixed_interpret (cairo_path_fixed_t *path,
439
cairo_direction_t dir,
440
cairo_path_fixed_move_to_func_t *move_to,
441
cairo_path_fixed_line_to_func_t *line_to,
442
cairo_path_fixed_curve_to_func_t *curve_to,
443
cairo_path_fixed_close_path_func_t *close_path,
446
cairo_status_t status;
447
cairo_path_buf_t *buf;
449
cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
450
int step = forward ? 1 : -1;
452
for (buf = forward ? path->buf_head : path->buf_tail;
454
buf = forward ? buf->next : buf->prev)
456
cairo_point_t *points;
461
points = buf->points;
463
start = buf->num_ops - 1;
465
points = buf->points + buf->num_points;
468
for (i=start; i != stop; i += step) {
472
points -= num_args[op];
476
case CAIRO_PATH_OP_MOVE_TO:
477
status = (*move_to) (closure, &points[0]);
479
case CAIRO_PATH_OP_LINE_TO:
480
status = (*line_to) (closure, &points[0]);
482
case CAIRO_PATH_OP_CURVE_TO:
483
status = (*curve_to) (closure, &points[0], &points[1], &points[2]);
485
case CAIRO_PATH_OP_CLOSE_PATH:
487
status = (*close_path) (closure);
494
points += num_args[op];
500
return CAIRO_STATUS_SUCCESS;
504
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
507
cairo_fixed_t scalex,
508
cairo_fixed_t scaley)
510
cairo_path_buf_t *buf = path->buf_head;
512
cairo_int64_t i64temp;
513
cairo_fixed_t fixedtemp;
516
for (i = 0; i < buf->num_points; i++) {
517
if (scalex == CAIRO_FIXED_ONE) {
518
buf->points[i].x += offx;
520
fixedtemp = buf->points[i].x + offx;
521
i64temp = _cairo_int32x32_64_mul (fixedtemp, scalex);
522
buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
525
if (scaley == CAIRO_FIXED_ONE) {
526
buf->points[i].y += offy;
528
fixedtemp = buf->points[i].y + offy;
529
i64temp = _cairo_int32x32_64_mul (fixedtemp, scaley);
530
buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
540
* _cairo_path_fixed_device_transform:
541
* @path: a #cairo_path_fixed_t to be transformed
542
* @device_transform: a matrix with only scaling/translation (no rotation or shear)
544
* Transform the fixed-point path according to the scaling and
545
* translation of the given matrix. This function assert()s that the
546
* given matrix has no rotation or shear elements, (that is, xy and yx
550
_cairo_path_fixed_device_transform (cairo_path_fixed_t *path,
551
cairo_matrix_t *device_transform)
553
assert (device_transform->yx == 0.0 && device_transform->xy == 0.0);
554
/* XXX: FRAGILE: I'm not really sure whether we're doing the
555
* "right" thing here if there is both scaling and translation in
556
* the matrix. But for now, the internals guarantee that we won't
557
* really ever have both going on. */
558
_cairo_path_fixed_offset_and_scale (path,
559
_cairo_fixed_from_double (device_transform->x0),
560
_cairo_fixed_from_double (device_transform->y0),
561
_cairo_fixed_from_double (device_transform->xx),
562
_cairo_fixed_from_double (device_transform->yy));