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>
41
#include "cairo-path-fixed-private.h"
43
/* private functions */
45
_cairo_path_fixed_add (cairo_path_fixed_t *path,
47
cairo_point_t *points,
51
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
52
cairo_path_buf_t *buf);
54
static cairo_path_buf_t *
55
_cairo_path_buf_create (void);
58
_cairo_path_buf_destroy (cairo_path_buf_t *buf);
61
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
65
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
66
cairo_point_t *points,
70
_cairo_path_fixed_init (cairo_path_fixed_t *path)
72
path->buf_head->next = NULL;
73
path->buf_head->prev = NULL;
74
path->buf_tail = path->buf_head;
76
path->buf_head->num_ops = 0;
77
path->buf_head->num_points = 0;
79
path->current_point.x = 0;
80
path->current_point.y = 0;
81
path->has_current_point = FALSE;
82
path->has_curve_to = FALSE;
83
path->last_move_point = path->current_point;
87
_cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
88
cairo_path_fixed_t *other)
90
cairo_path_buf_t *buf, *other_buf;
92
_cairo_path_fixed_init (path);
93
path->current_point = other->current_point;
94
path->has_current_point = other->has_current_point;
95
path->has_curve_to = other->has_curve_to;
96
path->last_move_point = other->last_move_point;
98
path->buf_head->num_ops = other->buf_head->num_ops;
99
path->buf_head->num_points = other->buf_head->num_points;
100
memcpy (path->buf_head->op, other->buf_head->op,
101
other->buf_head->num_ops * sizeof (other->buf_head->op[0]));
102
memcpy (path->buf_head->points, other->buf_head->points,
103
other->buf_head->num_points * sizeof (other->buf_head->points[0]));
104
for (other_buf = other->buf_head->next;
106
other_buf = other_buf->next)
108
buf = _cairo_path_buf_create ();
110
_cairo_path_fixed_fini (path);
111
return CAIRO_STATUS_NO_MEMORY;
113
memcpy (buf, other_buf, sizeof (cairo_path_buf_t));
114
_cairo_path_fixed_add_buf (path, buf);
117
return CAIRO_STATUS_SUCCESS;
121
_cairo_path_fixed_create (void)
123
cairo_path_fixed_t *path = malloc (sizeof (cairo_path_fixed_t));
127
_cairo_path_fixed_init (path);
132
_cairo_path_fixed_fini (cairo_path_fixed_t *path)
134
cairo_path_buf_t *buf;
136
buf = path->buf_head->next;
138
cairo_path_buf_t *this = buf;
140
_cairo_path_buf_destroy (this);
142
path->buf_head->next = NULL;
143
path->buf_head->prev = NULL;
144
path->buf_tail = path->buf_head;
145
path->buf_head->num_ops = 0;
146
path->buf_head->num_points = 0;
148
path->has_current_point = FALSE;
149
path->has_curve_to = FALSE;
153
_cairo_path_fixed_destroy (cairo_path_fixed_t *path)
155
_cairo_path_fixed_fini (path);
160
_cairo_path_fixed_move_to (cairo_path_fixed_t *path,
164
cairo_status_t status;
170
/* If the previous op was also a MOVE_TO, then just change its
171
* point rather than adding a new op. */
172
if (path->buf_tail && path->buf_tail->num_ops &&
173
path->buf_tail->op[path->buf_tail->num_ops - 1] == CAIRO_PATH_OP_MOVE_TO)
175
cairo_point_t *last_move_to_point;
176
last_move_to_point = &path->buf_tail->points[path->buf_tail->num_points - 1];
177
*last_move_to_point = point;
179
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
184
path->current_point = point;
185
path->has_current_point = TRUE;
186
path->last_move_point = path->current_point;
188
return CAIRO_STATUS_SUCCESS;
192
_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path)
194
path->has_current_point = FALSE;
198
_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
204
if (! path->has_current_point)
205
return CAIRO_STATUS_NO_CURRENT_POINT;
207
x = path->current_point.x + dx;
208
y = path->current_point.y + dy;
210
return _cairo_path_fixed_move_to (path, x, y);
214
_cairo_path_fixed_line_to (cairo_path_fixed_t *path,
218
cairo_status_t status;
224
/* When there is not yet a current point, the line_to operation
225
* becomes a move_to instead. Note: We have to do this by
226
* explicitly calling into _cairo_path_fixed_line_to to ensure
227
* that the last_move_point state is updated properly.
229
if (! path->has_current_point)
230
status = _cairo_path_fixed_move_to (path, point.x, point.y);
232
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
237
path->current_point = point;
238
path->has_current_point = TRUE;
240
return CAIRO_STATUS_SUCCESS;
244
_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
250
if (! path->has_current_point)
251
return CAIRO_STATUS_NO_CURRENT_POINT;
253
x = path->current_point.x + dx;
254
y = path->current_point.y + dy;
256
return _cairo_path_fixed_line_to (path, x, y);
260
_cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
261
cairo_fixed_t x0, cairo_fixed_t y0,
262
cairo_fixed_t x1, cairo_fixed_t y1,
263
cairo_fixed_t x2, cairo_fixed_t y2)
265
cairo_status_t status;
266
cairo_point_t point[3];
268
point[0].x = x0; point[0].y = y0;
269
point[1].x = x1; point[1].y = y1;
270
point[2].x = x2; point[2].y = y2;
272
if (! path->has_current_point) {
273
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO,
279
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
283
path->current_point = point[2];
284
path->has_current_point = TRUE;
285
path->has_curve_to = TRUE;
287
return CAIRO_STATUS_SUCCESS;
291
_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
292
cairo_fixed_t dx0, cairo_fixed_t dy0,
293
cairo_fixed_t dx1, cairo_fixed_t dy1,
294
cairo_fixed_t dx2, cairo_fixed_t dy2)
296
cairo_fixed_t x0, y0;
297
cairo_fixed_t x1, y1;
298
cairo_fixed_t x2, y2;
300
if (! path->has_current_point)
301
return CAIRO_STATUS_NO_CURRENT_POINT;
303
x0 = path->current_point.x + dx0;
304
y0 = path->current_point.y + dy0;
306
x1 = path->current_point.x + dx1;
307
y1 = path->current_point.y + dy1;
309
x2 = path->current_point.x + dx2;
310
y2 = path->current_point.y + dy2;
312
return _cairo_path_fixed_curve_to (path,
319
_cairo_path_fixed_close_path (cairo_path_fixed_t *path)
321
cairo_status_t status;
323
if (! path->has_current_point)
324
return CAIRO_STATUS_SUCCESS;
326
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
330
status = _cairo_path_fixed_move_to (path,
331
path->last_move_point.x,
332
path->last_move_point.y);
336
return CAIRO_STATUS_SUCCESS;
340
_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
344
if (! path->has_current_point)
345
return CAIRO_STATUS_NO_CURRENT_POINT;
347
*x = path->current_point.x;
348
*y = path->current_point.y;
350
return CAIRO_STATUS_SUCCESS;
353
static cairo_status_t
354
_cairo_path_fixed_add (cairo_path_fixed_t *path,
356
cairo_point_t *points,
359
if (path->buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE ||
360
path->buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE)
362
cairo_path_buf_t *buf;
364
buf = _cairo_path_buf_create ();
366
return CAIRO_STATUS_NO_MEMORY;
368
_cairo_path_fixed_add_buf (path, buf);
371
_cairo_path_buf_add_op (path->buf_tail, op);
372
_cairo_path_buf_add_points (path->buf_tail, points, num_points);
374
return CAIRO_STATUS_SUCCESS;
378
_cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
379
cairo_path_buf_t *buf)
382
buf->prev = path->buf_tail;
384
path->buf_tail->next = buf;
385
path->buf_tail = buf;
388
static cairo_path_buf_t *
389
_cairo_path_buf_create (void)
391
cairo_path_buf_t *buf;
393
buf = malloc (sizeof (cairo_path_buf_t));
406
_cairo_path_buf_destroy (cairo_path_buf_t *buf)
412
_cairo_path_buf_add_op (cairo_path_buf_t *buf,
415
buf->op[buf->num_ops++] = op;
419
_cairo_path_buf_add_points (cairo_path_buf_t *buf,
420
cairo_point_t *points,
425
for (i=0; i < num_points; i++) {
426
buf->points[buf->num_points++] = points[i];
430
static int const num_args[] =
432
1, /* cairo_path_move_to */
433
1, /* cairo_path_op_line_to */
434
3, /* cairo_path_op_curve_to */
435
0, /* cairo_path_op_close_path */
439
_cairo_path_fixed_interpret (cairo_path_fixed_t *path,
440
cairo_direction_t dir,
441
cairo_path_fixed_move_to_func_t *move_to,
442
cairo_path_fixed_line_to_func_t *line_to,
443
cairo_path_fixed_curve_to_func_t *curve_to,
444
cairo_path_fixed_close_path_func_t *close_path,
447
cairo_status_t status;
448
cairo_path_buf_t *buf;
450
cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
451
int step = forward ? 1 : -1;
453
for (buf = forward ? path->buf_head : path->buf_tail;
455
buf = forward ? buf->next : buf->prev)
457
cairo_point_t *points;
462
points = buf->points;
464
start = buf->num_ops - 1;
466
points = buf->points + buf->num_points;
469
for (i=start; i != stop; i += step) {
473
points -= num_args[op];
477
case CAIRO_PATH_OP_MOVE_TO:
478
status = (*move_to) (closure, &points[0]);
480
case CAIRO_PATH_OP_LINE_TO:
481
status = (*line_to) (closure, &points[0]);
483
case CAIRO_PATH_OP_CURVE_TO:
484
status = (*curve_to) (closure, &points[0], &points[1], &points[2]);
486
case CAIRO_PATH_OP_CLOSE_PATH:
488
status = (*close_path) (closure);
495
points += num_args[op];
501
return CAIRO_STATUS_SUCCESS;
505
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
508
cairo_fixed_t scalex,
509
cairo_fixed_t scaley)
511
cairo_path_buf_t *buf = path->buf_head;
513
cairo_int64_t i64temp;
514
cairo_fixed_t fixedtemp;
517
for (i = 0; i < buf->num_points; i++) {
518
if (scalex == CAIRO_FIXED_ONE) {
519
buf->points[i].x += offx;
521
fixedtemp = buf->points[i].x + offx;
522
i64temp = _cairo_int32x32_64_mul (fixedtemp, scalex);
523
buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
526
if (scaley == CAIRO_FIXED_ONE) {
527
buf->points[i].y += offy;
529
fixedtemp = buf->points[i].y + offy;
530
i64temp = _cairo_int32x32_64_mul (fixedtemp, scaley);
531
buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16));
541
* _cairo_path_fixed_device_transform:
542
* @path: a #cairo_path_fixed_t to be transformed
543
* @device_transform: a matrix with only scaling/translation (no rotation or shear)
545
* Transform the fixed-point path according to the scaling and
546
* translation of the given matrix. This function assert()s that the
547
* given matrix has no rotation or shear elements, (that is, xy and yx
551
_cairo_path_fixed_device_transform (cairo_path_fixed_t *path,
552
cairo_matrix_t *device_transform)
554
assert (device_transform->yx == 0.0 && device_transform->xy == 0.0);
555
/* XXX: FRAGILE: I'm not really sure whether we're doing the
556
* "right" thing here if there is both scaling and translation in
557
* the matrix. But for now, the internals guarantee that we won't
558
* really ever have both going on. */
559
_cairo_path_fixed_offset_and_scale (path,
560
_cairo_fixed_from_double (device_transform->x0),
561
_cairo_fixed_from_double (device_transform->y0),
562
_cairo_fixed_from_double (device_transform->xx),
563
_cairo_fixed_from_double (device_transform->yy));