1 /* cairo - a vector graphics library with display and print output
2 *
3 * Copyright © 2002 University of Southern California
4 * Copyright © 2005 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipient may use your version of this file under either
12 * the MPL or the LGPL.
13 *
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
19 *
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
24 *
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
28 *
29 * The Original Code is the cairo graphics library.
30 *
31 * The Initial Developer of the Original Code is University of Southern
32 * California.
33 *
34 * Contributor(s):
35 * Carl D. Worth <cworth@cworth.org>
36 */
37
38 #include "cairoint.h"
39
40 #include "cairo-clip-private.h"
41 #include "cairo-error-private.h"
42 #include "cairo-gstate-private.h"
43
44 #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
45 #define ISFINITE(x) isfinite (x)
46 #else
47 #define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
48 #endif
49
50 static cairo_status_t
51 _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other);
52
53 static cairo_status_t
54 _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
55
56 static cairo_status_t
57 _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate);
58
59 static void
60 _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate);
61
62 static cairo_status_t
63 _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
64 const cairo_glyph_t *glyphs,
65 int num_glyphs,
66 const cairo_text_cluster_t *clusters,
67 int num_clusters,
68 cairo_text_cluster_flags_t cluster_flags,
69 cairo_glyph_t *transformed_glyphs,
70 int *num_transformed_glyphs,
71 cairo_text_cluster_t *transformed_clusters);
72
73 static void
_cairo_gstate_update_device_transform(cairo_observer_t * observer,void * arg)74 _cairo_gstate_update_device_transform (cairo_observer_t *observer,
75 void *arg)
76 {
77 cairo_gstate_t *gstate = cairo_container_of (observer,
78 cairo_gstate_t,
79 device_transform_observer);
80
81 gstate->is_identity = (_cairo_matrix_is_identity (&gstate->ctm) &&
82 _cairo_matrix_is_identity (&gstate->target->device_transform));
83 }
84
85 cairo_status_t
_cairo_gstate_init(cairo_gstate_t * gstate,cairo_surface_t * target)86 _cairo_gstate_init (cairo_gstate_t *gstate,
87 cairo_surface_t *target)
88 {
89 cairo_status_t status;
90
91 VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
92
93 gstate->next = NULL;
94
95 gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT;
96
97 gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
98 gstate->antialias = CAIRO_ANTIALIAS_DEFAULT;
99
100 _cairo_stroke_style_init (&gstate->stroke_style);
101
102 gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
103
104 gstate->font_face = NULL;
105 gstate->scaled_font = NULL;
106 gstate->previous_scaled_font = NULL;
107
108 cairo_matrix_init_scale (&gstate->font_matrix,
109 CAIRO_GSTATE_DEFAULT_FONT_SIZE,
110 CAIRO_GSTATE_DEFAULT_FONT_SIZE);
111
112 _cairo_font_options_init_default (&gstate->font_options);
113
114 _cairo_clip_init (&gstate->clip);
115
116 gstate->target = cairo_surface_reference (target);
117 gstate->parent_target = NULL;
118 gstate->original_target = cairo_surface_reference (target);
119
120 gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
121 cairo_list_add (&gstate->device_transform_observer.link,
122 &gstate->target->device_transform_observers);
123
124 gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
125 cairo_matrix_init_identity (&gstate->ctm);
126 gstate->ctm_inverse = gstate->ctm;
127 gstate->source_ctm_inverse = gstate->ctm;
128
129 gstate->source = (cairo_pattern_t *) &_cairo_pattern_black.base;
130
131 /* Now that the gstate is fully initialized and ready for the eventual
132 * _cairo_gstate_fini(), we can check for errors (and not worry about
133 * the resource deallocation). */
134 status = target->status;
135 if (unlikely (status))
136 return status;
137
138 status = gstate->source->status;
139 if (unlikely (status))
140 return status;
141
142 return CAIRO_STATUS_SUCCESS;
143 }
144
145 /**
146 * _cairo_gstate_init_copy:
147 *
148 * Initialize @gstate by performing a deep copy of state fields from
149 * @other. Note that gstate->next is not copied but is set to %NULL by
150 * this function.
151 **/
152 static cairo_status_t
_cairo_gstate_init_copy(cairo_gstate_t * gstate,cairo_gstate_t * other)153 _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
154 {
155 cairo_status_t status;
156
157 VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t)));
158
159 gstate->op = other->op;
160
161 gstate->tolerance = other->tolerance;
162 gstate->antialias = other->antialias;
163
164 status = _cairo_stroke_style_init_copy (&gstate->stroke_style,
165 &other->stroke_style);
166 if (unlikely (status))
167 return status;
168
169 gstate->fill_rule = other->fill_rule;
170
171 gstate->font_face = cairo_font_face_reference (other->font_face);
172 gstate->scaled_font = cairo_scaled_font_reference (other->scaled_font);
173 gstate->previous_scaled_font = cairo_scaled_font_reference (other->previous_scaled_font);
174
175 gstate->font_matrix = other->font_matrix;
176
177 _cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
178
179 _cairo_clip_init_copy (&gstate->clip, &other->clip);
180
181 gstate->target = cairo_surface_reference (other->target);
182 /* parent_target is always set to NULL; it's only ever set by redirect_target */
183 gstate->parent_target = NULL;
184 gstate->original_target = cairo_surface_reference (other->original_target);
185
186 gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
187 cairo_list_add (&gstate->device_transform_observer.link,
188 &gstate->target->device_transform_observers);
189
190 gstate->is_identity = other->is_identity;
191 gstate->ctm = other->ctm;
192 gstate->ctm_inverse = other->ctm_inverse;
193 gstate->source_ctm_inverse = other->source_ctm_inverse;
194
195 gstate->source = cairo_pattern_reference (other->source);
196
197 gstate->next = NULL;
198
199 return CAIRO_STATUS_SUCCESS;
200 }
201
202 void
_cairo_gstate_fini(cairo_gstate_t * gstate)203 _cairo_gstate_fini (cairo_gstate_t *gstate)
204 {
205 _cairo_stroke_style_fini (&gstate->stroke_style);
206
207 cairo_font_face_destroy (gstate->font_face);
208 gstate->font_face = NULL;
209
210 cairo_scaled_font_destroy (gstate->previous_scaled_font);
211 gstate->previous_scaled_font = NULL;
212
213 cairo_scaled_font_destroy (gstate->scaled_font);
214 gstate->scaled_font = NULL;
215
216 _cairo_clip_reset (&gstate->clip);
217
218 cairo_list_del (&gstate->device_transform_observer.link);
219
220 cairo_surface_destroy (gstate->target);
221 gstate->target = NULL;
222
223 cairo_surface_destroy (gstate->parent_target);
224 gstate->parent_target = NULL;
225
226 cairo_surface_destroy (gstate->original_target);
227 gstate->original_target = NULL;
228
229 cairo_pattern_destroy (gstate->source);
230 gstate->source = NULL;
231
232 VG (VALGRIND_MAKE_MEM_NOACCESS (gstate, sizeof (cairo_gstate_t)));
233 }
234
235 /**
236 * _cairo_gstate_save:
237 * @gstate: input/output gstate pointer
238 *
239 * Makes a copy of the current state of @gstate and saves it
240 * to @gstate->next, then put the address of the newly allcated
241 * copy into @gstate. _cairo_gstate_restore() reverses this.
242 **/
243 cairo_status_t
_cairo_gstate_save(cairo_gstate_t ** gstate,cairo_gstate_t ** freelist)244 _cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
245 {
246 cairo_gstate_t *top;
247 cairo_status_t status;
248
249 if (CAIRO_INJECT_FAULT ())
250 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
251
252 top = *freelist;
253 if (top == NULL) {
254 top = malloc (sizeof (cairo_gstate_t));
255 if (unlikely (top == NULL))
256 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
257 } else
258 *freelist = top->next;
259
260 status = _cairo_gstate_init_copy (top, *gstate);
261 if (unlikely (status)) {
262 top->next = *freelist;
263 *freelist = top;
264 return status;
265 }
266
267 top->next = *gstate;
268 *gstate = top;
269
270 return CAIRO_STATUS_SUCCESS;
271 }
272
273 /**
274 * _cairo_gstate_restore:
275 * @gstate: input/output gstate pointer
276 *
277 * Reverses the effects of one _cairo_gstate_save() call.
278 **/
279 cairo_status_t
_cairo_gstate_restore(cairo_gstate_t ** gstate,cairo_gstate_t ** freelist)280 _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
281 {
282 cairo_gstate_t *top;
283
284 top = *gstate;
285 if (top->next == NULL)
286 return _cairo_error (CAIRO_STATUS_INVALID_RESTORE);
287
288 *gstate = top->next;
289
290 _cairo_gstate_fini (top);
291 VG (VALGRIND_MAKE_MEM_UNDEFINED (&top->next, sizeof (cairo_gstate_t *)));
292 top->next = *freelist;
293 *freelist = top;
294
295 return CAIRO_STATUS_SUCCESS;
296 }
297
298 /**
299 * _cairo_gstate_redirect_target:
300 * @gstate: a #cairo_gstate_t
301 * @child: the new child target
302 *
303 * Redirect @gstate rendering to a "child" target. The original
304 * "parent" target with which the gstate was created will not be
305 * affected. See _cairo_gstate_get_target().
306 *
307 * Unless the redirected target has the same device offsets as the
308 * original #cairo_t target, the clip will be INVALID after this call,
309 * and the caller should either recreate or reset the clip.
310 **/
311 cairo_status_t
_cairo_gstate_redirect_target(cairo_gstate_t * gstate,cairo_surface_t * child)312 _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
313 {
314 cairo_matrix_t matrix;
315
316 /* If this gstate is already redirected, this is an error; we need a
317 * new gstate to be able to redirect */
318 assert (gstate->parent_target == NULL);
319
320 /* Set up our new parent_target based on our current target;
321 * gstate->parent_target will take the ref that is held by gstate->target
322 */
323 cairo_surface_destroy (gstate->parent_target);
324 gstate->parent_target = gstate->target;
325
326 /* Now set up our new target; we overwrite gstate->target directly,
327 * since its ref is now owned by gstate->parent_target */
328 gstate->target = cairo_surface_reference (child);
329 gstate->is_identity &= _cairo_matrix_is_identity (&child->device_transform);
330 cairo_list_move (&gstate->device_transform_observer.link,
331 &gstate->target->device_transform_observers);
332
333 /* The clip is in surface backend coordinates for the previous target;
334 * translate it into the child's backend coordinates. */
335 cairo_matrix_init_translate (&matrix,
336 child->device_transform.x0 - gstate->parent_target->device_transform.x0,
337 child->device_transform.y0 - gstate->parent_target->device_transform.y0);
338 _cairo_clip_reset (&gstate->clip);
339 return _cairo_clip_init_copy_transformed (&gstate->clip,
340 &gstate->next->clip,
341 &matrix);
342 }
343
344 /**
345 * _cairo_gstate_is_redirected
346 * @gstate: a #cairo_gstate_t
347 *
348 * This space left intentionally blank.
349 *
350 * Return value: %TRUE if the gstate is redirected to a target
351 * different than the original, %FALSE otherwise.
352 **/
353 cairo_bool_t
_cairo_gstate_is_redirected(cairo_gstate_t * gstate)354 _cairo_gstate_is_redirected (cairo_gstate_t *gstate)
355 {
356 return (gstate->target != gstate->original_target);
357 }
358
359 /**
360 * _cairo_gstate_get_target:
361 * @gstate: a #cairo_gstate_t
362 *
363 * Return the current drawing target; if drawing is not redirected,
364 * this will be the same as _cairo_gstate_get_original_target().
365 *
366 * Return value: the current target surface
367 **/
368 cairo_surface_t *
_cairo_gstate_get_target(cairo_gstate_t * gstate)369 _cairo_gstate_get_target (cairo_gstate_t *gstate)
370 {
371 return gstate->target;
372 }
373
374 /**
375 * _cairo_gstate_get_parent_target:
376 * @gstate: a #cairo_gstate_t
377 *
378 * Return the parent surface of the current drawing target surface;
379 * if this particular gstate isn't a redirect gstate, this will return %NULL.
380 **/
381 cairo_surface_t *
_cairo_gstate_get_parent_target(cairo_gstate_t * gstate)382 _cairo_gstate_get_parent_target (cairo_gstate_t *gstate)
383 {
384 return gstate->parent_target;
385 }
386
387 /**
388 * _cairo_gstate_get_original_target:
389 * @gstate: a #cairo_gstate_t
390 *
391 * Return the original target with which @gstate was created. This
392 * function always returns the original target independent of any
393 * child target that may have been set with
394 * _cairo_gstate_redirect_target.
395 *
396 * Return value: the original target surface
397 **/
398 cairo_surface_t *
_cairo_gstate_get_original_target(cairo_gstate_t * gstate)399 _cairo_gstate_get_original_target (cairo_gstate_t *gstate)
400 {
401 return gstate->original_target;
402 }
403
404 /**
405 * _cairo_gstate_get_clip:
406 * @gstate: a #cairo_gstate_t
407 *
408 * This space left intentionally blank.
409 *
410 * Return value: a pointer to the gstate's #cairo_clip_t structure.
411 */
412 cairo_clip_t *
_cairo_gstate_get_clip(cairo_gstate_t * gstate)413 _cairo_gstate_get_clip (cairo_gstate_t *gstate)
414 {
415 return &gstate->clip;
416 }
417
418 cairo_status_t
_cairo_gstate_set_source(cairo_gstate_t * gstate,cairo_pattern_t * source)419 _cairo_gstate_set_source (cairo_gstate_t *gstate,
420 cairo_pattern_t *source)
421 {
422 if (source->status)
423 return source->status;
424
425 source = cairo_pattern_reference (source);
426 cairo_pattern_destroy (gstate->source);
427 gstate->source = source;
428 gstate->source_ctm_inverse = gstate->ctm_inverse;
429
430 return CAIRO_STATUS_SUCCESS;
431 }
432
433 cairo_pattern_t *
_cairo_gstate_get_source(cairo_gstate_t * gstate)434 _cairo_gstate_get_source (cairo_gstate_t *gstate)
435 {
436 if (gstate->source == &_cairo_pattern_black.base) {
437 /* do not expose the static object to the user */
438 gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
439 }
440
441 return gstate->source;
442 }
443
444 cairo_status_t
_cairo_gstate_set_operator(cairo_gstate_t * gstate,cairo_operator_t op)445 _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op)
446 {
447 gstate->op = op;
448
449 return CAIRO_STATUS_SUCCESS;
450 }
451
452 cairo_operator_t
_cairo_gstate_get_operator(cairo_gstate_t * gstate)453 _cairo_gstate_get_operator (cairo_gstate_t *gstate)
454 {
455 return gstate->op;
456 }
457
458 cairo_status_t
_cairo_gstate_set_tolerance(cairo_gstate_t * gstate,double tolerance)459 _cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
460 {
461 gstate->tolerance = tolerance;
462
463 return CAIRO_STATUS_SUCCESS;
464 }
465
466 double
_cairo_gstate_get_tolerance(cairo_gstate_t * gstate)467 _cairo_gstate_get_tolerance (cairo_gstate_t *gstate)
468 {
469 return gstate->tolerance;
470 }
471
472 cairo_status_t
_cairo_gstate_set_fill_rule(cairo_gstate_t * gstate,cairo_fill_rule_t fill_rule)473 _cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
474 {
475 gstate->fill_rule = fill_rule;
476
477 return CAIRO_STATUS_SUCCESS;
478 }
479
480 cairo_fill_rule_t
_cairo_gstate_get_fill_rule(cairo_gstate_t * gstate)481 _cairo_gstate_get_fill_rule (cairo_gstate_t *gstate)
482 {
483 return gstate->fill_rule;
484 }
485
486 cairo_status_t
_cairo_gstate_set_line_width(cairo_gstate_t * gstate,double width)487 _cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
488 {
489 gstate->stroke_style.line_width = width;
490
491 return CAIRO_STATUS_SUCCESS;
492 }
493
494 double
_cairo_gstate_get_line_width(cairo_gstate_t * gstate)495 _cairo_gstate_get_line_width (cairo_gstate_t *gstate)
496 {
497 return gstate->stroke_style.line_width;
498 }
499
500 cairo_status_t
_cairo_gstate_set_line_cap(cairo_gstate_t * gstate,cairo_line_cap_t line_cap)501 _cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
502 {
503 gstate->stroke_style.line_cap = line_cap;
504
505 return CAIRO_STATUS_SUCCESS;
506 }
507
508 cairo_line_cap_t
_cairo_gstate_get_line_cap(cairo_gstate_t * gstate)509 _cairo_gstate_get_line_cap (cairo_gstate_t *gstate)
510 {
511 return gstate->stroke_style.line_cap;
512 }
513
514 cairo_status_t
_cairo_gstate_set_line_join(cairo_gstate_t * gstate,cairo_line_join_t line_join)515 _cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join)
516 {
517 gstate->stroke_style.line_join = line_join;
518
519 return CAIRO_STATUS_SUCCESS;
520 }
521
522 cairo_line_join_t
_cairo_gstate_get_line_join(cairo_gstate_t * gstate)523 _cairo_gstate_get_line_join (cairo_gstate_t *gstate)
524 {
525 return gstate->stroke_style.line_join;
526 }
527
528 cairo_status_t
_cairo_gstate_set_dash(cairo_gstate_t * gstate,const double * dash,int num_dashes,double offset)529 _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset)
530 {
531 unsigned int i;
532 double dash_total;
533
534 if (gstate->stroke_style.dash)
535 free (gstate->stroke_style.dash);
536
537 gstate->stroke_style.num_dashes = num_dashes;
538
539 if (gstate->stroke_style.num_dashes == 0) {
540 gstate->stroke_style.dash = NULL;
541 gstate->stroke_style.dash_offset = 0.0;
542 return CAIRO_STATUS_SUCCESS;
543 }
544
545 gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double));
546 if (unlikely (gstate->stroke_style.dash == NULL)) {
547 gstate->stroke_style.num_dashes = 0;
548 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
549 }
550
551 memcpy (gstate->stroke_style.dash, dash, gstate->stroke_style.num_dashes * sizeof (double));
552
553 dash_total = 0.0;
554 for (i = 0; i < gstate->stroke_style.num_dashes; i++) {
555 if (gstate->stroke_style.dash[i] < 0)
556 return _cairo_error (CAIRO_STATUS_INVALID_DASH);
557
558 dash_total += gstate->stroke_style.dash[i];
559 }
560
561 if (dash_total == 0.0)
562 return _cairo_error (CAIRO_STATUS_INVALID_DASH);
563
564 /* An odd dash value indicate symmetric repeating, so the total
565 * is twice as long. */
566 if (gstate->stroke_style.num_dashes & 1)
567 dash_total *= 2;
568
569 /* The dashing code doesn't like a negative offset or a big positive
570 * offset, so we compute an equivalent offset which is guaranteed to be
571 * positive and less than twice the pattern length. */
572 offset = fmod (offset, dash_total);
573 if (offset < 0.0)
574 offset += dash_total;
575 if (offset <= 0.0) /* Take care of -0 */
576 offset = 0.0;
577 gstate->stroke_style.dash_offset = offset;
578
579 return CAIRO_STATUS_SUCCESS;
580 }
581
582 void
_cairo_gstate_get_dash(cairo_gstate_t * gstate,double * dashes,int * num_dashes,double * offset)583 _cairo_gstate_get_dash (cairo_gstate_t *gstate,
584 double *dashes,
585 int *num_dashes,
586 double *offset)
587 {
588 if (dashes) {
589 memcpy (dashes,
590 gstate->stroke_style.dash,
591 sizeof (double) * gstate->stroke_style.num_dashes);
592 }
593
594 if (num_dashes)
595 *num_dashes = gstate->stroke_style.num_dashes;
596
597 if (offset)
598 *offset = gstate->stroke_style.dash_offset;
599 }
600
601 cairo_status_t
_cairo_gstate_set_miter_limit(cairo_gstate_t * gstate,double limit)602 _cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
603 {
604 gstate->stroke_style.miter_limit = limit;
605
606 return CAIRO_STATUS_SUCCESS;
607 }
608
609 double
_cairo_gstate_get_miter_limit(cairo_gstate_t * gstate)610 _cairo_gstate_get_miter_limit (cairo_gstate_t *gstate)
611 {
612 return gstate->stroke_style.miter_limit;
613 }
614
615 void
_cairo_gstate_get_matrix(cairo_gstate_t * gstate,cairo_matrix_t * matrix)616 _cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
617 {
618 *matrix = gstate->ctm;
619 }
620
621 cairo_status_t
_cairo_gstate_translate(cairo_gstate_t * gstate,double tx,double ty)622 _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
623 {
624 cairo_matrix_t tmp;
625
626 if (! ISFINITE (tx) || ! ISFINITE (ty))
627 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
628
629 _cairo_gstate_unset_scaled_font (gstate);
630
631 cairo_matrix_init_translate (&tmp, tx, ty);
632 cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
633 gstate->is_identity = FALSE;
634
635 /* paranoid check against gradual numerical instability */
636 if (! _cairo_matrix_is_invertible (&gstate->ctm))
637 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
638
639 cairo_matrix_init_translate (&tmp, -tx, -ty);
640 cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
641
642 return CAIRO_STATUS_SUCCESS;
643 }
644
645 cairo_status_t
_cairo_gstate_scale(cairo_gstate_t * gstate,double sx,double sy)646 _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
647 {
648 cairo_matrix_t tmp;
649
650 if (sx * sy == 0.) /* either sx or sy is 0, or det == 0 due to underflow */
651 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
652 if (! ISFINITE (sx) || ! ISFINITE (sy))
653 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
654
655 _cairo_gstate_unset_scaled_font (gstate);
656
657 cairo_matrix_init_scale (&tmp, sx, sy);
658 cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
659 gstate->is_identity = FALSE;
660
661 /* paranoid check against gradual numerical instability */
662 if (! _cairo_matrix_is_invertible (&gstate->ctm))
663 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
664
665 cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
666 cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
667
668 return CAIRO_STATUS_SUCCESS;
669 }
670
671 cairo_status_t
_cairo_gstate_rotate(cairo_gstate_t * gstate,double angle)672 _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
673 {
674 cairo_matrix_t tmp;
675
676 if (angle == 0.)
677 return CAIRO_STATUS_SUCCESS;
678
679 if (! ISFINITE (angle))
680 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
681
682 _cairo_gstate_unset_scaled_font (gstate);
683
684 cairo_matrix_init_rotate (&tmp, angle);
685 cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
686 gstate->is_identity = FALSE;
687
688 /* paranoid check against gradual numerical instability */
689 if (! _cairo_matrix_is_invertible (&gstate->ctm))
690 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
691
692 cairo_matrix_init_rotate (&tmp, -angle);
693 cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
694
695 return CAIRO_STATUS_SUCCESS;
696 }
697
698 cairo_status_t
_cairo_gstate_transform(cairo_gstate_t * gstate,const cairo_matrix_t * matrix)699 _cairo_gstate_transform (cairo_gstate_t *gstate,
700 const cairo_matrix_t *matrix)
701 {
702 cairo_matrix_t tmp;
703 cairo_status_t status;
704
705 if (! _cairo_matrix_is_invertible (matrix))
706 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
707
708 if (_cairo_matrix_is_identity (matrix))
709 return CAIRO_STATUS_SUCCESS;
710
711 tmp = *matrix;
712 status = cairo_matrix_invert (&tmp);
713 if (unlikely (status))
714 return status;
715
716 _cairo_gstate_unset_scaled_font (gstate);
717
718 cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm);
719 cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
720 gstate->is_identity = FALSE;
721
722 /* paranoid check against gradual numerical instability */
723 if (! _cairo_matrix_is_invertible (&gstate->ctm))
724 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
725
726 return CAIRO_STATUS_SUCCESS;
727 }
728
729 cairo_status_t
_cairo_gstate_set_matrix(cairo_gstate_t * gstate,const cairo_matrix_t * matrix)730 _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
731 const cairo_matrix_t *matrix)
732 {
733 cairo_status_t status;
734
735 if (memcmp (matrix, &gstate->ctm, sizeof (cairo_matrix_t)) == 0)
736 return CAIRO_STATUS_SUCCESS;
737
738 if (! _cairo_matrix_is_invertible (matrix))
739 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
740
741 if (_cairo_matrix_is_identity (matrix)) {
742 _cairo_gstate_identity_matrix (gstate);
743 return CAIRO_STATUS_SUCCESS;
744 }
745
746 _cairo_gstate_unset_scaled_font (gstate);
747
748 gstate->ctm = *matrix;
749 gstate->ctm_inverse = *matrix;
750 status = cairo_matrix_invert (&gstate->ctm_inverse);
751 assert (status == CAIRO_STATUS_SUCCESS);
752 gstate->is_identity = FALSE;
753
754 return CAIRO_STATUS_SUCCESS;
755 }
756
757 void
_cairo_gstate_identity_matrix(cairo_gstate_t * gstate)758 _cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
759 {
760 if (_cairo_matrix_is_identity (&gstate->ctm))
761 return;
762
763 _cairo_gstate_unset_scaled_font (gstate);
764
765 cairo_matrix_init_identity (&gstate->ctm);
766 cairo_matrix_init_identity (&gstate->ctm_inverse);
767 gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
768 }
769
770 void
_cairo_gstate_user_to_device(cairo_gstate_t * gstate,double * x,double * y)771 _cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y)
772 {
773 cairo_matrix_transform_point (&gstate->ctm, x, y);
774 }
775
776 void
_cairo_gstate_user_to_device_distance(cairo_gstate_t * gstate,double * dx,double * dy)777 _cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate,
778 double *dx, double *dy)
779 {
780 cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
781 }
782
783 void
_cairo_gstate_device_to_user(cairo_gstate_t * gstate,double * x,double * y)784 _cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y)
785 {
786 cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
787 }
788
789 void
_cairo_gstate_device_to_user_distance(cairo_gstate_t * gstate,double * dx,double * dy)790 _cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
791 double *dx, double *dy)
792 {
793 cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
794 }
795
796 void
_do_cairo_gstate_user_to_backend(cairo_gstate_t * gstate,double * x,double * y)797 _do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
798 {
799 cairo_matrix_transform_point (&gstate->ctm, x, y);
800 cairo_matrix_transform_point (&gstate->target->device_transform, x, y);
801 }
802
803 void
_do_cairo_gstate_backend_to_user(cairo_gstate_t * gstate,double * x,double * y)804 _do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
805 {
806 cairo_matrix_transform_point (&gstate->target->device_transform_inverse, x, y);
807 cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
808 }
809
810 void
_cairo_gstate_backend_to_user_rectangle(cairo_gstate_t * gstate,double * x1,double * y1,double * x2,double * y2,cairo_bool_t * is_tight)811 _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
812 double *x1, double *y1,
813 double *x2, double *y2,
814 cairo_bool_t *is_tight)
815 {
816 cairo_matrix_t matrix_inverse;
817
818 cairo_matrix_multiply (&matrix_inverse,
819 &gstate->target->device_transform_inverse,
820 &gstate->ctm_inverse);
821 _cairo_matrix_transform_bounding_box (&matrix_inverse,
822 x1, y1, x2, y2, is_tight);
823 }
824
825 /* XXX: NYI
826 cairo_status_t
827 _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
828 {
829 cairo_status_t status;
830
831 _cairo_pen_init (&gstate);
832 return CAIRO_STATUS_SUCCESS;
833 }
834 */
835
836 void
_cairo_gstate_path_extents(cairo_gstate_t * gstate,cairo_path_fixed_t * path,double * x1,double * y1,double * x2,double * y2)837 _cairo_gstate_path_extents (cairo_gstate_t *gstate,
838 cairo_path_fixed_t *path,
839 double *x1, double *y1,
840 double *x2, double *y2)
841 {
842 cairo_box_t box;
843 double px1, py1, px2, py2;
844
845 if (_cairo_path_fixed_extents (path, &box)) {
846 px1 = _cairo_fixed_to_double (box.p1.x);
847 py1 = _cairo_fixed_to_double (box.p1.y);
848 px2 = _cairo_fixed_to_double (box.p2.x);
849 py2 = _cairo_fixed_to_double (box.p2.y);
850
851 _cairo_gstate_backend_to_user_rectangle (gstate,
852 &px1, &py1, &px2, &py2,
853 NULL);
854 } else {
855 px1 = 0.0;
856 py1 = 0.0;
857 px2 = 0.0;
858 py2 = 0.0;
859 }
860
861 if (x1)
862 *x1 = px1;
863 if (y1)
864 *y1 = py1;
865 if (x2)
866 *x2 = px2;
867 if (y2)
868 *y2 = py2;
869 }
870
871 static void
_cairo_gstate_copy_pattern(cairo_pattern_t * pattern,const cairo_pattern_t * original)872 _cairo_gstate_copy_pattern (cairo_pattern_t *pattern,
873 const cairo_pattern_t *original)
874 {
875 /* First check if the we can replace the original with a much simpler
876 * pattern. For example, gradients that are uniform or just have a single
877 * stop can sometimes be replaced with a solid.
878 */
879
880 if (_cairo_pattern_is_clear (original)) {
881 _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
882 CAIRO_COLOR_TRANSPARENT);
883 return;
884 }
885
886 if (original->type == CAIRO_PATTERN_TYPE_LINEAR ||
887 original->type == CAIRO_PATTERN_TYPE_RADIAL)
888 {
889 cairo_color_t color;
890 if (_cairo_gradient_pattern_is_solid ((cairo_gradient_pattern_t *) original,
891 NULL,
892 &color))
893 {
894 _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
895 &color);
896 return;
897 }
898 }
899
900 _cairo_pattern_init_static_copy (pattern, original);
901 }
902
903 static void
_cairo_gstate_copy_transformed_pattern(cairo_gstate_t * gstate,cairo_pattern_t * pattern,const cairo_pattern_t * original,const cairo_matrix_t * ctm_inverse)904 _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
905 cairo_pattern_t *pattern,
906 const cairo_pattern_t *original,
907 const cairo_matrix_t *ctm_inverse)
908 {
909 _cairo_gstate_copy_pattern (pattern, original);
910
911 /* apply device_transform first so that it is transformed by ctm_inverse */
912 if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
913 cairo_surface_pattern_t *surface_pattern;
914 cairo_surface_t *surface;
915
916 surface_pattern = (cairo_surface_pattern_t *) original;
917 surface = surface_pattern->surface;
918
919 if (_cairo_surface_has_device_transform (surface))
920 _cairo_pattern_transform (pattern, &surface->device_transform);
921 }
922
923 if (! _cairo_matrix_is_identity (ctm_inverse))
924 _cairo_pattern_transform (pattern, ctm_inverse);
925
926 if (_cairo_surface_has_device_transform (gstate->target)) {
927 _cairo_pattern_transform (pattern,
928 &gstate->target->device_transform_inverse);
929 }
930 }
931
932 static void
_cairo_gstate_copy_transformed_source(cairo_gstate_t * gstate,cairo_pattern_t * pattern)933 _cairo_gstate_copy_transformed_source (cairo_gstate_t *gstate,
934 cairo_pattern_t *pattern)
935 {
936 _cairo_gstate_copy_transformed_pattern (gstate, pattern,
937 gstate->source,
938 &gstate->source_ctm_inverse);
939 }
940
941 static void
_cairo_gstate_copy_transformed_mask(cairo_gstate_t * gstate,cairo_pattern_t * pattern,cairo_pattern_t * mask)942 _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate,
943 cairo_pattern_t *pattern,
944 cairo_pattern_t *mask)
945 {
946 _cairo_gstate_copy_transformed_pattern (gstate, pattern,
947 mask,
948 &gstate->ctm_inverse);
949 }
950
951 /* We need to take a copy of the clip so that the lower layers may modify it
952 * by, perhaps, intersecting it with the operation extents and other paths.
953 */
954 #define _gstate_get_clip(G, C) _cairo_clip_init_copy ((C), &(G)->clip)
955
956 static cairo_bool_t
_clipped(cairo_gstate_t * gstate)957 _clipped (cairo_gstate_t *gstate)
958 {
959 cairo_rectangle_int_t extents;
960
961 if (gstate->clip.all_clipped)
962 return TRUE;
963
964 /* XXX consider applying a surface clip? */
965
966 if (gstate->clip.path == NULL)
967 return FALSE;
968
969 if (_cairo_surface_get_extents (gstate->target, &extents)) {
970 if (extents.width == 0 || extents.height == 0)
971 return TRUE;
972
973 if (! _cairo_rectangle_intersect (&extents,
974 &gstate->clip.path->extents))
975 {
976 return TRUE;
977 }
978 }
979
980 /* perform a simple query to exclude trivial all-clipped cases */
981 return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO;
982 }
983
984 static cairo_operator_t
_reduce_op(cairo_gstate_t * gstate)985 _reduce_op (cairo_gstate_t *gstate)
986 {
987 cairo_operator_t op;
988 const cairo_pattern_t *pattern;
989
990 op = gstate->op;
991 if (op != CAIRO_OPERATOR_SOURCE)
992 return op;
993
994 pattern = gstate->source;
995 if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
996 const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
997 if (solid->color.alpha_short <= 0x00ff) {
998 op = CAIRO_OPERATOR_CLEAR;
999 } else if ((gstate->target->content & CAIRO_CONTENT_ALPHA) == 0) {
1000 if ((solid->color.red_short |
1001 solid->color.green_short |
1002 solid->color.blue_short) <= 0x00ff)
1003 {
1004 op = CAIRO_OPERATOR_CLEAR;
1005 }
1006 }
1007 } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1008 const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
1009 if (surface->surface->is_clear &&
1010 surface->surface->content & CAIRO_CONTENT_ALPHA)
1011 {
1012 op = CAIRO_OPERATOR_CLEAR;
1013 }
1014 } else {
1015 const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
1016 if (gradient->n_stops == 0)
1017 op = CAIRO_OPERATOR_CLEAR;
1018 }
1019
1020 return op;
1021 }
1022
1023 cairo_status_t
_cairo_gstate_paint(cairo_gstate_t * gstate)1024 _cairo_gstate_paint (cairo_gstate_t *gstate)
1025 {
1026 cairo_pattern_union_t source_pattern;
1027 const cairo_pattern_t *pattern;
1028 cairo_clip_t clip;
1029 cairo_status_t status;
1030 cairo_operator_t op;
1031
1032 if (unlikely (gstate->source->status))
1033 return gstate->source->status;
1034
1035 if (gstate->op == CAIRO_OPERATOR_DEST)
1036 return CAIRO_STATUS_SUCCESS;
1037
1038 if (_clipped (gstate))
1039 return CAIRO_STATUS_SUCCESS;
1040
1041 op = _reduce_op (gstate);
1042 if (op == CAIRO_OPERATOR_CLEAR) {
1043 pattern = &_cairo_pattern_clear.base;
1044 } else {
1045 _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1046 pattern = &source_pattern.base;
1047 }
1048
1049 status = _cairo_surface_paint (gstate->target,
1050 op, pattern,
1051 _gstate_get_clip (gstate, &clip));
1052 _cairo_clip_fini (&clip);
1053
1054 return status;
1055 }
1056
1057 cairo_status_t
_cairo_gstate_mask(cairo_gstate_t * gstate,cairo_pattern_t * mask)1058 _cairo_gstate_mask (cairo_gstate_t *gstate,
1059 cairo_pattern_t *mask)
1060 {
1061 cairo_pattern_union_t source_pattern, mask_pattern;
1062 const cairo_pattern_t *source;
1063 cairo_operator_t op;
1064 cairo_clip_t clip;
1065 cairo_status_t status;
1066
1067 if (unlikely (mask->status))
1068 return mask->status;
1069
1070 if (unlikely (gstate->source->status))
1071 return gstate->source->status;
1072
1073 if (gstate->op == CAIRO_OPERATOR_DEST)
1074 return CAIRO_STATUS_SUCCESS;
1075
1076 if (_clipped (gstate))
1077 return CAIRO_STATUS_SUCCESS;
1078
1079 if (_cairo_pattern_is_opaque (mask, NULL))
1080 return _cairo_gstate_paint (gstate);
1081
1082 if (_cairo_pattern_is_clear (mask) &&
1083 _cairo_operator_bounded_by_mask (gstate->op))
1084 {
1085 return CAIRO_STATUS_SUCCESS;
1086 }
1087
1088 op = _reduce_op (gstate);
1089 if (op == CAIRO_OPERATOR_CLEAR) {
1090 source = &_cairo_pattern_clear.base;
1091 } else {
1092 _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1093 source = &source_pattern.base;
1094 }
1095 _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
1096
1097 if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
1098 mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
1099 _cairo_operator_bounded_by_source (op))
1100 {
1101 const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
1102 cairo_color_t combined;
1103
1104 if (mask_pattern.base.has_component_alpha) {
1105 #define M(R, A, B, c) R.c = A.c * B.c
1106 M(combined, solid->color, mask_pattern.solid.color, red);
1107 M(combined, solid->color, mask_pattern.solid.color, green);
1108 M(combined, solid->color, mask_pattern.solid.color, blue);
1109 M(combined, solid->color, mask_pattern.solid.color, alpha);
1110 #undef M
1111 } else {
1112 combined = solid->color;
1113 _cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
1114 }
1115
1116 _cairo_pattern_init_solid (&source_pattern.solid, &combined);
1117
1118 status = _cairo_surface_paint (gstate->target, op,
1119 &source_pattern.base,
1120 _gstate_get_clip (gstate, &clip));
1121 }
1122 else
1123 {
1124 status = _cairo_surface_mask (gstate->target, op,
1125 source,
1126 &mask_pattern.base,
1127 _gstate_get_clip (gstate, &clip));
1128 }
1129 _cairo_clip_fini (&clip);
1130
1131 return status;
1132 }
1133
1134 cairo_status_t
_cairo_gstate_stroke(cairo_gstate_t * gstate,cairo_path_fixed_t * path)1135 _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
1136 {
1137 cairo_pattern_union_t source_pattern;
1138 cairo_stroke_style_t style;
1139 double dash[2];
1140 cairo_clip_t clip;
1141 cairo_status_t status;
1142
1143 if (unlikely (gstate->source->status))
1144 return gstate->source->status;
1145
1146 if (gstate->op == CAIRO_OPERATOR_DEST)
1147 return CAIRO_STATUS_SUCCESS;
1148
1149 if (gstate->stroke_style.line_width <= 0.0)
1150 return CAIRO_STATUS_SUCCESS;
1151
1152 if (_clipped (gstate))
1153 return CAIRO_STATUS_SUCCESS;
1154
1155 memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style));
1156 if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) {
1157 style.dash = dash;
1158 _cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance,
1159 &style.dash_offset,
1160 style.dash,
1161 &style.num_dashes);
1162 }
1163
1164 _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1165
1166 status = _cairo_surface_stroke (gstate->target,
1167 gstate->op,
1168 &source_pattern.base,
1169 path,
1170 &style,
1171 &gstate->ctm,
1172 &gstate->ctm_inverse,
1173 gstate->tolerance,
1174 gstate->antialias,
1175 _gstate_get_clip (gstate, &clip));
1176 _cairo_clip_fini (&clip);
1177
1178 return status;
1179 }
1180
1181 cairo_status_t
_cairo_gstate_in_stroke(cairo_gstate_t * gstate,cairo_path_fixed_t * path,double x,double y,cairo_bool_t * inside_ret)1182 _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
1183 cairo_path_fixed_t *path,
1184 double x,
1185 double y,
1186 cairo_bool_t *inside_ret)
1187 {
1188 cairo_status_t status;
1189 cairo_rectangle_int_t extents;
1190 cairo_box_t limit;
1191 cairo_traps_t traps;
1192
1193 if (gstate->stroke_style.line_width <= 0.0) {
1194 *inside_ret = FALSE;
1195 return CAIRO_STATUS_SUCCESS;
1196 }
1197
1198 _cairo_gstate_user_to_backend (gstate, &x, &y);
1199
1200 /* Before we perform the expensive stroke analysis,
1201 * check whether the point is within the extents of the path.
1202 */
1203 _cairo_path_fixed_approximate_stroke_extents (path,
1204 &gstate->stroke_style,
1205 &gstate->ctm,
1206 &extents);
1207 if (x < extents.x || x > extents.x + extents.width ||
1208 y < extents.y || y > extents.y + extents.height)
1209 {
1210 *inside_ret = FALSE;
1211 return CAIRO_STATUS_SUCCESS;
1212 }
1213
1214 limit.p1.x = _cairo_fixed_from_double (x) - 5;
1215 limit.p1.y = _cairo_fixed_from_double (y) - 5;
1216 limit.p2.x = limit.p1.x + 10;
1217 limit.p2.y = limit.p1.y + 10;
1218
1219 _cairo_traps_init (&traps);
1220 _cairo_traps_limit (&traps, &limit, 1);
1221
1222 status = _cairo_path_fixed_stroke_to_traps (path,
1223 &gstate->stroke_style,
1224 &gstate->ctm,
1225 &gstate->ctm_inverse,
1226 gstate->tolerance,
1227 &traps);
1228 if (unlikely (status))
1229 goto BAIL;
1230
1231 *inside_ret = _cairo_traps_contain (&traps, x, y);
1232
1233 BAIL:
1234 _cairo_traps_fini (&traps);
1235
1236 return status;
1237 }
1238
1239 cairo_status_t
_cairo_gstate_fill(cairo_gstate_t * gstate,cairo_path_fixed_t * path)1240 _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
1241 {
1242 cairo_clip_t clip;
1243 cairo_status_t status;
1244
1245 if (unlikely (gstate->source->status))
1246 return gstate->source->status;
1247
1248 if (gstate->op == CAIRO_OPERATOR_DEST)
1249 return CAIRO_STATUS_SUCCESS;
1250
1251 if (_clipped (gstate))
1252 return CAIRO_STATUS_SUCCESS;
1253
1254 if (_cairo_path_fixed_fill_is_empty (path)) {
1255 if (_cairo_operator_bounded_by_mask (gstate->op))
1256 return CAIRO_STATUS_SUCCESS;
1257
1258 status = _cairo_surface_paint (gstate->target,
1259 CAIRO_OPERATOR_CLEAR,
1260 &_cairo_pattern_clear.base,
1261 _gstate_get_clip (gstate, &clip));
1262 } else {
1263 cairo_pattern_union_t source_pattern;
1264 const cairo_pattern_t *pattern;
1265 cairo_operator_t op;
1266 cairo_rectangle_int_t extents;
1267 cairo_box_t box;
1268
1269 op = _reduce_op (gstate);
1270 if (op == CAIRO_OPERATOR_CLEAR) {
1271 pattern = &_cairo_pattern_clear.base;
1272 } else {
1273 _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1274 pattern = &source_pattern.base;
1275 }
1276
1277 /* Toolkits often paint the entire background with a fill */
1278 if (_cairo_surface_get_extents (gstate->target, &extents) &&
1279 _cairo_path_fixed_is_box (path, &box) &&
1280 box.p1.x <= _cairo_fixed_from_int (extents.x) &&
1281 box.p1.y <= _cairo_fixed_from_int (extents.y) &&
1282 box.p2.x >= _cairo_fixed_from_int (extents.x + extents.width) &&
1283 box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height))
1284 {
1285 status = _cairo_surface_paint (gstate->target, op, pattern,
1286 _gstate_get_clip (gstate, &clip));
1287 }
1288 else
1289 {
1290 status = _cairo_surface_fill (gstate->target, op, pattern,
1291 path,
1292 gstate->fill_rule,
1293 gstate->tolerance,
1294 gstate->antialias,
1295 _gstate_get_clip (gstate, &clip));
1296 }
1297 }
1298
1299 _cairo_clip_fini (&clip);
1300
1301 return status;
1302 }
1303
1304 cairo_bool_t
_cairo_gstate_in_fill(cairo_gstate_t * gstate,cairo_path_fixed_t * path,double x,double y)1305 _cairo_gstate_in_fill (cairo_gstate_t *gstate,
1306 cairo_path_fixed_t *path,
1307 double x,
1308 double y)
1309 {
1310 _cairo_gstate_user_to_backend (gstate, &x, &y);
1311
1312 return _cairo_path_fixed_in_fill (path,
1313 gstate->fill_rule,
1314 gstate->tolerance,
1315 x, y);
1316 }
1317
1318 cairo_bool_t
_cairo_gstate_in_clip(cairo_gstate_t * gstate,double x,double y)1319 _cairo_gstate_in_clip (cairo_gstate_t *gstate,
1320 double x,
1321 double y)
1322 {
1323 cairo_clip_path_t *clip_path;
1324
1325 if (gstate->clip.all_clipped)
1326 return FALSE;
1327
1328 clip_path = gstate->clip.path;
1329 if (clip_path == NULL)
1330 return TRUE;
1331
1332 _cairo_gstate_user_to_backend (gstate, &x, &y);
1333
1334 if (x < clip_path->extents.x ||
1335 x >= clip_path->extents.x + clip_path->extents.width ||
1336 y < clip_path->extents.y ||
1337 y >= clip_path->extents.y + clip_path->extents.height)
1338 {
1339 return FALSE;
1340 }
1341
1342 do {
1343 if (! _cairo_path_fixed_in_fill (&clip_path->path,
1344 clip_path->fill_rule,
1345 clip_path->tolerance,
1346 x, y))
1347 return FALSE;
1348 } while ((clip_path = clip_path->prev) != NULL);
1349
1350 return TRUE;
1351 }
1352
1353 cairo_status_t
_cairo_gstate_copy_page(cairo_gstate_t * gstate)1354 _cairo_gstate_copy_page (cairo_gstate_t *gstate)
1355 {
1356 cairo_surface_copy_page (gstate->target);
1357 return cairo_surface_status (gstate->target);
1358 }
1359
1360 cairo_status_t
_cairo_gstate_show_page(cairo_gstate_t * gstate)1361 _cairo_gstate_show_page (cairo_gstate_t *gstate)
1362 {
1363 cairo_surface_show_page (gstate->target);
1364 return cairo_surface_status (gstate->target);
1365 }
1366
1367 static void
_cairo_gstate_traps_extents_to_user_rectangle(cairo_gstate_t * gstate,cairo_traps_t * traps,double * x1,double * y1,double * x2,double * y2)1368 _cairo_gstate_traps_extents_to_user_rectangle (cairo_gstate_t *gstate,
1369 cairo_traps_t *traps,
1370 double *x1, double *y1,
1371 double *x2, double *y2)
1372 {
1373 cairo_box_t extents;
1374
1375 if (traps->num_traps == 0) {
1376 /* no traps, so we actually won't draw anything */
1377 if (x1)
1378 *x1 = 0.0;
1379 if (y1)
1380 *y1 = 0.0;
1381 if (x2)
1382 *x2 = 0.0;
1383 if (y2)
1384 *y2 = 0.0;
1385 } else {
1386 double px1, py1, px2, py2;
1387
1388 _cairo_traps_extents (traps, &extents);
1389
1390 px1 = _cairo_fixed_to_double (extents.p1.x);
1391 py1 = _cairo_fixed_to_double (extents.p1.y);
1392 px2 = _cairo_fixed_to_double (extents.p2.x);
1393 py2 = _cairo_fixed_to_double (extents.p2.y);
1394
1395 _cairo_gstate_backend_to_user_rectangle (gstate,
1396 &px1, &py1, &px2, &py2,
1397 NULL);
1398 if (x1)
1399 *x1 = px1;
1400 if (y1)
1401 *y1 = py1;
1402 if (x2)
1403 *x2 = px2;
1404 if (y2)
1405 *y2 = py2;
1406 }
1407 }
1408
1409 cairo_status_t
_cairo_gstate_stroke_extents(cairo_gstate_t * gstate,cairo_path_fixed_t * path,double * x1,double * y1,double * x2,double * y2)1410 _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
1411 cairo_path_fixed_t *path,
1412 double *x1, double *y1,
1413 double *x2, double *y2)
1414 {
1415 cairo_status_t status;
1416 cairo_traps_t traps;
1417
1418 if (gstate->stroke_style.line_width <= 0.0) {
1419 if (x1)
1420 *x1 = 0.0;
1421 if (y1)
1422 *y1 = 0.0;
1423 if (x2)
1424 *x2 = 0.0;
1425 if (y2)
1426 *y2 = 0.0;
1427 return CAIRO_STATUS_SUCCESS;
1428 }
1429
1430 _cairo_traps_init (&traps);
1431
1432 status = _cairo_path_fixed_stroke_to_traps (path,
1433 &gstate->stroke_style,
1434 &gstate->ctm,
1435 &gstate->ctm_inverse,
1436 gstate->tolerance,
1437 &traps);
1438 if (likely (status == CAIRO_STATUS_SUCCESS)) {
1439 _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
1440 x1, y1, x2, y2);
1441 }
1442
1443 _cairo_traps_fini (&traps);
1444
1445 return status;
1446 }
1447
1448 cairo_status_t
_cairo_gstate_fill_extents(cairo_gstate_t * gstate,cairo_path_fixed_t * path,double * x1,double * y1,double * x2,double * y2)1449 _cairo_gstate_fill_extents (cairo_gstate_t *gstate,
1450 cairo_path_fixed_t *path,
1451 double *x1, double *y1,
1452 double *x2, double *y2)
1453 {
1454 cairo_status_t status;
1455 cairo_traps_t traps;
1456
1457 if (path->is_empty_fill) {
1458 if (x1)
1459 *x1 = 0.0;
1460 if (y1)
1461 *y1 = 0.0;
1462 if (x2)
1463 *x2 = 0.0;
1464 if (y2)
1465 *y2 = 0.0;
1466 return CAIRO_STATUS_SUCCESS;
1467 }
1468
1469 _cairo_traps_init (&traps);
1470
1471 status = _cairo_path_fixed_fill_to_traps (path,
1472 gstate->fill_rule,
1473 gstate->tolerance,
1474 &traps);
1475 if (likely (status == CAIRO_STATUS_SUCCESS)) {
1476 _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
1477 x1, y1, x2, y2);
1478 }
1479
1480 _cairo_traps_fini (&traps);
1481
1482 return status;
1483 }
1484
1485 cairo_status_t
_cairo_gstate_reset_clip(cairo_gstate_t * gstate)1486 _cairo_gstate_reset_clip (cairo_gstate_t *gstate)
1487 {
1488 _cairo_clip_reset (&gstate->clip);
1489
1490 return CAIRO_STATUS_SUCCESS;
1491 }
1492
1493 cairo_status_t
_cairo_gstate_clip(cairo_gstate_t * gstate,cairo_path_fixed_t * path)1494 _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
1495 {
1496 return _cairo_clip_clip (&gstate->clip,
1497 path, gstate->fill_rule,
1498 gstate->tolerance, gstate->antialias);
1499 }
1500
1501 static cairo_bool_t
_cairo_gstate_int_clip_extents(cairo_gstate_t * gstate,cairo_rectangle_int_t * extents)1502 _cairo_gstate_int_clip_extents (cairo_gstate_t *gstate,
1503 cairo_rectangle_int_t *extents)
1504 {
1505 const cairo_rectangle_int_t *clip_extents;
1506 cairo_bool_t is_bounded;
1507
1508 is_bounded = _cairo_surface_get_extents (gstate->target, extents);
1509
1510 clip_extents = _cairo_clip_get_extents (&gstate->clip);
1511 if (clip_extents != NULL) {
1512 cairo_bool_t is_empty;
1513
1514 is_empty = _cairo_rectangle_intersect (extents, clip_extents);
1515 is_bounded = TRUE;
1516 }
1517
1518 return is_bounded;
1519 }
1520
1521 cairo_bool_t
_cairo_gstate_clip_extents(cairo_gstate_t * gstate,double * x1,double * y1,double * x2,double * y2)1522 _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
1523 double *x1,
1524 double *y1,
1525 double *x2,
1526 double *y2)
1527 {
1528 cairo_rectangle_int_t extents;
1529 double px1, py1, px2, py2;
1530
1531 if (! _cairo_gstate_int_clip_extents (gstate, &extents))
1532 return FALSE;
1533
1534 px1 = extents.x;
1535 py1 = extents.y;
1536 px2 = extents.x + (int) extents.width;
1537 py2 = extents.y + (int) extents.height;
1538
1539 _cairo_gstate_backend_to_user_rectangle (gstate,
1540 &px1, &py1, &px2, &py2,
1541 NULL);
1542
1543 if (x1)
1544 *x1 = px1;
1545 if (y1)
1546 *y1 = py1;
1547 if (x2)
1548 *x2 = px2;
1549 if (y2)
1550 *y2 = py2;
1551
1552 return TRUE;
1553 }
1554
1555 cairo_rectangle_list_t*
_cairo_gstate_copy_clip_rectangle_list(cairo_gstate_t * gstate)1556 _cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate)
1557 {
1558 cairo_clip_t clip;
1559 cairo_rectangle_int_t extents;
1560 cairo_rectangle_list_t *list;
1561
1562 _cairo_clip_init_copy (&clip, &gstate->clip);
1563
1564 if (_cairo_surface_get_extents (gstate->target, &extents))
1565 _cairo_clip_rectangle (&clip, &extents);
1566
1567 list = _cairo_clip_copy_rectangle_list (&clip, gstate);
1568 _cairo_clip_fini (&clip);
1569
1570 return list;
1571 }
1572
1573 static void
_cairo_gstate_unset_scaled_font(cairo_gstate_t * gstate)1574 _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
1575 {
1576 if (gstate->scaled_font == NULL)
1577 return;
1578
1579 if (gstate->previous_scaled_font != NULL)
1580 cairo_scaled_font_destroy (gstate->previous_scaled_font);
1581
1582 gstate->previous_scaled_font = gstate->scaled_font;
1583 gstate->scaled_font = NULL;
1584 }
1585
1586 cairo_status_t
_cairo_gstate_select_font_face(cairo_gstate_t * gstate,const char * family,cairo_font_slant_t slant,cairo_font_weight_t weight)1587 _cairo_gstate_select_font_face (cairo_gstate_t *gstate,
1588 const char *family,
1589 cairo_font_slant_t slant,
1590 cairo_font_weight_t weight)
1591 {
1592 cairo_font_face_t *font_face;
1593 cairo_status_t status;
1594
1595 font_face = cairo_toy_font_face_create (family, slant, weight);
1596 if (font_face->status)
1597 return font_face->status;
1598
1599 status = _cairo_gstate_set_font_face (gstate, font_face);
1600 cairo_font_face_destroy (font_face);
1601
1602 return status;
1603 }
1604
1605 cairo_status_t
_cairo_gstate_set_font_size(cairo_gstate_t * gstate,double size)1606 _cairo_gstate_set_font_size (cairo_gstate_t *gstate,
1607 double size)
1608 {
1609 _cairo_gstate_unset_scaled_font (gstate);
1610
1611 cairo_matrix_init_scale (&gstate->font_matrix, size, size);
1612
1613 return CAIRO_STATUS_SUCCESS;
1614 }
1615
1616 cairo_status_t
_cairo_gstate_set_font_matrix(cairo_gstate_t * gstate,const cairo_matrix_t * matrix)1617 _cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
1618 const cairo_matrix_t *matrix)
1619 {
1620 if (memcmp (matrix, &gstate->font_matrix, sizeof (cairo_matrix_t)) == 0)
1621 return CAIRO_STATUS_SUCCESS;
1622
1623 if (! _cairo_matrix_is_invertible (matrix)) {
1624 /* rank 0 matrices are ok even though they are not invertible */
1625 if (!(matrix->xx == 0. && matrix->xy == 0. &&
1626 matrix->yx == 0. && matrix->yy == 0.)) {
1627 return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
1628 }
1629 }
1630
1631 _cairo_gstate_unset_scaled_font (gstate);
1632
1633 gstate->font_matrix = *matrix;
1634
1635 return CAIRO_STATUS_SUCCESS;
1636 }
1637
1638 void
_cairo_gstate_get_font_matrix(cairo_gstate_t * gstate,cairo_matrix_t * matrix)1639 _cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
1640 cairo_matrix_t *matrix)
1641 {
1642 *matrix = gstate->font_matrix;
1643 }
1644
1645 void
_cairo_gstate_set_font_options(cairo_gstate_t * gstate,const cairo_font_options_t * options)1646 _cairo_gstate_set_font_options (cairo_gstate_t *gstate,
1647 const cairo_font_options_t *options)
1648 {
1649 if (memcmp (options, &gstate->font_options, sizeof (cairo_font_options_t)) == 0)
1650 return;
1651
1652 _cairo_gstate_unset_scaled_font (gstate);
1653
1654 _cairo_font_options_init_copy (&gstate->font_options, options);
1655 }
1656
1657 void
_cairo_gstate_get_font_options(cairo_gstate_t * gstate,cairo_font_options_t * options)1658 _cairo_gstate_get_font_options (cairo_gstate_t *gstate,
1659 cairo_font_options_t *options)
1660 {
1661 *options = gstate->font_options;
1662 }
1663
1664 cairo_status_t
_cairo_gstate_get_font_face(cairo_gstate_t * gstate,cairo_font_face_t ** font_face)1665 _cairo_gstate_get_font_face (cairo_gstate_t *gstate,
1666 cairo_font_face_t **font_face)
1667 {
1668 cairo_status_t status;
1669
1670 status = _cairo_gstate_ensure_font_face (gstate);
1671 if (unlikely (status))
1672 return status;
1673
1674 *font_face = gstate->font_face;
1675
1676 return CAIRO_STATUS_SUCCESS;
1677 }
1678
1679 cairo_status_t
_cairo_gstate_get_scaled_font(cairo_gstate_t * gstate,cairo_scaled_font_t ** scaled_font)1680 _cairo_gstate_get_scaled_font (cairo_gstate_t *gstate,
1681 cairo_scaled_font_t **scaled_font)
1682 {
1683 cairo_status_t status;
1684
1685 status = _cairo_gstate_ensure_scaled_font (gstate);
1686 if (unlikely (status))
1687 return status;
1688
1689 *scaled_font = gstate->scaled_font;
1690
1691 return CAIRO_STATUS_SUCCESS;
1692 }
1693
1694 /*
1695 * Like everything else in this file, fonts involve Too Many Coordinate Spaces;
1696 * it is easy to get confused about what's going on.
1697 *
1698 * The user's view
1699 * ---------------
1700 *
1701 * Users ask for things in user space. When cairo starts, a user space unit
1702 * is about 1/96 inch, which is similar to (but importantly different from)
1703 * the normal "point" units most users think in terms of. When a user
1704 * selects a font, its scale is set to "one user unit". The user can then
1705 * independently scale the user coordinate system *or* the font matrix, in
1706 * order to adjust the rendered size of the font.
1707 *
1708 * Metrics are returned in user space, whether they are obtained from
1709 * the currently selected font in a #cairo_t or from a #cairo_scaled_font_t
1710 * which is a font specialized to a particular scale matrix, CTM, and target
1711 * surface.
1712 *
1713 * The font's view
1714 * ---------------
1715 *
1716 * Fonts are designed and stored (in say .ttf files) in "font space", which
1717 * describes an "EM Square" (a design tile) and has some abstract number
1718 * such as 1000, 1024, or 2048 units per "EM". This is basically an
1719 * uninteresting space for us, but we need to remember that it exists.
1720 *
1721 * Font resources (from libraries or operating systems) render themselves
1722 * to a particular device. Since they do not want to make most programmers
1723 * worry about the font design space, the scaling API is simplified to
1724 * involve just telling the font the required pixel size of the EM square
1725 * (that is, in device space).
1726 *
1727 *
1728 * Cairo's gstate view
1729 * -------------------
1730 *
1731 * In addition to the CTM and CTM inverse, we keep a matrix in the gstate
1732 * called the "font matrix" which describes the user's most recent
1733 * font-scaling or font-transforming request. This is kept in terms of an
1734 * abstract scale factor, composed with the CTM and used to set the font's
1735 * pixel size. So if the user asks to "scale the font by 12", the matrix
1736 * is:
1737 *
1738 * [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ]
1739 *
1740 * It is an affine matrix, like all cairo matrices, where its tx and ty
1741 * components are used to "nudging" fonts around and are handled in gstate
1742 * and then ignored by the "scaled-font" layer.
1743 *
1744 * In order to perform any action on a font, we must build an object
1745 * called a #cairo_font_scale_t; this contains the central 2x2 matrix
1746 * resulting from "font matrix * CTM" (sans the font matrix translation
1747 * components as stated in the previous paragraph).
1748 *
1749 * We pass this to the font when making requests of it, which causes it to
1750 * reply for a particular [user request, device] combination, under the CTM
1751 * (to accommodate the "zoom in" == "bigger fonts" issue above).
1752 *
1753 * The other terms in our communication with the font are therefore in
1754 * device space. When we ask it to perform text->glyph conversion, it will
1755 * produce a glyph string in device space. Glyph vectors we pass to it for
1756 * measuring or rendering should be in device space. The metrics which we
1757 * get back from the font will be in device space. The contents of the
1758 * global glyph image cache will be in device space.
1759 *
1760 *
1761 * Cairo's public view
1762 * -------------------
1763 *
1764 * Since the values entering and leaving via public API calls are in user
1765 * space, the gstate functions typically need to multiply arguments by the
1766 * CTM (for user-input glyph vectors), and return values by the CTM inverse
1767 * (for font responses such as metrics or glyph vectors).
1768 *
1769 */
1770
1771 static cairo_status_t
_cairo_gstate_ensure_font_face(cairo_gstate_t * gstate)1772 _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
1773 {
1774 cairo_font_face_t *font_face;
1775
1776 if (gstate->font_face != NULL)
1777 return gstate->font_face->status;
1778
1779
1780 font_face = cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
1781 CAIRO_FONT_SLANT_DEFAULT,
1782 CAIRO_FONT_WEIGHT_DEFAULT);
1783 if (font_face->status)
1784 return font_face->status;
1785
1786 gstate->font_face = font_face;
1787
1788 return CAIRO_STATUS_SUCCESS;
1789 }
1790
1791 static cairo_status_t
_cairo_gstate_ensure_scaled_font(cairo_gstate_t * gstate)1792 _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
1793 {
1794 cairo_status_t status;
1795 cairo_font_options_t options;
1796 cairo_scaled_font_t *scaled_font;
1797
1798 if (gstate->scaled_font != NULL)
1799 return gstate->scaled_font->status;
1800
1801 status = _cairo_gstate_ensure_font_face (gstate);
1802 if (unlikely (status))
1803 return status;
1804
1805 cairo_surface_get_font_options (gstate->target, &options);
1806 cairo_font_options_merge (&options, &gstate->font_options);
1807
1808 scaled_font = cairo_scaled_font_create (gstate->font_face,
1809 &gstate->font_matrix,
1810 &gstate->ctm,
1811 &options);
1812
1813 status = cairo_scaled_font_status (scaled_font);
1814 if (unlikely (status))
1815 return status;
1816
1817 gstate->scaled_font = scaled_font;
1818
1819 return CAIRO_STATUS_SUCCESS;
1820 }
1821
1822 cairo_status_t
_cairo_gstate_get_font_extents(cairo_gstate_t * gstate,cairo_font_extents_t * extents)1823 _cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
1824 cairo_font_extents_t *extents)
1825 {
1826 cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate);
1827 if (unlikely (status))
1828 return status;
1829
1830 cairo_scaled_font_extents (gstate->scaled_font, extents);
1831
1832 return cairo_scaled_font_status (gstate->scaled_font);
1833 }
1834
1835 cairo_status_t
_cairo_gstate_text_to_glyphs(cairo_gstate_t * gstate,double x,double y,const char * utf8,int utf8_len,cairo_glyph_t ** glyphs,int * num_glyphs,cairo_text_cluster_t ** clusters,int * num_clusters,cairo_text_cluster_flags_t * cluster_flags)1836 _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
1837 double x,
1838 double y,
1839 const char *utf8,
1840 int utf8_len,
1841 cairo_glyph_t **glyphs,
1842 int *num_glyphs,
1843 cairo_text_cluster_t **clusters,
1844 int *num_clusters,
1845 cairo_text_cluster_flags_t *cluster_flags)
1846 {
1847 cairo_status_t status;
1848
1849 status = _cairo_gstate_ensure_scaled_font (gstate);
1850 if (unlikely (status))
1851 return status;
1852
1853 return cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y,
1854 utf8, utf8_len,
1855 glyphs, num_glyphs,
1856 clusters, num_clusters,
1857 cluster_flags);
1858 }
1859
1860 cairo_status_t
_cairo_gstate_set_font_face(cairo_gstate_t * gstate,cairo_font_face_t * font_face)1861 _cairo_gstate_set_font_face (cairo_gstate_t *gstate,
1862 cairo_font_face_t *font_face)
1863 {
1864 if (font_face && font_face->status)
1865 return _cairo_error (font_face->status);
1866
1867 if (font_face == gstate->font_face)
1868 return CAIRO_STATUS_SUCCESS;
1869
1870 cairo_font_face_destroy (gstate->font_face);
1871 gstate->font_face = cairo_font_face_reference (font_face);
1872
1873 _cairo_gstate_unset_scaled_font (gstate);
1874
1875 return CAIRO_STATUS_SUCCESS;
1876 }
1877
1878 cairo_status_t
_cairo_gstate_glyph_extents(cairo_gstate_t * gstate,const cairo_glyph_t * glyphs,int num_glyphs,cairo_text_extents_t * extents)1879 _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
1880 const cairo_glyph_t *glyphs,
1881 int num_glyphs,
1882 cairo_text_extents_t *extents)
1883 {
1884 cairo_status_t status;
1885
1886 status = _cairo_gstate_ensure_scaled_font (gstate);
1887 if (unlikely (status))
1888 return status;
1889
1890 cairo_scaled_font_glyph_extents (gstate->scaled_font,
1891 glyphs, num_glyphs,
1892 extents);
1893
1894 return cairo_scaled_font_status (gstate->scaled_font);
1895 }
1896
1897 cairo_status_t
_cairo_gstate_show_text_glyphs(cairo_gstate_t * gstate,const char * utf8,int utf8_len,const cairo_glyph_t * glyphs,int num_glyphs,const cairo_text_cluster_t * clusters,int num_clusters,cairo_text_cluster_flags_t cluster_flags)1898 _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
1899 const char *utf8,
1900 int utf8_len,
1901 const cairo_glyph_t *glyphs,
1902 int num_glyphs,
1903 const cairo_text_cluster_t *clusters,
1904 int num_clusters,
1905 cairo_text_cluster_flags_t cluster_flags)
1906 {
1907 cairo_pattern_union_t source_pattern;
1908 const cairo_pattern_t *pattern;
1909 cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
1910 cairo_glyph_t *transformed_glyphs;
1911 cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
1912 cairo_text_cluster_t *transformed_clusters;
1913 cairo_operator_t op;
1914 cairo_status_t status;
1915 cairo_clip_t clip;
1916
1917 if (unlikely (gstate->source->status))
1918 return gstate->source->status;
1919
1920 if (gstate->op == CAIRO_OPERATOR_DEST)
1921 return CAIRO_STATUS_SUCCESS;
1922
1923 if (_clipped (gstate))
1924 return CAIRO_STATUS_SUCCESS;
1925
1926 status = _cairo_gstate_ensure_scaled_font (gstate);
1927 if (unlikely (status))
1928 return status;
1929
1930 transformed_glyphs = stack_transformed_glyphs;
1931 transformed_clusters = stack_transformed_clusters;
1932
1933 if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) {
1934 transformed_glyphs = cairo_glyph_allocate (num_glyphs);
1935 if (unlikely (transformed_glyphs == NULL)) {
1936 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1937 goto CLEANUP_GLYPHS;
1938 }
1939 }
1940
1941 /* Just in case */
1942 if (!clusters)
1943 num_clusters = 0;
1944
1945 if (num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
1946 transformed_clusters = cairo_text_cluster_allocate (num_clusters);
1947 if (unlikely (transformed_clusters == NULL)) {
1948 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1949 goto CLEANUP_GLYPHS;
1950 }
1951 }
1952
1953 status = _cairo_gstate_transform_glyphs_to_backend (gstate,
1954 glyphs, num_glyphs,
1955 clusters,
1956 num_clusters,
1957 cluster_flags,
1958 transformed_glyphs,
1959 &num_glyphs,
1960 transformed_clusters);
1961
1962 if (status || num_glyphs == 0)
1963 goto CLEANUP_GLYPHS;
1964
1965 op = _reduce_op (gstate);
1966 if (op == CAIRO_OPERATOR_CLEAR) {
1967 pattern = &_cairo_pattern_clear.base;
1968 } else {
1969 _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1970 pattern = &source_pattern.base;
1971 }
1972 _cairo_clip_init(&clip);
1973
1974 /* For really huge font sizes, we can just do path;fill instead of
1975 * show_glyphs, as show_glyphs would put excess pressure on the cache,
1976 * not all components below us correctly handle huge font sizes, and
1977 * path filling can be cheaper since parts of glyphs are likely to be
1978 * clipped out. 256 seems like a good limit. But alas, seems like cairo's
1979 * rasterizer is something like ten times slower than freetype's for huge
1980 * sizes. So, no win just yet when we're using cairo's rasterizer.
1981 * For now, if we're using cairo's rasterizer, use path filling only
1982 * for insanely-huge sizes, just to make sure we don't make anyone
1983 * unhappy. When we get a really fast rasterizer in cairo, we may
1984 * want to readjust this. The threshold calculation is
1985 * encapsulated in _cairo_surface_get_text_path_fill_threshold.
1986 *
1987 * Needless to say, do this only if show_text_glyphs is not available. */
1988 if (cairo_surface_has_show_text_glyphs (gstate->target) ||
1989 _cairo_scaled_font_get_max_scale (gstate->scaled_font) <=
1990 _cairo_surface_get_text_path_fill_threshold (gstate->target))
1991 {
1992 status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
1993 utf8, utf8_len,
1994 transformed_glyphs, num_glyphs,
1995 transformed_clusters, num_clusters,
1996 cluster_flags,
1997 gstate->scaled_font,
1998 _gstate_get_clip (gstate, &clip));
1999 }
2000 else
2001 {
2002 cairo_path_fixed_t path;
2003
2004 _cairo_path_fixed_init (&path);
2005
2006 status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
2007 transformed_glyphs, num_glyphs,
2008 &path);
2009
2010 if (status == CAIRO_STATUS_SUCCESS && !_cairo_path_fixed_fill_is_empty (&path)) {
2011 status = _cairo_surface_fill (gstate->target, op, pattern,
2012 &path,
2013 CAIRO_FILL_RULE_WINDING,
2014 gstate->tolerance,
2015 gstate->scaled_font->options.antialias,
2016 _gstate_get_clip (gstate, &clip));
2017 } else {
2018 /* if _cairo_scaled_font_glyph_path() failed, maybe the font doesn't support
2019 * returning paths, so try the _cairo_surface_show_text_glyphs() option
2020 */
2021 status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern,
2022 utf8, utf8_len,
2023 transformed_glyphs, num_glyphs,
2024 transformed_clusters, num_clusters,
2025 cluster_flags,
2026 gstate->scaled_font,
2027 _gstate_get_clip (gstate, &clip));
2028 }
2029
2030 _cairo_path_fixed_fini (&path);
2031 }
2032
2033 _cairo_clip_fini (&clip);
2034
2035 CLEANUP_GLYPHS:
2036 if (transformed_glyphs != stack_transformed_glyphs)
2037 cairo_glyph_free (transformed_glyphs);
2038 if (transformed_clusters != stack_transformed_clusters)
2039 cairo_text_cluster_free (transformed_clusters);
2040
2041 return status;
2042 }
2043
2044 cairo_status_t
_cairo_gstate_glyph_path(cairo_gstate_t * gstate,const cairo_glyph_t * glyphs,int num_glyphs,cairo_path_fixed_t * path)2045 _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
2046 const cairo_glyph_t *glyphs,
2047 int num_glyphs,
2048 cairo_path_fixed_t *path)
2049 {
2050 cairo_status_t status;
2051 cairo_glyph_t *transformed_glyphs;
2052 cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
2053
2054 status = _cairo_gstate_ensure_scaled_font (gstate);
2055 if (unlikely (status))
2056 return status;
2057
2058 if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) {
2059 transformed_glyphs = stack_transformed_glyphs;
2060 } else {
2061 transformed_glyphs = cairo_glyph_allocate (num_glyphs);
2062 if (unlikely (transformed_glyphs == NULL))
2063 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2064 }
2065
2066 status = _cairo_gstate_transform_glyphs_to_backend (gstate,
2067 glyphs, num_glyphs,
2068 NULL, 0, 0,
2069 transformed_glyphs,
2070 NULL, NULL);
2071 if (unlikely (status))
2072 goto CLEANUP_GLYPHS;
2073
2074 status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
2075 transformed_glyphs, num_glyphs,
2076 path);
2077
2078 CLEANUP_GLYPHS:
2079 if (transformed_glyphs != stack_transformed_glyphs)
2080 cairo_glyph_free (transformed_glyphs);
2081
2082 return status;
2083 }
2084
2085 cairo_status_t
_cairo_gstate_set_antialias(cairo_gstate_t * gstate,cairo_antialias_t antialias)2086 _cairo_gstate_set_antialias (cairo_gstate_t *gstate,
2087 cairo_antialias_t antialias)
2088 {
2089 gstate->antialias = antialias;
2090
2091 return CAIRO_STATUS_SUCCESS;
2092 }
2093
2094 cairo_antialias_t
_cairo_gstate_get_antialias(cairo_gstate_t * gstate)2095 _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
2096 {
2097 return gstate->antialias;
2098 }
2099
2100 /**
2101 * _cairo_gstate_transform_glyphs_to_backend:
2102 * @gstate: a #cairo_gstate_t
2103 * @glyphs: the array of #cairo_glyph_t objects to be transformed
2104 * @num_glyphs: the number of elements in @glyphs
2105 * @transformed_glyphs: a pre-allocated array of at least @num_glyphs
2106 * #cairo_glyph_t objects
2107 * @num_transformed_glyphs: the number of elements in @transformed_glyphs
2108 * after dropping out of bounds glyphs, or %NULL if glyphs shouldn't be
2109 * dropped
2110 *
2111 * Transform an array of glyphs to backend space by first adding the offset
2112 * of the font matrix, then transforming from user space to backend space.
2113 * The result of the transformation is placed in @transformed_glyphs.
2114 *
2115 * This also uses information from the scaled font and the surface to
2116 * cull/drop glyphs that will not be visible.
2117 **/
2118 static cairo_status_t
_cairo_gstate_transform_glyphs_to_backend(cairo_gstate_t * gstate,const cairo_glyph_t * glyphs,int num_glyphs,const cairo_text_cluster_t * clusters,int num_clusters,cairo_text_cluster_flags_t cluster_flags,cairo_glyph_t * transformed_glyphs,int * num_transformed_glyphs,cairo_text_cluster_t * transformed_clusters)2119 _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
2120 const cairo_glyph_t *glyphs,
2121 int num_glyphs,
2122 const cairo_text_cluster_t *clusters,
2123 int num_clusters,
2124 cairo_text_cluster_flags_t cluster_flags,
2125 cairo_glyph_t *transformed_glyphs,
2126 int *num_transformed_glyphs,
2127 cairo_text_cluster_t *transformed_clusters)
2128 {
2129 int i, j, k;
2130 cairo_matrix_t *ctm = &gstate->ctm;
2131 cairo_matrix_t *font_matrix = &gstate->font_matrix;
2132 cairo_matrix_t *device_transform = &gstate->target->device_transform;
2133 cairo_bool_t drop = FALSE;
2134 double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
2135
2136 if (num_transformed_glyphs != NULL) {
2137 cairo_rectangle_int_t surface_extents;
2138
2139 drop = TRUE;
2140 if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
2141 drop = FALSE; /* unbounded surface */
2142 } else {
2143 double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);
2144 if (surface_extents.width == 0 || surface_extents.height == 0) {
2145 /* No visible area. Don't draw anything */
2146 *num_transformed_glyphs = 0;
2147 return CAIRO_STATUS_SUCCESS;
2148 }
2149 /* XXX We currently drop any glyphs that has its position outside
2150 * of the surface boundaries by a safety margin depending on the
2151 * font scale. This however can fail in extreme cases where the
2152 * font has really long swashes for example... We can correctly
2153 * handle that by looking the glyph up and using its device bbox
2154 * to device if it's going to be visible, but I'm not inclined to
2155 * do that now.
2156 */
2157 x1 = surface_extents.x - scale10;
2158 y1 = surface_extents.y - scale10;
2159 x2 = surface_extents.x + (int) surface_extents.width + scale10;
2160 y2 = surface_extents.y + (int) surface_extents.height + scale10;
2161 }
2162
2163 if (!drop)
2164 *num_transformed_glyphs = num_glyphs;
2165 } else
2166 num_transformed_glyphs = &j;
2167
2168 #define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
2169
2170 j = 0;
2171 if (_cairo_matrix_is_identity (ctm) &&
2172 _cairo_matrix_is_identity (device_transform) &&
2173 font_matrix->x0 == 0 && font_matrix->y0 == 0)
2174 {
2175 if (! drop) {
2176 memcpy (transformed_glyphs, glyphs,
2177 num_glyphs * sizeof (cairo_glyph_t));
2178 j = num_glyphs;
2179 } else if (num_clusters == 0) {
2180 for (i = 0; i < num_glyphs; i++) {
2181 transformed_glyphs[j].index = glyphs[i].index;
2182 transformed_glyphs[j].x = glyphs[i].x;
2183 transformed_glyphs[j].y = glyphs[i].y;
2184 if (KEEP_GLYPH (transformed_glyphs[j]))
2185 j++;
2186 }
2187 } else {
2188 const cairo_glyph_t *cur_glyph;
2189
2190 if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2191 cur_glyph = glyphs + num_glyphs - 1;
2192 else
2193 cur_glyph = glyphs;
2194
2195 for (i = 0; i < num_clusters; i++) {
2196 cairo_bool_t cluster_visible = FALSE;
2197
2198 for (k = 0; k < clusters[i].num_glyphs; k++) {
2199 transformed_glyphs[j+k].index = cur_glyph->index;
2200 transformed_glyphs[j+k].x = cur_glyph->x;
2201 transformed_glyphs[j+k].y = cur_glyph->y;
2202 if (KEEP_GLYPH (transformed_glyphs[j+k]))
2203 cluster_visible = TRUE;
2204
2205 if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2206 cur_glyph--;
2207 else
2208 cur_glyph++;
2209 }
2210
2211 transformed_clusters[i] = clusters[i];
2212 if (cluster_visible)
2213 j += k;
2214 else
2215 transformed_clusters[i].num_glyphs = 0;
2216 }
2217 }
2218 }
2219 else if (_cairo_matrix_is_translation (ctm) &&
2220 _cairo_matrix_is_translation (device_transform))
2221 {
2222 double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
2223 double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
2224
2225 if (! drop || num_clusters == 0) {
2226 for (i = 0; i < num_glyphs; i++) {
2227 transformed_glyphs[j].index = glyphs[i].index;
2228 transformed_glyphs[j].x = glyphs[i].x + tx;
2229 transformed_glyphs[j].y = glyphs[i].y + ty;
2230 if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
2231 j++;
2232 }
2233 } else {
2234 const cairo_glyph_t *cur_glyph;
2235
2236 if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2237 cur_glyph = glyphs + num_glyphs - 1;
2238 else
2239 cur_glyph = glyphs;
2240
2241 for (i = 0; i < num_clusters; i++) {
2242 cairo_bool_t cluster_visible = FALSE;
2243
2244 for (k = 0; k < clusters[i].num_glyphs; k++) {
2245 transformed_glyphs[j+k].index = cur_glyph->index;
2246 transformed_glyphs[j+k].x = cur_glyph->x + tx;
2247 transformed_glyphs[j+k].y = cur_glyph->y + ty;
2248 if (KEEP_GLYPH (transformed_glyphs[j+k]))
2249 cluster_visible = TRUE;
2250
2251 if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2252 cur_glyph--;
2253 else
2254 cur_glyph++;
2255 }
2256
2257 transformed_clusters[i] = clusters[i];
2258 if (cluster_visible)
2259 j += k;
2260 else
2261 transformed_clusters[i].num_glyphs = 0;
2262 }
2263 }
2264 }
2265 else
2266 {
2267 cairo_matrix_t aggregate_transform;
2268
2269 cairo_matrix_init_translate (&aggregate_transform,
2270 gstate->font_matrix.x0,
2271 gstate->font_matrix.y0);
2272 cairo_matrix_multiply (&aggregate_transform,
2273 &aggregate_transform, ctm);
2274 cairo_matrix_multiply (&aggregate_transform,
2275 &aggregate_transform, device_transform);
2276
2277 if (! drop || num_clusters == 0) {
2278 for (i = 0; i < num_glyphs; i++) {
2279 transformed_glyphs[j] = glyphs[i];
2280 cairo_matrix_transform_point (&aggregate_transform,
2281 &transformed_glyphs[j].x,
2282 &transformed_glyphs[j].y);
2283 if (! drop || KEEP_GLYPH (transformed_glyphs[j]))
2284 j++;
2285 }
2286 } else {
2287 const cairo_glyph_t *cur_glyph;
2288
2289 if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2290 cur_glyph = glyphs + num_glyphs - 1;
2291 else
2292 cur_glyph = glyphs;
2293
2294 for (i = 0; i < num_clusters; i++) {
2295 cairo_bool_t cluster_visible = FALSE;
2296 for (k = 0; k < clusters[i].num_glyphs; k++) {
2297 transformed_glyphs[j+k] = *cur_glyph;
2298 cairo_matrix_transform_point (&aggregate_transform,
2299 &transformed_glyphs[j+k].x,
2300 &transformed_glyphs[j+k].y);
2301 if (KEEP_GLYPH (transformed_glyphs[j+k]))
2302 cluster_visible = TRUE;
2303
2304 if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2305 cur_glyph--;
2306 else
2307 cur_glyph++;
2308 }
2309
2310 transformed_clusters[i] = clusters[i];
2311 if (cluster_visible)
2312 j += k;
2313 else
2314 transformed_clusters[i].num_glyphs = 0;
2315 }
2316 }
2317 }
2318 *num_transformed_glyphs = j;
2319
2320 if (num_clusters != 0 && cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) {
2321 for (i = 0; i < --j; i++) {
2322 cairo_glyph_t tmp;
2323
2324 tmp = transformed_glyphs[i];
2325 transformed_glyphs[i] = transformed_glyphs[j];
2326 transformed_glyphs[j] = tmp;
2327 }
2328 }
2329
2330 return CAIRO_STATUS_SUCCESS;
2331 }
2332