~ubuntu-branches/ubuntu/trusty/moon/trusty

« back to all changes in this revision

Viewing changes to cairo/src/cairo-path.c

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2009-02-14 12:01:08 UTC
  • Revision ID: james.westby@ubuntu.com-20090214120108-06539vb25vhbd8bn
Tags: upstream-1.0
Import upstream version 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* cairo - a vector graphics library with display and print output
 
2
 *
 
3
 * Copyright © 2005 Red Hat, Inc.
 
4
 * Copyright © 2006 Red Hat, Inc.
 
5
 *
 
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.
 
13
 *
 
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
 
19
 *
 
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/
 
24
 *
 
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.
 
28
 *
 
29
 * The Original Code is the cairo graphics library.
 
30
 *
 
31
 * The Initial Developer of the Original Code is Red Hat, Inc.
 
32
 *
 
33
 * Contributor(s):
 
34
 *      Carl D. Worth <cworth@redhat.com>
 
35
 */
 
36
 
 
37
#include "cairoint.h"
 
38
 
 
39
#include "cairo-path-private.h"
 
40
#include "cairo-path-fixed-private.h"
 
41
 
 
42
static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
 
43
 
 
44
/* Closure for path interpretation. */
 
45
typedef struct cairo_path_count {
 
46
    int count;
 
47
    cairo_point_t current_point;
 
48
} cpc_t;
 
49
 
 
50
static cairo_status_t
 
51
_cpc_move_to (void *closure, cairo_point_t *point)
 
52
{
 
53
    cpc_t *cpc = closure;
 
54
 
 
55
    cpc->count += 2;
 
56
 
 
57
    cpc->current_point = *point;
 
58
 
 
59
    return CAIRO_STATUS_SUCCESS;
 
60
}
 
61
 
 
62
static cairo_status_t
 
63
_cpc_line_to (void *closure, cairo_point_t *point)
 
64
{
 
65
    cpc_t *cpc = closure;
 
66
 
 
67
    cpc->count += 2;
 
68
 
 
69
    cpc->current_point = *point;
 
70
 
 
71
    return CAIRO_STATUS_SUCCESS;
 
72
}
 
73
 
 
74
static cairo_status_t
 
75
_cpc_curve_to (void             *closure,
 
76
               cairo_point_t    *p1,
 
77
               cairo_point_t    *p2,
 
78
               cairo_point_t    *p3)
 
79
{
 
80
    cpc_t *cpc = closure;
 
81
 
 
82
    cpc->count += 4;
 
83
 
 
84
    cpc->current_point = *p3;
 
85
 
 
86
    return CAIRO_STATUS_SUCCESS;
 
87
}
 
88
 
 
89
static cairo_status_t
 
90
_cpc_close_path (void *closure)
 
91
{
 
92
    cpc_t *cpc = closure;
 
93
 
 
94
    cpc->count += 1;
 
95
 
 
96
    return CAIRO_STATUS_SUCCESS;
 
97
}
 
98
 
 
99
static int
 
100
_cairo_path_count (cairo_path_t         *path,
 
101
                   cairo_path_fixed_t   *path_fixed,
 
102
                   double                tolerance,
 
103
                   cairo_bool_t          flatten)
 
104
{
 
105
    cairo_status_t status;
 
106
    cpc_t cpc;
 
107
 
 
108
    cpc.count = 0;
 
109
    cpc.current_point.x = 0;
 
110
    cpc.current_point.y = 0;
 
111
 
 
112
    if (flatten) {
 
113
        status = _cairo_path_fixed_interpret_flat (path_fixed,
 
114
                                                   CAIRO_DIRECTION_FORWARD,
 
115
                                                   _cpc_move_to,
 
116
                                                   _cpc_line_to,
 
117
                                                   _cpc_close_path,
 
118
                                                   &cpc,
 
119
                                                   tolerance);
 
120
    } else {
 
121
        status = _cairo_path_fixed_interpret (path_fixed,
 
122
                                              CAIRO_DIRECTION_FORWARD,
 
123
                                              _cpc_move_to,
 
124
                                              _cpc_line_to,
 
125
                                              _cpc_curve_to,
 
126
                                              _cpc_close_path,
 
127
                                              &cpc);
 
128
    }
 
129
 
 
130
    if (status)
 
131
        return -1;
 
132
 
 
133
    return cpc.count;
 
134
}
 
135
 
 
136
/* Closure for path interpretation. */
 
137
typedef struct cairo_path_populate {
 
138
    cairo_path_data_t *data;
 
139
    cairo_gstate_t    *gstate;
 
140
    cairo_point_t      current_point;
 
141
} cpp_t;
 
142
 
 
143
static cairo_status_t
 
144
_cpp_move_to (void *closure, cairo_point_t *point)
 
145
{
 
146
    cpp_t *cpp = closure;
 
147
    cairo_path_data_t *data = cpp->data;
 
148
    double x, y;
 
149
 
 
150
    x = _cairo_fixed_to_double (point->x);
 
151
    y = _cairo_fixed_to_double (point->y);
 
152
 
 
153
    _cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
 
154
 
 
155
    data->header.type = CAIRO_PATH_MOVE_TO;
 
156
    data->header.length = 2;
 
157
 
 
158
    /* We index from 1 to leave room for data->header */
 
159
    data[1].point.x = x;
 
160
    data[1].point.y = y;
 
161
 
 
162
    cpp->data += data->header.length;
 
163
 
 
164
    cpp->current_point = *point;
 
165
 
 
166
    return CAIRO_STATUS_SUCCESS;
 
167
}
 
168
 
 
169
static cairo_status_t
 
170
_cpp_line_to (void *closure, cairo_point_t *point)
 
171
{
 
172
    cpp_t *cpp = closure;
 
173
    cairo_path_data_t *data = cpp->data;
 
174
    double x, y;
 
175
 
 
176
    x = _cairo_fixed_to_double (point->x);
 
177
    y = _cairo_fixed_to_double (point->y);
 
178
 
 
179
    _cairo_gstate_backend_to_user (cpp->gstate, &x, &y);
 
180
 
 
181
    data->header.type = CAIRO_PATH_LINE_TO;
 
182
    data->header.length = 2;
 
183
 
 
184
    /* We index from 1 to leave room for data->header */
 
185
    data[1].point.x = x;
 
186
    data[1].point.y = y;
 
187
 
 
188
    cpp->data += data->header.length;
 
189
 
 
190
    cpp->current_point = *point;
 
191
 
 
192
    return CAIRO_STATUS_SUCCESS;
 
193
}
 
194
 
 
195
static cairo_status_t
 
196
_cpp_curve_to (void             *closure,
 
197
               cairo_point_t    *p1,
 
198
               cairo_point_t    *p2,
 
199
               cairo_point_t    *p3)
 
200
{
 
201
    cpp_t *cpp = closure;
 
202
    cairo_path_data_t *data = cpp->data;
 
203
    double x1, y1;
 
204
    double x2, y2;
 
205
    double x3, y3;
 
206
 
 
207
    x1 = _cairo_fixed_to_double (p1->x);
 
208
    y1 = _cairo_fixed_to_double (p1->y);
 
209
    _cairo_gstate_backend_to_user (cpp->gstate, &x1, &y1);
 
210
 
 
211
    x2 = _cairo_fixed_to_double (p2->x);
 
212
    y2 = _cairo_fixed_to_double (p2->y);
 
213
    _cairo_gstate_backend_to_user (cpp->gstate, &x2, &y2);
 
214
 
 
215
    x3 = _cairo_fixed_to_double (p3->x);
 
216
    y3 = _cairo_fixed_to_double (p3->y);
 
217
    _cairo_gstate_backend_to_user (cpp->gstate, &x3, &y3);
 
218
 
 
219
    data->header.type = CAIRO_PATH_CURVE_TO;
 
220
    data->header.length = 4;
 
221
 
 
222
    /* We index from 1 to leave room for data->header */
 
223
    data[1].point.x = x1;
 
224
    data[1].point.y = y1;
 
225
 
 
226
    data[2].point.x = x2;
 
227
    data[2].point.y = y2;
 
228
 
 
229
    data[3].point.x = x3;
 
230
    data[3].point.y = y3;
 
231
 
 
232
    cpp->data += data->header.length;
 
233
 
 
234
    cpp->current_point = *p3;
 
235
 
 
236
    return CAIRO_STATUS_SUCCESS;
 
237
}
 
238
 
 
239
static cairo_status_t
 
240
_cpp_close_path (void *closure)
 
241
{
 
242
    cpp_t *cpp = closure;
 
243
    cairo_path_data_t *data = cpp->data;
 
244
 
 
245
    data->header.type = CAIRO_PATH_CLOSE_PATH;
 
246
    data->header.length = 1;
 
247
 
 
248
    cpp->data += data->header.length;
 
249
 
 
250
    return CAIRO_STATUS_SUCCESS;
 
251
}
 
252
 
 
253
static cairo_status_t
 
254
_cairo_path_populate (cairo_path_t              *path,
 
255
                      cairo_path_fixed_t        *path_fixed,
 
256
                      cairo_gstate_t            *gstate,
 
257
                      cairo_bool_t               flatten)
 
258
{
 
259
    cairo_status_t status;
 
260
    cpp_t cpp;
 
261
 
 
262
    cpp.data = path->data;
 
263
    cpp.gstate = gstate;
 
264
    cpp.current_point.x = 0;
 
265
    cpp.current_point.y = 0;
 
266
 
 
267
    if (flatten) {
 
268
        double tolerance = _cairo_gstate_get_tolerance (gstate);
 
269
        status = _cairo_path_fixed_interpret_flat (path_fixed,
 
270
                                                   CAIRO_DIRECTION_FORWARD,
 
271
                                                   _cpp_move_to,
 
272
                                                   _cpp_line_to,
 
273
                                                   _cpp_close_path,
 
274
                                                   &cpp,
 
275
                                                   tolerance);
 
276
    } else {
 
277
        status = _cairo_path_fixed_interpret (path_fixed,
 
278
                                          CAIRO_DIRECTION_FORWARD,
 
279
                                          _cpp_move_to,
 
280
                                          _cpp_line_to,
 
281
                                          _cpp_curve_to,
 
282
                                          _cpp_close_path,
 
283
                                          &cpp);
 
284
    }
 
285
 
 
286
    if (status)
 
287
        return status;
 
288
 
 
289
    /* Sanity check the count */
 
290
    assert (cpp.data - path->data == path->num_data);
 
291
 
 
292
    return CAIRO_STATUS_SUCCESS;
 
293
}
 
294
 
 
295
cairo_path_t *
 
296
_cairo_path_create_in_error (cairo_status_t status)
 
297
{
 
298
    cairo_path_t *path;
 
299
 
 
300
    /* special case NO_MEMORY so as to avoid allocations */
 
301
    if (status == CAIRO_STATUS_NO_MEMORY)
 
302
        return (cairo_path_t*) &_cairo_path_nil;
 
303
 
 
304
    path = malloc (sizeof (cairo_path_t));
 
305
    if (path == NULL) {
 
306
        _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 
307
        return (cairo_path_t*) &_cairo_path_nil;
 
308
    }
 
309
 
 
310
    path->num_data = 0;
 
311
    path->data = NULL;
 
312
    path->status = status;
 
313
 
 
314
    return path;
 
315
}
 
316
 
 
317
static cairo_path_t *
 
318
_cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
 
319
                             cairo_gstate_t     *gstate,
 
320
                             cairo_bool_t        flatten)
 
321
{
 
322
    cairo_path_t *path;
 
323
 
 
324
    path = malloc (sizeof (cairo_path_t));
 
325
    if (path == NULL) {
 
326
        _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 
327
        return (cairo_path_t*) &_cairo_path_nil;
 
328
    }
 
329
 
 
330
    path->num_data = _cairo_path_count (path, path_fixed,
 
331
                                        _cairo_gstate_get_tolerance (gstate),
 
332
                                        flatten);
 
333
    if (path->num_data < 0) {
 
334
        free (path);
 
335
        return (cairo_path_t*) &_cairo_path_nil;
 
336
    }
 
337
 
 
338
    if (path->num_data) {
 
339
        path->data = _cairo_malloc_ab (path->num_data,
 
340
                                       sizeof (cairo_path_data_t));
 
341
        if (path->data == NULL) {
 
342
            free (path);
 
343
            _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 
344
            return (cairo_path_t*) &_cairo_path_nil;
 
345
        }
 
346
 
 
347
        path->status = _cairo_path_populate (path, path_fixed,
 
348
                                             gstate, flatten);
 
349
    } else {
 
350
        path->data = NULL;
 
351
        path->status = CAIRO_STATUS_SUCCESS;
 
352
    }
 
353
 
 
354
    return path;
 
355
}
 
356
 
 
357
/**
 
358
 * cairo_path_destroy:
 
359
 * @path: a path previously returned by either cairo_copy_path() or
 
360
 * cairo_copy_path_flat().
 
361
 *
 
362
 * Immediately releases all memory associated with @path. After a call
 
363
 * to cairo_path_destroy() the @path pointer is no longer valid and
 
364
 * should not be used further.
 
365
 *
 
366
 * Note: cairo_path_destroy() should only be called with a
 
367
 * pointer to a #cairo_path_t returned by a cairo function. Any path
 
368
 * that is created manually (ie. outside of cairo) should be destroyed
 
369
 * manually as well.
 
370
 **/
 
371
void
 
372
cairo_path_destroy (cairo_path_t *path)
 
373
{
 
374
    if (path == NULL || path == &_cairo_path_nil)
 
375
        return;
 
376
 
 
377
    if (path->data)
 
378
        free (path->data);
 
379
 
 
380
    free (path);
 
381
}
 
382
 
 
383
/**
 
384
 * _cairo_path_create:
 
385
 * @path: a fixed-point, device-space path to be converted and copied
 
386
 * @gstate: the current graphics state
 
387
 *
 
388
 * Creates a user-space #cairo_path_t copy of the given device-space
 
389
 * @path. The @gstate parameter provides the inverse CTM for the
 
390
 * conversion.
 
391
 *
 
392
 * Return value: the new copy of the path. If there is insufficient
 
393
 * memory a pointer to a special static nil #cairo_path_t will be
 
394
 * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
 
395
 * data==%NULL.
 
396
 **/
 
397
cairo_path_t *
 
398
_cairo_path_create (cairo_path_fixed_t *path,
 
399
                    cairo_gstate_t     *gstate)
 
400
{
 
401
    return _cairo_path_create_internal (path, gstate, FALSE);
 
402
}
 
403
 
 
404
/**
 
405
 * _cairo_path_create_flat:
 
406
 * @path: a fixed-point, device-space path to be flattened, converted and copied
 
407
 * @gstate: the current graphics state
 
408
 *
 
409
 * Creates a flattened, user-space #cairo_path_t copy of the given
 
410
 * device-space @path. The @gstate parameter provide the inverse CTM
 
411
 * for the conversion, as well as the tolerance value to control the
 
412
 * accuracy of the flattening.
 
413
 *
 
414
 * Return value: the flattened copy of the path. If there is insufficient
 
415
 * memory a pointer to a special static nil #cairo_path_t will be
 
416
 * returned instead with status==%CAIRO_STATUS_NO_MEMORY and
 
417
 * data==%NULL.
 
418
 **/
 
419
cairo_path_t *
 
420
_cairo_path_create_flat (cairo_path_fixed_t *path,
 
421
                         cairo_gstate_t     *gstate)
 
422
{
 
423
    return _cairo_path_create_internal (path, gstate, TRUE);
 
424
}
 
425
 
 
426
/**
 
427
 * _cairo_path_append_to_context:
 
428
 * @path: the path data to be appended
 
429
 * @cr: a cairo context
 
430
 *
 
431
 * Append @path to the current path within @cr.
 
432
 *
 
433
 * Return value: %CAIRO_STATUS_INVALID_PATH_DATA if the data in @path
 
434
 * is invalid, and %CAIRO_STATUS_SUCCESS otherwise.
 
435
 **/
 
436
cairo_status_t
 
437
_cairo_path_append_to_context (const cairo_path_t       *path,
 
438
                               cairo_t                  *cr)
 
439
{
 
440
    int i;
 
441
    cairo_path_data_t *p;
 
442
    cairo_status_t status;
 
443
 
 
444
    for (i=0; i < path->num_data; i += path->data[i].header.length) {
 
445
        p = &path->data[i];
 
446
        switch (p->header.type) {
 
447
        case CAIRO_PATH_MOVE_TO:
 
448
            if (p->header.length < 2)
 
449
                return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
450
            cairo_move_to (cr,
 
451
                           p[1].point.x, p[1].point.y);
 
452
            break;
 
453
        case CAIRO_PATH_LINE_TO:
 
454
            if (p->header.length < 2)
 
455
                return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
456
            cairo_line_to (cr,
 
457
                           p[1].point.x, p[1].point.y);
 
458
            break;
 
459
        case CAIRO_PATH_CURVE_TO:
 
460
            if (p->header.length < 4)
 
461
                return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
462
            cairo_curve_to (cr,
 
463
                            p[1].point.x, p[1].point.y,
 
464
                            p[2].point.x, p[2].point.y,
 
465
                            p[3].point.x, p[3].point.y);
 
466
            break;
 
467
        case CAIRO_PATH_CLOSE_PATH:
 
468
            if (p->header.length < 1)
 
469
                return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
470
            cairo_close_path (cr);
 
471
            break;
 
472
        default:
 
473
            return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
 
474
        }
 
475
 
 
476
        status = cairo_status (cr);
 
477
        if (status)
 
478
            return status;
 
479
    }
 
480
 
 
481
    return CAIRO_STATUS_SUCCESS;
 
482
}