~ubuntu-branches/ubuntu/breezy/libcairo/breezy-security

« back to all changes in this revision

Viewing changes to src/cairo_gstate.c

  • Committer: Bazaar Package Importer
  • Author(s): Dave Beckett
  • Date: 2004-05-29 21:10:58 UTC
  • Revision ID: james.westby@ubuntu.com-20040529211058-h596wztdkmpvul0k
Tags: upstream-0.1.23
Import upstream version 0.1.23

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright � 2002 University of Southern California
 
3
 *
 
4
 * Permission to use, copy, modify, distribute, and sell this software
 
5
 * and its documentation for any purpose is hereby granted without
 
6
 * fee, provided that the above copyright notice appear in all copies
 
7
 * and that both that copyright notice and this permission notice
 
8
 * appear in supporting documentation, and that the name of the
 
9
 * University of Southern California not be used in advertising or
 
10
 * publicity pertaining to distribution of the software without
 
11
 * specific, written prior permission. The University of Southern
 
12
 * California makes no representations about the suitability of this
 
13
 * software for any purpose.  It is provided "as is" without express
 
14
 * or implied warranty.
 
15
 *
 
16
 * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
 
17
 * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
 
18
 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
 
19
 * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 
20
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 
21
 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 
22
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 
23
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
24
 *
 
25
 * Author: Carl D. Worth <cworth@isi.edu>
 
26
 */
 
27
 
 
28
#include <stdlib.h>
 
29
#include <math.h>
 
30
 
 
31
#include "cairoint.h"
 
32
 
 
33
static cairo_status_t
 
34
_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
 
35
                                             cairo_pattern_t *src,
 
36
                                             cairo_operator_t operator,
 
37
                                             cairo_surface_t *dst,
 
38
                                             cairo_traps_t *traps);
 
39
 
 
40
cairo_gstate_t *
 
41
_cairo_gstate_create ()
 
42
{
 
43
    cairo_gstate_t *gstate;
 
44
 
 
45
    gstate = malloc (sizeof (cairo_gstate_t));
 
46
 
 
47
    if (gstate)
 
48
        _cairo_gstate_init (gstate);
 
49
 
 
50
    return gstate;
 
51
}
 
52
 
 
53
void
 
54
_cairo_gstate_init (cairo_gstate_t *gstate)
 
55
{
 
56
    gstate->operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
 
57
 
 
58
    gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
 
59
 
 
60
    gstate->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT;
 
61
    gstate->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT;
 
62
    gstate->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT;
 
63
    gstate->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT;
 
64
 
 
65
    gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
 
66
 
 
67
    gstate->dash = NULL;
 
68
    gstate->num_dashes = 0;
 
69
    gstate->dash_offset = 0.0;
 
70
 
 
71
    gstate->font = _cairo_font_create (CAIRO_FONT_FAMILY_DEFAULT,
 
72
                                       CAIRO_FONT_SLANT_DEFAULT,
 
73
                                       CAIRO_FONT_WEIGHT_DEFAULT);
 
74
 
 
75
    gstate->surface = NULL;
 
76
 
 
77
    gstate->clip.region = NULL;
 
78
    gstate->clip.surface = NULL;
 
79
    
 
80
    gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0);
 
81
    gstate->pattern_offset.x = 0.0;
 
82
    gstate->pattern_offset.y = 0.0;
 
83
    gstate->alpha = 1.0;
 
84
 
 
85
    gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT;
 
86
    _cairo_gstate_default_matrix (gstate);
 
87
 
 
88
    _cairo_path_init (&gstate->path);
 
89
 
 
90
    _cairo_pen_init_empty (&gstate->pen_regular);
 
91
 
 
92
    gstate->next = NULL;
 
93
}
 
94
 
 
95
cairo_status_t
 
96
_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
 
97
{
 
98
    cairo_status_t status;
 
99
    cairo_gstate_t *next;
 
100
    
 
101
    /* Copy all members, but don't smash the next pointer */
 
102
    next = gstate->next;
 
103
    *gstate = *other;
 
104
    gstate->next = next;
 
105
 
 
106
    /* Now fix up pointer data that needs to be cloned/referenced */
 
107
    if (other->dash) {
 
108
        gstate->dash = malloc (other->num_dashes * sizeof (double));
 
109
        if (gstate->dash == NULL)
 
110
            return CAIRO_STATUS_NO_MEMORY;
 
111
        memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
 
112
    }
 
113
 
 
114
    if (other->font) {
 
115
        gstate->font = _cairo_font_copy (other->font);
 
116
        if (!gstate->font) {
 
117
            status = CAIRO_STATUS_NO_MEMORY;
 
118
            goto CLEANUP_DASHES;
 
119
        }
 
120
    }
 
121
 
 
122
    if (other->clip.region)
 
123
    {   
 
124
        gstate->clip.region = pixman_region_create ();
 
125
        pixman_region_copy (gstate->clip.region, other->clip.region);
 
126
    }
 
127
 
 
128
    cairo_surface_reference (gstate->surface);
 
129
    cairo_surface_reference (gstate->clip.surface);
 
130
 
 
131
    cairo_pattern_reference (gstate->pattern);
 
132
    
 
133
    status = _cairo_path_init_copy (&gstate->path, &other->path);
 
134
    if (status)
 
135
        goto CLEANUP_FONT;
 
136
 
 
137
    status = _cairo_pen_init_copy (&gstate->pen_regular, &other->pen_regular);
 
138
    if (status)
 
139
        goto CLEANUP_PATH;
 
140
 
 
141
    return status;
 
142
 
 
143
  CLEANUP_PATH:
 
144
    _cairo_path_fini (&gstate->path);
 
145
  CLEANUP_FONT:
 
146
    cairo_font_destroy (gstate->font);
 
147
  CLEANUP_DASHES:
 
148
    free (gstate->dash);
 
149
    gstate->dash = NULL;
 
150
 
 
151
    return status;
 
152
}
 
153
 
 
154
void
 
155
_cairo_gstate_fini (cairo_gstate_t *gstate)
 
156
{
 
157
    cairo_font_destroy (gstate->font);
 
158
 
 
159
    if (gstate->surface)
 
160
        cairo_surface_destroy (gstate->surface);
 
161
    gstate->surface = NULL;
 
162
 
 
163
    if (gstate->clip.surface)
 
164
        cairo_surface_destroy (gstate->clip.surface);
 
165
    gstate->clip.surface = NULL;
 
166
 
 
167
    if (gstate->clip.region)
 
168
        pixman_region_destroy (gstate->clip.region);
 
169
    gstate->clip.region = NULL;
 
170
 
 
171
    cairo_pattern_destroy (gstate->pattern);
 
172
 
 
173
    _cairo_matrix_fini (&gstate->ctm);
 
174
    _cairo_matrix_fini (&gstate->ctm_inverse);
 
175
 
 
176
    _cairo_path_fini (&gstate->path);
 
177
 
 
178
    _cairo_pen_fini (&gstate->pen_regular);
 
179
 
 
180
    if (gstate->dash) {
 
181
        free (gstate->dash);
 
182
        gstate->dash = NULL;
 
183
    }
 
184
}
 
185
 
 
186
void
 
187
_cairo_gstate_destroy (cairo_gstate_t *gstate)
 
188
{
 
189
    _cairo_gstate_fini (gstate);
 
190
    free (gstate);
 
191
}
 
192
 
 
193
cairo_gstate_t*
 
194
_cairo_gstate_clone (cairo_gstate_t *gstate)
 
195
{
 
196
    cairo_status_t status;
 
197
    cairo_gstate_t *clone;
 
198
 
 
199
    clone = malloc (sizeof (cairo_gstate_t));
 
200
    if (clone) {
 
201
        status = _cairo_gstate_init_copy (clone, gstate);
 
202
        if (status) {
 
203
            free (clone);
 
204
            return NULL;
 
205
        }
 
206
    }
 
207
    clone->next = NULL;
 
208
 
 
209
    return clone;
 
210
}
 
211
 
 
212
cairo_status_t
 
213
_cairo_gstate_copy (cairo_gstate_t *dest, cairo_gstate_t *src)
 
214
{
 
215
    cairo_status_t status;
 
216
    cairo_gstate_t *next;
 
217
 
 
218
    /* Preserve next pointer over fini/init */
 
219
    next = dest->next;
 
220
    _cairo_gstate_fini (dest);
 
221
    status = _cairo_gstate_init_copy (dest, src);
 
222
    dest->next = next;
 
223
 
 
224
    return status;
 
225
}
 
226
 
 
227
/* Push rendering off to an off-screen group. */
 
228
/* XXX: Rethinking this API
 
229
cairo_status_t
 
230
_cairo_gstate_begin_group (cairo_gstate_t *gstate)
 
231
{
 
232
    Pixmap pix;
 
233
    cairo_color_t clear;
 
234
    unsigned int width, height;
 
235
 
 
236
    gstate->parent_surface = gstate->surface;
 
237
 
 
238
    width = _cairo_surface_get_width (gstate->surface);
 
239
    height = _cairo_surface_get_height (gstate->surface);
 
240
 
 
241
    pix = XCreatePixmap (gstate->dpy,
 
242
                         _cairo_surface_get_drawable (gstate->surface),
 
243
                         width, height,
 
244
                         _cairo_surface_get_depth (gstate->surface));
 
245
    if (pix == 0)
 
246
        return CAIRO_STATUS_NO_MEMORY;
 
247
 
 
248
    gstate->surface = cairo_surface_create (gstate->dpy);
 
249
    if (gstate->surface == NULL)
 
250
        return CAIRO_STATUS_NO_MEMORY;
 
251
 
 
252
    _cairo_surface_set_drawableWH (gstate->surface, pix, width, height);
 
253
 
 
254
    _cairo_color_init (&clear);
 
255
    _cairo_color_set_alpha (&clear, 0);
 
256
 
 
257
    status = _cairo_surface_fill_rectangle (gstate->surface,
 
258
                                   CAIRO_OPERATOR_SRC,
 
259
                                   &clear,
 
260
                                   0, 0,
 
261
                                   _cairo_surface_get_width (gstate->surface),
 
262
                                   _cairo_surface_get_height (gstate->surface));
 
263
    if (status)                          
 
264
        return status;
 
265
 
 
266
    return CAIRO_STATUS_SUCCESS;
 
267
}
 
268
*/
 
269
 
 
270
/* Complete the current offscreen group, composing its contents onto the parent surface. */
 
271
/* XXX: Rethinking this API
 
272
cairo_status_t
 
273
_cairo_gstate_end_group (cairo_gstate_t *gstate)
 
274
{
 
275
    Pixmap pix;
 
276
    cairo_color_t mask_color;
 
277
    cairo_surface_t mask;
 
278
 
 
279
    if (gstate->parent_surface == NULL)
 
280
        return CAIRO_STATUS_INVALID_POP_GROUP;
 
281
 
 
282
    _cairo_surface_init (&mask, gstate->dpy);
 
283
    _cairo_color_init (&mask_color);
 
284
    _cairo_color_set_alpha (&mask_color, gstate->alpha);
 
285
 
 
286
    _cairo_surface_set_solid_color (&mask, &mask_color);
 
287
 
 
288
    * XXX: This could be made much more efficient by using
 
289
       _cairo_surface_get_damaged_width/Height if cairo_surface_t actually kept
 
290
       track of such informaton. *
 
291
    _cairo_surface_composite (gstate->operator,
 
292
                              gstate->surface,
 
293
                              mask,
 
294
                              gstate->parent_surface,
 
295
                              0, 0,
 
296
                              0, 0,
 
297
                              0, 0,
 
298
                              _cairo_surface_get_width (gstate->surface),
 
299
                              _cairo_surface_get_height (gstate->surface));
 
300
 
 
301
    _cairo_surface_fini (&mask);
 
302
 
 
303
    pix = _cairo_surface_get_drawable (gstate->surface);
 
304
    XFreePixmap (gstate->dpy, pix);
 
305
 
 
306
    cairo_surface_destroy (gstate->surface);
 
307
    gstate->surface = gstate->parent_surface;
 
308
    gstate->parent_surface = NULL;
 
309
 
 
310
    return CAIRO_STATUS_SUCCESS;
 
311
}
 
312
*/
 
313
 
 
314
cairo_status_t
 
315
_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface)
 
316
{
 
317
    double scale;
 
318
 
 
319
    if (gstate->surface)
 
320
        cairo_surface_destroy (gstate->surface);
 
321
 
 
322
    gstate->surface = surface;
 
323
 
 
324
    /* Sometimes the user wants to return to having no target surface,
 
325
     * (just like after cairo_create). This can be useful for forcing
 
326
     * the old surface to be destroyed. */
 
327
    if (surface == NULL)
 
328
        return CAIRO_STATUS_SUCCESS;
 
329
 
 
330
    cairo_surface_reference (gstate->surface);
 
331
 
 
332
    scale = _cairo_surface_pixels_per_inch (surface) / gstate->pixels_per_inch;
 
333
    _cairo_gstate_scale (gstate, scale, scale);
 
334
    gstate->pixels_per_inch = _cairo_surface_pixels_per_inch (surface);
 
335
 
 
336
    return CAIRO_STATUS_SUCCESS;
 
337
}
 
338
 
 
339
/* XXX: Need to decide the memory mangement semantics of this
 
340
   function. Should it reference the surface again? */
 
341
cairo_surface_t *
 
342
_cairo_gstate_current_target_surface (cairo_gstate_t *gstate)
 
343
{
 
344
    if (gstate == NULL)
 
345
        return NULL;
 
346
 
 
347
/* XXX: Do we want this?
 
348
    if (gstate->surface)
 
349
        _cairo_surface_reference (gstate->surface);
 
350
*/
 
351
 
 
352
    return gstate->surface;
 
353
}
 
354
 
 
355
cairo_status_t
 
356
_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern)
 
357
{
 
358
    if (pattern == NULL)
 
359
        return CAIRO_STATUS_NULL_POINTER;
 
360
 
 
361
    if (gstate->pattern)
 
362
        cairo_pattern_destroy (gstate->pattern);
 
363
    
 
364
    gstate->pattern = pattern;
 
365
    cairo_pattern_reference (pattern);
 
366
    
 
367
    return CAIRO_STATUS_SUCCESS;
 
368
}
 
369
 
 
370
cairo_pattern_t *
 
371
_cairo_gstate_current_pattern (cairo_gstate_t *gstate)
 
372
{
 
373
    if (gstate == NULL)
 
374
        return NULL;
 
375
 
 
376
/* XXX: Do we want this?    
 
377
   cairo_pattern_reference (gstate->pattern);
 
378
*/
 
379
 
 
380
    return gstate->pattern;
 
381
}
 
382
 
 
383
cairo_status_t
 
384
_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator)
 
385
{
 
386
    gstate->operator = operator;
 
387
 
 
388
    return CAIRO_STATUS_SUCCESS;
 
389
}
 
390
 
 
391
cairo_operator_t
 
392
_cairo_gstate_current_operator (cairo_gstate_t *gstate)
 
393
{
 
394
    return gstate->operator;
 
395
}
 
396
 
 
397
cairo_status_t
 
398
_cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue)
 
399
{
 
400
    cairo_pattern_destroy (gstate->pattern);
 
401
    
 
402
    gstate->pattern = _cairo_pattern_create_solid (red, green, blue);
 
403
    gstate->pattern_offset.x = 0.0;
 
404
    gstate->pattern_offset.y = 0.0;
 
405
    
 
406
    return CAIRO_STATUS_SUCCESS;
 
407
}
 
408
 
 
409
cairo_status_t
 
410
_cairo_gstate_current_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue)
 
411
{
 
412
    return _cairo_pattern_get_rgb (gstate->pattern, red, green, blue);
 
413
}
 
414
 
 
415
cairo_status_t
 
416
_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
 
417
{
 
418
    gstate->tolerance = tolerance;
 
419
 
 
420
    return CAIRO_STATUS_SUCCESS;
 
421
}
 
422
 
 
423
double
 
424
_cairo_gstate_current_tolerance (cairo_gstate_t *gstate)
 
425
{
 
426
    return gstate->tolerance;
 
427
}
 
428
 
 
429
cairo_status_t
 
430
_cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha)
 
431
{
 
432
    gstate->alpha = alpha;
 
433
 
 
434
    return CAIRO_STATUS_SUCCESS;
 
435
}
 
436
 
 
437
double
 
438
_cairo_gstate_current_alpha (cairo_gstate_t *gstate)
 
439
{
 
440
    return gstate->alpha;
 
441
}
 
442
 
 
443
cairo_status_t
 
444
_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
 
445
{
 
446
    gstate->fill_rule = fill_rule;
 
447
 
 
448
    return CAIRO_STATUS_SUCCESS;
 
449
}
 
450
 
 
451
cairo_fill_rule_t
 
452
_cairo_gstate_current_fill_rule (cairo_gstate_t *gstate)
 
453
{
 
454
    return gstate->fill_rule;
 
455
}
 
456
 
 
457
cairo_status_t
 
458
_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
 
459
{
 
460
    gstate->line_width = width;
 
461
 
 
462
    return CAIRO_STATUS_SUCCESS;
 
463
}
 
464
 
 
465
double
 
466
_cairo_gstate_current_line_width (cairo_gstate_t *gstate)
 
467
{
 
468
    return gstate->line_width;
 
469
}
 
470
 
 
471
cairo_status_t
 
472
_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
 
473
{
 
474
    gstate->line_cap = line_cap;
 
475
 
 
476
    return CAIRO_STATUS_SUCCESS;
 
477
}
 
478
 
 
479
cairo_line_cap_t
 
480
_cairo_gstate_current_line_cap (cairo_gstate_t *gstate)
 
481
{
 
482
    return gstate->line_cap;
 
483
}
 
484
 
 
485
cairo_status_t
 
486
_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join)
 
487
{
 
488
    gstate->line_join = line_join;
 
489
 
 
490
    return CAIRO_STATUS_SUCCESS;
 
491
}
 
492
 
 
493
cairo_line_join_t
 
494
_cairo_gstate_current_line_join (cairo_gstate_t *gstate)
 
495
{
 
496
    return gstate->line_join;
 
497
}
 
498
 
 
499
cairo_status_t
 
500
_cairo_gstate_set_dash (cairo_gstate_t *gstate, double *dash, int num_dashes, double offset)
 
501
{
 
502
    if (gstate->dash) {
 
503
        free (gstate->dash);
 
504
        gstate->dash = NULL;
 
505
    }
 
506
    
 
507
    gstate->num_dashes = num_dashes;
 
508
    if (gstate->num_dashes) {
 
509
        gstate->dash = malloc (gstate->num_dashes * sizeof (double));
 
510
        if (gstate->dash == NULL) {
 
511
            gstate->num_dashes = 0;
 
512
            return CAIRO_STATUS_NO_MEMORY;
 
513
        }
 
514
    }
 
515
 
 
516
    memcpy (gstate->dash, dash, gstate->num_dashes * sizeof (double));
 
517
    gstate->dash_offset = offset;
 
518
 
 
519
    return CAIRO_STATUS_SUCCESS;
 
520
}
 
521
 
 
522
cairo_status_t
 
523
_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
 
524
{
 
525
    gstate->miter_limit = limit;
 
526
 
 
527
    return CAIRO_STATUS_SUCCESS;
 
528
}
 
529
 
 
530
double
 
531
_cairo_gstate_current_miter_limit (cairo_gstate_t *gstate)
 
532
{
 
533
    return gstate->miter_limit;
 
534
}
 
535
 
 
536
void
 
537
_cairo_gstate_current_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
 
538
{
 
539
    cairo_matrix_copy (matrix, &gstate->ctm);
 
540
}
 
541
 
 
542
cairo_status_t
 
543
_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
 
544
{
 
545
    cairo_matrix_t tmp;
 
546
 
 
547
    _cairo_matrix_set_translate (&tmp, tx, ty);
 
548
    cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
549
 
 
550
    _cairo_matrix_set_translate (&tmp, -tx, -ty);
 
551
    cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
552
 
 
553
    return CAIRO_STATUS_SUCCESS;
 
554
}
 
555
 
 
556
cairo_status_t
 
557
_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
 
558
{
 
559
    cairo_matrix_t tmp;
 
560
 
 
561
    if (sx == 0 || sy == 0)
 
562
        return CAIRO_STATUS_INVALID_MATRIX;
 
563
 
 
564
    _cairo_matrix_set_scale (&tmp, sx, sy);
 
565
    cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
566
 
 
567
    _cairo_matrix_set_scale (&tmp, 1/sx, 1/sy);
 
568
    cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
569
 
 
570
    return CAIRO_STATUS_SUCCESS;
 
571
}
 
572
 
 
573
cairo_status_t
 
574
_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
 
575
{
 
576
    cairo_matrix_t tmp;
 
577
 
 
578
    _cairo_matrix_set_rotate (&tmp, angle);
 
579
    cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
580
 
 
581
    _cairo_matrix_set_rotate (&tmp, -angle);
 
582
    cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
583
 
 
584
    return CAIRO_STATUS_SUCCESS;
 
585
}
 
586
 
 
587
cairo_status_t
 
588
_cairo_gstate_concat_matrix (cairo_gstate_t *gstate,
 
589
                      cairo_matrix_t *matrix)
 
590
{
 
591
    cairo_matrix_t tmp;
 
592
 
 
593
    cairo_matrix_copy (&tmp, matrix);
 
594
    cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
 
595
 
 
596
    cairo_matrix_invert (&tmp);
 
597
    cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
 
598
 
 
599
    return CAIRO_STATUS_SUCCESS;
 
600
}
 
601
 
 
602
cairo_status_t
 
603
_cairo_gstate_set_matrix (cairo_gstate_t *gstate,
 
604
                   cairo_matrix_t *matrix)
 
605
{
 
606
    cairo_status_t status;
 
607
 
 
608
    cairo_matrix_copy (&gstate->ctm, matrix);
 
609
 
 
610
    cairo_matrix_copy (&gstate->ctm_inverse, matrix);
 
611
    status = cairo_matrix_invert (&gstate->ctm_inverse);
 
612
    if (status)
 
613
        return status;
 
614
 
 
615
    return CAIRO_STATUS_SUCCESS;
 
616
}
 
617
 
 
618
cairo_status_t
 
619
_cairo_gstate_default_matrix (cairo_gstate_t *gstate)
 
620
{
 
621
    int scale = gstate->pixels_per_inch / CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT + 0.5;
 
622
    if (scale == 0)
 
623
        scale = 1;
 
624
 
 
625
    cairo_matrix_set_identity (&gstate->ctm);
 
626
    cairo_matrix_scale (&gstate->ctm, scale, scale);
 
627
    cairo_matrix_copy (&gstate->ctm_inverse, &gstate->ctm);
 
628
    cairo_matrix_invert (&gstate->ctm_inverse);
 
629
 
 
630
    return CAIRO_STATUS_SUCCESS;
 
631
}
 
632
 
 
633
cairo_status_t
 
634
_cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
 
635
{
 
636
    cairo_matrix_set_identity (&gstate->ctm);
 
637
    cairo_matrix_set_identity (&gstate->ctm_inverse);
 
638
 
 
639
    return CAIRO_STATUS_SUCCESS;
 
640
}
 
641
 
 
642
cairo_status_t
 
643
_cairo_gstate_transform_point (cairo_gstate_t *gstate, double *x, double *y)
 
644
{
 
645
    cairo_matrix_transform_point (&gstate->ctm, x, y);
 
646
 
 
647
    return CAIRO_STATUS_SUCCESS;
 
648
}
 
649
 
 
650
cairo_status_t
 
651
_cairo_gstate_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
 
652
{
 
653
    cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
 
654
 
 
655
    return CAIRO_STATUS_SUCCESS;
 
656
}
 
657
 
 
658
cairo_status_t
 
659
_cairo_gstate_inverse_transform_point (cairo_gstate_t *gstate, double *x, double *y)
 
660
{
 
661
    cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
 
662
 
 
663
    return CAIRO_STATUS_SUCCESS;
 
664
}
 
665
 
 
666
cairo_status_t
 
667
_cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, double *dy)
 
668
{
 
669
    cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
 
670
 
 
671
    return CAIRO_STATUS_SUCCESS;
 
672
}
 
673
 
 
674
cairo_status_t
 
675
_cairo_gstate_new_path (cairo_gstate_t *gstate)
 
676
{
 
677
    _cairo_path_fini (&gstate->path);
 
678
 
 
679
    return CAIRO_STATUS_SUCCESS;
 
680
}
 
681
 
 
682
cairo_status_t
 
683
_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y)
 
684
{
 
685
    cairo_point_t point;
 
686
 
 
687
    cairo_matrix_transform_point (&gstate->ctm, &x, &y);
 
688
 
 
689
    point.x = _cairo_fixed_from_double (x);
 
690
    point.y = _cairo_fixed_from_double (y);
 
691
 
 
692
    return _cairo_path_move_to (&gstate->path, &point);
 
693
}
 
694
 
 
695
cairo_status_t
 
696
_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y)
 
697
{
 
698
    cairo_point_t point;
 
699
 
 
700
    cairo_matrix_transform_point (&gstate->ctm, &x, &y);
 
701
 
 
702
    point.x = _cairo_fixed_from_double (x);
 
703
    point.y = _cairo_fixed_from_double (y);
 
704
 
 
705
    return _cairo_path_line_to (&gstate->path, &point);
 
706
}
 
707
 
 
708
cairo_status_t
 
709
_cairo_gstate_curve_to (cairo_gstate_t *gstate,
 
710
                        double x0, double y0,
 
711
                        double x1, double y1,
 
712
                        double x2, double y2)
 
713
{
 
714
    cairo_point_t p0, p1, p2;
 
715
 
 
716
    cairo_matrix_transform_point (&gstate->ctm, &x0, &y0);
 
717
    cairo_matrix_transform_point (&gstate->ctm, &x1, &y1);
 
718
    cairo_matrix_transform_point (&gstate->ctm, &x2, &y2);
 
719
 
 
720
    p0.x = _cairo_fixed_from_double (x0);
 
721
    p0.y = _cairo_fixed_from_double (y0);
 
722
 
 
723
    p1.x = _cairo_fixed_from_double (x1);
 
724
    p1.y = _cairo_fixed_from_double (y1);
 
725
 
 
726
    p2.x = _cairo_fixed_from_double (x2);
 
727
    p2.y = _cairo_fixed_from_double (y2);
 
728
 
 
729
    return _cairo_path_curve_to (&gstate->path, &p0, &p1, &p2);
 
730
}
 
731
 
 
732
/* Spline deviation from the circle in radius would be given by:
 
733
 
 
734
        error = sqrt (x**2 + y**2) - 1
 
735
 
 
736
   A simpler error function to work with is:
 
737
 
 
738
        e = x**2 + y**2 - 1
 
739
 
 
740
   From "Good approximation of circles by curvature-continuous Bezier
 
741
   curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
 
742
   Design 8 (1990) 22-41, we learn:
 
743
 
 
744
        abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
 
745
 
 
746
   and
 
747
        abs (error) =~ 1/2 * e
 
748
 
 
749
   Of course, this error value applies only for the particular spline
 
750
   approximation that is used in _cairo_gstate_arc_segment.
 
751
*/
 
752
static double
 
753
_arc_error_normalized (double angle)
 
754
{
 
755
    return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
 
756
}
 
757
 
 
758
static double
 
759
_arc_max_angle_for_tolerance_normalized (double tolerance)
 
760
{
 
761
    double angle, error;
 
762
    int i;
 
763
 
 
764
    /* Use table lookup to reduce search time in most cases. */
 
765
    struct {
 
766
        double angle;
 
767
        double error;
 
768
    } table[] = {
 
769
        { M_PI / 1.0,   0.0185185185185185036127 },
 
770
        { M_PI / 2.0,   0.000272567143730179811158 },
 
771
        { M_PI / 3.0,   2.38647043651461047433e-05 },
 
772
        { M_PI / 4.0,   4.2455377443222443279e-06 },
 
773
        { M_PI / 5.0,   1.11281001494389081528e-06 },
 
774
        { M_PI / 6.0,   3.72662000942734705475e-07 },
 
775
        { M_PI / 7.0,   1.47783685574284411325e-07 },
 
776
        { M_PI / 8.0,   6.63240432022601149057e-08 },
 
777
        { M_PI / 9.0,   3.2715520137536980553e-08 },
 
778
        { M_PI / 10.0,  1.73863223499021216974e-08 },
 
779
        { M_PI / 11.0,  9.81410988043554039085e-09 },
 
780
    };
 
781
    int table_size = (sizeof (table) / sizeof (table[0]));
 
782
 
 
783
    for (i = 0; i < table_size; i++)
 
784
        if (table[i].error < tolerance)
 
785
            return table[i].angle;
 
786
 
 
787
    ++i;
 
788
    do {
 
789
        angle = M_PI / i++;
 
790
        error = _arc_error_normalized (angle);
 
791
    } while (error > tolerance);
 
792
 
 
793
    return angle;
 
794
}
 
795
 
 
796
static int
 
797
_cairo_gstate_arc_segments_needed (cairo_gstate_t *gstate,
 
798
                                   double angle,
 
799
                                   double radius)
 
800
{
 
801
    double l1, l2, lmax;
 
802
    double max_angle;
 
803
 
 
804
    _cairo_matrix_compute_eigen_values (&gstate->ctm, &l1, &l2);
 
805
 
 
806
    l1 = fabs (l1);
 
807
    l2 = fabs (l2);
 
808
    if (l1 > l2)
 
809
        lmax = l1;
 
810
    else
 
811
        lmax = l2;
 
812
 
 
813
    max_angle = _arc_max_angle_for_tolerance_normalized (gstate->tolerance / (radius * lmax));
 
814
 
 
815
    return (int) ceil (angle / max_angle);
 
816
}
 
817
 
 
818
/* We want to draw a single spline approximating a circular arc radius
 
819
   R from angle A to angle B. Since we want a symmetric spline that
 
820
   matches the endpoints of the arc in position and slope, we know
 
821
   that the spline control points must be:
 
822
 
 
823
        (R * cos(A), R * sin(A))
 
824
        (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
 
825
        (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
 
826
        (R * cos(B), R * sin(B))
 
827
 
 
828
   for some value of h.
 
829
 
 
830
   "Approximation of circular arcs by cubic poynomials", Michael
 
831
   Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
 
832
   various values of h along with error analysis for each.
 
833
 
 
834
   From that paper, a very practical value of h is:
 
835
 
 
836
        h = 4/3 * tan(angle/4)
 
837
 
 
838
   This value does not give the spline with minimal error, but it does
 
839
   provide a very good approximation, (6th-order convergence), and the
 
840
   error expression is quite simple, (see the comment for
 
841
   _arc_error_normalized).
 
842
*/
 
843
static cairo_status_t
 
844
_cairo_gstate_arc_segment (cairo_gstate_t *gstate,
 
845
                           double xc, double yc,
 
846
                           double radius,
 
847
                           double angle_A, double angle_B)
 
848
{
 
849
    cairo_status_t status;
 
850
    double r_sin_A, r_cos_A;
 
851
    double r_sin_B, r_cos_B;
 
852
    double h;
 
853
 
 
854
    r_sin_A = radius * sin (angle_A);
 
855
    r_cos_A = radius * cos (angle_A);
 
856
    r_sin_B = radius * sin (angle_B);
 
857
    r_cos_B = radius * cos (angle_B);
 
858
 
 
859
    h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
 
860
 
 
861
    status = _cairo_gstate_curve_to (gstate,
 
862
                                     xc + r_cos_A - h * r_sin_A, yc + r_sin_A + h * r_cos_A,
 
863
                                     xc + r_cos_B + h * r_sin_B, yc + r_sin_B - h * r_cos_B,
 
864
                                     xc + r_cos_B, yc + r_sin_B);
 
865
    if (status)
 
866
        return status;
 
867
 
 
868
    return CAIRO_STATUS_SUCCESS;
 
869
}
 
870
 
 
871
static cairo_status_t
 
872
_cairo_gstate_arc_dir (cairo_gstate_t *gstate,
 
873
                       double xc, double yc,
 
874
                       double radius,
 
875
                       double angle_min,
 
876
                       double angle_max,
 
877
                       cairo_direction_t dir)
 
878
{
 
879
    cairo_status_t status;
 
880
 
 
881
    while (angle_max - angle_min > 4 * M_PI)
 
882
        angle_max -= 2 * M_PI;
 
883
 
 
884
    /* Recurse if drawing arc larger than pi */
 
885
    if (angle_max - angle_min > M_PI) {
 
886
        /* XXX: Something tells me this block could be condensed. */
 
887
        if (dir == CAIRO_DIRECTION_FORWARD) {
 
888
            status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
 
889
                                            angle_min, angle_min + M_PI, dir);
 
890
            if (status)
 
891
                return status;
 
892
            
 
893
            status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
 
894
                                            angle_min + M_PI, angle_max, dir);
 
895
            if (status)
 
896
                return status;
 
897
        } else {
 
898
            status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
 
899
                                            angle_min + M_PI, angle_max, dir);
 
900
            if (status)
 
901
                return status;
 
902
 
 
903
            status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
 
904
                                            angle_min, angle_min + M_PI, dir);
 
905
            if (status)
 
906
                return status;
 
907
        }
 
908
    } else {
 
909
        int i, segments;
 
910
        double angle, angle_step;
 
911
 
 
912
        segments = _cairo_gstate_arc_segments_needed (gstate,
 
913
                                                      angle_max - angle_min,
 
914
                                                      radius);
 
915
        angle_step = (angle_max - angle_min) / (double) segments;
 
916
 
 
917
        if (dir == CAIRO_DIRECTION_FORWARD) {
 
918
            angle = angle_min;
 
919
        } else {
 
920
            angle = angle_max;
 
921
            angle_step = - angle_step;
 
922
        }
 
923
 
 
924
        for (i = 0; i < segments; i++, angle += angle_step) {
 
925
            _cairo_gstate_arc_segment (gstate,
 
926
                                       xc, yc,
 
927
                                       radius,
 
928
                                       angle,
 
929
                                       angle + angle_step);
 
930
        }
 
931
        
 
932
    }
 
933
 
 
934
    return CAIRO_STATUS_SUCCESS;
 
935
}
 
936
 
 
937
cairo_status_t
 
938
_cairo_gstate_arc (cairo_gstate_t *gstate,
 
939
                   double xc, double yc,
 
940
                   double radius,
 
941
                   double angle1, double angle2)
 
942
{
 
943
    cairo_status_t status;
 
944
 
 
945
    if (radius <= 0.0)
 
946
        return CAIRO_STATUS_SUCCESS;
 
947
 
 
948
    while (angle2 < angle1)
 
949
        angle2 += 2 * M_PI;
 
950
 
 
951
    status = _cairo_gstate_line_to (gstate,
 
952
                                    xc + radius * cos (angle1),
 
953
                                    yc + radius * sin (angle1));
 
954
    if (status)
 
955
        return status;
 
956
 
 
957
    status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
 
958
                                    angle1, angle2, CAIRO_DIRECTION_FORWARD);
 
959
    if (status)
 
960
        return status;
 
961
 
 
962
    return CAIRO_STATUS_SUCCESS;
 
963
}
 
964
 
 
965
cairo_status_t
 
966
_cairo_gstate_arc_negative (cairo_gstate_t *gstate,
 
967
                            double xc, double yc,
 
968
                            double radius,
 
969
                            double angle1, double angle2)
 
970
{
 
971
    cairo_status_t status;
 
972
 
 
973
    if (radius <= 0.0)
 
974
        return CAIRO_STATUS_SUCCESS;
 
975
 
 
976
    while (angle2 > angle1)
 
977
        angle2 -= 2 * M_PI;
 
978
 
 
979
    status = _cairo_gstate_line_to (gstate,
 
980
                                    xc + radius * cos (angle1),
 
981
                                    yc + radius * sin (angle1));
 
982
    if (status)
 
983
        return status;
 
984
 
 
985
    status = _cairo_gstate_arc_dir (gstate, xc, yc, radius,
 
986
                                    angle2, angle1, CAIRO_DIRECTION_REVERSE);
 
987
    if (status)
 
988
        return status;
 
989
 
 
990
    return CAIRO_STATUS_SUCCESS;
 
991
}
 
992
 
 
993
/* XXX: NYI
 
994
cairo_status_t
 
995
_cairo_gstate_arc_to (cairo_gstate_t *gstate,
 
996
                      double x1, double y1,
 
997
                      double x2, double y2,
 
998
                      double radius)
 
999
{
 
1000
 
 
1001
}
 
1002
*/
 
1003
 
 
1004
cairo_status_t
 
1005
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
 
1006
{
 
1007
    cairo_distance_t distance;
 
1008
 
 
1009
    cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
 
1010
 
 
1011
    distance.dx = _cairo_fixed_from_double (dx);
 
1012
    distance.dy = _cairo_fixed_from_double (dy);
 
1013
 
 
1014
    return _cairo_path_rel_move_to (&gstate->path, &distance);
 
1015
}
 
1016
 
 
1017
cairo_status_t
 
1018
_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy)
 
1019
{
 
1020
    cairo_distance_t distance;
 
1021
 
 
1022
    cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
 
1023
 
 
1024
    distance.dx = _cairo_fixed_from_double (dx);
 
1025
    distance.dy = _cairo_fixed_from_double (dy);
 
1026
 
 
1027
    return _cairo_path_rel_line_to (&gstate->path, &distance);
 
1028
}
 
1029
 
 
1030
cairo_status_t
 
1031
_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
 
1032
                            double dx0, double dy0,
 
1033
                            double dx1, double dy1,
 
1034
                            double dx2, double dy2)
 
1035
{
 
1036
    cairo_distance_t distance[3];
 
1037
 
 
1038
    cairo_matrix_transform_distance (&gstate->ctm, &dx0, &dy0);
 
1039
    cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
 
1040
    cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
 
1041
 
 
1042
    distance[0].dx = _cairo_fixed_from_double (dx0);
 
1043
    distance[0].dy = _cairo_fixed_from_double (dy0);
 
1044
 
 
1045
    distance[1].dx = _cairo_fixed_from_double (dx1);
 
1046
    distance[1].dy = _cairo_fixed_from_double (dy1);
 
1047
 
 
1048
    distance[2].dx = _cairo_fixed_from_double (dx2);
 
1049
    distance[2].dy = _cairo_fixed_from_double (dy2);
 
1050
 
 
1051
    return _cairo_path_rel_curve_to (&gstate->path,
 
1052
                                     &distance[0],
 
1053
                                     &distance[1],
 
1054
                                     &distance[2]);
 
1055
}
 
1056
 
 
1057
/* XXX: NYI 
 
1058
cairo_status_t
 
1059
_cairo_gstate_stroke_path (cairo_gstate_t *gstate)
 
1060
{
 
1061
    cairo_status_t status;
 
1062
 
 
1063
    _cairo_pen_init (&gstate);
 
1064
    return CAIRO_STATUS_SUCCESS;
 
1065
}
 
1066
*/
 
1067
 
 
1068
cairo_status_t
 
1069
_cairo_gstate_close_path (cairo_gstate_t *gstate)
 
1070
{
 
1071
    return _cairo_path_close_path (&gstate->path);
 
1072
}
 
1073
 
 
1074
cairo_status_t
 
1075
_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_ret)
 
1076
{
 
1077
    cairo_status_t status;
 
1078
    cairo_point_t point;
 
1079
    double x, y;
 
1080
 
 
1081
    status = _cairo_path_current_point (&gstate->path, &point);
 
1082
    if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
 
1083
        x = 0.0;
 
1084
        y = 0.0;
 
1085
    } else {
 
1086
        x = _cairo_fixed_to_double (point.x);
 
1087
        y = _cairo_fixed_to_double (point.y);
 
1088
        cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
 
1089
    }
 
1090
 
 
1091
    *x_ret = x;
 
1092
    *y_ret = y;
 
1093
 
 
1094
    return CAIRO_STATUS_SUCCESS;
 
1095
}
 
1096
 
 
1097
typedef struct gstate_path_interpreter {
 
1098
    cairo_matrix_t              ctm_inverse;
 
1099
    double                      tolerance;
 
1100
    cairo_point_t               current_point;
 
1101
 
 
1102
    cairo_move_to_func_t        *move_to;
 
1103
    cairo_line_to_func_t        *line_to;
 
1104
    cairo_curve_to_func_t       *curve_to;
 
1105
    cairo_close_path_func_t     *close_path;
 
1106
 
 
1107
    void                        *closure;
 
1108
} gpi_t;
 
1109
 
 
1110
static cairo_status_t
 
1111
_gpi_move_to (void *closure, cairo_point_t *point)
 
1112
{
 
1113
    gpi_t *gpi = closure;
 
1114
    double x, y;
 
1115
 
 
1116
    x = _cairo_fixed_to_double (point->x);
 
1117
    y = _cairo_fixed_to_double (point->y);
 
1118
 
 
1119
    cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
 
1120
 
 
1121
    gpi->move_to (gpi->closure, x, y);
 
1122
    gpi->current_point = *point;
 
1123
 
 
1124
    return CAIRO_STATUS_SUCCESS;
 
1125
}
 
1126
 
 
1127
static cairo_status_t
 
1128
_gpi_line_to (void *closure, cairo_point_t *point)
 
1129
{
 
1130
    gpi_t *gpi = closure;
 
1131
    double x, y;
 
1132
 
 
1133
    x = _cairo_fixed_to_double (point->x);
 
1134
    y = _cairo_fixed_to_double (point->y);
 
1135
 
 
1136
    cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
 
1137
 
 
1138
    gpi->line_to (gpi->closure, x, y);
 
1139
    gpi->current_point = *point;
 
1140
 
 
1141
    return CAIRO_STATUS_SUCCESS;
 
1142
}
 
1143
 
 
1144
static cairo_status_t
 
1145
_gpi_curve_to (void *closure,
 
1146
               cairo_point_t *p1,
 
1147
               cairo_point_t *p2,
 
1148
               cairo_point_t *p3)
 
1149
{
 
1150
    gpi_t *gpi = closure;
 
1151
    cairo_status_t status;
 
1152
    cairo_spline_t spline;
 
1153
    double x1, y1, x2, y2, x3, y3;
 
1154
 
 
1155
    if (gpi->curve_to) {
 
1156
        x1 = _cairo_fixed_to_double (p1->x);
 
1157
        y1 = _cairo_fixed_to_double (p1->y);
 
1158
        cairo_matrix_transform_point (&gpi->ctm_inverse, &x1, &y1);
 
1159
 
 
1160
        x2 = _cairo_fixed_to_double (p2->x);
 
1161
        y2 = _cairo_fixed_to_double (p2->y);
 
1162
        cairo_matrix_transform_point (&gpi->ctm_inverse, &x2, &y2);
 
1163
 
 
1164
        x3 = _cairo_fixed_to_double (p3->x);
 
1165
        y3 = _cairo_fixed_to_double (p3->y);
 
1166
        cairo_matrix_transform_point (&gpi->ctm_inverse, &x3, &y3);
 
1167
 
 
1168
        gpi->curve_to (gpi->closure, x1, y1, x2, y2, x3, y3);
 
1169
    } else {
 
1170
        cairo_point_t *p0 = &gpi->current_point;
 
1171
        int i;
 
1172
        double x, y;
 
1173
 
 
1174
        status = _cairo_spline_init (&spline, p0, p1, p2, p3);
 
1175
        if (status == CAIRO_INT_STATUS_DEGENERATE)
 
1176
            return CAIRO_STATUS_SUCCESS;
 
1177
 
 
1178
        status = _cairo_spline_decompose (&spline, gpi->tolerance);
 
1179
        if (status)
 
1180
            return status;
 
1181
 
 
1182
        for (i=1; i < spline.num_points; i++) {
 
1183
            x = _cairo_fixed_to_double (spline.points[i].x);
 
1184
            y = _cairo_fixed_to_double (spline.points[i].y);
 
1185
 
 
1186
            cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
 
1187
 
 
1188
            gpi->line_to (gpi->closure, x, y);
 
1189
        }
 
1190
    }
 
1191
 
 
1192
    gpi->current_point = *p3;
 
1193
 
 
1194
    return CAIRO_STATUS_SUCCESS;
 
1195
}
 
1196
 
 
1197
static cairo_status_t
 
1198
_gpi_close_path (void *closure)
 
1199
{
 
1200
    gpi_t *gpi = closure;
 
1201
 
 
1202
    gpi->close_path (gpi->closure);
 
1203
 
 
1204
    gpi->current_point.x = 0;
 
1205
    gpi->current_point.y = 0;
 
1206
 
 
1207
    return CAIRO_STATUS_SUCCESS;
 
1208
}
 
1209
 
 
1210
/* It's OK for curve_path to be NULL. In that case, all curves in the
 
1211
   path will be decomposed into one or more calls to the line_to
 
1212
   function, (according to the current tolerance). */
 
1213
cairo_status_t
 
1214
_cairo_gstate_interpret_path (cairo_gstate_t            *gstate,
 
1215
                              cairo_move_to_func_t      *move_to,
 
1216
                              cairo_line_to_func_t      *line_to,
 
1217
                              cairo_curve_to_func_t     *curve_to,
 
1218
                              cairo_close_path_func_t   *close_path,
 
1219
                              void                      *closure)
 
1220
{
 
1221
    cairo_path_t path;
 
1222
    gpi_t gpi;
 
1223
 
 
1224
    /* Anything we want from gstate must be copied. We must not retain
 
1225
       pointers into gstate. */
 
1226
    _cairo_path_init_copy (&path, &gstate->path);
 
1227
 
 
1228
    cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse);
 
1229
    gpi.tolerance = gstate->tolerance;
 
1230
 
 
1231
    gpi.move_to = move_to;
 
1232
    gpi.line_to = line_to;
 
1233
    gpi.curve_to = curve_to;
 
1234
    gpi.close_path = close_path;
 
1235
    gpi.closure = closure;
 
1236
 
 
1237
    gpi.current_point.x = 0;
 
1238
    gpi.current_point.y = 0;
 
1239
 
 
1240
    return _cairo_path_interpret (&path,
 
1241
                                  CAIRO_DIRECTION_FORWARD,
 
1242
                                  _gpi_move_to,
 
1243
                                  _gpi_line_to,
 
1244
                                  _gpi_curve_to,
 
1245
                                  _gpi_close_path,
 
1246
                                  &gpi);
 
1247
}
 
1248
 
 
1249
/* This function modifies the pattern and the state of the pattern surface it
 
1250
   may contain. The pattern surface will be restored to its orignal state
 
1251
   when the pattern is destroyed. The appropriate way is to pass a copy of
 
1252
   the original pattern to this function just before the pattern should be
 
1253
   used and destroy the copy when done. */
 
1254
static cairo_status_t
 
1255
_cairo_gstate_create_pattern (cairo_gstate_t *gstate,
 
1256
                              cairo_pattern_t *pattern,
 
1257
                              cairo_box_t *extents)
 
1258
{
 
1259
    cairo_int_status_t status;
 
1260
  
 
1261
    if (gstate->surface == NULL) {
 
1262
        _cairo_pattern_fini (pattern);
 
1263
        return CAIRO_STATUS_NO_TARGET_SURFACE;
 
1264
    }
 
1265
 
 
1266
    if (pattern->type == CAIRO_PATTERN_LINEAR ||
 
1267
        pattern->type == CAIRO_PATTERN_RADIAL) {
 
1268
        if (pattern->n_stops < 2) {
 
1269
            pattern->type = CAIRO_PATTERN_SOLID;
 
1270
      
 
1271
            if (pattern->n_stops)
 
1272
                pattern->color = pattern->stops->color;
 
1273
        }
 
1274
    }
 
1275
  
 
1276
    _cairo_pattern_set_alpha (pattern, gstate->alpha);
 
1277
    _cairo_pattern_transform (pattern, &gstate->ctm_inverse);
 
1278
 
 
1279
    _cairo_pattern_set_source_offset (pattern,
 
1280
                                      gstate->pattern_offset.x,
 
1281
                                      gstate->pattern_offset.y);
 
1282
 
 
1283
    status = _cairo_surface_create_pattern (gstate->surface, pattern, extents);
 
1284
    if (status) {
 
1285
        _cairo_pattern_fini (pattern);
 
1286
        return status;
 
1287
    }
 
1288
 
 
1289
    if (pattern->type == CAIRO_PATTERN_SURFACE)
 
1290
        _cairo_pattern_prepare_surface (pattern);
 
1291
    
 
1292
    return CAIRO_STATUS_SUCCESS;
 
1293
}
 
1294
 
 
1295
cairo_status_t
 
1296
_cairo_gstate_stroke (cairo_gstate_t *gstate)
 
1297
{
 
1298
    cairo_status_t status;
 
1299
    cairo_traps_t traps;
 
1300
 
 
1301
    if (gstate->line_width <= 0.0)
 
1302
        return CAIRO_STATUS_SUCCESS;
 
1303
 
 
1304
    _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
 
1305
 
 
1306
    _cairo_traps_init (&traps);
 
1307
 
 
1308
    status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
 
1309
    if (status) {
 
1310
        _cairo_traps_fini (&traps);
 
1311
        return status;
 
1312
    }
 
1313
 
 
1314
    _cairo_gstate_clip_and_composite_trapezoids (gstate,
 
1315
                                                 gstate->pattern,
 
1316
                                                 gstate->operator,
 
1317
                                                 gstate->surface,
 
1318
                                                 &traps);
 
1319
 
 
1320
    _cairo_traps_fini (&traps);
 
1321
 
 
1322
    _cairo_gstate_new_path (gstate);
 
1323
 
 
1324
    return CAIRO_STATUS_SUCCESS;
 
1325
}
 
1326
 
 
1327
cairo_status_t
 
1328
_cairo_gstate_in_stroke (cairo_gstate_t *gstate,
 
1329
                         double         x,
 
1330
                         double         y,
 
1331
                         int            *inside_ret)
 
1332
{
 
1333
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
1334
    cairo_traps_t traps;
 
1335
 
 
1336
    cairo_matrix_transform_point (&gstate->ctm, &x, &y);
 
1337
 
 
1338
    _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
 
1339
 
 
1340
    _cairo_traps_init (&traps);
 
1341
 
 
1342
    status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
 
1343
    if (status)
 
1344
        goto BAIL;
 
1345
 
 
1346
    *inside_ret = _cairo_traps_contain (&traps, x, y);
 
1347
 
 
1348
BAIL:
 
1349
    _cairo_traps_fini (&traps);
 
1350
 
 
1351
    return status;
 
1352
}
 
1353
 
 
1354
/* Warning: This call modifies the coordinates of traps */
 
1355
static cairo_status_t
 
1356
_cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
 
1357
                                             cairo_pattern_t *src,
 
1358
                                             cairo_operator_t operator,
 
1359
                                             cairo_surface_t *dst,
 
1360
                                             cairo_traps_t *traps)
 
1361
{
 
1362
    cairo_status_t status;
 
1363
    cairo_pattern_t pattern;
 
1364
    cairo_box_t extents;
 
1365
 
 
1366
    if (traps->num_traps == 0)
 
1367
        return CAIRO_STATUS_SUCCESS;
 
1368
 
 
1369
    if (gstate->clip.surface) {
 
1370
        cairo_fixed_t xoff, yoff;
 
1371
        cairo_trapezoid_t *t;
 
1372
        int i;
 
1373
        cairo_surface_t *intermediate;
 
1374
        cairo_color_t empty_color;
 
1375
 
 
1376
        _cairo_color_init (&empty_color);
 
1377
        _cairo_color_set_alpha (&empty_color, 0.);
 
1378
        intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
 
1379
                                                            CAIRO_FORMAT_A8,
 
1380
                                                            gstate->clip.width,
 
1381
                                                            gstate->clip.height,
 
1382
                                &empty_color);    
 
1383
        if (intermediate == NULL) {
 
1384
            status = CAIRO_STATUS_NO_MEMORY;
 
1385
            goto BAIL0;
 
1386
        }
 
1387
 
 
1388
        /* Ugh. The cairo_composite/(Render) interface doesn't allow
 
1389
           an offset for the trapezoids. Need to manually shift all
 
1390
           the coordinates to align with the offset origin of the clip
 
1391
           surface. */
 
1392
        xoff = _cairo_fixed_from_double (gstate->clip.x);
 
1393
        yoff = _cairo_fixed_from_double (gstate->clip.y);
 
1394
        for (i=0, t=traps->traps; i < traps->num_traps; i++, t++) {
 
1395
            t->top -= yoff;
 
1396
            t->bottom -= yoff;
 
1397
            t->left.p1.x -= xoff;
 
1398
            t->left.p1.y -= yoff;
 
1399
            t->left.p2.x -= xoff;
 
1400
            t->left.p2.y -= yoff;
 
1401
            t->right.p1.x -= xoff;
 
1402
            t->right.p1.y -= yoff;
 
1403
            t->right.p2.x -= xoff;
 
1404
            t->right.p2.y -= yoff;
 
1405
        }
 
1406
 
 
1407
        _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
 
1408
        _cairo_pattern_set_alpha (&pattern, 1.0);
 
1409
 
 
1410
        _cairo_traps_extents (traps, &extents);
 
1411
        status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
 
1412
        if (status)
 
1413
            goto BAIL1;
 
1414
 
 
1415
        status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD,
 
1416
                                                      pattern.source, intermediate,
 
1417
                                                      0, 0,
 
1418
                                                      traps->traps,
 
1419
                                                      traps->num_traps);
 
1420
        if (status)
 
1421
            goto BAIL2;
 
1422
 
 
1423
        status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
 
1424
                                           gstate->clip.surface,
 
1425
                                           NULL,
 
1426
                                           intermediate,
 
1427
                                           0, 0, 0, 0, 0, 0,
 
1428
                                           gstate->clip.width, gstate->clip.height);
 
1429
        if (status)
 
1430
            goto BAIL2;
 
1431
    
 
1432
        _cairo_pattern_fini (&pattern);
 
1433
    
 
1434
        _cairo_pattern_init_copy (&pattern, src);
 
1435
    
 
1436
        extents.p1.x = _cairo_fixed_from_int (gstate->clip.x);
 
1437
        extents.p1.y = _cairo_fixed_from_int (gstate->clip.y);
 
1438
        extents.p2.x =
 
1439
            _cairo_fixed_from_int (gstate->clip.x + gstate->clip.width);
 
1440
        extents.p2.y =
 
1441
            _cairo_fixed_from_int (gstate->clip.y + gstate->clip.height);
 
1442
        status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
 
1443
        if (status)
 
1444
            goto BAIL2;
 
1445
 
 
1446
        status = _cairo_surface_composite (operator,
 
1447
                                           pattern.source, intermediate, dst,
 
1448
                                           0, 0,
 
1449
                                           0, 0,
 
1450
                                           gstate->clip.x,
 
1451
                                           gstate->clip.y,
 
1452
                                           gstate->clip.width,
 
1453
                                           gstate->clip.height);
 
1454
        
 
1455
    BAIL2:
 
1456
        cairo_surface_destroy (intermediate);
 
1457
    BAIL1:
 
1458
        _cairo_pattern_fini (&pattern);
 
1459
    BAIL0:
 
1460
 
 
1461
        if (status)
 
1462
            return status;
 
1463
        
 
1464
    } else {
 
1465
        int xoff, yoff;
 
1466
 
 
1467
        if (traps->traps[0].left.p1.y < traps->traps[0].left.p2.y) {
 
1468
            xoff = _cairo_fixed_to_double (traps->traps[0].left.p1.x);
 
1469
            yoff = _cairo_fixed_to_double (traps->traps[0].left.p1.y);
 
1470
        } else {
 
1471
            xoff = _cairo_fixed_to_double (traps->traps[0].left.p2.x);
 
1472
            yoff = _cairo_fixed_to_double (traps->traps[0].left.p2.y);
 
1473
        }
 
1474
 
 
1475
        _cairo_pattern_init_copy (&pattern, src);
 
1476
        
 
1477
        _cairo_traps_extents (traps, &extents);
 
1478
        status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
 
1479
        if (status)
 
1480
            return status;
 
1481
 
 
1482
        status = _cairo_surface_composite_trapezoids (gstate->operator,
 
1483
                                                      pattern.source, dst,
 
1484
                                                      xoff - pattern.source_offset.x,
 
1485
                                                      yoff - pattern.source_offset.y,
 
1486
                                                      traps->traps,
 
1487
                                                      traps->num_traps);
 
1488
 
 
1489
        _cairo_pattern_fini (&pattern);
 
1490
    
 
1491
        if (status)
 
1492
            return status;
 
1493
    }
 
1494
    
 
1495
    return CAIRO_STATUS_SUCCESS;
 
1496
}
 
1497
 
 
1498
cairo_status_t
 
1499
_cairo_gstate_fill (cairo_gstate_t *gstate)
 
1500
{
 
1501
    cairo_status_t status;
 
1502
    cairo_traps_t traps;
 
1503
 
 
1504
    _cairo_traps_init (&traps);
 
1505
 
 
1506
    status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
 
1507
    if (status) {
 
1508
        _cairo_traps_fini (&traps);
 
1509
        return status;
 
1510
    }
 
1511
 
 
1512
    _cairo_gstate_clip_and_composite_trapezoids (gstate,
 
1513
                                                 gstate->pattern,
 
1514
                                                 gstate->operator,
 
1515
                                                 gstate->surface,
 
1516
                                                 &traps);
 
1517
 
 
1518
    _cairo_traps_fini (&traps);
 
1519
 
 
1520
    _cairo_gstate_new_path (gstate);
 
1521
 
 
1522
    return CAIRO_STATUS_SUCCESS;
 
1523
}
 
1524
 
 
1525
cairo_status_t
 
1526
_cairo_gstate_in_fill (cairo_gstate_t   *gstate,
 
1527
                       double           x,
 
1528
                       double           y,
 
1529
                       int              *inside_ret)
 
1530
{
 
1531
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
1532
    cairo_traps_t traps;
 
1533
 
 
1534
    cairo_matrix_transform_point (&gstate->ctm, &x, &y);
 
1535
 
 
1536
    _cairo_traps_init (&traps);
 
1537
 
 
1538
    status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
 
1539
    if (status)
 
1540
        goto BAIL;
 
1541
 
 
1542
    *inside_ret = _cairo_traps_contain (&traps, x, y);
 
1543
    
 
1544
BAIL:
 
1545
    _cairo_traps_fini (&traps);
 
1546
 
 
1547
    return status;
 
1548
}
 
1549
 
 
1550
cairo_status_t
 
1551
_cairo_gstate_copy_page (cairo_gstate_t *gstate)
 
1552
{
 
1553
    if (gstate->surface == NULL)
 
1554
        return CAIRO_STATUS_NO_TARGET_SURFACE;
 
1555
 
 
1556
    return _cairo_surface_copy_page (gstate->surface);
 
1557
}
 
1558
 
 
1559
cairo_status_t
 
1560
_cairo_gstate_show_page (cairo_gstate_t *gstate)
 
1561
{
 
1562
    if (gstate->surface == NULL)
 
1563
        return CAIRO_STATUS_NO_TARGET_SURFACE;
 
1564
 
 
1565
    return _cairo_surface_show_page (gstate->surface);
 
1566
}
 
1567
 
 
1568
cairo_status_t
 
1569
_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
 
1570
                              double *x1, double *y1,
 
1571
                              double *x2, double *y2)
 
1572
{
 
1573
    cairo_status_t status;
 
1574
    cairo_traps_t traps;
 
1575
    cairo_box_t extents;
 
1576
  
 
1577
    _cairo_traps_init (&traps);
 
1578
  
 
1579
    status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
 
1580
    if (status)
 
1581
        goto BAIL;
 
1582
 
 
1583
    _cairo_traps_extents (&traps, &extents);
 
1584
 
 
1585
    *x1 = _cairo_fixed_to_double (extents.p1.x);
 
1586
    *y1 = _cairo_fixed_to_double (extents.p1.y);
 
1587
    *x2 = _cairo_fixed_to_double (extents.p2.x);
 
1588
    *y2 = _cairo_fixed_to_double (extents.p2.y);
 
1589
 
 
1590
    cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
 
1591
    cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
 
1592
  
 
1593
BAIL:
 
1594
    _cairo_traps_fini (&traps);
 
1595
  
 
1596
    return status;
 
1597
}
 
1598
 
 
1599
cairo_status_t
 
1600
_cairo_gstate_fill_extents (cairo_gstate_t *gstate,
 
1601
                            double *x1, double *y1,
 
1602
                            double *x2, double *y2)
 
1603
{
 
1604
    cairo_status_t status;
 
1605
    cairo_traps_t traps;
 
1606
    cairo_box_t extents;
 
1607
  
 
1608
    _cairo_traps_init (&traps);
 
1609
  
 
1610
    status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
 
1611
    if (status)
 
1612
        goto BAIL;
 
1613
  
 
1614
    _cairo_traps_extents (&traps, &extents);
 
1615
 
 
1616
    *x1 = _cairo_fixed_to_double (extents.p1.x);
 
1617
    *y1 = _cairo_fixed_to_double (extents.p1.y);
 
1618
    *x2 = _cairo_fixed_to_double (extents.p2.x);
 
1619
    *y2 = _cairo_fixed_to_double (extents.p2.y);
 
1620
 
 
1621
    cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1);
 
1622
    cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2);
 
1623
  
 
1624
BAIL:
 
1625
    _cairo_traps_fini (&traps);
 
1626
  
 
1627
    return status;
 
1628
}
 
1629
 
 
1630
cairo_status_t
 
1631
_cairo_gstate_init_clip (cairo_gstate_t *gstate)
 
1632
{
 
1633
    /* destroy any existing clip-region artifacts */
 
1634
    if (gstate->clip.surface)
 
1635
        cairo_surface_destroy (gstate->clip.surface);
 
1636
    gstate->clip.surface = NULL;
 
1637
 
 
1638
    if (gstate->clip.region)
 
1639
        pixman_region_destroy (gstate->clip.region);
 
1640
    gstate->clip.region = NULL;
 
1641
 
 
1642
    /* reset the surface's clip to the whole surface */
 
1643
    _cairo_surface_set_clip_region (gstate->surface, 
 
1644
                                    gstate->clip.region);
 
1645
 
 
1646
    return CAIRO_STATUS_SUCCESS;
 
1647
}
 
1648
 
 
1649
static int
 
1650
extract_transformed_rectangle(cairo_matrix_t *mat,
 
1651
                              cairo_traps_t *tr,
 
1652
                              pixman_box16_t *box)
 
1653
{
 
1654
#define CAIRO_FIXED_IS_INTEGER(x) (((x) & 0xFFFF) == 0)
 
1655
#define CAIRO_FIXED_INTEGER_PART(x) ((x) >> 16)
 
1656
 
 
1657
    double a, b, c, d, tx, ty;
 
1658
    cairo_status_t st;
 
1659
 
 
1660
    st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);    
 
1661
    if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
 
1662
        return 0;
 
1663
 
 
1664
    if (tr->num_traps == 1 
 
1665
        && tr->traps[0].left.p1.x == tr->traps[0].left.p2.x
 
1666
        && tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
 
1667
        && tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
 
1668
        && tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
 
1669
        && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.x)
 
1670
        && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.y)
 
1671
        && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.x)
 
1672
        && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.y)
 
1673
        && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.x)
 
1674
        && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.y)
 
1675
        && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.x)
 
1676
        && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.y)) {
 
1677
 
 
1678
        box->x1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.x);
 
1679
        box->x2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].right.p1.x);
 
1680
        box->y1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.y);
 
1681
        box->y2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p2.y);
 
1682
        return 1;
 
1683
    }
 
1684
    return 0;
 
1685
 
 
1686
#undef CAIRO_FIXED_IS_INTEGER
 
1687
#undef CAIRO_FIXED_INTEGER_PART
 
1688
}
 
1689
 
 
1690
cairo_status_t
 
1691
_cairo_gstate_clip (cairo_gstate_t *gstate)
 
1692
{
 
1693
    cairo_status_t status;
 
1694
    cairo_pattern_t pattern;
 
1695
    cairo_traps_t traps;
 
1696
    cairo_color_t white_color;
 
1697
    pixman_box16_t box;
 
1698
 
 
1699
    /* Fill the clip region as traps. */
 
1700
 
 
1701
    _cairo_traps_init (&traps);
 
1702
    status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
 
1703
    if (status) {
 
1704
        _cairo_traps_fini (&traps);
 
1705
        return status;
 
1706
    }
 
1707
 
 
1708
    /* Check to see if we can represent these traps as a PixRegion. */
 
1709
 
 
1710
    if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) {
 
1711
 
 
1712
        pixman_region16_t *rect = NULL;
 
1713
        pixman_region16_t *intersection = NULL;
 
1714
 
 
1715
        status = CAIRO_STATUS_SUCCESS;
 
1716
        rect = pixman_region_create_simple (&box);
 
1717
        
 
1718
        if (rect == NULL) {
 
1719
            status = CAIRO_STATUS_NO_MEMORY;
 
1720
 
 
1721
        } else {
 
1722
            
 
1723
            if (gstate->clip.region == NULL) {
 
1724
                gstate->clip.region = rect;             
 
1725
            } else {
 
1726
                intersection = pixman_region_create();
 
1727
                if (pixman_region_intersect (intersection, 
 
1728
                                             gstate->clip.region, rect)
 
1729
                    == PIXMAN_REGION_STATUS_SUCCESS) {
 
1730
                    pixman_region_destroy (gstate->clip.region);
 
1731
                    gstate->clip.region = intersection;
 
1732
                } else {                
 
1733
                    status = CAIRO_STATUS_NO_MEMORY;
 
1734
                }
 
1735
                pixman_region_destroy (rect);
 
1736
            }
 
1737
            
 
1738
            if (!status)
 
1739
                status = _cairo_surface_set_clip_region (gstate->surface, 
 
1740
                                                         gstate->clip.region);
 
1741
        }
 
1742
        
 
1743
        if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
 
1744
            _cairo_traps_fini (&traps);
 
1745
            return status;
 
1746
        }
 
1747
    }
 
1748
 
 
1749
    /* Otherwise represent the clip as a mask surface. */
 
1750
 
 
1751
    _cairo_color_init (&white_color);
 
1752
 
 
1753
    if (gstate->clip.surface == NULL) {
 
1754
        double x1, y1, x2, y2;
 
1755
      _cairo_path_bounds (&gstate->path,
 
1756
                          &x1, &y1, &x2, &y2);
 
1757
      gstate->clip.x = floor (x1);
 
1758
      gstate->clip.y = floor (y1);
 
1759
      gstate->clip.width = ceil (x2 - gstate->clip.x);
 
1760
      gstate->clip.height = ceil (y2 - gstate->clip.y);
 
1761
      gstate->clip.surface =
 
1762
        _cairo_surface_create_similar_solid (gstate->surface,
 
1763
                                             CAIRO_FORMAT_A8,
 
1764
                                             gstate->clip.width,
 
1765
                                             gstate->clip.height,
 
1766
                                             &white_color);
 
1767
      if (gstate->clip.surface == NULL)
 
1768
            return CAIRO_STATUS_NO_MEMORY;
 
1769
    }
 
1770
 
 
1771
    _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0);
 
1772
    _cairo_pattern_set_alpha (&pattern, 1.0);
 
1773
    
 
1774
    _cairo_gstate_clip_and_composite_trapezoids (gstate,
 
1775
                                                 &pattern,
 
1776
                                                 CAIRO_OPERATOR_IN,
 
1777
                                                 gstate->clip.surface,
 
1778
                                                 &traps);
 
1779
    
 
1780
    _cairo_pattern_fini (&pattern);
 
1781
    
 
1782
    _cairo_traps_fini (&traps);
 
1783
 
 
1784
    return status;
 
1785
}
 
1786
 
 
1787
cairo_status_t
 
1788
_cairo_gstate_show_surface (cairo_gstate_t      *gstate,
 
1789
                            cairo_surface_t     *surface,
 
1790
                            int                 width,
 
1791
                            int                 height)
 
1792
{
 
1793
    cairo_status_t status;
 
1794
    cairo_matrix_t user_to_image, image_to_user;
 
1795
    cairo_matrix_t image_to_device, device_to_image;
 
1796
    double device_x, device_y;
 
1797
    double device_width, device_height;
 
1798
    cairo_pattern_t pattern;
 
1799
    cairo_box_t extents;
 
1800
 
 
1801
    cairo_surface_get_matrix (surface, &user_to_image);
 
1802
    cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image);
 
1803
    cairo_surface_set_matrix (surface, &device_to_image);
 
1804
 
 
1805
    image_to_user = user_to_image;
 
1806
    cairo_matrix_invert (&image_to_user);
 
1807
    cairo_matrix_multiply (&image_to_device, &image_to_user, &gstate->ctm);
 
1808
 
 
1809
    _cairo_gstate_current_point (gstate, &device_x, &device_y);
 
1810
    device_width = width;
 
1811
    device_height = height;
 
1812
    _cairo_matrix_transform_bounding_box (&image_to_device,
 
1813
                                          &device_x, &device_y,
 
1814
                                          &device_width, &device_height);
 
1815
 
 
1816
    _cairo_pattern_init (&pattern);
 
1817
 
 
1818
    if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
 
1819
        (gstate->alpha != 1.0)) {
 
1820
        /* I'm allowing any type of pattern for the mask right now.
 
1821
           Maybe this is bad. Will allow for some cool effects though. */
 
1822
        _cairo_pattern_init_copy (&pattern, gstate->pattern);
 
1823
        extents.p1.x = _cairo_fixed_from_double (device_x);
 
1824
        extents.p1.y = _cairo_fixed_from_double (device_y);
 
1825
        extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
 
1826
        extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
 
1827
        status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
 
1828
        if (status)
 
1829
            return status;
 
1830
    }
 
1831
    
 
1832
    /* XXX: The rendered size is sometimes 1 or 2 pixels short from
 
1833
       what I expect. Need to fix this. */
 
1834
    status = _cairo_surface_composite (gstate->operator,
 
1835
                                       surface, pattern.source, gstate->surface,
 
1836
                                       device_x, device_y,
 
1837
                                       0, 0,
 
1838
                                       device_x, device_y,
 
1839
                                       device_width,
 
1840
                                       device_height);
 
1841
 
 
1842
    _cairo_pattern_fini (&pattern);
 
1843
 
 
1844
    /* restore the matrix originally in the surface */
 
1845
    cairo_surface_set_matrix (surface, &user_to_image);
 
1846
    
 
1847
    if (status)
 
1848
        return status;    
 
1849
 
 
1850
    return CAIRO_STATUS_SUCCESS;
 
1851
}
 
1852
 
 
1853
cairo_status_t
 
1854
_cairo_gstate_select_font (cairo_gstate_t       *gstate, 
 
1855
                           const char           *family, 
 
1856
                           cairo_font_slant_t   slant, 
 
1857
                           cairo_font_weight_t  weight)
 
1858
{
 
1859
    if (gstate->font != NULL)
 
1860
        cairo_font_destroy (gstate->font);
 
1861
 
 
1862
    gstate->font = _cairo_font_create (family, slant, weight);
 
1863
  
 
1864
    return CAIRO_STATUS_SUCCESS;
 
1865
}
 
1866
 
 
1867
cairo_status_t
 
1868
_cairo_gstate_scale_font (cairo_gstate_t *gstate, 
 
1869
                          double scale)
 
1870
{
 
1871
    return _cairo_font_scale (gstate->font, scale);
 
1872
}
 
1873
 
 
1874
cairo_status_t
 
1875
_cairo_gstate_transform_font (cairo_gstate_t *gstate, 
 
1876
                              cairo_matrix_t *matrix)
 
1877
{
 
1878
    return _cairo_font_transform (gstate->font, matrix);    
 
1879
}
 
1880
 
 
1881
cairo_status_t
 
1882
_cairo_gstate_current_font (cairo_gstate_t *gstate, 
 
1883
                            cairo_font_t **font)
 
1884
{
 
1885
    *font = gstate->font;
 
1886
 
 
1887
    return CAIRO_STATUS_SUCCESS;
 
1888
}
 
1889
 
 
1890
cairo_status_t
 
1891
_cairo_gstate_current_font_extents (cairo_gstate_t *gstate, 
 
1892
                                    cairo_font_extents_t *extents)
 
1893
{
 
1894
    cairo_int_status_t status;
 
1895
    cairo_matrix_t saved_font_matrix;
 
1896
    
 
1897
    cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
 
1898
    cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
 
1899
    
 
1900
    status = _cairo_font_font_extents (gstate->font, extents);
 
1901
 
 
1902
    cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);    
 
1903
 
 
1904
    return status;
 
1905
}
 
1906
 
 
1907
 
 
1908
cairo_status_t
 
1909
_cairo_gstate_set_font (cairo_gstate_t *gstate, 
 
1910
                        cairo_font_t *font)
 
1911
{
 
1912
    if (gstate->font != NULL)    
 
1913
        cairo_font_destroy (gstate->font);
 
1914
    gstate->font = font;
 
1915
    cairo_font_reference (gstate->font);
 
1916
    return CAIRO_STATUS_SUCCESS;
 
1917
}
 
1918
 
 
1919
cairo_status_t
 
1920
_cairo_gstate_text_extents (cairo_gstate_t *gstate,
 
1921
                            const unsigned char *utf8,
 
1922
                            cairo_text_extents_t *extents)
 
1923
{
 
1924
    cairo_matrix_t saved_font_matrix;
 
1925
    cairo_status_t status;
 
1926
    double scale_x, scale_y;
 
1927
 
 
1928
    cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
 
1929
    _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
 
1930
    cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
 
1931
 
 
1932
    status = _cairo_font_text_extents (gstate->font,
 
1933
                                       utf8, extents);
 
1934
 
 
1935
    cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
 
1936
 
 
1937
    extents->x_bearing /= scale_x;
 
1938
    extents->y_bearing /= scale_y;
 
1939
    extents->width  /= scale_x;
 
1940
    extents->height /= scale_y;
 
1941
    extents->x_advance /= scale_x;
 
1942
    extents->y_advance /= scale_y;
 
1943
 
 
1944
    return status;
 
1945
}
 
1946
 
 
1947
cairo_status_t
 
1948
_cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
 
1949
                             cairo_glyph_t *glyphs, 
 
1950
                             int num_glyphs,
 
1951
                             cairo_text_extents_t *extents)
 
1952
{
 
1953
    cairo_status_t status;
 
1954
    cairo_matrix_t saved_font_matrix;
 
1955
    double scale_x, scale_y;
 
1956
 
 
1957
    cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
 
1958
    _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
 
1959
    cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
 
1960
 
 
1961
    status = _cairo_font_glyph_extents (gstate->font,
 
1962
                                        glyphs, num_glyphs,
 
1963
                                        extents);
 
1964
 
 
1965
    cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
 
1966
 
 
1967
    extents->x_bearing /= scale_x;
 
1968
    extents->y_bearing /= scale_y;
 
1969
    extents->width  /= scale_x;
 
1970
    extents->height /= scale_y;
 
1971
    extents->x_advance /= scale_x;
 
1972
    extents->y_advance /= scale_y;
 
1973
 
 
1974
    return status;
 
1975
}
 
1976
 
 
1977
cairo_status_t
 
1978
_cairo_gstate_show_text (cairo_gstate_t *gstate, 
 
1979
                         const unsigned char *utf8)
 
1980
{
 
1981
    cairo_status_t status;
 
1982
    cairo_point_t point;
 
1983
    double x, y;
 
1984
    cairo_matrix_t saved_font_matrix;
 
1985
    cairo_pattern_t pattern;
 
1986
    cairo_text_extents_t text_extents;
 
1987
    cairo_box_t extents;
 
1988
 
 
1989
    status = _cairo_path_current_point (&gstate->path, &point);
 
1990
    if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
 
1991
        x = 0;
 
1992
        y = 0;
 
1993
        cairo_matrix_transform_point (&gstate->ctm, &x, &y);
 
1994
    } else {
 
1995
        x = _cairo_fixed_to_double (point.x);
 
1996
        y = _cairo_fixed_to_double (point.y);
 
1997
    }
 
1998
    
 
1999
    cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
 
2000
    cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
 
2001
 
 
2002
    _cairo_pattern_init_copy (&pattern, gstate->pattern);
 
2003
    
 
2004
    status = _cairo_gstate_text_extents (gstate, utf8, &text_extents);
 
2005
    if (status)
 
2006
        return status;
 
2007
    
 
2008
    extents.p1.x = _cairo_fixed_from_double (x);
 
2009
    extents.p1.y = _cairo_fixed_from_double (y);
 
2010
    extents.p2.x = _cairo_fixed_from_double (x + text_extents.width);
 
2011
    extents.p2.y = _cairo_fixed_from_double (y + text_extents.height);
 
2012
    status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
 
2013
    if (status)
 
2014
        return status;
 
2015
    
 
2016
    status = _cairo_font_show_text (gstate->font,
 
2017
                                    gstate->operator, pattern.source,
 
2018
                                    gstate->surface, x, y, utf8);
 
2019
    
 
2020
    cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
 
2021
 
 
2022
    _cairo_pattern_fini (&pattern);
 
2023
 
 
2024
    return status;
 
2025
}
 
2026
 
 
2027
cairo_status_t
 
2028
_cairo_gstate_show_glyphs (cairo_gstate_t *gstate, 
 
2029
                           cairo_glyph_t *glyphs, 
 
2030
                           int num_glyphs)
 
2031
{
 
2032
    cairo_status_t status;
 
2033
    cairo_matrix_t saved_font_matrix;
 
2034
    int i;
 
2035
    cairo_glyph_t *transformed_glyphs = NULL;
 
2036
    cairo_pattern_t pattern;
 
2037
    cairo_text_extents_t text_extents;
 
2038
    cairo_box_t extents;
 
2039
 
 
2040
    transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
 
2041
    if (transformed_glyphs == NULL)
 
2042
        return CAIRO_STATUS_NO_MEMORY;
 
2043
    
 
2044
    for (i = 0; i < num_glyphs; ++i)
 
2045
    {
 
2046
        transformed_glyphs[i] = glyphs[i];
 
2047
        cairo_matrix_transform_point (&gstate->ctm, 
 
2048
                                      &(transformed_glyphs[i].x), 
 
2049
                                      &(transformed_glyphs[i].y));
 
2050
    }
 
2051
    
 
2052
    cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
 
2053
    cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
 
2054
 
 
2055
    _cairo_pattern_init_copy (&pattern, gstate->pattern);
 
2056
    _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs,
 
2057
                                 &text_extents);
 
2058
    if (status)
 
2059
        return status;
 
2060
 
 
2061
    extents.p1.x = _cairo_fixed_from_double (transformed_glyphs[0].x);
 
2062
    extents.p1.y = _cairo_fixed_from_double (transformed_glyphs[0].y);
 
2063
    extents.p2.x = _cairo_fixed_from_double (transformed_glyphs[0].x +
 
2064
                                             text_extents.width);
 
2065
    extents.p2.y = _cairo_fixed_from_double (transformed_glyphs[0].y +
 
2066
                                             text_extents.height);
 
2067
    status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
 
2068
    if (status)
 
2069
        return status;
 
2070
 
 
2071
    status = _cairo_font_show_glyphs (gstate->font, 
 
2072
                                      gstate->operator, pattern.source,
 
2073
                                      gstate->surface,
 
2074
                                      transformed_glyphs, num_glyphs);
 
2075
    
 
2076
    cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
 
2077
 
 
2078
    _cairo_pattern_fini (&pattern);
 
2079
 
 
2080
    free (transformed_glyphs);
 
2081
    
 
2082
    return status;
 
2083
}
 
2084
 
 
2085
 
 
2086
cairo_status_t
 
2087
_cairo_gstate_text_path (cairo_gstate_t *gstate, 
 
2088
                         const unsigned char *utf8)
 
2089
{
 
2090
    cairo_status_t status;
 
2091
    cairo_matrix_t saved_font_matrix;
 
2092
    cairo_point_t point;
 
2093
    double x, y;
 
2094
 
 
2095
    status = _cairo_path_current_point (&gstate->path, &point);
 
2096
    if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
 
2097
        x = 0;
 
2098
        y = 0;
 
2099
        cairo_matrix_transform_point (&gstate->ctm, &x, &y);
 
2100
    } else {
 
2101
        x = _cairo_fixed_to_double (point.x);
 
2102
        y = _cairo_fixed_to_double (point.y);
 
2103
    }
 
2104
 
 
2105
    cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
 
2106
    cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
 
2107
 
 
2108
    status = _cairo_font_text_path (gstate->font, 
 
2109
                                    x, y,
 
2110
                                    utf8,
 
2111
                                    &gstate->path);
 
2112
 
 
2113
    cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
 
2114
 
 
2115
    return status;
 
2116
}
 
2117
 
 
2118
 
 
2119
cairo_status_t
 
2120
_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
 
2121
                          cairo_glyph_t *glyphs, 
 
2122
                          int num_glyphs)
 
2123
{
 
2124
    cairo_status_t status;
 
2125
    int i;
 
2126
    cairo_glyph_t *transformed_glyphs = NULL;
 
2127
    cairo_matrix_t saved_font_matrix;
 
2128
 
 
2129
    transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
 
2130
    if (transformed_glyphs == NULL)
 
2131
        return CAIRO_STATUS_NO_MEMORY;
 
2132
    
 
2133
    for (i = 0; i < num_glyphs; ++i)
 
2134
    {
 
2135
        transformed_glyphs[i] = glyphs[i];
 
2136
        cairo_matrix_transform_point (&gstate->ctm, 
 
2137
                                      &(transformed_glyphs[i].x), 
 
2138
                                      &(transformed_glyphs[i].y));
 
2139
    }
 
2140
 
 
2141
    cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
 
2142
    cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
 
2143
 
 
2144
    status = _cairo_font_glyph_path (gstate->font, 
 
2145
                                     transformed_glyphs, num_glyphs,
 
2146
                                     &gstate->path);
 
2147
 
 
2148
    cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
 
2149
 
 
2150
    free (transformed_glyphs);
 
2151
    return status;
 
2152
}