Subversion Repositories Scribus

Rev

Rev 14952 | Details | Compare with Previous | Last modification | View Log | RSS feed

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