Line data Source code
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
74 0 : _cairo_gstate_update_device_transform (cairo_observer_t *observer,
75 : void *arg)
76 : {
77 0 : cairo_gstate_t *gstate = cairo_container_of (observer,
78 : cairo_gstate_t,
79 : device_transform_observer);
80 :
81 0 : gstate->is_identity = (_cairo_matrix_is_identity (&gstate->ctm) &&
82 0 : _cairo_matrix_is_identity (&gstate->target->device_transform));
83 0 : }
84 :
85 : cairo_status_t
86 2 : _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 2 : gstate->next = NULL;
94 :
95 2 : gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT;
96 :
97 2 : gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
98 2 : gstate->antialias = CAIRO_ANTIALIAS_DEFAULT;
99 :
100 2 : _cairo_stroke_style_init (&gstate->stroke_style);
101 :
102 2 : gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
103 :
104 2 : gstate->font_face = NULL;
105 2 : gstate->scaled_font = NULL;
106 2 : gstate->previous_scaled_font = NULL;
107 :
108 2 : cairo_matrix_init_scale (&gstate->font_matrix,
109 : CAIRO_GSTATE_DEFAULT_FONT_SIZE,
110 : CAIRO_GSTATE_DEFAULT_FONT_SIZE);
111 :
112 2 : _cairo_font_options_init_default (&gstate->font_options);
113 :
114 2 : _cairo_clip_init (&gstate->clip);
115 :
116 2 : gstate->target = cairo_surface_reference (target);
117 2 : gstate->parent_target = NULL;
118 2 : gstate->original_target = cairo_surface_reference (target);
119 :
120 2 : gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
121 2 : cairo_list_add (&gstate->device_transform_observer.link,
122 2 : &gstate->target->device_transform_observers);
123 :
124 2 : gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
125 2 : cairo_matrix_init_identity (&gstate->ctm);
126 2 : gstate->ctm_inverse = gstate->ctm;
127 2 : gstate->source_ctm_inverse = gstate->ctm;
128 :
129 2 : 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 2 : status = target->status;
135 2 : if (unlikely (status))
136 0 : return status;
137 :
138 2 : status = gstate->source->status;
139 2 : if (unlikely (status))
140 0 : return status;
141 :
142 2 : 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
153 0 : _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 0 : gstate->op = other->op;
160 :
161 0 : gstate->tolerance = other->tolerance;
162 0 : gstate->antialias = other->antialias;
163 :
164 0 : status = _cairo_stroke_style_init_copy (&gstate->stroke_style,
165 0 : &other->stroke_style);
166 0 : if (unlikely (status))
167 0 : return status;
168 :
169 0 : gstate->fill_rule = other->fill_rule;
170 :
171 0 : gstate->font_face = cairo_font_face_reference (other->font_face);
172 0 : gstate->scaled_font = cairo_scaled_font_reference (other->scaled_font);
173 0 : gstate->previous_scaled_font = cairo_scaled_font_reference (other->previous_scaled_font);
174 :
175 0 : gstate->font_matrix = other->font_matrix;
176 :
177 0 : _cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
178 :
179 0 : _cairo_clip_init_copy (&gstate->clip, &other->clip);
180 :
181 0 : gstate->target = cairo_surface_reference (other->target);
182 : /* parent_target is always set to NULL; it's only ever set by redirect_target */
183 0 : gstate->parent_target = NULL;
184 0 : gstate->original_target = cairo_surface_reference (other->original_target);
185 :
186 0 : gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform;
187 0 : cairo_list_add (&gstate->device_transform_observer.link,
188 0 : &gstate->target->device_transform_observers);
189 :
190 0 : gstate->is_identity = other->is_identity;
191 0 : gstate->ctm = other->ctm;
192 0 : gstate->ctm_inverse = other->ctm_inverse;
193 0 : gstate->source_ctm_inverse = other->source_ctm_inverse;
194 :
195 0 : gstate->source = cairo_pattern_reference (other->source);
196 :
197 0 : gstate->next = NULL;
198 :
199 0 : return CAIRO_STATUS_SUCCESS;
200 : }
201 :
202 : void
203 0 : _cairo_gstate_fini (cairo_gstate_t *gstate)
204 : {
205 0 : _cairo_stroke_style_fini (&gstate->stroke_style);
206 :
207 0 : cairo_font_face_destroy (gstate->font_face);
208 0 : gstate->font_face = NULL;
209 :
210 0 : cairo_scaled_font_destroy (gstate->previous_scaled_font);
211 0 : gstate->previous_scaled_font = NULL;
212 :
213 0 : cairo_scaled_font_destroy (gstate->scaled_font);
214 0 : gstate->scaled_font = NULL;
215 :
216 0 : _cairo_clip_reset (&gstate->clip);
217 :
218 0 : cairo_list_del (&gstate->device_transform_observer.link);
219 :
220 0 : cairo_surface_destroy (gstate->target);
221 0 : gstate->target = NULL;
222 :
223 0 : cairo_surface_destroy (gstate->parent_target);
224 0 : gstate->parent_target = NULL;
225 :
226 0 : cairo_surface_destroy (gstate->original_target);
227 0 : gstate->original_target = NULL;
228 :
229 0 : cairo_pattern_destroy (gstate->source);
230 0 : gstate->source = NULL;
231 :
232 : VG (VALGRIND_MAKE_MEM_NOACCESS (gstate, sizeof (cairo_gstate_t)));
233 0 : }
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
244 0 : _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 0 : top = *freelist;
253 0 : if (top == NULL) {
254 0 : top = malloc (sizeof (cairo_gstate_t));
255 0 : if (unlikely (top == NULL))
256 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
257 : } else
258 0 : *freelist = top->next;
259 :
260 0 : status = _cairo_gstate_init_copy (top, *gstate);
261 0 : if (unlikely (status)) {
262 0 : top->next = *freelist;
263 0 : *freelist = top;
264 0 : return status;
265 : }
266 :
267 0 : top->next = *gstate;
268 0 : *gstate = top;
269 :
270 0 : 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
280 0 : _cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
281 : {
282 : cairo_gstate_t *top;
283 :
284 0 : top = *gstate;
285 0 : if (top->next == NULL)
286 0 : return _cairo_error (CAIRO_STATUS_INVALID_RESTORE);
287 :
288 0 : *gstate = top->next;
289 :
290 0 : _cairo_gstate_fini (top);
291 : VG (VALGRIND_MAKE_MEM_UNDEFINED (&top->next, sizeof (cairo_gstate_t *)));
292 0 : top->next = *freelist;
293 0 : *freelist = top;
294 :
295 0 : 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
312 0 : _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 0 : 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 0 : cairo_surface_destroy (gstate->parent_target);
324 0 : 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 0 : gstate->target = cairo_surface_reference (child);
329 0 : gstate->is_identity &= _cairo_matrix_is_identity (&child->device_transform);
330 0 : cairo_list_move (&gstate->device_transform_observer.link,
331 0 : &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 0 : cairo_matrix_init_translate (&matrix,
336 0 : child->device_transform.x0 - gstate->parent_target->device_transform.x0,
337 0 : child->device_transform.y0 - gstate->parent_target->device_transform.y0);
338 0 : _cairo_clip_reset (&gstate->clip);
339 0 : return _cairo_clip_init_copy_transformed (&gstate->clip,
340 0 : &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
354 0 : _cairo_gstate_is_redirected (cairo_gstate_t *gstate)
355 : {
356 0 : 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 *
369 0 : _cairo_gstate_get_target (cairo_gstate_t *gstate)
370 : {
371 0 : 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 *
382 0 : _cairo_gstate_get_parent_target (cairo_gstate_t *gstate)
383 : {
384 0 : 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 *
399 0 : _cairo_gstate_get_original_target (cairo_gstate_t *gstate)
400 : {
401 0 : 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 *
413 0 : _cairo_gstate_get_clip (cairo_gstate_t *gstate)
414 : {
415 0 : return &gstate->clip;
416 : }
417 :
418 : cairo_status_t
419 0 : _cairo_gstate_set_source (cairo_gstate_t *gstate,
420 : cairo_pattern_t *source)
421 : {
422 0 : if (source->status)
423 0 : return source->status;
424 :
425 0 : source = cairo_pattern_reference (source);
426 0 : cairo_pattern_destroy (gstate->source);
427 0 : gstate->source = source;
428 0 : gstate->source_ctm_inverse = gstate->ctm_inverse;
429 :
430 0 : return CAIRO_STATUS_SUCCESS;
431 : }
432 :
433 : cairo_pattern_t *
434 0 : _cairo_gstate_get_source (cairo_gstate_t *gstate)
435 : {
436 0 : if (gstate->source == &_cairo_pattern_black.base) {
437 : /* do not expose the static object to the user */
438 0 : gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
439 : }
440 :
441 0 : return gstate->source;
442 : }
443 :
444 : cairo_status_t
445 0 : _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op)
446 : {
447 0 : gstate->op = op;
448 :
449 0 : return CAIRO_STATUS_SUCCESS;
450 : }
451 :
452 : cairo_operator_t
453 0 : _cairo_gstate_get_operator (cairo_gstate_t *gstate)
454 : {
455 0 : return gstate->op;
456 : }
457 :
458 : cairo_status_t
459 0 : _cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance)
460 : {
461 0 : gstate->tolerance = tolerance;
462 :
463 0 : return CAIRO_STATUS_SUCCESS;
464 : }
465 :
466 : double
467 0 : _cairo_gstate_get_tolerance (cairo_gstate_t *gstate)
468 : {
469 0 : return gstate->tolerance;
470 : }
471 :
472 : cairo_status_t
473 0 : _cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule)
474 : {
475 0 : gstate->fill_rule = fill_rule;
476 :
477 0 : return CAIRO_STATUS_SUCCESS;
478 : }
479 :
480 : cairo_fill_rule_t
481 0 : _cairo_gstate_get_fill_rule (cairo_gstate_t *gstate)
482 : {
483 0 : return gstate->fill_rule;
484 : }
485 :
486 : cairo_status_t
487 0 : _cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width)
488 : {
489 0 : gstate->stroke_style.line_width = width;
490 :
491 0 : return CAIRO_STATUS_SUCCESS;
492 : }
493 :
494 : double
495 0 : _cairo_gstate_get_line_width (cairo_gstate_t *gstate)
496 : {
497 0 : return gstate->stroke_style.line_width;
498 : }
499 :
500 : cairo_status_t
501 0 : _cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap)
502 : {
503 0 : gstate->stroke_style.line_cap = line_cap;
504 :
505 0 : return CAIRO_STATUS_SUCCESS;
506 : }
507 :
508 : cairo_line_cap_t
509 0 : _cairo_gstate_get_line_cap (cairo_gstate_t *gstate)
510 : {
511 0 : return gstate->stroke_style.line_cap;
512 : }
513 :
514 : cairo_status_t
515 0 : _cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join)
516 : {
517 0 : gstate->stroke_style.line_join = line_join;
518 :
519 0 : return CAIRO_STATUS_SUCCESS;
520 : }
521 :
522 : cairo_line_join_t
523 0 : _cairo_gstate_get_line_join (cairo_gstate_t *gstate)
524 : {
525 0 : return gstate->stroke_style.line_join;
526 : }
527 :
528 : cairo_status_t
529 0 : _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 0 : if (gstate->stroke_style.dash)
535 0 : free (gstate->stroke_style.dash);
536 :
537 0 : gstate->stroke_style.num_dashes = num_dashes;
538 :
539 0 : if (gstate->stroke_style.num_dashes == 0) {
540 0 : gstate->stroke_style.dash = NULL;
541 0 : gstate->stroke_style.dash_offset = 0.0;
542 0 : return CAIRO_STATUS_SUCCESS;
543 : }
544 :
545 0 : gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double));
546 0 : if (unlikely (gstate->stroke_style.dash == NULL)) {
547 0 : gstate->stroke_style.num_dashes = 0;
548 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
549 : }
550 :
551 0 : memcpy (gstate->stroke_style.dash, dash, gstate->stroke_style.num_dashes * sizeof (double));
552 :
553 0 : dash_total = 0.0;
554 0 : for (i = 0; i < gstate->stroke_style.num_dashes; i++) {
555 0 : if (gstate->stroke_style.dash[i] < 0)
556 0 : return _cairo_error (CAIRO_STATUS_INVALID_DASH);
557 :
558 0 : dash_total += gstate->stroke_style.dash[i];
559 : }
560 :
561 0 : if (dash_total == 0.0)
562 0 : 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 0 : if (gstate->stroke_style.num_dashes & 1)
567 0 : 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 0 : offset = fmod (offset, dash_total);
573 0 : if (offset < 0.0)
574 0 : offset += dash_total;
575 0 : if (offset <= 0.0) /* Take care of -0 */
576 0 : offset = 0.0;
577 0 : gstate->stroke_style.dash_offset = offset;
578 :
579 0 : return CAIRO_STATUS_SUCCESS;
580 : }
581 :
582 : void
583 0 : _cairo_gstate_get_dash (cairo_gstate_t *gstate,
584 : double *dashes,
585 : int *num_dashes,
586 : double *offset)
587 : {
588 0 : if (dashes) {
589 0 : memcpy (dashes,
590 0 : gstate->stroke_style.dash,
591 0 : sizeof (double) * gstate->stroke_style.num_dashes);
592 : }
593 :
594 0 : if (num_dashes)
595 0 : *num_dashes = gstate->stroke_style.num_dashes;
596 :
597 0 : if (offset)
598 0 : *offset = gstate->stroke_style.dash_offset;
599 0 : }
600 :
601 : cairo_status_t
602 0 : _cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit)
603 : {
604 0 : gstate->stroke_style.miter_limit = limit;
605 :
606 0 : return CAIRO_STATUS_SUCCESS;
607 : }
608 :
609 : double
610 0 : _cairo_gstate_get_miter_limit (cairo_gstate_t *gstate)
611 : {
612 0 : return gstate->stroke_style.miter_limit;
613 : }
614 :
615 : void
616 0 : _cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix)
617 : {
618 0 : *matrix = gstate->ctm;
619 0 : }
620 :
621 : cairo_status_t
622 0 : _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
623 : {
624 : cairo_matrix_t tmp;
625 :
626 0 : if (! ISFINITE (tx) || ! ISFINITE (ty))
627 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
628 :
629 0 : _cairo_gstate_unset_scaled_font (gstate);
630 :
631 0 : cairo_matrix_init_translate (&tmp, tx, ty);
632 0 : cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
633 0 : gstate->is_identity = FALSE;
634 :
635 : /* paranoid check against gradual numerical instability */
636 0 : if (! _cairo_matrix_is_invertible (&gstate->ctm))
637 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
638 :
639 0 : cairo_matrix_init_translate (&tmp, -tx, -ty);
640 0 : cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
641 :
642 0 : return CAIRO_STATUS_SUCCESS;
643 : }
644 :
645 : cairo_status_t
646 0 : _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
647 : {
648 : cairo_matrix_t tmp;
649 :
650 0 : if (sx * sy == 0.) /* either sx or sy is 0, or det == 0 due to underflow */
651 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
652 0 : if (! ISFINITE (sx) || ! ISFINITE (sy))
653 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
654 :
655 0 : _cairo_gstate_unset_scaled_font (gstate);
656 :
657 0 : cairo_matrix_init_scale (&tmp, sx, sy);
658 0 : cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
659 0 : gstate->is_identity = FALSE;
660 :
661 : /* paranoid check against gradual numerical instability */
662 0 : if (! _cairo_matrix_is_invertible (&gstate->ctm))
663 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
664 :
665 0 : cairo_matrix_init_scale (&tmp, 1/sx, 1/sy);
666 0 : cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
667 :
668 0 : return CAIRO_STATUS_SUCCESS;
669 : }
670 :
671 : cairo_status_t
672 0 : _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
673 : {
674 : cairo_matrix_t tmp;
675 :
676 0 : if (angle == 0.)
677 0 : return CAIRO_STATUS_SUCCESS;
678 :
679 0 : if (! ISFINITE (angle))
680 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
681 :
682 0 : _cairo_gstate_unset_scaled_font (gstate);
683 :
684 0 : cairo_matrix_init_rotate (&tmp, angle);
685 0 : cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm);
686 0 : gstate->is_identity = FALSE;
687 :
688 : /* paranoid check against gradual numerical instability */
689 0 : if (! _cairo_matrix_is_invertible (&gstate->ctm))
690 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
691 :
692 0 : cairo_matrix_init_rotate (&tmp, -angle);
693 0 : cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
694 :
695 0 : return CAIRO_STATUS_SUCCESS;
696 : }
697 :
698 : cairo_status_t
699 0 : _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 0 : if (! _cairo_matrix_is_invertible (matrix))
706 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
707 :
708 0 : if (_cairo_matrix_is_identity (matrix))
709 0 : return CAIRO_STATUS_SUCCESS;
710 :
711 0 : tmp = *matrix;
712 0 : status = cairo_matrix_invert (&tmp);
713 0 : if (unlikely (status))
714 0 : return status;
715 :
716 0 : _cairo_gstate_unset_scaled_font (gstate);
717 :
718 0 : cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm);
719 0 : cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp);
720 0 : gstate->is_identity = FALSE;
721 :
722 : /* paranoid check against gradual numerical instability */
723 0 : if (! _cairo_matrix_is_invertible (&gstate->ctm))
724 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
725 :
726 0 : return CAIRO_STATUS_SUCCESS;
727 : }
728 :
729 : cairo_status_t
730 0 : _cairo_gstate_set_matrix (cairo_gstate_t *gstate,
731 : const cairo_matrix_t *matrix)
732 : {
733 : cairo_status_t status;
734 :
735 0 : if (memcmp (matrix, &gstate->ctm, sizeof (cairo_matrix_t)) == 0)
736 0 : return CAIRO_STATUS_SUCCESS;
737 :
738 0 : if (! _cairo_matrix_is_invertible (matrix))
739 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
740 :
741 0 : if (_cairo_matrix_is_identity (matrix)) {
742 0 : _cairo_gstate_identity_matrix (gstate);
743 0 : return CAIRO_STATUS_SUCCESS;
744 : }
745 :
746 0 : _cairo_gstate_unset_scaled_font (gstate);
747 :
748 0 : gstate->ctm = *matrix;
749 0 : gstate->ctm_inverse = *matrix;
750 0 : status = cairo_matrix_invert (&gstate->ctm_inverse);
751 0 : assert (status == CAIRO_STATUS_SUCCESS);
752 0 : gstate->is_identity = FALSE;
753 :
754 0 : return CAIRO_STATUS_SUCCESS;
755 : }
756 :
757 : void
758 0 : _cairo_gstate_identity_matrix (cairo_gstate_t *gstate)
759 : {
760 0 : if (_cairo_matrix_is_identity (&gstate->ctm))
761 0 : return;
762 :
763 0 : _cairo_gstate_unset_scaled_font (gstate);
764 :
765 0 : cairo_matrix_init_identity (&gstate->ctm);
766 0 : cairo_matrix_init_identity (&gstate->ctm_inverse);
767 0 : gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform);
768 : }
769 :
770 : void
771 0 : _cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y)
772 : {
773 0 : cairo_matrix_transform_point (&gstate->ctm, x, y);
774 0 : }
775 :
776 : void
777 0 : _cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate,
778 : double *dx, double *dy)
779 : {
780 0 : cairo_matrix_transform_distance (&gstate->ctm, dx, dy);
781 0 : }
782 :
783 : void
784 0 : _cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y)
785 : {
786 0 : cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
787 0 : }
788 :
789 : void
790 0 : _cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate,
791 : double *dx, double *dy)
792 : {
793 0 : cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy);
794 0 : }
795 :
796 : void
797 0 : _do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y)
798 : {
799 0 : cairo_matrix_transform_point (&gstate->ctm, x, y);
800 0 : cairo_matrix_transform_point (&gstate->target->device_transform, x, y);
801 0 : }
802 :
803 : void
804 0 : _do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y)
805 : {
806 0 : cairo_matrix_transform_point (&gstate->target->device_transform_inverse, x, y);
807 0 : cairo_matrix_transform_point (&gstate->ctm_inverse, x, y);
808 0 : }
809 :
810 : void
811 0 : _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 0 : cairo_matrix_multiply (&matrix_inverse,
819 0 : &gstate->target->device_transform_inverse,
820 0 : &gstate->ctm_inverse);
821 0 : _cairo_matrix_transform_bounding_box (&matrix_inverse,
822 : x1, y1, x2, y2, is_tight);
823 0 : }
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
837 0 : _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 0 : if (_cairo_path_fixed_extents (path, &box)) {
846 0 : px1 = _cairo_fixed_to_double (box.p1.x);
847 0 : py1 = _cairo_fixed_to_double (box.p1.y);
848 0 : px2 = _cairo_fixed_to_double (box.p2.x);
849 0 : py2 = _cairo_fixed_to_double (box.p2.y);
850 :
851 0 : _cairo_gstate_backend_to_user_rectangle (gstate,
852 : &px1, &py1, &px2, &py2,
853 : NULL);
854 : } else {
855 0 : px1 = 0.0;
856 0 : py1 = 0.0;
857 0 : px2 = 0.0;
858 0 : py2 = 0.0;
859 : }
860 :
861 0 : if (x1)
862 0 : *x1 = px1;
863 0 : if (y1)
864 0 : *y1 = py1;
865 0 : if (x2)
866 0 : *x2 = px2;
867 0 : if (y2)
868 0 : *y2 = py2;
869 0 : }
870 :
871 : static void
872 0 : _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 0 : if (_cairo_pattern_is_clear (original)) {
881 0 : _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
882 : CAIRO_COLOR_TRANSPARENT);
883 0 : return;
884 : }
885 :
886 0 : if (original->type == CAIRO_PATTERN_TYPE_LINEAR ||
887 0 : original->type == CAIRO_PATTERN_TYPE_RADIAL)
888 : {
889 : cairo_color_t color;
890 0 : if (_cairo_gradient_pattern_is_solid ((cairo_gradient_pattern_t *) original,
891 : NULL,
892 : &color))
893 : {
894 0 : _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern,
895 : &color);
896 0 : return;
897 : }
898 : }
899 :
900 0 : _cairo_pattern_init_static_copy (pattern, original);
901 : }
902 :
903 : static void
904 0 : _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 0 : _cairo_gstate_copy_pattern (pattern, original);
910 :
911 : /* apply device_transform first so that it is transformed by ctm_inverse */
912 0 : if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
913 : cairo_surface_pattern_t *surface_pattern;
914 : cairo_surface_t *surface;
915 :
916 0 : surface_pattern = (cairo_surface_pattern_t *) original;
917 0 : surface = surface_pattern->surface;
918 :
919 0 : if (_cairo_surface_has_device_transform (surface))
920 0 : _cairo_pattern_transform (pattern, &surface->device_transform);
921 : }
922 :
923 0 : if (! _cairo_matrix_is_identity (ctm_inverse))
924 0 : _cairo_pattern_transform (pattern, ctm_inverse);
925 :
926 0 : if (_cairo_surface_has_device_transform (gstate->target)) {
927 0 : _cairo_pattern_transform (pattern,
928 0 : &gstate->target->device_transform_inverse);
929 : }
930 0 : }
931 :
932 : static void
933 0 : _cairo_gstate_copy_transformed_source (cairo_gstate_t *gstate,
934 : cairo_pattern_t *pattern)
935 : {
936 0 : _cairo_gstate_copy_transformed_pattern (gstate, pattern,
937 0 : gstate->source,
938 0 : &gstate->source_ctm_inverse);
939 0 : }
940 :
941 : static void
942 0 : _cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate,
943 : cairo_pattern_t *pattern,
944 : cairo_pattern_t *mask)
945 : {
946 0 : _cairo_gstate_copy_transformed_pattern (gstate, pattern,
947 : mask,
948 0 : &gstate->ctm_inverse);
949 0 : }
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
957 0 : _clipped (cairo_gstate_t *gstate)
958 : {
959 : cairo_rectangle_int_t extents;
960 :
961 0 : if (gstate->clip.all_clipped)
962 0 : return TRUE;
963 :
964 : /* XXX consider applying a surface clip? */
965 :
966 0 : if (gstate->clip.path == NULL)
967 0 : return FALSE;
968 :
969 0 : if (_cairo_surface_get_extents (gstate->target, &extents)) {
970 0 : if (extents.width == 0 || extents.height == 0)
971 0 : return TRUE;
972 :
973 0 : if (! _cairo_rectangle_intersect (&extents,
974 0 : &gstate->clip.path->extents))
975 : {
976 0 : return TRUE;
977 : }
978 : }
979 :
980 : /* perform a simple query to exclude trivial all-clipped cases */
981 0 : return _cairo_clip_get_region (&gstate->clip, NULL) == CAIRO_INT_STATUS_NOTHING_TO_DO;
982 : }
983 :
984 : static cairo_operator_t
985 0 : _reduce_op (cairo_gstate_t *gstate)
986 : {
987 : cairo_operator_t op;
988 : const cairo_pattern_t *pattern;
989 :
990 0 : op = gstate->op;
991 0 : if (op != CAIRO_OPERATOR_SOURCE)
992 0 : return op;
993 :
994 0 : pattern = gstate->source;
995 0 : if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
996 0 : const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
997 0 : if (solid->color.alpha_short <= 0x00ff) {
998 0 : op = CAIRO_OPERATOR_CLEAR;
999 0 : } else if ((gstate->target->content & CAIRO_CONTENT_ALPHA) == 0) {
1000 0 : if ((solid->color.red_short |
1001 0 : solid->color.green_short |
1002 0 : solid->color.blue_short) <= 0x00ff)
1003 : {
1004 0 : op = CAIRO_OPERATOR_CLEAR;
1005 : }
1006 : }
1007 0 : } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
1008 0 : const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
1009 0 : if (surface->surface->is_clear &&
1010 0 : surface->surface->content & CAIRO_CONTENT_ALPHA)
1011 : {
1012 0 : op = CAIRO_OPERATOR_CLEAR;
1013 : }
1014 : } else {
1015 0 : const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
1016 0 : if (gradient->n_stops == 0)
1017 0 : op = CAIRO_OPERATOR_CLEAR;
1018 : }
1019 :
1020 0 : return op;
1021 : }
1022 :
1023 : cairo_status_t
1024 0 : _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 0 : if (unlikely (gstate->source->status))
1033 0 : return gstate->source->status;
1034 :
1035 0 : if (gstate->op == CAIRO_OPERATOR_DEST)
1036 0 : return CAIRO_STATUS_SUCCESS;
1037 :
1038 0 : if (_clipped (gstate))
1039 0 : return CAIRO_STATUS_SUCCESS;
1040 :
1041 0 : op = _reduce_op (gstate);
1042 0 : if (op == CAIRO_OPERATOR_CLEAR) {
1043 0 : pattern = &_cairo_pattern_clear.base;
1044 : } else {
1045 0 : _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1046 0 : pattern = &source_pattern.base;
1047 : }
1048 :
1049 0 : status = _cairo_surface_paint (gstate->target,
1050 : op, pattern,
1051 : _gstate_get_clip (gstate, &clip));
1052 0 : _cairo_clip_fini (&clip);
1053 :
1054 0 : return status;
1055 : }
1056 :
1057 : cairo_status_t
1058 0 : _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 0 : if (unlikely (mask->status))
1068 0 : return mask->status;
1069 :
1070 0 : if (unlikely (gstate->source->status))
1071 0 : return gstate->source->status;
1072 :
1073 0 : if (gstate->op == CAIRO_OPERATOR_DEST)
1074 0 : return CAIRO_STATUS_SUCCESS;
1075 :
1076 0 : if (_clipped (gstate))
1077 0 : return CAIRO_STATUS_SUCCESS;
1078 :
1079 0 : if (_cairo_pattern_is_opaque (mask, NULL))
1080 0 : return _cairo_gstate_paint (gstate);
1081 :
1082 0 : if (_cairo_pattern_is_clear (mask) &&
1083 0 : _cairo_operator_bounded_by_mask (gstate->op))
1084 : {
1085 0 : return CAIRO_STATUS_SUCCESS;
1086 : }
1087 :
1088 0 : op = _reduce_op (gstate);
1089 0 : if (op == CAIRO_OPERATOR_CLEAR) {
1090 0 : source = &_cairo_pattern_clear.base;
1091 : } else {
1092 0 : _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1093 0 : source = &source_pattern.base;
1094 : }
1095 0 : _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
1096 :
1097 0 : if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
1098 0 : mask_pattern.type == CAIRO_PATTERN_TYPE_SOLID &&
1099 0 : _cairo_operator_bounded_by_source (op))
1100 0 : {
1101 0 : const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
1102 : cairo_color_t combined;
1103 :
1104 0 : if (mask_pattern.base.has_component_alpha) {
1105 : #define M(R, A, B, c) R.c = A.c * B.c
1106 0 : M(combined, solid->color, mask_pattern.solid.color, red);
1107 0 : M(combined, solid->color, mask_pattern.solid.color, green);
1108 0 : M(combined, solid->color, mask_pattern.solid.color, blue);
1109 0 : M(combined, solid->color, mask_pattern.solid.color, alpha);
1110 : #undef M
1111 : } else {
1112 0 : combined = solid->color;
1113 0 : _cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha);
1114 : }
1115 :
1116 0 : _cairo_pattern_init_solid (&source_pattern.solid, &combined);
1117 :
1118 0 : status = _cairo_surface_paint (gstate->target, op,
1119 : &source_pattern.base,
1120 : _gstate_get_clip (gstate, &clip));
1121 : }
1122 : else
1123 : {
1124 0 : status = _cairo_surface_mask (gstate->target, op,
1125 : source,
1126 : &mask_pattern.base,
1127 : _gstate_get_clip (gstate, &clip));
1128 : }
1129 0 : _cairo_clip_fini (&clip);
1130 :
1131 0 : return status;
1132 : }
1133 :
1134 : cairo_status_t
1135 0 : _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 0 : if (unlikely (gstate->source->status))
1144 0 : return gstate->source->status;
1145 :
1146 0 : if (gstate->op == CAIRO_OPERATOR_DEST)
1147 0 : return CAIRO_STATUS_SUCCESS;
1148 :
1149 0 : if (gstate->stroke_style.line_width <= 0.0)
1150 0 : return CAIRO_STATUS_SUCCESS;
1151 :
1152 0 : if (_clipped (gstate))
1153 0 : return CAIRO_STATUS_SUCCESS;
1154 :
1155 0 : memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style));
1156 0 : if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance)) {
1157 0 : style.dash = dash;
1158 0 : _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 0 : _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1165 :
1166 0 : status = _cairo_surface_stroke (gstate->target,
1167 : gstate->op,
1168 : &source_pattern.base,
1169 : path,
1170 : &style,
1171 0 : &gstate->ctm,
1172 0 : &gstate->ctm_inverse,
1173 : gstate->tolerance,
1174 : gstate->antialias,
1175 : _gstate_get_clip (gstate, &clip));
1176 0 : _cairo_clip_fini (&clip);
1177 :
1178 0 : return status;
1179 : }
1180 :
1181 : cairo_status_t
1182 0 : _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 0 : if (gstate->stroke_style.line_width <= 0.0) {
1194 0 : *inside_ret = FALSE;
1195 0 : return CAIRO_STATUS_SUCCESS;
1196 : }
1197 :
1198 0 : _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 0 : _cairo_path_fixed_approximate_stroke_extents (path,
1204 0 : &gstate->stroke_style,
1205 0 : &gstate->ctm,
1206 : &extents);
1207 0 : if (x < extents.x || x > extents.x + extents.width ||
1208 0 : y < extents.y || y > extents.y + extents.height)
1209 : {
1210 0 : *inside_ret = FALSE;
1211 0 : return CAIRO_STATUS_SUCCESS;
1212 : }
1213 :
1214 0 : limit.p1.x = _cairo_fixed_from_double (x) - 5;
1215 0 : limit.p1.y = _cairo_fixed_from_double (y) - 5;
1216 0 : limit.p2.x = limit.p1.x + 10;
1217 0 : limit.p2.y = limit.p1.y + 10;
1218 :
1219 0 : _cairo_traps_init (&traps);
1220 0 : _cairo_traps_limit (&traps, &limit, 1);
1221 :
1222 0 : status = _cairo_path_fixed_stroke_to_traps (path,
1223 0 : &gstate->stroke_style,
1224 0 : &gstate->ctm,
1225 0 : &gstate->ctm_inverse,
1226 : gstate->tolerance,
1227 : &traps);
1228 0 : if (unlikely (status))
1229 0 : goto BAIL;
1230 :
1231 0 : *inside_ret = _cairo_traps_contain (&traps, x, y);
1232 :
1233 : BAIL:
1234 0 : _cairo_traps_fini (&traps);
1235 :
1236 0 : return status;
1237 : }
1238 :
1239 : cairo_status_t
1240 0 : _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 0 : if (unlikely (gstate->source->status))
1246 0 : return gstate->source->status;
1247 :
1248 0 : if (gstate->op == CAIRO_OPERATOR_DEST)
1249 0 : return CAIRO_STATUS_SUCCESS;
1250 :
1251 0 : if (_clipped (gstate))
1252 0 : return CAIRO_STATUS_SUCCESS;
1253 :
1254 0 : if (_cairo_path_fixed_fill_is_empty (path)) {
1255 0 : if (_cairo_operator_bounded_by_mask (gstate->op))
1256 0 : return CAIRO_STATUS_SUCCESS;
1257 :
1258 0 : 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 0 : op = _reduce_op (gstate);
1270 0 : if (op == CAIRO_OPERATOR_CLEAR) {
1271 0 : pattern = &_cairo_pattern_clear.base;
1272 : } else {
1273 0 : _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1274 0 : pattern = &source_pattern.base;
1275 : }
1276 :
1277 : /* Toolkits often paint the entire background with a fill */
1278 0 : if (_cairo_surface_get_extents (gstate->target, &extents) &&
1279 0 : _cairo_path_fixed_is_box (path, &box) &&
1280 0 : box.p1.x <= _cairo_fixed_from_int (extents.x) &&
1281 0 : box.p1.y <= _cairo_fixed_from_int (extents.y) &&
1282 0 : box.p2.x >= _cairo_fixed_from_int (extents.x + extents.width) &&
1283 0 : box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height))
1284 : {
1285 0 : status = _cairo_surface_paint (gstate->target, op, pattern,
1286 : _gstate_get_clip (gstate, &clip));
1287 : }
1288 : else
1289 : {
1290 0 : 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 0 : _cairo_clip_fini (&clip);
1300 :
1301 0 : return status;
1302 : }
1303 :
1304 : cairo_bool_t
1305 0 : _cairo_gstate_in_fill (cairo_gstate_t *gstate,
1306 : cairo_path_fixed_t *path,
1307 : double x,
1308 : double y)
1309 : {
1310 0 : _cairo_gstate_user_to_backend (gstate, &x, &y);
1311 :
1312 0 : return _cairo_path_fixed_in_fill (path,
1313 : gstate->fill_rule,
1314 : gstate->tolerance,
1315 : x, y);
1316 : }
1317 :
1318 : cairo_bool_t
1319 0 : _cairo_gstate_in_clip (cairo_gstate_t *gstate,
1320 : double x,
1321 : double y)
1322 : {
1323 : cairo_clip_path_t *clip_path;
1324 :
1325 0 : if (gstate->clip.all_clipped)
1326 0 : return FALSE;
1327 :
1328 0 : clip_path = gstate->clip.path;
1329 0 : if (clip_path == NULL)
1330 0 : return TRUE;
1331 :
1332 0 : _cairo_gstate_user_to_backend (gstate, &x, &y);
1333 :
1334 0 : if (x < clip_path->extents.x ||
1335 0 : x >= clip_path->extents.x + clip_path->extents.width ||
1336 0 : y < clip_path->extents.y ||
1337 0 : y >= clip_path->extents.y + clip_path->extents.height)
1338 : {
1339 0 : return FALSE;
1340 : }
1341 :
1342 : do {
1343 0 : if (! _cairo_path_fixed_in_fill (&clip_path->path,
1344 : clip_path->fill_rule,
1345 : clip_path->tolerance,
1346 : x, y))
1347 0 : return FALSE;
1348 0 : } while ((clip_path = clip_path->prev) != NULL);
1349 :
1350 0 : return TRUE;
1351 : }
1352 :
1353 : cairo_status_t
1354 0 : _cairo_gstate_copy_page (cairo_gstate_t *gstate)
1355 : {
1356 0 : cairo_surface_copy_page (gstate->target);
1357 0 : return cairo_surface_status (gstate->target);
1358 : }
1359 :
1360 : cairo_status_t
1361 0 : _cairo_gstate_show_page (cairo_gstate_t *gstate)
1362 : {
1363 0 : cairo_surface_show_page (gstate->target);
1364 0 : return cairo_surface_status (gstate->target);
1365 : }
1366 :
1367 : static void
1368 0 : _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 0 : if (traps->num_traps == 0) {
1376 : /* no traps, so we actually won't draw anything */
1377 0 : if (x1)
1378 0 : *x1 = 0.0;
1379 0 : if (y1)
1380 0 : *y1 = 0.0;
1381 0 : if (x2)
1382 0 : *x2 = 0.0;
1383 0 : if (y2)
1384 0 : *y2 = 0.0;
1385 : } else {
1386 : double px1, py1, px2, py2;
1387 :
1388 0 : _cairo_traps_extents (traps, &extents);
1389 :
1390 0 : px1 = _cairo_fixed_to_double (extents.p1.x);
1391 0 : py1 = _cairo_fixed_to_double (extents.p1.y);
1392 0 : px2 = _cairo_fixed_to_double (extents.p2.x);
1393 0 : py2 = _cairo_fixed_to_double (extents.p2.y);
1394 :
1395 0 : _cairo_gstate_backend_to_user_rectangle (gstate,
1396 : &px1, &py1, &px2, &py2,
1397 : NULL);
1398 0 : if (x1)
1399 0 : *x1 = px1;
1400 0 : if (y1)
1401 0 : *y1 = py1;
1402 0 : if (x2)
1403 0 : *x2 = px2;
1404 0 : if (y2)
1405 0 : *y2 = py2;
1406 : }
1407 0 : }
1408 :
1409 : cairo_status_t
1410 0 : _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 0 : if (gstate->stroke_style.line_width <= 0.0) {
1419 0 : if (x1)
1420 0 : *x1 = 0.0;
1421 0 : if (y1)
1422 0 : *y1 = 0.0;
1423 0 : if (x2)
1424 0 : *x2 = 0.0;
1425 0 : if (y2)
1426 0 : *y2 = 0.0;
1427 0 : return CAIRO_STATUS_SUCCESS;
1428 : }
1429 :
1430 0 : _cairo_traps_init (&traps);
1431 :
1432 0 : status = _cairo_path_fixed_stroke_to_traps (path,
1433 0 : &gstate->stroke_style,
1434 0 : &gstate->ctm,
1435 0 : &gstate->ctm_inverse,
1436 : gstate->tolerance,
1437 : &traps);
1438 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
1439 0 : _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
1440 : x1, y1, x2, y2);
1441 : }
1442 :
1443 0 : _cairo_traps_fini (&traps);
1444 :
1445 0 : return status;
1446 : }
1447 :
1448 : cairo_status_t
1449 0 : _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 0 : if (path->is_empty_fill) {
1458 0 : if (x1)
1459 0 : *x1 = 0.0;
1460 0 : if (y1)
1461 0 : *y1 = 0.0;
1462 0 : if (x2)
1463 0 : *x2 = 0.0;
1464 0 : if (y2)
1465 0 : *y2 = 0.0;
1466 0 : return CAIRO_STATUS_SUCCESS;
1467 : }
1468 :
1469 0 : _cairo_traps_init (&traps);
1470 :
1471 0 : status = _cairo_path_fixed_fill_to_traps (path,
1472 : gstate->fill_rule,
1473 : gstate->tolerance,
1474 : &traps);
1475 0 : if (likely (status == CAIRO_STATUS_SUCCESS)) {
1476 0 : _cairo_gstate_traps_extents_to_user_rectangle (gstate, &traps,
1477 : x1, y1, x2, y2);
1478 : }
1479 :
1480 0 : _cairo_traps_fini (&traps);
1481 :
1482 0 : return status;
1483 : }
1484 :
1485 : cairo_status_t
1486 0 : _cairo_gstate_reset_clip (cairo_gstate_t *gstate)
1487 : {
1488 0 : _cairo_clip_reset (&gstate->clip);
1489 :
1490 0 : return CAIRO_STATUS_SUCCESS;
1491 : }
1492 :
1493 : cairo_status_t
1494 0 : _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
1495 : {
1496 0 : return _cairo_clip_clip (&gstate->clip,
1497 : path, gstate->fill_rule,
1498 : gstate->tolerance, gstate->antialias);
1499 : }
1500 :
1501 : static cairo_bool_t
1502 0 : _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 0 : is_bounded = _cairo_surface_get_extents (gstate->target, extents);
1509 :
1510 0 : clip_extents = _cairo_clip_get_extents (&gstate->clip);
1511 0 : if (clip_extents != NULL) {
1512 : cairo_bool_t is_empty;
1513 :
1514 0 : is_empty = _cairo_rectangle_intersect (extents, clip_extents);
1515 0 : is_bounded = TRUE;
1516 : }
1517 :
1518 0 : return is_bounded;
1519 : }
1520 :
1521 : cairo_bool_t
1522 0 : _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 0 : if (! _cairo_gstate_int_clip_extents (gstate, &extents))
1532 0 : return FALSE;
1533 :
1534 0 : px1 = extents.x;
1535 0 : py1 = extents.y;
1536 0 : px2 = extents.x + (int) extents.width;
1537 0 : py2 = extents.y + (int) extents.height;
1538 :
1539 0 : _cairo_gstate_backend_to_user_rectangle (gstate,
1540 : &px1, &py1, &px2, &py2,
1541 : NULL);
1542 :
1543 0 : if (x1)
1544 0 : *x1 = px1;
1545 0 : if (y1)
1546 0 : *y1 = py1;
1547 0 : if (x2)
1548 0 : *x2 = px2;
1549 0 : if (y2)
1550 0 : *y2 = py2;
1551 :
1552 0 : return TRUE;
1553 : }
1554 :
1555 : cairo_rectangle_list_t*
1556 0 : _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 0 : _cairo_clip_init_copy (&clip, &gstate->clip);
1563 :
1564 0 : if (_cairo_surface_get_extents (gstate->target, &extents))
1565 0 : _cairo_clip_rectangle (&clip, &extents);
1566 :
1567 0 : list = _cairo_clip_copy_rectangle_list (&clip, gstate);
1568 0 : _cairo_clip_fini (&clip);
1569 :
1570 0 : return list;
1571 : }
1572 :
1573 : static void
1574 6 : _cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate)
1575 : {
1576 6 : if (gstate->scaled_font == NULL)
1577 6 : return;
1578 :
1579 0 : if (gstate->previous_scaled_font != NULL)
1580 0 : cairo_scaled_font_destroy (gstate->previous_scaled_font);
1581 :
1582 0 : gstate->previous_scaled_font = gstate->scaled_font;
1583 0 : gstate->scaled_font = NULL;
1584 : }
1585 :
1586 : cairo_status_t
1587 0 : _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 0 : font_face = cairo_toy_font_face_create (family, slant, weight);
1596 0 : if (font_face->status)
1597 0 : return font_face->status;
1598 :
1599 0 : status = _cairo_gstate_set_font_face (gstate, font_face);
1600 0 : cairo_font_face_destroy (font_face);
1601 :
1602 0 : return status;
1603 : }
1604 :
1605 : cairo_status_t
1606 0 : _cairo_gstate_set_font_size (cairo_gstate_t *gstate,
1607 : double size)
1608 : {
1609 0 : _cairo_gstate_unset_scaled_font (gstate);
1610 :
1611 0 : cairo_matrix_init_scale (&gstate->font_matrix, size, size);
1612 :
1613 0 : return CAIRO_STATUS_SUCCESS;
1614 : }
1615 :
1616 : cairo_status_t
1617 111 : _cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
1618 : const cairo_matrix_t *matrix)
1619 : {
1620 111 : if (memcmp (matrix, &gstate->font_matrix, sizeof (cairo_matrix_t)) == 0)
1621 109 : return CAIRO_STATUS_SUCCESS;
1622 :
1623 2 : if (! _cairo_matrix_is_invertible (matrix)) {
1624 : /* rank 0 matrices are ok even though they are not invertible */
1625 0 : if (!(matrix->xx == 0. && matrix->xy == 0. &&
1626 0 : matrix->yx == 0. && matrix->yy == 0.)) {
1627 0 : return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
1628 : }
1629 : }
1630 :
1631 2 : _cairo_gstate_unset_scaled_font (gstate);
1632 :
1633 2 : gstate->font_matrix = *matrix;
1634 :
1635 2 : return CAIRO_STATUS_SUCCESS;
1636 : }
1637 :
1638 : void
1639 0 : _cairo_gstate_get_font_matrix (cairo_gstate_t *gstate,
1640 : cairo_matrix_t *matrix)
1641 : {
1642 0 : *matrix = gstate->font_matrix;
1643 0 : }
1644 :
1645 : void
1646 111 : _cairo_gstate_set_font_options (cairo_gstate_t *gstate,
1647 : const cairo_font_options_t *options)
1648 : {
1649 111 : if (memcmp (options, &gstate->font_options, sizeof (cairo_font_options_t)) == 0)
1650 109 : return;
1651 :
1652 2 : _cairo_gstate_unset_scaled_font (gstate);
1653 :
1654 2 : _cairo_font_options_init_copy (&gstate->font_options, options);
1655 : }
1656 :
1657 : void
1658 0 : _cairo_gstate_get_font_options (cairo_gstate_t *gstate,
1659 : cairo_font_options_t *options)
1660 : {
1661 0 : *options = gstate->font_options;
1662 0 : }
1663 :
1664 : cairo_status_t
1665 0 : _cairo_gstate_get_font_face (cairo_gstate_t *gstate,
1666 : cairo_font_face_t **font_face)
1667 : {
1668 : cairo_status_t status;
1669 :
1670 0 : status = _cairo_gstate_ensure_font_face (gstate);
1671 0 : if (unlikely (status))
1672 0 : return status;
1673 :
1674 0 : *font_face = gstate->font_face;
1675 :
1676 0 : return CAIRO_STATUS_SUCCESS;
1677 : }
1678 :
1679 : cairo_status_t
1680 71 : _cairo_gstate_get_scaled_font (cairo_gstate_t *gstate,
1681 : cairo_scaled_font_t **scaled_font)
1682 : {
1683 : cairo_status_t status;
1684 :
1685 71 : status = _cairo_gstate_ensure_scaled_font (gstate);
1686 71 : if (unlikely (status))
1687 0 : return status;
1688 :
1689 71 : *scaled_font = gstate->scaled_font;
1690 :
1691 71 : 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
1772 2 : _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate)
1773 : {
1774 : cairo_font_face_t *font_face;
1775 :
1776 2 : if (gstate->font_face != NULL)
1777 2 : return gstate->font_face->status;
1778 :
1779 :
1780 0 : font_face = cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT,
1781 : CAIRO_FONT_SLANT_DEFAULT,
1782 : CAIRO_FONT_WEIGHT_DEFAULT);
1783 0 : if (font_face->status)
1784 0 : return font_face->status;
1785 :
1786 0 : gstate->font_face = font_face;
1787 :
1788 0 : return CAIRO_STATUS_SUCCESS;
1789 : }
1790 :
1791 : static cairo_status_t
1792 125 : _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 125 : if (gstate->scaled_font != NULL)
1799 123 : return gstate->scaled_font->status;
1800 :
1801 2 : status = _cairo_gstate_ensure_font_face (gstate);
1802 2 : if (unlikely (status))
1803 0 : return status;
1804 :
1805 2 : cairo_surface_get_font_options (gstate->target, &options);
1806 2 : cairo_font_options_merge (&options, &gstate->font_options);
1807 :
1808 2 : scaled_font = cairo_scaled_font_create (gstate->font_face,
1809 2 : &gstate->font_matrix,
1810 2 : &gstate->ctm,
1811 : &options);
1812 :
1813 2 : status = cairo_scaled_font_status (scaled_font);
1814 2 : if (unlikely (status))
1815 0 : return status;
1816 :
1817 2 : gstate->scaled_font = scaled_font;
1818 :
1819 2 : return CAIRO_STATUS_SUCCESS;
1820 : }
1821 :
1822 : cairo_status_t
1823 0 : _cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
1824 : cairo_font_extents_t *extents)
1825 : {
1826 0 : cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate);
1827 0 : if (unlikely (status))
1828 0 : return status;
1829 :
1830 0 : cairo_scaled_font_extents (gstate->scaled_font, extents);
1831 :
1832 0 : return cairo_scaled_font_status (gstate->scaled_font);
1833 : }
1834 :
1835 : cairo_status_t
1836 0 : _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 0 : status = _cairo_gstate_ensure_scaled_font (gstate);
1850 0 : if (unlikely (status))
1851 0 : return status;
1852 :
1853 0 : 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
1861 111 : _cairo_gstate_set_font_face (cairo_gstate_t *gstate,
1862 : cairo_font_face_t *font_face)
1863 : {
1864 111 : if (font_face && font_face->status)
1865 0 : return _cairo_error (font_face->status);
1866 :
1867 111 : if (font_face == gstate->font_face)
1868 109 : return CAIRO_STATUS_SUCCESS;
1869 :
1870 2 : cairo_font_face_destroy (gstate->font_face);
1871 2 : gstate->font_face = cairo_font_face_reference (font_face);
1872 :
1873 2 : _cairo_gstate_unset_scaled_font (gstate);
1874 :
1875 2 : return CAIRO_STATUS_SUCCESS;
1876 : }
1877 :
1878 : cairo_status_t
1879 54 : _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 54 : status = _cairo_gstate_ensure_scaled_font (gstate);
1887 54 : if (unlikely (status))
1888 0 : return status;
1889 :
1890 54 : cairo_scaled_font_glyph_extents (gstate->scaled_font,
1891 : glyphs, num_glyphs,
1892 : extents);
1893 :
1894 54 : return cairo_scaled_font_status (gstate->scaled_font);
1895 : }
1896 :
1897 : cairo_status_t
1898 0 : _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 0 : if (unlikely (gstate->source->status))
1918 0 : return gstate->source->status;
1919 :
1920 0 : if (gstate->op == CAIRO_OPERATOR_DEST)
1921 0 : return CAIRO_STATUS_SUCCESS;
1922 :
1923 0 : if (_clipped (gstate))
1924 0 : return CAIRO_STATUS_SUCCESS;
1925 :
1926 0 : status = _cairo_gstate_ensure_scaled_font (gstate);
1927 0 : if (unlikely (status))
1928 0 : return status;
1929 :
1930 0 : transformed_glyphs = stack_transformed_glyphs;
1931 0 : transformed_clusters = stack_transformed_clusters;
1932 :
1933 0 : if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) {
1934 0 : transformed_glyphs = cairo_glyph_allocate (num_glyphs);
1935 0 : if (unlikely (transformed_glyphs == NULL)) {
1936 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1937 0 : goto CLEANUP_GLYPHS;
1938 : }
1939 : }
1940 :
1941 : /* Just in case */
1942 0 : if (!clusters)
1943 0 : num_clusters = 0;
1944 :
1945 0 : if (num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) {
1946 0 : transformed_clusters = cairo_text_cluster_allocate (num_clusters);
1947 0 : if (unlikely (transformed_clusters == NULL)) {
1948 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1949 0 : goto CLEANUP_GLYPHS;
1950 : }
1951 : }
1952 :
1953 0 : 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 0 : if (status || num_glyphs == 0)
1963 : goto CLEANUP_GLYPHS;
1964 :
1965 0 : op = _reduce_op (gstate);
1966 0 : if (op == CAIRO_OPERATOR_CLEAR) {
1967 0 : pattern = &_cairo_pattern_clear.base;
1968 : } else {
1969 0 : _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
1970 0 : pattern = &source_pattern.base;
1971 : }
1972 0 : _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 0 : if (cairo_surface_has_show_text_glyphs (gstate->target) ||
1989 0 : _cairo_scaled_font_get_max_scale (gstate->scaled_font) <=
1990 0 : _cairo_surface_get_text_path_fill_threshold (gstate->target))
1991 : {
1992 0 : 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 0 : _cairo_path_fixed_init (&path);
2005 :
2006 0 : status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
2007 : transformed_glyphs, num_glyphs,
2008 : &path);
2009 :
2010 0 : if (status == CAIRO_STATUS_SUCCESS && !_cairo_path_fixed_fill_is_empty (&path)) {
2011 0 : status = _cairo_surface_fill (gstate->target, op, pattern,
2012 : &path,
2013 : CAIRO_FILL_RULE_WINDING,
2014 : gstate->tolerance,
2015 0 : 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 0 : 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 0 : _cairo_path_fixed_fini (&path);
2031 : }
2032 :
2033 0 : _cairo_clip_fini (&clip);
2034 :
2035 : CLEANUP_GLYPHS:
2036 0 : if (transformed_glyphs != stack_transformed_glyphs)
2037 0 : cairo_glyph_free (transformed_glyphs);
2038 0 : if (transformed_clusters != stack_transformed_clusters)
2039 0 : cairo_text_cluster_free (transformed_clusters);
2040 :
2041 0 : return status;
2042 : }
2043 :
2044 : cairo_status_t
2045 0 : _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 0 : status = _cairo_gstate_ensure_scaled_font (gstate);
2055 0 : if (unlikely (status))
2056 0 : return status;
2057 :
2058 0 : if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) {
2059 0 : transformed_glyphs = stack_transformed_glyphs;
2060 : } else {
2061 0 : transformed_glyphs = cairo_glyph_allocate (num_glyphs);
2062 0 : if (unlikely (transformed_glyphs == NULL))
2063 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2064 : }
2065 :
2066 0 : status = _cairo_gstate_transform_glyphs_to_backend (gstate,
2067 : glyphs, num_glyphs,
2068 : NULL, 0, 0,
2069 : transformed_glyphs,
2070 : NULL, NULL);
2071 0 : if (unlikely (status))
2072 0 : goto CLEANUP_GLYPHS;
2073 :
2074 0 : status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
2075 : transformed_glyphs, num_glyphs,
2076 : path);
2077 :
2078 : CLEANUP_GLYPHS:
2079 0 : if (transformed_glyphs != stack_transformed_glyphs)
2080 0 : cairo_glyph_free (transformed_glyphs);
2081 :
2082 0 : return status;
2083 : }
2084 :
2085 : cairo_status_t
2086 0 : _cairo_gstate_set_antialias (cairo_gstate_t *gstate,
2087 : cairo_antialias_t antialias)
2088 : {
2089 0 : gstate->antialias = antialias;
2090 :
2091 0 : return CAIRO_STATUS_SUCCESS;
2092 : }
2093 :
2094 : cairo_antialias_t
2095 0 : _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
2096 : {
2097 0 : 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
2119 0 : _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 0 : cairo_matrix_t *ctm = &gstate->ctm;
2131 0 : cairo_matrix_t *font_matrix = &gstate->font_matrix;
2132 0 : cairo_matrix_t *device_transform = &gstate->target->device_transform;
2133 0 : cairo_bool_t drop = FALSE;
2134 0 : double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
2135 :
2136 0 : if (num_transformed_glyphs != NULL) {
2137 : cairo_rectangle_int_t surface_extents;
2138 :
2139 0 : drop = TRUE;
2140 0 : if (! _cairo_gstate_int_clip_extents (gstate, &surface_extents)) {
2141 0 : drop = FALSE; /* unbounded surface */
2142 : } else {
2143 0 : double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font);
2144 0 : if (surface_extents.width == 0 || surface_extents.height == 0) {
2145 : /* No visible area. Don't draw anything */
2146 0 : *num_transformed_glyphs = 0;
2147 0 : 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 0 : x1 = surface_extents.x - scale10;
2158 0 : y1 = surface_extents.y - scale10;
2159 0 : x2 = surface_extents.x + (int) surface_extents.width + scale10;
2160 0 : y2 = surface_extents.y + (int) surface_extents.height + scale10;
2161 : }
2162 :
2163 0 : if (!drop)
2164 0 : *num_transformed_glyphs = num_glyphs;
2165 : } else
2166 0 : num_transformed_glyphs = &j;
2167 :
2168 : #define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
2169 :
2170 0 : j = 0;
2171 0 : if (_cairo_matrix_is_identity (ctm) &&
2172 0 : _cairo_matrix_is_identity (device_transform) &&
2173 0 : font_matrix->x0 == 0 && font_matrix->y0 == 0)
2174 : {
2175 0 : if (! drop) {
2176 0 : memcpy (transformed_glyphs, glyphs,
2177 : num_glyphs * sizeof (cairo_glyph_t));
2178 0 : j = num_glyphs;
2179 0 : } else if (num_clusters == 0) {
2180 0 : for (i = 0; i < num_glyphs; i++) {
2181 0 : transformed_glyphs[j].index = glyphs[i].index;
2182 0 : transformed_glyphs[j].x = glyphs[i].x;
2183 0 : transformed_glyphs[j].y = glyphs[i].y;
2184 0 : if (KEEP_GLYPH (transformed_glyphs[j]))
2185 0 : j++;
2186 : }
2187 : } else {
2188 : const cairo_glyph_t *cur_glyph;
2189 :
2190 0 : if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2191 0 : cur_glyph = glyphs + num_glyphs - 1;
2192 : else
2193 0 : cur_glyph = glyphs;
2194 :
2195 0 : for (i = 0; i < num_clusters; i++) {
2196 0 : cairo_bool_t cluster_visible = FALSE;
2197 :
2198 0 : for (k = 0; k < clusters[i].num_glyphs; k++) {
2199 0 : transformed_glyphs[j+k].index = cur_glyph->index;
2200 0 : transformed_glyphs[j+k].x = cur_glyph->x;
2201 0 : transformed_glyphs[j+k].y = cur_glyph->y;
2202 0 : if (KEEP_GLYPH (transformed_glyphs[j+k]))
2203 0 : cluster_visible = TRUE;
2204 :
2205 0 : if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2206 0 : cur_glyph--;
2207 : else
2208 0 : cur_glyph++;
2209 : }
2210 :
2211 0 : transformed_clusters[i] = clusters[i];
2212 0 : if (cluster_visible)
2213 0 : j += k;
2214 : else
2215 0 : transformed_clusters[i].num_glyphs = 0;
2216 : }
2217 : }
2218 : }
2219 0 : else if (_cairo_matrix_is_translation (ctm) &&
2220 0 : _cairo_matrix_is_translation (device_transform))
2221 0 : {
2222 0 : double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
2223 0 : double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
2224 :
2225 0 : if (! drop || num_clusters == 0) {
2226 0 : for (i = 0; i < num_glyphs; i++) {
2227 0 : transformed_glyphs[j].index = glyphs[i].index;
2228 0 : transformed_glyphs[j].x = glyphs[i].x + tx;
2229 0 : transformed_glyphs[j].y = glyphs[i].y + ty;
2230 0 : if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
2231 0 : j++;
2232 : }
2233 : } else {
2234 : const cairo_glyph_t *cur_glyph;
2235 :
2236 0 : if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2237 0 : cur_glyph = glyphs + num_glyphs - 1;
2238 : else
2239 0 : cur_glyph = glyphs;
2240 :
2241 0 : for (i = 0; i < num_clusters; i++) {
2242 0 : cairo_bool_t cluster_visible = FALSE;
2243 :
2244 0 : for (k = 0; k < clusters[i].num_glyphs; k++) {
2245 0 : transformed_glyphs[j+k].index = cur_glyph->index;
2246 0 : transformed_glyphs[j+k].x = cur_glyph->x + tx;
2247 0 : transformed_glyphs[j+k].y = cur_glyph->y + ty;
2248 0 : if (KEEP_GLYPH (transformed_glyphs[j+k]))
2249 0 : cluster_visible = TRUE;
2250 :
2251 0 : if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2252 0 : cur_glyph--;
2253 : else
2254 0 : cur_glyph++;
2255 : }
2256 :
2257 0 : transformed_clusters[i] = clusters[i];
2258 0 : if (cluster_visible)
2259 0 : j += k;
2260 : else
2261 0 : transformed_clusters[i].num_glyphs = 0;
2262 : }
2263 : }
2264 : }
2265 : else
2266 : {
2267 : cairo_matrix_t aggregate_transform;
2268 :
2269 0 : cairo_matrix_init_translate (&aggregate_transform,
2270 : gstate->font_matrix.x0,
2271 : gstate->font_matrix.y0);
2272 0 : cairo_matrix_multiply (&aggregate_transform,
2273 : &aggregate_transform, ctm);
2274 0 : cairo_matrix_multiply (&aggregate_transform,
2275 : &aggregate_transform, device_transform);
2276 :
2277 0 : if (! drop || num_clusters == 0) {
2278 0 : for (i = 0; i < num_glyphs; i++) {
2279 0 : transformed_glyphs[j] = glyphs[i];
2280 0 : cairo_matrix_transform_point (&aggregate_transform,
2281 0 : &transformed_glyphs[j].x,
2282 0 : &transformed_glyphs[j].y);
2283 0 : if (! drop || KEEP_GLYPH (transformed_glyphs[j]))
2284 0 : j++;
2285 : }
2286 : } else {
2287 : const cairo_glyph_t *cur_glyph;
2288 :
2289 0 : if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2290 0 : cur_glyph = glyphs + num_glyphs - 1;
2291 : else
2292 0 : cur_glyph = glyphs;
2293 :
2294 0 : for (i = 0; i < num_clusters; i++) {
2295 0 : cairo_bool_t cluster_visible = FALSE;
2296 0 : for (k = 0; k < clusters[i].num_glyphs; k++) {
2297 0 : transformed_glyphs[j+k] = *cur_glyph;
2298 0 : cairo_matrix_transform_point (&aggregate_transform,
2299 0 : &transformed_glyphs[j+k].x,
2300 0 : &transformed_glyphs[j+k].y);
2301 0 : if (KEEP_GLYPH (transformed_glyphs[j+k]))
2302 0 : cluster_visible = TRUE;
2303 :
2304 0 : if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)
2305 0 : cur_glyph--;
2306 : else
2307 0 : cur_glyph++;
2308 : }
2309 :
2310 0 : transformed_clusters[i] = clusters[i];
2311 0 : if (cluster_visible)
2312 0 : j += k;
2313 : else
2314 0 : transformed_clusters[i].num_glyphs = 0;
2315 : }
2316 : }
2317 : }
2318 0 : *num_transformed_glyphs = j;
2319 :
2320 0 : if (num_clusters != 0 && cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) {
2321 0 : for (i = 0; i < --j; i++) {
2322 : cairo_glyph_t tmp;
2323 :
2324 0 : tmp = transformed_glyphs[i];
2325 0 : transformed_glyphs[i] = transformed_glyphs[j];
2326 0 : transformed_glyphs[j] = tmp;
2327 : }
2328 : }
2329 :
2330 0 : return CAIRO_STATUS_SUCCESS;
2331 : }
|