Rev 14952 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14952 | fschmid | 1 | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | /* cairo - a vector graphics library with display and print output |
||
3 | * |
||
4 | * Copyright © 2002 University of Southern California |
||
5 | * Copyright © 2005 Red Hat, Inc. |
||
6 | * |
||
7 | * This library is free software; you can redistribute it and/or |
||
8 | * modify it either under the terms of the GNU Lesser General Public |
||
9 | * License version 2.1 as published by the Free Software Foundation |
||
10 | * (the "LGPL") or, at your option, under the terms of the Mozilla |
||
11 | * Public License Version 1.1 (the "MPL"). If you do not alter this |
||
12 | * notice, a recipient may use your version of this file under either |
||
13 | * the MPL or the LGPL. |
||
14 | * |
||
15 | * You should have received a copy of the LGPL along with this library |
||
16 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
||
18122 | mrdocs | 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
14952 | fschmid | 18 | * You should have received a copy of the MPL along with this library |
19 | * in the file COPYING-MPL-1.1 |
||
20 | * |
||
21 | * The contents of this file are subject to the Mozilla Public License |
||
22 | * Version 1.1 (the "License"); you may not use this file except in |
||
23 | * compliance with the License. You may obtain a copy of the License at |
||
24 | * http://www.mozilla.org/MPL/ |
||
25 | * |
||
26 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
||
27 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
||
28 | * the specific language governing rights and limitations. |
||
29 | * |
||
30 | * The Original Code is the cairo graphics library. |
||
31 | * |
||
32 | * The Initial Developer of the Original Code is University of Southern |
||
33 | * California. |
||
34 | * |
||
35 | * Contributor(s): |
||
36 | * Carl D. Worth <cworth@cworth.org> |
||
37 | */ |
||
38 | |||
39 | #include "cairoint.h" |
||
40 | |||
41 | #include "cairo-surface-fallback-private.h" |
||
42 | #include "cairo-clip-private.h" |
||
43 | #include "cairo-meta-surface-private.h" |
||
44 | #include "cairo-region-private.h" |
||
45 | #include "cairo-tee-surface-private.h" |
||
46 | |||
47 | #define DEFINE_NIL_SURFACE(status, name) \ |
||
48 | const cairo_surface_t name = { \ |
||
49 | NULL, /* backend */ \ |
||
50 | CAIRO_SURFACE_TYPE_IMAGE, /* type */ \ |
||
51 | CAIRO_CONTENT_COLOR, /* content */ \ |
||
52 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \ |
||
53 | status, /* status */ \ |
||
54 | FALSE, /* finished */ \ |
||
55 | 0, /* unique id */ \ |
||
56 | { 0, 0, 0, NULL, }, /* user_data */ \ |
||
57 | { 0, 0, 0, NULL, }, /* mime_data */ \ |
||
58 | { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform */ \ |
||
59 | { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform_inverse */ \ |
||
60 | 0.0, /* x_resolution */ \ |
||
61 | 0.0, /* y_resolution */ \ |
||
62 | 0.0, /* x_fallback_resolution */ \ |
||
63 | 0.0, /* y_fallback_resolution */ \ |
||
64 | NULL, /* snapshot_of */ \ |
||
65 | NULL, /* snapshot_detach */ \ |
||
66 | { 0, /* size */ \ |
||
67 | 0, /* num_elements */ \ |
||
68 | 0, /* element_size */ \ |
||
69 | NULL, /* elements */ \ |
||
70 | }, /* snapshots */ \ |
||
71 | FALSE, /* has_font_options */ \ |
||
72 | { CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \ |
||
73 | CAIRO_SUBPIXEL_ORDER_DEFAULT, /* subpixel_order */ \ |
||
74 | CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \ |
||
75 | CAIRO_HINT_METRICS_DEFAULT /* hint_metrics */ \ |
||
76 | } /* font_options */ \ |
||
77 | } |
||
78 | |||
79 | /* XXX error object! */ |
||
80 | |||
81 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil); |
||
82 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_SURFACE_TYPE_MISMATCH, _cairo_surface_nil_surface_type_mismatch); |
||
83 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STATUS, _cairo_surface_nil_invalid_status); |
||
84 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_CONTENT, _cairo_surface_nil_invalid_content); |
||
85 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_FORMAT, _cairo_surface_nil_invalid_format); |
||
86 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_VISUAL, _cairo_surface_nil_invalid_visual); |
||
87 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_FILE_NOT_FOUND, _cairo_surface_nil_file_not_found); |
||
88 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_TEMP_FILE_ERROR, _cairo_surface_nil_temp_file_error); |
||
89 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_READ_ERROR, _cairo_surface_nil_read_error); |
||
90 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_error); |
||
91 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STRIDE, _cairo_surface_nil_invalid_stride); |
||
92 | static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_SIZE, _cairo_surface_nil_invalid_size); |
||
93 | |||
94 | static void |
||
95 | _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern, |
||
96 | cairo_surface_t *destination, |
||
97 | cairo_pattern_t *pattern_copy); |
||
98 | |||
99 | /** |
||
100 | * _cairo_surface_set_error: |
||
101 | * @surface: a surface |
||
102 | * @status: a status value indicating an error |
||
103 | * |
||
104 | * Atomically sets surface->status to @status and calls _cairo_error; |
||
105 | * Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal |
||
106 | * status values. |
||
107 | * |
||
108 | * All assignments of an error status to surface->status should happen |
||
109 | * through _cairo_surface_set_error(). Note that due to the nature of |
||
110 | * the atomic operation, it is not safe to call this function on the |
||
111 | * nil objects. |
||
112 | * |
||
113 | * The purpose of this function is to allow the user to set a |
||
114 | * breakpoint in _cairo_error() to generate a stack trace for when the |
||
115 | * user causes cairo to detect an error. |
||
116 | * |
||
117 | * Return value: the error status. |
||
118 | **/ |
||
119 | cairo_status_t |
||
120 | _cairo_surface_set_error (cairo_surface_t *surface, |
||
121 | cairo_status_t status) |
||
122 | { |
||
123 | if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED) |
||
124 | return status; |
||
125 | |||
126 | /* Don't overwrite an existing error. This preserves the first |
||
127 | * error, which is the most significant. */ |
||
128 | _cairo_status_set_error (&surface->status, status); |
||
129 | |||
130 | return _cairo_error (status); |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * cairo_surface_get_type: |
||
135 | * @surface: a #cairo_surface_t |
||
136 | * |
||
137 | * This function returns the type of the backend used to create |
||
138 | * a surface. See #cairo_surface_type_t for available types. |
||
139 | * |
||
140 | * Return value: The type of @surface. |
||
141 | * |
||
142 | * Since: 1.2 |
||
143 | **/ |
||
144 | cairo_surface_type_t |
||
145 | cairo_surface_get_type (cairo_surface_t *surface) |
||
146 | { |
||
147 | /* We don't use surface->backend->type here so that some of the |
||
148 | * special "wrapper" surfaces such as cairo_paginated_surface_t |
||
149 | * can override surface->type with the type of the "child" |
||
150 | * surface. */ |
||
151 | return surface->type; |
||
152 | } |
||
153 | slim_hidden_def (cairo_surface_get_type); |
||
154 | |||
155 | /** |
||
156 | * cairo_surface_get_content: |
||
157 | * @surface: a #cairo_surface_t |
||
158 | * |
||
159 | * This function returns the content type of @surface which indicates |
||
160 | * whether the surface contains color and/or alpha information. See |
||
161 | * #cairo_content_t. |
||
162 | * |
||
163 | * Return value: The content type of @surface. |
||
164 | * |
||
165 | * Since: 1.2 |
||
166 | **/ |
||
167 | cairo_content_t |
||
168 | cairo_surface_get_content (cairo_surface_t *surface) |
||
169 | { |
||
170 | return surface->content; |
||
171 | } |
||
172 | slim_hidden_def(cairo_surface_get_content); |
||
173 | |||
174 | /** |
||
175 | * cairo_surface_status: |
||
176 | * @surface: a #cairo_surface_t |
||
177 | * |
||
178 | * Checks whether an error has previously occurred for this |
||
179 | * surface. |
||
180 | * |
||
181 | * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NULL_POINTER, |
||
182 | * %CAIRO_STATUS_NO_MEMORY, %CAIRO_STATUS_READ_ERROR, |
||
183 | * %CAIRO_STATUS_INVALID_CONTENT, %CAIRO_STATUS_INVALID_FORMAT, or |
||
184 | * %CAIRO_STATUS_INVALID_VISUAL. |
||
185 | **/ |
||
186 | cairo_status_t |
||
187 | cairo_surface_status (cairo_surface_t *surface) |
||
188 | { |
||
189 | return surface->status; |
||
190 | } |
||
191 | slim_hidden_def (cairo_surface_status); |
||
192 | |||
193 | static unsigned int |
||
194 | _cairo_surface_allocate_unique_id (void) |
||
195 | { |
||
196 | static unsigned int unique_id; |
||
197 | |||
198 | #if CAIRO_NO_MUTEX |
||
199 | if (++unique_id == 0) |
||
200 | unique_id = 1; |
||
201 | return unique_id; |
||
202 | #else |
||
203 | unsigned int old, id; |
||
204 | |||
205 | do { |
||
206 | old = _cairo_atomic_uint_get (&unique_id); |
||
207 | id = old + 1; |
||
208 | if (id == 0) |
||
209 | id = 1; |
||
210 | } while (! _cairo_atomic_uint_cmpxchg (&unique_id, old, id)); |
||
211 | |||
212 | return id; |
||
213 | #endif |
||
214 | } |
||
215 | |||
216 | static cairo_bool_t |
||
217 | _cairo_surface_has_snapshots (cairo_surface_t *surface) |
||
218 | { |
||
219 | return surface->snapshots.num_elements != 0; |
||
220 | } |
||
221 | |||
222 | static void |
||
223 | _cairo_surface_detach_snapshots (cairo_surface_t *surface) |
||
224 | { |
||
225 | cairo_surface_t **snapshots; |
||
226 | unsigned int i; |
||
227 | |||
228 | if (! _cairo_surface_has_snapshots (surface)) |
||
229 | return; |
||
230 | |||
231 | /* XXX do something intelligent! */ |
||
232 | |||
233 | snapshots = _cairo_array_index (&surface->snapshots, 0); |
||
234 | for (i = 0; i < surface->snapshots.num_elements; i++) { |
||
235 | snapshots[i]->snapshot_of = NULL; |
||
236 | |||
237 | if (snapshots[i]->snapshot_detach != NULL) |
||
238 | snapshots[i]->snapshot_detach (snapshots[i]); |
||
239 | |||
240 | cairo_surface_destroy (snapshots[i]); |
||
241 | } |
||
242 | surface->snapshots.num_elements = 0; |
||
243 | |||
244 | assert (! _cairo_surface_has_snapshots (surface)); |
||
245 | } |
||
246 | |||
247 | cairo_status_t |
||
248 | _cairo_surface_attach_snapshot (cairo_surface_t *surface, |
||
249 | cairo_surface_t *snapshot, |
||
250 | cairo_surface_func_t detach_func) |
||
251 | { |
||
252 | cairo_status_t status; |
||
253 | |||
254 | assert (surface != snapshot); |
||
255 | |||
256 | if (snapshot->snapshot_of != NULL) |
||
257 | _cairo_surface_detach_snapshot (snapshot); |
||
258 | |||
259 | snapshot->snapshot_of = surface; |
||
260 | snapshot->snapshot_detach = detach_func; |
||
261 | |||
262 | status = _cairo_array_append (&surface->snapshots, &snapshot); |
||
263 | if (unlikely (status)) |
||
264 | return status; |
||
265 | |||
266 | cairo_surface_reference (snapshot); |
||
267 | return CAIRO_STATUS_SUCCESS; |
||
268 | } |
||
269 | |||
270 | cairo_surface_t * |
||
271 | _cairo_surface_has_snapshot (cairo_surface_t *surface, |
||
272 | const cairo_surface_backend_t *backend, |
||
273 | cairo_content_t content) |
||
274 | { |
||
275 | cairo_surface_t **snapshots; |
||
276 | unsigned int i; |
||
277 | |||
278 | snapshots = _cairo_array_index (&surface->snapshots, 0); |
||
279 | for (i = 0; i < surface->snapshots.num_elements; i++) { |
||
280 | if (snapshots[i]->backend == backend && |
||
281 | snapshots[i]->content == content) |
||
282 | { |
||
283 | return snapshots[i]; |
||
284 | } |
||
285 | } |
||
286 | |||
287 | return NULL; |
||
288 | } |
||
289 | |||
290 | void |
||
291 | _cairo_surface_detach_snapshot (cairo_surface_t *snapshot) |
||
292 | { |
||
293 | cairo_surface_t *surface; |
||
294 | cairo_surface_t **snapshots; |
||
295 | unsigned int i; |
||
296 | |||
297 | assert (snapshot->snapshot_of != NULL); |
||
298 | surface = snapshot->snapshot_of; |
||
299 | |||
300 | snapshots = _cairo_array_index (&surface->snapshots, 0); |
||
301 | for (i = 0; i < surface->snapshots.num_elements; i++) { |
||
302 | if (snapshots[i] == snapshot) |
||
303 | break; |
||
304 | } |
||
305 | assert (i < surface->snapshots.num_elements); |
||
306 | |||
307 | surface->snapshots.num_elements--; |
||
308 | memmove (&snapshots[i], |
||
309 | &snapshots[i+1], |
||
310 | sizeof (cairo_surface_t *)*(surface->snapshots.num_elements - i)); |
||
311 | |||
312 | snapshot->snapshot_of = NULL; |
||
313 | |||
314 | if (snapshot->snapshot_detach != NULL) |
||
315 | snapshot->snapshot_detach (snapshot); |
||
316 | |||
317 | cairo_surface_destroy (snapshot); |
||
318 | } |
||
319 | |||
320 | static cairo_bool_t |
||
321 | _cairo_surface_is_writable (cairo_surface_t *surface) |
||
322 | { |
||
323 | return ! surface->finished && |
||
324 | surface->snapshot_of == NULL && |
||
325 | ! _cairo_surface_has_snapshots (surface); |
||
326 | } |
||
327 | |||
328 | static void |
||
329 | _cairo_surface_begin_modification (cairo_surface_t *surface) |
||
330 | { |
||
331 | assert (surface->status == CAIRO_STATUS_SUCCESS); |
||
332 | assert (! surface->finished); |
||
333 | assert (surface->snapshot_of == NULL); |
||
334 | |||
335 | _cairo_surface_detach_snapshots (surface); |
||
336 | } |
||
337 | |||
338 | void |
||
339 | _cairo_surface_init (cairo_surface_t *surface, |
||
340 | const cairo_surface_backend_t *backend, |
||
341 | cairo_content_t content) |
||
342 | { |
||
343 | CAIRO_MUTEX_INITIALIZE (); |
||
344 | |||
345 | surface->backend = backend; |
||
346 | surface->content = content; |
||
347 | surface->type = backend->type; |
||
348 | |||
349 | CAIRO_REFERENCE_COUNT_INIT (&surface->ref_count, 1); |
||
350 | surface->status = CAIRO_STATUS_SUCCESS; |
||
351 | surface->finished = FALSE; |
||
352 | surface->unique_id = _cairo_surface_allocate_unique_id (); |
||
353 | |||
354 | _cairo_user_data_array_init (&surface->user_data); |
||
355 | _cairo_user_data_array_init (&surface->mime_data); |
||
356 | |||
357 | cairo_matrix_init_identity (&surface->device_transform); |
||
358 | cairo_matrix_init_identity (&surface->device_transform_inverse); |
||
359 | |||
360 | surface->x_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; |
||
361 | surface->y_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; |
||
362 | |||
363 | surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; |
||
364 | surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; |
||
365 | |||
366 | _cairo_array_init (&surface->snapshots, sizeof (cairo_surface_t *)); |
||
367 | surface->snapshot_of = NULL; |
||
368 | |||
369 | surface->has_font_options = FALSE; |
||
370 | } |
||
371 | |||
372 | static void |
||
373 | _cairo_surface_copy_similar_properties (cairo_surface_t *surface, |
||
374 | cairo_surface_t *other) |
||
375 | { |
||
376 | if (other->has_font_options || other->backend != surface->backend) { |
||
377 | cairo_font_options_t options; |
||
378 | |||
379 | cairo_surface_get_font_options (other, &options); |
||
380 | _cairo_surface_set_font_options (surface, &options); |
||
381 | } |
||
382 | |||
383 | cairo_surface_set_fallback_resolution (surface, |
||
384 | other->x_fallback_resolution, |
||
385 | other->y_fallback_resolution); |
||
386 | } |
||
387 | |||
388 | cairo_surface_t * |
||
389 | _cairo_surface_create_similar_scratch (cairo_surface_t *other, |
||
390 | cairo_content_t content, |
||
391 | int width, |
||
392 | int height) |
||
393 | { |
||
394 | cairo_surface_t *surface; |
||
395 | |||
396 | if (unlikely (other->status)) |
||
397 | return _cairo_surface_create_in_error (other->status); |
||
398 | |||
399 | if (other->backend->create_similar == NULL) |
||
400 | return NULL; |
||
401 | |||
402 | surface = other->backend->create_similar (other, |
||
403 | content, width, height); |
||
404 | if (surface == NULL || surface->status) |
||
405 | return surface; |
||
406 | |||
407 | _cairo_surface_copy_similar_properties (surface, other); |
||
408 | |||
409 | return surface; |
||
410 | } |
||
411 | |||
412 | /** |
||
413 | * cairo_surface_create_similar: |
||
414 | * @other: an existing surface used to select the backend of the new surface |
||
415 | * @content: the content for the new surface |
||
416 | * @width: width of the new surface, (in device-space units) |
||
417 | * @height: height of the new surface (in device-space units) |
||
418 | * |
||
419 | * Create a new surface that is as compatible as possible with an |
||
420 | * existing surface. For example the new surface will have the same |
||
421 | * fallback resolution and font options as @other. Generally, the new |
||
422 | * surface will also use the same backend as @other, unless that is |
||
423 | * not possible for some reason. The type of the returned surface may |
||
424 | * be examined with cairo_surface_get_type(). |
||
425 | * |
||
426 | * Initially the surface contents are all 0 (transparent if contents |
||
427 | * have transparency, black otherwise.) |
||
428 | * |
||
429 | * Return value: a pointer to the newly allocated surface. The caller |
||
430 | * owns the surface and should call cairo_surface_destroy() when done |
||
431 | * with it. |
||
432 | * |
||
433 | * This function always returns a valid pointer, but it will return a |
||
434 | * pointer to a "nil" surface if @other is already in an error state |
||
435 | * or any other error occurs. |
||
436 | **/ |
||
437 | cairo_surface_t * |
||
438 | cairo_surface_create_similar (cairo_surface_t *other, |
||
439 | cairo_content_t content, |
||
440 | int width, |
||
441 | int height) |
||
442 | { |
||
443 | if (unlikely (other->status)) |
||
444 | return _cairo_surface_create_in_error (other->status); |
||
445 | |||
446 | if (unlikely (! CAIRO_CONTENT_VALID (content))) |
||
447 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); |
||
448 | |||
449 | return _cairo_surface_create_similar_solid (other, |
||
450 | content, width, height, |
||
451 | CAIRO_COLOR_TRANSPARENT, |
||
452 | TRUE); |
||
453 | } |
||
454 | |||
455 | cairo_surface_t * |
||
456 | _cairo_surface_create_similar_solid (cairo_surface_t *other, |
||
457 | cairo_content_t content, |
||
458 | int width, |
||
459 | int height, |
||
460 | const cairo_color_t *color, |
||
461 | cairo_bool_t allow_fallback) |
||
462 | { |
||
463 | cairo_status_t status; |
||
464 | cairo_surface_t *surface; |
||
465 | cairo_solid_pattern_t pattern; |
||
466 | |||
467 | surface = _cairo_surface_create_similar_scratch (other, content, |
||
468 | width, height); |
||
469 | if (surface == NULL && allow_fallback) |
||
470 | surface = _cairo_image_surface_create_with_content (content, |
||
471 | width, height); |
||
472 | if (surface == NULL || surface->status) |
||
473 | return surface; |
||
474 | |||
475 | _cairo_pattern_init_solid (&pattern, color, content); |
||
476 | status = _cairo_surface_paint (surface, |
||
477 | color == CAIRO_COLOR_TRANSPARENT ? |
||
478 | CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, |
||
479 | &pattern.base, NULL); |
||
480 | if (unlikely (status)) { |
||
481 | cairo_surface_destroy (surface); |
||
482 | surface = _cairo_surface_create_in_error (status); |
||
483 | } |
||
484 | |||
485 | return surface; |
||
486 | } |
||
487 | |||
488 | cairo_surface_t * |
||
489 | _cairo_surface_create_solid_pattern_surface (cairo_surface_t *other, |
||
490 | const cairo_solid_pattern_t *solid_pattern) |
||
491 | { |
||
492 | if (other->backend->create_solid_pattern_surface != NULL) { |
||
493 | cairo_surface_t *surface; |
||
494 | |||
495 | surface = other->backend->create_solid_pattern_surface (other, |
||
496 | solid_pattern); |
||
497 | if (surface) |
||
498 | return surface; |
||
499 | } |
||
500 | |||
501 | return _cairo_surface_create_similar_solid (other, |
||
502 | solid_pattern->content, |
||
503 | 1, 1, |
||
504 | &solid_pattern->color, |
||
505 | FALSE); |
||
506 | } |
||
507 | |||
508 | cairo_int_status_t |
||
509 | _cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other, |
||
510 | cairo_surface_t *solid_surface, |
||
511 | const cairo_solid_pattern_t *solid_pattern) |
||
512 | { |
||
513 | /* Solid pattern surface for these backends are special and not trivial |
||
514 | * to repaint. Skip repainting. |
||
515 | * |
||
516 | * This does not work optimally with things like analysis surface that |
||
517 | * are proxies. But returning UNSUPPORTED is *safe* as it only |
||
518 | * disables some caching. |
||
519 | */ |
||
520 | if (other->backend->create_solid_pattern_surface != NULL && |
||
521 | ! other->backend->can_repaint_solid_pattern_surface (solid_surface, |
||
522 | solid_pattern)) |
||
523 | { |
||
524 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
525 | } |
||
526 | |||
527 | return _cairo_surface_paint (solid_surface, |
||
528 | CAIRO_OPERATOR_SOURCE, |
||
529 | &solid_pattern->base, |
||
530 | NULL); |
||
531 | } |
||
532 | |||
533 | /** |
||
534 | * cairo_surface_reference: |
||
535 | * @surface: a #cairo_surface_t |
||
536 | * |
||
537 | * Increases the reference count on @surface by one. This prevents |
||
538 | * @surface from being destroyed until a matching call to |
||
539 | * cairo_surface_destroy() is made. |
||
540 | * |
||
541 | * The number of references to a #cairo_surface_t can be get using |
||
542 | * cairo_surface_get_reference_count(). |
||
543 | * |
||
544 | * Return value: the referenced #cairo_surface_t. |
||
545 | **/ |
||
546 | cairo_surface_t * |
||
547 | cairo_surface_reference (cairo_surface_t *surface) |
||
548 | { |
||
549 | if (surface == NULL || |
||
550 | CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) |
||
551 | return surface; |
||
552 | |||
553 | assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)); |
||
554 | |||
555 | _cairo_reference_count_inc (&surface->ref_count); |
||
556 | |||
557 | return surface; |
||
558 | } |
||
559 | slim_hidden_def (cairo_surface_reference); |
||
560 | |||
561 | /** |
||
562 | * cairo_surface_destroy: |
||
563 | * @surface: a #cairo_surface_t |
||
564 | * |
||
565 | * Decreases the reference count on @surface by one. If the result is |
||
566 | * zero, then @surface and all associated resources are freed. See |
||
567 | * cairo_surface_reference(). |
||
568 | **/ |
||
569 | void |
||
570 | cairo_surface_destroy (cairo_surface_t *surface) |
||
571 | { |
||
572 | if (surface == NULL || |
||
573 | CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) |
||
574 | return; |
||
575 | |||
576 | assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)); |
||
577 | |||
578 | if (! _cairo_reference_count_dec_and_test (&surface->ref_count)) |
||
579 | return; |
||
580 | |||
581 | assert (surface->snapshot_of == NULL); |
||
582 | |||
583 | if (! surface->finished) |
||
584 | cairo_surface_finish (surface); |
||
585 | |||
586 | _cairo_user_data_array_fini (&surface->user_data); |
||
587 | _cairo_user_data_array_fini (&surface->mime_data); |
||
588 | _cairo_array_fini (&surface->snapshots); |
||
589 | |||
590 | free (surface); |
||
591 | } |
||
592 | slim_hidden_def(cairo_surface_destroy); |
||
593 | |||
594 | /** |
||
595 | * cairo_surface_get_reference_count: |
||
596 | * @surface: a #cairo_surface_t |
||
597 | * |
||
598 | * Returns the current reference count of @surface. |
||
599 | * |
||
600 | * Return value: the current reference count of @surface. If the |
||
601 | * object is a nil object, 0 will be returned. |
||
602 | * |
||
603 | * Since: 1.4 |
||
604 | **/ |
||
605 | unsigned int |
||
606 | cairo_surface_get_reference_count (cairo_surface_t *surface) |
||
607 | { |
||
608 | if (surface == NULL || |
||
609 | CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) |
||
610 | return 0; |
||
611 | |||
612 | return CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count); |
||
613 | } |
||
614 | |||
615 | /** |
||
616 | * cairo_surface_finish: |
||
617 | * @surface: the #cairo_surface_t to finish |
||
618 | * |
||
619 | * This function finishes the surface and drops all references to |
||
620 | * external resources. For example, for the Xlib backend it means |
||
621 | * that cairo will no longer access the drawable, which can be freed. |
||
622 | * After calling cairo_surface_finish() the only valid operations on a |
||
623 | * surface are getting and setting user, referencing and |
||
624 | * destroying, and flushing and finishing it. |
||
625 | * Further drawing to the surface will not affect the |
||
626 | * surface but will instead trigger a %CAIRO_STATUS_SURFACE_FINISHED |
||
627 | * error. |
||
628 | * |
||
629 | * When the last call to cairo_surface_destroy() decreases the |
||
630 | * reference count to zero, cairo will call cairo_surface_finish() if |
||
631 | * it hasn't been called already, before freeing the resources |
||
632 | * associated with the surface. |
||
633 | **/ |
||
634 | void |
||
635 | cairo_surface_finish (cairo_surface_t *surface) |
||
636 | { |
||
637 | cairo_status_t status; |
||
638 | |||
639 | if (surface == NULL) |
||
640 | return; |
||
641 | |||
642 | if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) |
||
643 | return; |
||
644 | |||
645 | if (surface->finished) |
||
646 | return; |
||
647 | |||
648 | cairo_surface_flush (surface); |
||
649 | |||
650 | /* call finish even if in error mode */ |
||
651 | if (surface->backend->finish) { |
||
652 | status = surface->backend->finish (surface); |
||
653 | if (unlikely (status)) |
||
654 | status = _cairo_surface_set_error (surface, status); |
||
655 | } |
||
656 | |||
657 | surface->finished = TRUE; |
||
658 | |||
659 | if (surface->snapshot_of != NULL) |
||
660 | _cairo_surface_detach_snapshot (surface); |
||
661 | } |
||
662 | slim_hidden_def (cairo_surface_finish); |
||
663 | |||
664 | /** |
||
665 | * cairo_surface_get_user_data: |
||
666 | * @surface: a #cairo_surface_t |
||
667 | * @key: the address of the #cairo_user_data_key_t the user data was |
||
668 | * attached to |
||
669 | * |
||
670 | * Return user data previously attached to @surface using the specified |
||
671 | * key. If no user data has been attached with the given key this |
||
672 | * function returns %NULL. |
||
673 | * |
||
674 | * Return value: the user data previously attached or %NULL. |
||
675 | **/ |
||
676 | void * |
||
677 | cairo_surface_get_user_data (cairo_surface_t *surface, |
||
678 | const cairo_user_data_key_t *key) |
||
679 | { |
||
680 | return _cairo_user_data_array_get_data (&surface->user_data, |
||
681 | key); |
||
682 | } |
||
683 | |||
684 | /** |
||
685 | * cairo_surface_set_user_data: |
||
686 | * @surface: a #cairo_surface_t |
||
687 | * @key: the address of a #cairo_user_data_key_t to attach the user data to |
||
688 | * @user_data: the user data to attach to the surface |
||
689 | * @destroy: a #cairo_destroy_func_t which will be called when the |
||
690 | * surface is destroyed or when new user data is attached using the |
||
691 | * same key. |
||
692 | * |
||
693 | * Attach user data to @surface. To remove user data from a surface, |
||
694 | * call this function with the key that was used to set it and %NULL |
||
695 | * for @data. |
||
696 | * |
||
697 | * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a |
||
698 | * slot could not be allocated for the user data. |
||
699 | **/ |
||
700 | cairo_status_t |
||
701 | cairo_surface_set_user_data (cairo_surface_t *surface, |
||
702 | const cairo_user_data_key_t *key, |
||
703 | void *user_data, |
||
704 | cairo_destroy_func_t destroy) |
||
705 | { |
||
706 | if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) |
||
707 | return surface->status; |
||
708 | |||
709 | return _cairo_user_data_array_set_data (&surface->user_data, |
||
710 | key, user_data, destroy); |
||
711 | } |
||
712 | |||
713 | /** |
||
714 | * cairo_surface_get_mime_data: |
||
715 | * @surface: a #cairo_surface_t |
||
716 | * @mime_type: the mime type of the image data |
||
717 | * @data: the image data to attached to the surface |
||
718 | * @length: the length of the image data |
||
719 | * |
||
720 | * Return mime data previously attached to @surface using the |
||
721 | * specified mime type. If no data has been attached with the given |
||
722 | * mime type, @data is set %NULL. |
||
723 | * |
||
724 | * Since: 1.10 |
||
725 | **/ |
||
726 | void |
||
727 | cairo_surface_get_mime_data (cairo_surface_t *surface, |
||
728 | const char *mime_type, |
||
729 | const unsigned char **data, |
||
730 | unsigned int *length) |
||
731 | { |
||
732 | cairo_user_data_slot_t *slots; |
||
733 | int i, num_slots; |
||
734 | |||
735 | *data = NULL; |
||
736 | *length = 0; |
||
737 | if (unlikely (surface->status)) |
||
738 | return; |
||
739 | |||
740 | /* The number of mime-types attached to a surface is usually small, |
||
741 | * typically zero. Therefore it is quicker to do a strcmp() against |
||
742 | * each key than it is to intern the string (i.e. compute a hash, |
||
743 | * search the hash table, and do a final strcmp). |
||
744 | */ |
||
745 | num_slots = surface->mime_data.num_elements; |
||
746 | slots = _cairo_array_index (&surface->mime_data, 0); |
||
747 | for (i = 0; i < num_slots; i++) { |
||
748 | if (strcmp ((char *) slots[i].key, mime_type) == 0) { |
||
749 | cairo_mime_data_t *mime_data = slots[i].user_data; |
||
750 | |||
751 | *data = mime_data->data; |
||
752 | *length = mime_data->length; |
||
753 | return; |
||
754 | } |
||
755 | } |
||
756 | } |
||
757 | slim_hidden_def (cairo_surface_get_mime_data); |
||
758 | |||
759 | static void |
||
760 | _cairo_mime_data_destroy (void *ptr) |
||
761 | { |
||
762 | cairo_mime_data_t *mime_data = ptr; |
||
763 | |||
764 | if (! _cairo_reference_count_dec_and_test (&mime_data->ref_count)) |
||
765 | return; |
||
766 | |||
767 | if (mime_data->destroy && mime_data->closure) |
||
768 | mime_data->destroy (mime_data->closure); |
||
769 | |||
770 | free (mime_data); |
||
771 | } |
||
772 | |||
773 | /** |
||
774 | * cairo_surface_set_mime_data: |
||
775 | * @surface: a #cairo_surface_t |
||
776 | * @mime_type: the mime type of the image data |
||
777 | * @data: the image data to attach to the surface |
||
778 | * @length: the length of the image data |
||
779 | * @destroy: a #cairo_destroy_func_t which will be called when the |
||
780 | * surface is destroyed or when new image data is attached using the |
||
781 | * same mime type. |
||
782 | * @closure: the data to be passed to the @destroy notifier |
||
783 | * |
||
784 | * Attach an image in the format @mime_type to @surface. To remove |
||
785 | * the data from a surface, call this function with same mime type |
||
786 | * and %NULL for @data. |
||
787 | * |
||
788 | * Since: 1.10 |
||
789 | * |
||
790 | * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a |
||
791 | * slot could not be allocated for the user data. |
||
792 | **/ |
||
793 | cairo_status_t |
||
794 | cairo_surface_set_mime_data (cairo_surface_t *surface, |
||
795 | const char *mime_type, |
||
796 | const unsigned char *data, |
||
797 | unsigned int length, |
||
798 | cairo_destroy_func_t destroy, |
||
799 | void *closure) |
||
800 | { |
||
801 | cairo_status_t status; |
||
802 | cairo_mime_data_t *mime_data; |
||
803 | |||
804 | if (unlikely (surface->status)) |
||
805 | return surface->status; |
||
806 | |||
807 | status = _cairo_intern_string (&mime_type, -1); |
||
808 | if (unlikely (status)) |
||
809 | return _cairo_surface_set_error (surface, status); |
||
810 | |||
811 | if (data != NULL) { |
||
812 | mime_data = malloc (sizeof (cairo_mime_data_t)); |
||
813 | if (unlikely (mime_data == NULL)) |
||
814 | return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
815 | |||
816 | CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1); |
||
817 | |||
818 | mime_data->data = (unsigned char *) data; |
||
819 | mime_data->length = length; |
||
820 | mime_data->destroy = destroy; |
||
821 | mime_data->closure = closure; |
||
822 | } else |
||
823 | mime_data = NULL; |
||
824 | |||
825 | status = _cairo_user_data_array_set_data (&surface->mime_data, |
||
826 | (cairo_user_data_key_t *) mime_type, |
||
827 | mime_data, |
||
828 | _cairo_mime_data_destroy); |
||
829 | if (unlikely (status)) { |
||
830 | if (mime_data != NULL) |
||
831 | free (mime_data); |
||
832 | |||
833 | return _cairo_surface_set_error (surface, status); |
||
834 | } |
||
835 | |||
836 | return CAIRO_STATUS_SUCCESS; |
||
837 | } |
||
838 | slim_hidden_def (cairo_surface_set_mime_data); |
||
839 | |||
840 | static void |
||
841 | _cairo_mime_data_reference (const void *key, void *elt, void *closure) |
||
842 | { |
||
843 | cairo_mime_data_t *mime_data = elt; |
||
844 | |||
845 | _cairo_reference_count_inc (&mime_data->ref_count); |
||
846 | } |
||
847 | |||
848 | cairo_status_t |
||
849 | _cairo_surface_copy_mime_data (cairo_surface_t *dst, |
||
850 | cairo_surface_t *src) |
||
851 | { |
||
852 | cairo_status_t status; |
||
853 | |||
854 | if (dst->status) |
||
855 | return dst->status; |
||
856 | |||
857 | if (src->status) |
||
858 | return _cairo_surface_set_error (dst, src->status); |
||
859 | |||
860 | /* first copy the mime-data, discarding any already set on dst */ |
||
861 | status = _cairo_user_data_array_copy (&dst->mime_data, &src->mime_data); |
||
862 | if (unlikely (status)) |
||
863 | return _cairo_surface_set_error (dst, status); |
||
864 | |||
865 | /* now increment the reference counters for the copies */ |
||
866 | _cairo_user_data_array_foreach (&dst->mime_data, |
||
867 | _cairo_mime_data_reference, |
||
868 | NULL); |
||
869 | |||
870 | return CAIRO_STATUS_SUCCESS; |
||
871 | } |
||
872 | |||
873 | /** |
||
874 | * _cairo_surface_set_font_options: |
||
875 | * @surface: a #cairo_surface_t |
||
876 | * @options: a #cairo_font_options_t object that contains the |
||
877 | * options to use for this surface instead of backend's default |
||
878 | * font options. |
||
879 | * |
||
880 | * Sets the default font rendering options for the surface. |
||
881 | * This is useful to correctly propagate default font options when |
||
882 | * falling back to an image surface in a backend implementation. |
||
883 | * This affects the options returned in cairo_surface_get_font_options(). |
||
884 | * |
||
885 | * If @options is %NULL the surface options are reset to those of |
||
886 | * the backend default. |
||
887 | **/ |
||
888 | void |
||
889 | _cairo_surface_set_font_options (cairo_surface_t *surface, |
||
890 | cairo_font_options_t *options) |
||
891 | { |
||
892 | cairo_status_t status; |
||
893 | |||
894 | if (surface->status) |
||
895 | return; |
||
896 | |||
897 | assert (surface->snapshot_of == NULL); |
||
898 | |||
899 | if (surface->finished) { |
||
900 | status = _cairo_surface_set_error (surface, |
||
901 | CAIRO_STATUS_SURFACE_FINISHED); |
||
902 | return; |
||
903 | } |
||
904 | |||
905 | if (options) { |
||
906 | surface->has_font_options = TRUE; |
||
907 | _cairo_font_options_init_copy (&surface->font_options, options); |
||
908 | } else { |
||
909 | surface->has_font_options = FALSE; |
||
910 | } |
||
911 | } |
||
912 | |||
913 | /** |
||
914 | * cairo_surface_get_font_options: |
||
915 | * @surface: a #cairo_surface_t |
||
916 | * @options: a #cairo_font_options_t object into which to store |
||
917 | * the retrieved options. All existing values are overwritten |
||
918 | * |
||
919 | * Retrieves the default font rendering options for the surface. |
||
920 | * This allows display surfaces to report the correct subpixel order |
||
921 | * for rendering on them, print surfaces to disable hinting of |
||
922 | * metrics and so forth. The result can then be used with |
||
923 | * cairo_scaled_font_create(). |
||
924 | **/ |
||
925 | void |
||
926 | cairo_surface_get_font_options (cairo_surface_t *surface, |
||
927 | cairo_font_options_t *options) |
||
928 | { |
||
929 | if (cairo_font_options_status (options)) |
||
930 | return; |
||
931 | |||
932 | if (surface->status) { |
||
933 | _cairo_font_options_init_default (options); |
||
934 | return; |
||
935 | } |
||
936 | |||
937 | if (! surface->has_font_options) { |
||
938 | surface->has_font_options = TRUE; |
||
939 | |||
940 | _cairo_font_options_init_default (&surface->font_options); |
||
941 | |||
942 | if (!surface->finished && surface->backend->get_font_options) { |
||
943 | surface->backend->get_font_options (surface, &surface->font_options); |
||
944 | } |
||
945 | } |
||
946 | |||
947 | _cairo_font_options_init_copy (options, &surface->font_options); |
||
948 | } |
||
949 | slim_hidden_def (cairo_surface_get_font_options); |
||
950 | |||
951 | /** |
||
952 | * cairo_surface_flush: |
||
953 | * @surface: a #cairo_surface_t |
||
954 | * |
||
955 | * Do any pending drawing for the surface and also restore any |
||
956 | * temporary modification's cairo has made to the surface's |
||
957 | * state. This function must be called before switching from |
||
958 | * drawing on the surface with cairo to drawing on it directly |
||
959 | * with native APIs. If the surface doesn't support direct access, |
||
960 | * then this function does nothing. |
||
961 | **/ |
||
962 | void |
||
963 | cairo_surface_flush (cairo_surface_t *surface) |
||
964 | { |
||
965 | cairo_status_t status; |
||
966 | |||
967 | if (surface->status) |
||
968 | return; |
||
969 | |||
970 | if (surface->finished) |
||
971 | return; |
||
972 | |||
973 | /* update the current snapshots *before* the user updates the surface */ |
||
974 | _cairo_surface_detach_snapshots (surface); |
||
975 | |||
976 | if (surface->backend->flush) { |
||
977 | status = surface->backend->flush (surface); |
||
978 | if (unlikely (status)) |
||
979 | status = _cairo_surface_set_error (surface, status); |
||
980 | } |
||
981 | } |
||
982 | slim_hidden_def (cairo_surface_flush); |
||
983 | |||
984 | /** |
||
985 | * cairo_surface_mark_dirty: |
||
986 | * @surface: a #cairo_surface_t |
||
987 | * |
||
988 | * Tells cairo that drawing has been done to surface using means other |
||
989 | * than cairo, and that cairo should reread any cached areas. Note |
||
990 | * that you must call cairo_surface_flush() before doing such drawing. |
||
991 | */ |
||
992 | void |
||
993 | cairo_surface_mark_dirty (cairo_surface_t *surface) |
||
994 | { |
||
995 | cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1); |
||
996 | } |
||
997 | |||
998 | /** |
||
999 | * cairo_surface_mark_dirty_rectangle: |
||
1000 | * @surface: a #cairo_surface_t |
||
1001 | * @x: X coordinate of dirty rectangle |
||
1002 | * @y: Y coordinate of dirty rectangle |
||
1003 | * @width: width of dirty rectangle |
||
1004 | * @height: height of dirty rectangle |
||
1005 | * |
||
1006 | * Like cairo_surface_mark_dirty(), but drawing has been done only to |
||
1007 | * the specified rectangle, so that cairo can retain cached contents |
||
1008 | * for other parts of the surface. |
||
1009 | * |
||
1010 | * Any cached clip set on the surface will be reset by this function, |
||
1011 | * to make sure that future cairo calls have the clip set that they |
||
1012 | * expect. |
||
1013 | */ |
||
1014 | void |
||
1015 | cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, |
||
1016 | int x, |
||
1017 | int y, |
||
1018 | int width, |
||
1019 | int height) |
||
1020 | { |
||
1021 | cairo_status_t status; |
||
1022 | |||
1023 | if (surface->status) |
||
1024 | return; |
||
1025 | |||
1026 | assert (surface->snapshot_of == NULL); |
||
1027 | |||
1028 | if (surface->finished) { |
||
1029 | status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); |
||
1030 | return; |
||
1031 | } |
||
1032 | |||
1033 | /* The application *should* have called cairo_surface_flush() before |
||
1034 | * modifying the surface independently of cairo (and thus having to |
||
1035 | * call mark_dirty()). */ |
||
1036 | assert (! _cairo_surface_has_snapshots (surface)); |
||
1037 | |||
1038 | if (surface->backend->mark_dirty_rectangle != NULL) { |
||
1039 | /* XXX: FRAGILE: We're ignoring the scaling component of |
||
1040 | * device_transform here. I don't know what the right thing to |
||
1041 | * do would actually be if there were some scaling here, but |
||
1042 | * we avoid this since device_transfom scaling is not exported |
||
1043 | * publicly and mark_dirty is not used internally. */ |
||
1044 | status = surface->backend->mark_dirty_rectangle (surface, |
||
1045 | x + surface->device_transform.x0, |
||
1046 | y + surface->device_transform.y0, |
||
1047 | width, height); |
||
1048 | |||
1049 | if (unlikely (status)) |
||
1050 | status = _cairo_surface_set_error (surface, status); |
||
1051 | } |
||
1052 | } |
||
1053 | slim_hidden_def (cairo_surface_mark_dirty_rectangle); |
||
1054 | |||
1055 | /** |
||
1056 | * _cairo_surface_set_device_scale: |
||
1057 | * @surface: a #cairo_surface_t |
||
1058 | * @sx: a scale factor in the X direction |
||
1059 | * @sy: a scale factor in the Y direction |
||
1060 | * |
||
1061 | * Private function for setting an extra scale factor to affect all |
||
1062 | * drawing to a surface. This is used, for example, when replaying a |
||
1063 | * meta surface to an image fallback intended for an eventual |
||
1064 | * vector-oriented backend. Since the meta surface will record |
||
1065 | * coordinates in one backend space, but the image fallback uses a |
||
1066 | * different backend space, (differing by the fallback resolution |
||
1067 | * scale factors), we need a scale factor correction. |
||
1068 | * |
||
1069 | * Caution: Not all places we use device transform correctly handle |
||
1070 | * both a translate and a scale. An audit would be nice. |
||
1071 | **/ |
||
1072 | void |
||
1073 | _cairo_surface_set_device_scale (cairo_surface_t *surface, |
||
1074 | double sx, |
||
1075 | double sy) |
||
1076 | { |
||
1077 | cairo_status_t status; |
||
1078 | |||
1079 | if (surface->status) |
||
1080 | return; |
||
1081 | |||
1082 | assert (surface->snapshot_of == NULL); |
||
1083 | |||
1084 | if (surface->finished) { |
||
1085 | status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); |
||
1086 | return; |
||
1087 | } |
||
1088 | |||
1089 | _cairo_surface_begin_modification (surface); |
||
1090 | |||
1091 | surface->device_transform.xx = sx; |
||
1092 | surface->device_transform.yy = sy; |
||
1093 | surface->device_transform.xy = 0.0; |
||
1094 | surface->device_transform.yx = 0.0; |
||
1095 | |||
1096 | surface->device_transform_inverse = surface->device_transform; |
||
1097 | status = cairo_matrix_invert (&surface->device_transform_inverse); |
||
1098 | /* should always be invertible unless given pathological input */ |
||
1099 | assert (status == CAIRO_STATUS_SUCCESS); |
||
1100 | } |
||
1101 | |||
1102 | /** |
||
1103 | * cairo_surface_set_device_offset: |
||
1104 | * @surface: a #cairo_surface_t |
||
1105 | * @x_offset: the offset in the X direction, in device units |
||
1106 | * @y_offset: the offset in the Y direction, in device units |
||
1107 | * |
||
1108 | * Sets an offset that is added to the device coordinates determined |
||
1109 | * by the CTM when drawing to @surface. One use case for this function |
||
1110 | * is when we want to create a #cairo_surface_t that redirects drawing |
||
1111 | * for a portion of an onscreen surface to an offscreen surface in a |
||
1112 | * way that is completely invisible to the user of the cairo |
||
1113 | * API. Setting a transformation via cairo_translate() isn't |
||
1114 | * sufficient to do this, since functions like |
||
1115 | * cairo_device_to_user() will expose the hidden offset. |
||
1116 | * |
||
1117 | * Note that the offset affects drawing to the surface as well as |
||
1118 | * using the surface in a source pattern. |
||
1119 | **/ |
||
1120 | void |
||
1121 | cairo_surface_set_device_offset (cairo_surface_t *surface, |
||
1122 | double x_offset, |
||
1123 | double y_offset) |
||
1124 | { |
||
1125 | cairo_status_t status; |
||
1126 | |||
1127 | if (surface->status) |
||
1128 | return; |
||
1129 | |||
1130 | assert (surface->snapshot_of == NULL); |
||
1131 | |||
1132 | if (surface->finished) { |
||
1133 | status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); |
||
1134 | return; |
||
1135 | } |
||
1136 | |||
1137 | _cairo_surface_begin_modification (surface); |
||
1138 | |||
1139 | surface->device_transform.x0 = x_offset; |
||
1140 | surface->device_transform.y0 = y_offset; |
||
1141 | |||
1142 | surface->device_transform_inverse = surface->device_transform; |
||
1143 | status = cairo_matrix_invert (&surface->device_transform_inverse); |
||
1144 | /* should always be invertible unless given pathological input */ |
||
1145 | assert (status == CAIRO_STATUS_SUCCESS); |
||
1146 | } |
||
1147 | slim_hidden_def (cairo_surface_set_device_offset); |
||
1148 | |||
1149 | /** |
||
1150 | * cairo_surface_get_device_offset: |
||
1151 | * @surface: a #cairo_surface_t |
||
1152 | * @x_offset: the offset in the X direction, in device units |
||
1153 | * @y_offset: the offset in the Y direction, in device units |
||
1154 | * |
||
1155 | * This function returns the previous device offset set by |
||
1156 | * cairo_surface_set_device_offset(). |
||
1157 | * |
||
1158 | * Since: 1.2 |
||
1159 | **/ |
||
1160 | void |
||
1161 | cairo_surface_get_device_offset (cairo_surface_t *surface, |
||
1162 | double *x_offset, |
||
1163 | double *y_offset) |
||
1164 | { |
||
1165 | if (x_offset) |
||
1166 | *x_offset = surface->device_transform.x0; |
||
1167 | if (y_offset) |
||
1168 | *y_offset = surface->device_transform.y0; |
||
1169 | } |
||
1170 | slim_hidden_def (cairo_surface_get_device_offset); |
||
1171 | |||
1172 | /** |
||
1173 | * cairo_surface_set_fallback_resolution: |
||
1174 | * @surface: a #cairo_surface_t |
||
1175 | * @x_pixels_per_inch: horizontal setting for pixels per inch |
||
1176 | * @y_pixels_per_inch: vertical setting for pixels per inch |
||
1177 | * |
||
1178 | * Set the horizontal and vertical resolution for image fallbacks. |
||
1179 | * |
||
1180 | * When certain operations aren't supported natively by a backend, |
||
1181 | * cairo will fallback by rendering operations to an image and then |
||
1182 | * overlaying that image onto the output. For backends that are |
||
1183 | * natively vector-oriented, this function can be used to set the |
||
1184 | * resolution used for these image fallbacks, (larger values will |
||
1185 | * result in more detailed images, but also larger file sizes). |
||
1186 | * |
||
1187 | * Some examples of natively vector-oriented backends are the ps, pdf, |
||
1188 | * and svg backends. |
||
1189 | * |
||
1190 | * For backends that are natively raster-oriented, image fallbacks are |
||
1191 | * still possible, but they are always performed at the native |
||
1192 | * device resolution. So this function has no effect on those |
||
1193 | * backends. |
||
1194 | * |
||
1195 | * Note: The fallback resolution only takes effect at the time of |
||
1196 | * completing a page (with cairo_show_page() or cairo_copy_page()) so |
||
1197 | * there is currently no way to have more than one fallback resolution |
||
1198 | * in effect on a single page. |
||
1199 | * |
||
1200 | * The default fallback resoultion is 300 pixels per inch in both |
||
1201 | * dimensions. |
||
1202 | * |
||
1203 | * Since: 1.2 |
||
1204 | **/ |
||
1205 | void |
||
1206 | cairo_surface_set_fallback_resolution (cairo_surface_t *surface, |
||
1207 | double x_pixels_per_inch, |
||
1208 | double y_pixels_per_inch) |
||
1209 | { |
||
1210 | cairo_status_t status; |
||
1211 | |||
1212 | if (surface->status) |
||
1213 | return; |
||
1214 | |||
1215 | assert (surface->snapshot_of == NULL); |
||
1216 | |||
1217 | if (surface->finished) { |
||
1218 | status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); |
||
1219 | return; |
||
1220 | } |
||
1221 | |||
1222 | if (x_pixels_per_inch <= 0 || y_pixels_per_inch <= 0) { |
||
1223 | /* XXX Could delay raising the error until we fallback, but throwing |
||
1224 | * the error here means that we can catch the real culprit. |
||
1225 | */ |
||
1226 | status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_MATRIX); |
||
1227 | return; |
||
1228 | } |
||
1229 | |||
1230 | _cairo_surface_begin_modification (surface); |
||
1231 | |||
1232 | surface->x_fallback_resolution = x_pixels_per_inch; |
||
1233 | surface->y_fallback_resolution = y_pixels_per_inch; |
||
1234 | } |
||
1235 | slim_hidden_def (cairo_surface_set_fallback_resolution); |
||
1236 | |||
1237 | /** |
||
1238 | * cairo_surface_get_fallback_resolution: |
||
1239 | * @surface: a #cairo_surface_t |
||
1240 | * @x_pixels_per_inch: horizontal pixels per inch |
||
1241 | * @y_pixels_per_inch: vertical pixels per inch |
||
1242 | * |
||
1243 | * This function returns the previous fallback resolution set by |
||
1244 | * cairo_surface_set_fallback_resolution(), or default fallback |
||
1245 | * resolution if never set. |
||
1246 | * |
||
1247 | * Since: 1.8 |
||
1248 | **/ |
||
1249 | void |
||
1250 | cairo_surface_get_fallback_resolution (cairo_surface_t *surface, |
||
1251 | double *x_pixels_per_inch, |
||
1252 | double *y_pixels_per_inch) |
||
1253 | { |
||
1254 | if (x_pixels_per_inch) |
||
1255 | *x_pixels_per_inch = surface->x_fallback_resolution; |
||
1256 | if (y_pixels_per_inch) |
||
1257 | *y_pixels_per_inch = surface->y_fallback_resolution; |
||
1258 | } |
||
1259 | |||
1260 | cairo_bool_t |
||
1261 | _cairo_surface_has_device_transform (cairo_surface_t *surface) |
||
1262 | { |
||
1263 | return ! _cairo_matrix_is_identity (&surface->device_transform); |
||
1264 | } |
||
1265 | |||
1266 | /** |
||
1267 | * _cairo_surface_acquire_source_image: |
||
1268 | * @surface: a #cairo_surface_t |
||
1269 | * @image_out: location to store a pointer to an image surface that |
||
1270 | * has identical contents to @surface. This surface could be @surface |
||
1271 | * itself, a surface held internal to @surface, or it could be a new |
||
1272 | * surface with a copy of the relevant portion of @surface. |
||
1273 | * @image_extra: location to store image specific backend data |
||
1274 | * |
||
1275 | * Gets an image surface to use when drawing as a fallback when drawing with |
||
1276 | * @surface as a source. _cairo_surface_release_source_image() must be called |
||
1277 | * when finished. |
||
1278 | * |
||
1279 | * Return value: %CAIRO_STATUS_SUCCESS if an image was stored in @image_out. |
||
1280 | * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified |
||
1281 | * surface. Or %CAIRO_STATUS_NO_MEMORY. |
||
1282 | **/ |
||
1283 | cairo_status_t |
||
1284 | _cairo_surface_acquire_source_image (cairo_surface_t *surface, |
||
1285 | cairo_image_surface_t **image_out, |
||
1286 | void **image_extra) |
||
1287 | { |
||
1288 | cairo_status_t status; |
||
1289 | |||
1290 | if (surface->status) |
||
1291 | return surface->status; |
||
1292 | |||
1293 | assert (!surface->finished); |
||
1294 | |||
1295 | if (surface->backend->acquire_source_image == NULL) |
||
1296 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1297 | |||
1298 | status = surface->backend->acquire_source_image (surface, |
||
1299 | image_out, image_extra); |
||
1300 | if (unlikely (status)) |
||
1301 | return _cairo_surface_set_error (surface, status); |
||
1302 | |||
1303 | _cairo_debug_check_image_surface_is_defined (&(*image_out)->base); |
||
1304 | |||
1305 | return CAIRO_STATUS_SUCCESS; |
||
1306 | } |
||
1307 | |||
1308 | /** |
||
1309 | * _cairo_surface_release_source_image: |
||
1310 | * @surface: a #cairo_surface_t |
||
1311 | * @image_extra: same as return from the matching _cairo_surface_acquire_source_image() |
||
1312 | * |
||
1313 | * Releases any resources obtained with _cairo_surface_acquire_source_image() |
||
1314 | **/ |
||
1315 | void |
||
1316 | _cairo_surface_release_source_image (cairo_surface_t *surface, |
||
1317 | cairo_image_surface_t *image, |
||
1318 | void *image_extra) |
||
1319 | { |
||
1320 | assert (!surface->finished); |
||
1321 | |||
1322 | if (surface->backend->release_source_image) |
||
1323 | surface->backend->release_source_image (surface, image, image_extra); |
||
1324 | } |
||
1325 | |||
1326 | /** |
||
1327 | * _cairo_surface_acquire_dest_image: |
||
1328 | * @surface: a #cairo_surface_t |
||
1329 | * @interest_rect: area of @surface for which fallback drawing is being done. |
||
1330 | * A value of %NULL indicates that the entire surface is desired. |
||
1331 | * XXXX I'd like to get rid of being able to pass %NULL here (nothing seems to) |
||
1332 | * @image_out: location to store a pointer to an image surface that includes at least |
||
1333 | * the intersection of @interest_rect with the visible area of @surface. |
||
1334 | * This surface could be @surface itself, a surface held internal to @surface, |
||
1335 | * or it could be a new surface with a copy of the relevant portion of @surface. |
||
1336 | * If a new surface is created, it should have the same channels and depth |
||
1337 | * as @surface so that copying to and from it is exact. |
||
1338 | * @image_rect: location to store area of the original surface occupied |
||
1339 | * by the surface stored in @image. |
||
1340 | * @image_extra: location to store image specific backend data |
||
1341 | * |
||
1342 | * Retrieves a local image for a surface for implementing a fallback drawing |
||
1343 | * operation. After calling this function, the implementation of the fallback |
||
1344 | * drawing operation draws the primitive to the surface stored in @image_out |
||
1345 | * then calls _cairo_surface_release_dest_image(), |
||
1346 | * which, if a temporary surface was created, copies the bits back to the |
||
1347 | * main surface and frees the temporary surface. |
||
1348 | * |
||
1349 | * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY. |
||
1350 | * %CAIRO_INT_STATUS_UNSUPPORTED can be returned but this will mean that |
||
1351 | * the backend can't draw with fallbacks. It's possible for the routine |
||
1352 | * to store %NULL in @local_out and return %CAIRO_STATUS_SUCCESS; |
||
1353 | * that indicates that no part of @interest_rect is visible, so no drawing |
||
1354 | * is necessary. _cairo_surface_release_dest_image() should not be called in that |
||
1355 | * case. |
||
1356 | **/ |
||
1357 | cairo_status_t |
||
1358 | _cairo_surface_acquire_dest_image (cairo_surface_t *surface, |
||
1359 | cairo_rectangle_int_t *interest_rect, |
||
1360 | cairo_image_surface_t **image_out, |
||
1361 | cairo_rectangle_int_t *image_rect, |
||
1362 | void **image_extra) |
||
1363 | { |
||
1364 | cairo_status_t status; |
||
1365 | |||
1366 | if (surface->status) |
||
1367 | return surface->status; |
||
1368 | |||
1369 | assert (_cairo_surface_is_writable (surface)); |
||
1370 | |||
1371 | if (surface->backend->acquire_dest_image == NULL) |
||
1372 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1373 | |||
1374 | status = surface->backend->acquire_dest_image (surface, |
||
1375 | interest_rect, |
||
1376 | image_out, |
||
1377 | image_rect, |
||
1378 | image_extra); |
||
1379 | if (unlikely (status)) |
||
1380 | return _cairo_surface_set_error (surface, status); |
||
1381 | |||
1382 | _cairo_debug_check_image_surface_is_defined (&(*image_out)->base); |
||
1383 | |||
1384 | return CAIRO_STATUS_SUCCESS; |
||
1385 | } |
||
1386 | |||
1387 | /** |
||
1388 | * _cairo_surface_release_dest_image: |
||
1389 | * @surface: a #cairo_surface_t |
||
1390 | * @interest_rect: same as passed to the matching _cairo_surface_acquire_dest_image() |
||
1391 | * @image: same as returned from the matching _cairo_surface_acquire_dest_image() |
||
1392 | * @image_rect: same as returned from the matching _cairo_surface_acquire_dest_image() |
||
1393 | * @image_extra: same as return from the matching _cairo_surface_acquire_dest_image() |
||
1394 | * |
||
1395 | * Finishes the operation started with _cairo_surface_acquire_dest_image(), by, if |
||
1396 | * necessary, copying the image from @image back to @surface and freeing any |
||
1397 | * resources that were allocated. |
||
1398 | **/ |
||
1399 | void |
||
1400 | _cairo_surface_release_dest_image (cairo_surface_t *surface, |
||
1401 | cairo_rectangle_int_t *interest_rect, |
||
1402 | cairo_image_surface_t *image, |
||
1403 | cairo_rectangle_int_t *image_rect, |
||
1404 | void *image_extra) |
||
1405 | { |
||
1406 | assert (_cairo_surface_is_writable (surface)); |
||
1407 | |||
1408 | if (surface->backend->release_dest_image) |
||
1409 | surface->backend->release_dest_image (surface, interest_rect, |
||
1410 | image, image_rect, image_extra); |
||
1411 | } |
||
1412 | |||
1413 | static cairo_status_t |
||
1414 | _cairo_meta_surface_clone_similar (cairo_surface_t *surface, |
||
1415 | cairo_surface_t *src, |
||
1416 | cairo_content_t content, |
||
1417 | int src_x, |
||
1418 | int src_y, |
||
1419 | int width, |
||
1420 | int height, |
||
1421 | int *clone_offset_x, |
||
1422 | int *clone_offset_y, |
||
1423 | cairo_surface_t **clone_out) |
||
1424 | { |
||
1425 | cairo_meta_surface_t *meta = (cairo_meta_surface_t *) src; |
||
1426 | cairo_surface_t *similar; |
||
1427 | cairo_status_t status; |
||
1428 | |||
1429 | similar = _cairo_surface_has_snapshot (src, |
||
1430 | surface->backend, |
||
1431 | src->content & content); |
||
1432 | if (similar != NULL) { |
||
1433 | *clone_out = cairo_surface_reference (similar); |
||
1434 | *clone_offset_x = 0; |
||
1435 | *clone_offset_y = 0; |
||
1436 | return CAIRO_STATUS_SUCCESS; |
||
1437 | } |
||
1438 | |||
1439 | if (meta->unbounded || |
||
1440 | width*height*8 < meta->extents.width*meta->extents.height) |
||
1441 | { |
||
1442 | /* XXX use _solid to perform an initial CLEAR? */ |
||
1443 | similar = _cairo_surface_create_similar_scratch (surface, |
||
1444 | src->content & content, |
||
1445 | width, height); |
||
1446 | if (similar == NULL) |
||
1447 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1448 | if (unlikely (similar->status)) |
||
1449 | return similar->status; |
||
1450 | |||
1451 | cairo_surface_set_device_offset (similar, -src_x, -src_y); |
||
1452 | |||
1453 | status = cairo_meta_surface_replay (src, similar); |
||
1454 | if (unlikely (status)) { |
||
1455 | cairo_surface_destroy (similar); |
||
1456 | return status; |
||
1457 | } |
||
1458 | } else { |
||
1459 | similar = _cairo_surface_create_similar_scratch (surface, |
||
1460 | src->content & content, |
||
1461 | meta->extents.width, |
||
1462 | meta->extents.height); |
||
1463 | if (similar == NULL) |
||
1464 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1465 | if (unlikely (similar->status)) |
||
1466 | return similar->status; |
||
1467 | |||
1468 | status = cairo_meta_surface_replay (src, similar); |
||
1469 | if (unlikely (status)) { |
||
1470 | cairo_surface_destroy (similar); |
||
1471 | return status; |
||
1472 | } |
||
1473 | |||
1474 | status = _cairo_surface_attach_snapshot (src, similar, NULL); |
||
1475 | if (unlikely (status)) { |
||
1476 | cairo_surface_destroy (similar); |
||
1477 | return status; |
||
1478 | } |
||
1479 | |||
1480 | src_x = src_y = 0; |
||
1481 | } |
||
1482 | |||
1483 | *clone_out = similar; |
||
1484 | *clone_offset_x = src_x; |
||
1485 | *clone_offset_y = src_y; |
||
1486 | return CAIRO_STATUS_SUCCESS; |
||
1487 | } |
||
1488 | |||
1489 | /** |
||
1490 | * _cairo_surface_clone_similar: |
||
1491 | * @surface: a #cairo_surface_t |
||
1492 | * @src: the source image |
||
1493 | * @content: target content mask |
||
1494 | * @src_x: extent for the rectangle in src we actually care about |
||
1495 | * @src_y: extent for the rectangle in src we actually care about |
||
1496 | * @width: extent for the rectangle in src we actually care about |
||
1497 | * @height: extent for the rectangle in src we actually care about |
||
1498 | * @clone_out: location to store a surface compatible with @surface |
||
1499 | * and with contents identical to @src. The caller must call |
||
1500 | * cairo_surface_destroy() on the result. |
||
1501 | * |
||
1502 | * Creates a surface with contents identical to @src but that |
||
1503 | * can be used efficiently with @surface. If @surface and @src are |
||
1504 | * already compatible then it may return a new reference to @src. |
||
1505 | * |
||
1506 | * Return value: %CAIRO_STATUS_SUCCESS if a surface was created and stored |
||
1507 | * in @clone_out. Otherwise %CAIRO_INT_STATUS_UNSUPPORTED or another |
||
1508 | * error like %CAIRO_STATUS_NO_MEMORY. |
||
1509 | **/ |
||
1510 | cairo_status_t |
||
1511 | _cairo_surface_clone_similar (cairo_surface_t *surface, |
||
1512 | cairo_surface_t *src, |
||
1513 | cairo_content_t content, |
||
1514 | int src_x, |
||
1515 | int src_y, |
||
1516 | int width, |
||
1517 | int height, |
||
1518 | int *clone_offset_x, |
||
1519 | int *clone_offset_y, |
||
1520 | cairo_surface_t **clone_out) |
||
1521 | { |
||
1522 | cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
1523 | cairo_image_surface_t *image; |
||
1524 | void *image_extra; |
||
1525 | |||
1526 | if (unlikely (surface->status)) |
||
1527 | return surface->status; |
||
1528 | |||
1529 | if (unlikely (surface->finished)) |
||
1530 | return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); |
||
1531 | |||
1532 | if (src->type == CAIRO_SURFACE_TYPE_TEE) { |
||
1533 | cairo_surface_t *match; |
||
1534 | |||
1535 | match = _cairo_tee_surface_find_match (src, |
||
1536 | surface->backend, |
||
1537 | content); |
||
1538 | if (match != NULL) |
||
1539 | src = match; |
||
1540 | } |
||
1541 | |||
1542 | if (surface->backend->clone_similar != NULL) { |
||
1543 | status = surface->backend->clone_similar (surface, src, |
||
1544 | content, |
||
1545 | src_x, src_y, |
||
1546 | width, height, |
||
1547 | clone_offset_x, |
||
1548 | clone_offset_y, |
||
1549 | clone_out); |
||
1550 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
1551 | if (_cairo_surface_is_image (src)) |
||
1552 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1553 | |||
1554 | /* First check to see if we can replay to a similar surface */ |
||
1555 | if (_cairo_surface_is_meta (src)) { |
||
1556 | return _cairo_meta_surface_clone_similar (surface, src, |
||
1557 | content, |
||
1558 | src_x, src_y, |
||
1559 | width, height, |
||
1560 | clone_offset_x, |
||
1561 | clone_offset_y, |
||
1562 | clone_out); |
||
1563 | } |
||
1564 | |||
1565 | /* If we failed, try again with an image surface */ |
||
1566 | status = _cairo_surface_acquire_source_image (src, &image, &image_extra); |
||
1567 | if (status == CAIRO_STATUS_SUCCESS) { |
||
1568 | status = |
||
1569 | surface->backend->clone_similar (surface, &image->base, |
||
1570 | content, |
||
1571 | src_x, src_y, |
||
1572 | width, height, |
||
1573 | clone_offset_x, |
||
1574 | clone_offset_y, |
||
1575 | clone_out); |
||
1576 | |||
1577 | _cairo_surface_release_source_image (src, image, image_extra); |
||
1578 | } |
||
1579 | } |
||
1580 | } |
||
1581 | |||
1582 | /* If we're still unsupported, hit our fallback path to get a clone */ |
||
1583 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
1584 | status = |
||
1585 | _cairo_surface_fallback_clone_similar (surface, src, |
||
1586 | content, |
||
1587 | src_x, src_y, |
||
1588 | width, height, |
||
1589 | clone_offset_x, |
||
1590 | clone_offset_y, |
||
1591 | clone_out); |
||
1592 | } |
||
1593 | |||
1594 | if (unlikely (status)) |
||
1595 | return status; |
||
1596 | |||
1597 | /* Update the clone's device_transform (which the underlying surface |
||
1598 | * backend knows nothing about) */ |
||
1599 | if (*clone_out != src) { |
||
1600 | (*clone_out)->device_transform = src->device_transform; |
||
1601 | (*clone_out)->device_transform_inverse = src->device_transform_inverse; |
||
1602 | } |
||
1603 | |||
1604 | return status; |
||
1605 | } |
||
1606 | |||
1607 | /* XXX: Shouldn't really need to do this here. */ |
||
1608 | #include "cairo-meta-surface-private.h" |
||
1609 | |||
1610 | /** |
||
1611 | * _cairo_surface_snapshot |
||
1612 | * @surface: a #cairo_surface_t |
||
1613 | * |
||
1614 | * Make an immutable copy of @surface. It is an error to call a |
||
1615 | * surface-modifying function on the result of this function. |
||
1616 | * |
||
1617 | * The caller owns the return value and should call |
||
1618 | * cairo_surface_destroy() when finished with it. This function will not |
||
1619 | * return %NULL, but will return a nil surface instead. |
||
1620 | * |
||
1621 | * Return value: The snapshot surface. Note that the return surface |
||
1622 | * may not necessarily be of the same type as @surface. |
||
1623 | **/ |
||
1624 | cairo_surface_t * |
||
1625 | _cairo_surface_snapshot (cairo_surface_t *surface) |
||
1626 | { |
||
1627 | cairo_surface_t *snapshot; |
||
1628 | cairo_status_t status; |
||
1629 | |||
1630 | if (surface->status) |
||
1631 | return _cairo_surface_create_in_error (surface->status); |
||
1632 | |||
1633 | if (surface->finished) |
||
1634 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); |
||
1635 | |||
1636 | if (surface->snapshot_of != NULL) |
||
1637 | return cairo_surface_reference (surface); |
||
1638 | |||
1639 | snapshot = _cairo_surface_has_snapshot (surface, |
||
1640 | surface->backend, |
||
1641 | surface->content); |
||
1642 | if (snapshot != NULL) |
||
1643 | return cairo_surface_reference (snapshot); |
||
1644 | |||
1645 | if (surface->backend->snapshot != NULL) { |
||
1646 | snapshot = surface->backend->snapshot (surface); |
||
1647 | if (snapshot != NULL) { |
||
1648 | if (unlikely (snapshot->status)) |
||
1649 | return snapshot; |
||
1650 | |||
1651 | /* Is this surface just a proxy - e.g. paginated surfaces? */ |
||
1652 | if (snapshot->backend != surface->backend) { |
||
1653 | cairo_surface_t *previous; |
||
1654 | |||
1655 | previous = _cairo_surface_has_snapshot (surface, |
||
1656 | snapshot->backend, |
||
1657 | snapshot->content); |
||
1658 | if (previous != NULL) { |
||
1659 | cairo_surface_destroy (snapshot); |
||
1660 | return cairo_surface_reference (previous); |
||
1661 | } |
||
1662 | } |
||
1663 | } |
||
1664 | } |
||
1665 | |||
1666 | if (snapshot == NULL) { |
||
1667 | snapshot = _cairo_surface_has_snapshot (surface, |
||
1668 | &_cairo_image_surface_backend, |
||
1669 | surface->content); |
||
1670 | if (snapshot != NULL) |
||
1671 | return cairo_surface_reference (snapshot); |
||
1672 | |||
1673 | snapshot = _cairo_surface_fallback_snapshot (surface); |
||
1674 | if (unlikely (snapshot->status)) |
||
1675 | return snapshot; |
||
1676 | } |
||
1677 | |||
1678 | status = _cairo_surface_copy_mime_data (snapshot, surface); |
||
1679 | if (unlikely (status)) { |
||
1680 | cairo_surface_destroy (snapshot); |
||
1681 | return _cairo_surface_create_in_error (status); |
||
1682 | } |
||
1683 | |||
1684 | snapshot->device_transform = surface->device_transform; |
||
1685 | snapshot->device_transform_inverse = surface->device_transform_inverse; |
||
1686 | |||
1687 | status = _cairo_surface_attach_snapshot (surface, snapshot, NULL); |
||
1688 | if (unlikely (status)) { |
||
1689 | cairo_surface_destroy (snapshot); |
||
1690 | return _cairo_surface_create_in_error (status); |
||
1691 | } |
||
1692 | |||
1693 | return snapshot; |
||
1694 | } |
||
1695 | |||
1696 | /** |
||
1697 | * _cairo_surface_is_similar |
||
1698 | * @surface_a: a #cairo_surface_t |
||
1699 | * @surface_b: a #cairo_surface_t |
||
1700 | * @content: a #cairo_content_t |
||
1701 | * |
||
1702 | * Find out whether the given surfaces share the same backend, |
||
1703 | * and if so, whether they can be considered similar. |
||
1704 | * |
||
1705 | * The definition of "similar" depends on the backend. In |
||
1706 | * general, it means that the surface is equivalent to one |
||
1707 | * that would have been generated by a call to cairo_surface_create_similar(). |
||
1708 | * |
||
1709 | * Return value: %TRUE if the surfaces are similar. |
||
1710 | **/ |
||
1711 | cairo_bool_t |
||
1712 | _cairo_surface_is_similar (cairo_surface_t *surface_a, |
||
1713 | cairo_surface_t *surface_b, |
||
1714 | cairo_content_t content) |
||
1715 | { |
||
1716 | if (surface_a->backend != surface_b->backend) |
||
1717 | return FALSE; |
||
1718 | |||
1719 | if (surface_a->backend->is_similar != NULL) |
||
1720 | return surface_a->backend->is_similar (surface_a, surface_b, content); |
||
1721 | |||
1722 | return TRUE; |
||
1723 | } |
||
1724 | |||
1725 | cairo_status_t |
||
1726 | _cairo_surface_composite (cairo_operator_t op, |
||
1727 | const cairo_pattern_t *src, |
||
1728 | const cairo_pattern_t *mask, |
||
1729 | cairo_surface_t *dst, |
||
1730 | int src_x, |
||
1731 | int src_y, |
||
1732 | int mask_x, |
||
1733 | int mask_y, |
||
1734 | int dst_x, |
||
1735 | int dst_y, |
||
1736 | unsigned int width, |
||
1737 | unsigned int height, |
||
1738 | cairo_region_t *clip_region) |
||
1739 | { |
||
1740 | cairo_int_status_t status; |
||
1741 | |||
1742 | if (unlikely (dst->status)) |
||
1743 | return dst->status; |
||
1744 | |||
1745 | assert (_cairo_surface_is_writable (dst)); |
||
1746 | |||
1747 | if (mask) { |
||
1748 | /* These operators aren't interpreted the same way by the backends; |
||
1749 | * they are implemented in terms of other operators in cairo-gstate.c |
||
1750 | */ |
||
1751 | assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR); |
||
1752 | } |
||
1753 | |||
1754 | if (dst->backend->composite) { |
||
1755 | status = dst->backend->composite (op, |
||
1756 | src, mask, dst, |
||
1757 | src_x, src_y, |
||
1758 | mask_x, mask_y, |
||
1759 | dst_x, dst_y, |
||
1760 | width, height, |
||
1761 | clip_region); |
||
1762 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
1763 | return _cairo_surface_set_error (dst, status); |
||
1764 | } |
||
1765 | |||
1766 | return _cairo_surface_set_error (dst, |
||
1767 | _cairo_surface_fallback_composite (op, |
||
1768 | src, mask, dst, |
||
1769 | src_x, src_y, |
||
1770 | mask_x, mask_y, |
||
1771 | dst_x, dst_y, |
||
1772 | width, height, |
||
1773 | clip_region)); |
||
1774 | } |
||
1775 | |||
1776 | /** |
||
1777 | * _cairo_surface_fill_rectangle: |
||
1778 | * @surface: a #cairo_surface_t |
||
1779 | * @op: the operator to apply to the rectangle |
||
1780 | * @color: the source color |
||
1781 | * @x: X coordinate of rectangle, in backend coordinates |
||
1782 | * @y: Y coordinate of rectangle, in backend coordinates |
||
1783 | * @width: width of rectangle, in backend coordinates |
||
1784 | * @height: height of rectangle, in backend coordinates |
||
1785 | * |
||
1786 | * Applies an operator to a rectangle using a solid color as the source. |
||
1787 | * See _cairo_surface_fill_rectangles() for full details. |
||
1788 | * |
||
1789 | * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred |
||
1790 | **/ |
||
1791 | cairo_status_t |
||
1792 | _cairo_surface_fill_rectangle (cairo_surface_t *surface, |
||
1793 | cairo_operator_t op, |
||
1794 | const cairo_color_t *color, |
||
1795 | int x, |
||
1796 | int y, |
||
1797 | int width, |
||
1798 | int height) |
||
1799 | { |
||
1800 | cairo_rectangle_int_t rect; |
||
1801 | |||
1802 | if (surface->status) |
||
1803 | return surface->status; |
||
1804 | |||
1805 | assert (_cairo_surface_is_writable (surface)); |
||
1806 | |||
1807 | rect.x = x; |
||
1808 | rect.y = y; |
||
1809 | rect.width = width; |
||
1810 | rect.height = height; |
||
1811 | |||
1812 | return _cairo_surface_fill_rectangles (surface, op, color, &rect, 1); |
||
1813 | } |
||
1814 | |||
1815 | /** |
||
1816 | * _cairo_surface_fill_region: |
||
1817 | * @surface: a #cairo_surface_t |
||
1818 | * @op: the operator to apply to the region |
||
1819 | * @color: the source color |
||
1820 | * @region: the region to modify, in backend coordinates |
||
1821 | * |
||
1822 | * Applies an operator to a set of rectangles specified as a |
||
1823 | * #cairo_region_t using a solid color as the source. |
||
1824 | * See _cairo_surface_fill_rectangles() for full details. |
||
1825 | * |
||
1826 | * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred |
||
1827 | **/ |
||
1828 | cairo_status_t |
||
1829 | _cairo_surface_fill_region (cairo_surface_t *surface, |
||
1830 | cairo_operator_t op, |
||
1831 | const cairo_color_t *color, |
||
1832 | cairo_region_t *region) |
||
1833 | { |
||
1834 | int num_rects; |
||
1835 | cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; |
||
1836 | cairo_rectangle_int_t *rects = stack_rects; |
||
1837 | cairo_status_t status; |
||
1838 | int i; |
||
1839 | |||
1840 | if (surface->status) |
||
1841 | return surface->status; |
||
1842 | |||
1843 | assert (_cairo_surface_is_writable (surface)); |
||
1844 | |||
1845 | num_rects = cairo_region_num_rectangles (region); |
||
1846 | if (num_rects == 0) |
||
1847 | return CAIRO_STATUS_SUCCESS; |
||
1848 | |||
1849 | if (num_rects > ARRAY_LENGTH (stack_rects)) { |
||
1850 | rects = _cairo_malloc_ab (num_rects, |
||
1851 | sizeof (cairo_rectangle_int_t)); |
||
1852 | if (rects == NULL) { |
||
1853 | return _cairo_surface_set_error (surface, |
||
1854 | _cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
1855 | } |
||
1856 | } |
||
1857 | |||
1858 | for (i = 0; i < num_rects; i++) |
||
1859 | cairo_region_get_rectangle (region, i, &rects[i]); |
||
1860 | |||
1861 | status = _cairo_surface_fill_rectangles (surface, |
||
1862 | op, color, rects, num_rects); |
||
1863 | |||
1864 | if (rects != stack_rects) |
||
1865 | free (rects); |
||
1866 | |||
1867 | return _cairo_surface_set_error (surface, status); |
||
1868 | } |
||
1869 | |||
1870 | /** |
||
1871 | * _cairo_surface_fill_rectangles: |
||
1872 | * @surface: a #cairo_surface_t |
||
1873 | * @op: the operator to apply to the region |
||
1874 | * @color: the source color |
||
1875 | * @rects: the rectangles to modify, in backend coordinates |
||
1876 | * @num_rects: the number of rectangles in @rects |
||
1877 | * |
||
1878 | * Applies an operator to a set of rectangles using a solid color |
||
1879 | * as the source. Note that even if the operator is an unbounded operator |
||
1880 | * such as %CAIRO_OPERATOR_IN, only the given set of rectangles |
||
1881 | * is affected. This differs from _cairo_surface_composite_trapezoids() |
||
1882 | * where the entire destination rectangle is cleared. |
||
1883 | * |
||
1884 | * Return value: %CAIRO_STATUS_SUCCESS or the error that occurred |
||
1885 | **/ |
||
1886 | cairo_status_t |
||
1887 | _cairo_surface_fill_rectangles (cairo_surface_t *surface, |
||
1888 | cairo_operator_t op, |
||
1889 | const cairo_color_t *color, |
||
1890 | cairo_rectangle_int_t *rects, |
||
1891 | int num_rects) |
||
1892 | { |
||
1893 | cairo_int_status_t status; |
||
1894 | |||
1895 | if (surface->status) |
||
1896 | return surface->status; |
||
1897 | |||
1898 | assert (_cairo_surface_is_writable (surface)); |
||
1899 | |||
1900 | if (num_rects == 0) |
||
1901 | return CAIRO_STATUS_SUCCESS; |
||
1902 | |||
1903 | if (surface->backend->fill_rectangles) { |
||
1904 | status = surface->backend->fill_rectangles (surface, |
||
1905 | op, color, |
||
1906 | rects, num_rects); |
||
1907 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
1908 | return _cairo_surface_set_error (surface, status); |
||
1909 | } |
||
1910 | |||
1911 | return _cairo_surface_set_error (surface, |
||
1912 | _cairo_surface_fallback_fill_rectangles (surface, |
||
1913 | op, color, |
||
1914 | rects, num_rects)); |
||
1915 | } |
||
1916 | |||
1917 | cairo_status_t |
||
1918 | _cairo_surface_paint (cairo_surface_t *surface, |
||
1919 | cairo_operator_t op, |
||
1920 | const cairo_pattern_t *source, |
||
1921 | cairo_clip_t *clip) |
||
1922 | { |
||
1923 | cairo_status_t status; |
||
1924 | cairo_pattern_union_t dev_source; |
||
1925 | |||
1926 | if (unlikely (surface->status)) |
||
1927 | return surface->status; |
||
1928 | |||
1929 | if (clip && clip->all_clipped) |
||
1930 | return CAIRO_STATUS_SUCCESS; |
||
1931 | |||
1932 | _cairo_surface_begin_modification (surface); |
||
1933 | |||
1934 | _cairo_surface_copy_pattern_for_destination (&source, |
||
1935 | surface, |
||
1936 | &dev_source.base); |
||
1937 | |||
1938 | if (surface->backend->paint != NULL) { |
||
1939 | status = surface->backend->paint (surface, op, source, clip); |
||
1940 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
1941 | goto FINISH; |
||
1942 | } |
||
1943 | |||
1944 | status = _cairo_surface_fallback_paint (surface, op, source, clip); |
||
1945 | |||
1946 | FINISH: |
||
1947 | return _cairo_surface_set_error (surface, status); |
||
1948 | } |
||
1949 | |||
1950 | cairo_status_t |
||
1951 | _cairo_surface_mask (cairo_surface_t *surface, |
||
1952 | cairo_operator_t op, |
||
1953 | const cairo_pattern_t *source, |
||
1954 | const cairo_pattern_t *mask, |
||
1955 | cairo_clip_t *clip) |
||
1956 | { |
||
1957 | cairo_status_t status; |
||
1958 | cairo_pattern_union_t dev_source; |
||
1959 | cairo_pattern_union_t dev_mask; |
||
1960 | |||
1961 | if (unlikely (surface->status)) |
||
1962 | return surface->status; |
||
1963 | |||
1964 | if (clip && clip->all_clipped) |
||
1965 | return CAIRO_STATUS_SUCCESS; |
||
1966 | |||
1967 | _cairo_surface_begin_modification (surface); |
||
1968 | |||
1969 | _cairo_surface_copy_pattern_for_destination (&source, surface, |
||
1970 | &dev_source.base); |
||
1971 | _cairo_surface_copy_pattern_for_destination (&mask, surface, |
||
1972 | &dev_mask.base); |
||
1973 | |||
1974 | if (surface->backend->mask != NULL) { |
||
1975 | status = surface->backend->mask (surface, op, source, mask, clip); |
||
1976 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
1977 | goto FINISH; |
||
1978 | } |
||
1979 | |||
1980 | status = _cairo_surface_fallback_mask (surface, op, source, mask, clip); |
||
1981 | |||
1982 | FINISH: |
||
1983 | return _cairo_surface_set_error (surface, status); |
||
1984 | } |
||
1985 | |||
1986 | cairo_status_t |
||
1987 | _cairo_surface_fill_stroke (cairo_surface_t *surface, |
||
1988 | cairo_operator_t fill_op, |
||
1989 | const cairo_pattern_t *fill_source, |
||
1990 | cairo_fill_rule_t fill_rule, |
||
1991 | double fill_tolerance, |
||
1992 | cairo_antialias_t fill_antialias, |
||
1993 | cairo_path_fixed_t *path, |
||
1994 | cairo_operator_t stroke_op, |
||
1995 | const cairo_pattern_t *stroke_source, |
||
1996 | cairo_stroke_style_t *stroke_style, |
||
1997 | cairo_matrix_t *stroke_ctm, |
||
1998 | cairo_matrix_t *stroke_ctm_inverse, |
||
1999 | double stroke_tolerance, |
||
2000 | cairo_antialias_t stroke_antialias, |
||
2001 | cairo_clip_t *clip) |
||
2002 | { |
||
2003 | cairo_status_t status; |
||
2004 | |||
2005 | if (unlikely (surface->status)) |
||
2006 | return surface->status; |
||
2007 | |||
2008 | if (clip && clip->all_clipped) |
||
2009 | return CAIRO_STATUS_SUCCESS; |
||
2010 | |||
2011 | _cairo_surface_begin_modification (surface); |
||
2012 | |||
2013 | if (surface->backend->fill_stroke) { |
||
2014 | cairo_pattern_union_t dev_stroke_source; |
||
2015 | cairo_pattern_union_t dev_fill_source; |
||
2016 | cairo_matrix_t dev_ctm = *stroke_ctm; |
||
2017 | cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; |
||
2018 | |||
2019 | _cairo_surface_copy_pattern_for_destination (&stroke_source, surface, |
||
2020 | &dev_stroke_source.base); |
||
2021 | _cairo_surface_copy_pattern_for_destination (&fill_source, surface, |
||
2022 | &dev_fill_source.base); |
||
2023 | |||
2024 | status = surface->backend->fill_stroke (surface, |
||
2025 | fill_op, fill_source, fill_rule, |
||
2026 | fill_tolerance, fill_antialias, |
||
2027 | path, |
||
2028 | stroke_op, stroke_source, |
||
2029 | stroke_style, |
||
2030 | &dev_ctm, &dev_ctm_inverse, |
||
2031 | stroke_tolerance, stroke_antialias, |
||
2032 | clip); |
||
2033 | |||
2034 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
2035 | return _cairo_surface_set_error (surface, status); |
||
2036 | } |
||
2037 | |||
2038 | status = _cairo_surface_fill (surface, fill_op, fill_source, path, |
||
2039 | fill_rule, fill_tolerance, fill_antialias, |
||
2040 | clip); |
||
2041 | if (unlikely (status)) |
||
2042 | return _cairo_surface_set_error (surface, status); |
||
2043 | |||
2044 | status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path, |
||
2045 | stroke_style, stroke_ctm, stroke_ctm_inverse, |
||
2046 | stroke_tolerance, stroke_antialias, |
||
2047 | clip); |
||
2048 | if (unlikely (status)) |
||
2049 | return _cairo_surface_set_error (surface, status); |
||
2050 | |||
2051 | return CAIRO_STATUS_SUCCESS; |
||
2052 | } |
||
2053 | |||
2054 | cairo_status_t |
||
2055 | _cairo_surface_stroke (cairo_surface_t *surface, |
||
2056 | cairo_operator_t op, |
||
2057 | const cairo_pattern_t *source, |
||
2058 | cairo_path_fixed_t *path, |
||
2059 | cairo_stroke_style_t *stroke_style, |
||
2060 | cairo_matrix_t *ctm, |
||
2061 | cairo_matrix_t *ctm_inverse, |
||
2062 | double tolerance, |
||
2063 | cairo_antialias_t antialias, |
||
2064 | cairo_clip_t *clip) |
||
2065 | { |
||
2066 | cairo_status_t status; |
||
2067 | cairo_pattern_union_t dev_source; |
||
2068 | |||
2069 | if (unlikely (surface->status)) |
||
2070 | return surface->status; |
||
2071 | |||
2072 | if (clip && clip->all_clipped) |
||
2073 | return CAIRO_STATUS_SUCCESS; |
||
2074 | |||
2075 | _cairo_surface_begin_modification (surface); |
||
2076 | |||
2077 | _cairo_surface_copy_pattern_for_destination (&source, surface, |
||
2078 | &dev_source.base); |
||
2079 | |||
2080 | if (surface->backend->stroke != NULL) { |
||
2081 | status = surface->backend->stroke (surface, op, source, |
||
2082 | path, stroke_style, |
||
2083 | ctm, ctm_inverse, |
||
2084 | tolerance, antialias, |
||
2085 | clip); |
||
2086 | |||
2087 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
2088 | goto FINISH; |
||
2089 | } |
||
2090 | |||
2091 | status = _cairo_surface_fallback_stroke (surface, op, source, |
||
2092 | path, stroke_style, |
||
2093 | ctm, ctm_inverse, |
||
2094 | tolerance, antialias, |
||
2095 | clip); |
||
2096 | |||
2097 | FINISH: |
||
2098 | return _cairo_surface_set_error (surface, status); |
||
2099 | } |
||
2100 | |||
2101 | cairo_status_t |
||
2102 | _cairo_surface_fill (cairo_surface_t *surface, |
||
2103 | cairo_operator_t op, |
||
2104 | const cairo_pattern_t *source, |
||
2105 | cairo_path_fixed_t *path, |
||
2106 | cairo_fill_rule_t fill_rule, |
||
2107 | double tolerance, |
||
2108 | cairo_antialias_t antialias, |
||
2109 | cairo_clip_t *clip) |
||
2110 | { |
||
2111 | cairo_status_t status; |
||
2112 | cairo_pattern_union_t dev_source; |
||
2113 | |||
2114 | if (unlikely (surface->status)) |
||
2115 | return surface->status; |
||
2116 | |||
2117 | if (clip && clip->all_clipped) |
||
2118 | return CAIRO_STATUS_SUCCESS; |
||
2119 | |||
2120 | _cairo_surface_begin_modification (surface); |
||
2121 | |||
2122 | _cairo_surface_copy_pattern_for_destination (&source, surface, |
||
2123 | &dev_source.base); |
||
2124 | if (surface->backend->fill != NULL) { |
||
2125 | status = surface->backend->fill (surface, op, source, |
||
2126 | path, fill_rule, |
||
2127 | tolerance, antialias, |
||
2128 | clip); |
||
2129 | |||
2130 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
2131 | goto FINISH; |
||
2132 | } |
||
2133 | |||
2134 | status = _cairo_surface_fallback_fill (surface, op, source, |
||
2135 | path, fill_rule, |
||
2136 | tolerance, antialias, |
||
2137 | clip); |
||
2138 | |||
2139 | FINISH: |
||
2140 | return _cairo_surface_set_error (surface, status); |
||
2141 | } |
||
2142 | |||
2143 | cairo_status_t |
||
2144 | _cairo_surface_composite_trapezoids (cairo_operator_t op, |
||
2145 | const cairo_pattern_t *pattern, |
||
2146 | cairo_surface_t *dst, |
||
2147 | cairo_antialias_t antialias, |
||
2148 | int src_x, |
||
2149 | int src_y, |
||
2150 | int dst_x, |
||
2151 | int dst_y, |
||
2152 | unsigned int width, |
||
2153 | unsigned int height, |
||
2154 | cairo_trapezoid_t *traps, |
||
2155 | int num_traps, |
||
2156 | cairo_region_t *clip_region) |
||
2157 | { |
||
2158 | cairo_int_status_t status; |
||
2159 | |||
2160 | if (dst->status) |
||
2161 | return dst->status; |
||
2162 | |||
2163 | assert (_cairo_surface_is_writable (dst)); |
||
2164 | |||
2165 | /* These operators aren't interpreted the same way by the backends; |
||
2166 | * they are implemented in terms of other operators in cairo-gstate.c |
||
2167 | */ |
||
2168 | assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR); |
||
2169 | |||
2170 | if (dst->backend->composite_trapezoids) { |
||
2171 | status = dst->backend->composite_trapezoids (op, |
||
2172 | pattern, dst, |
||
2173 | antialias, |
||
2174 | src_x, src_y, |
||
2175 | dst_x, dst_y, |
||
2176 | width, height, |
||
2177 | traps, num_traps, |
||
2178 | clip_region); |
||
2179 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
2180 | return _cairo_surface_set_error (dst, status); |
||
2181 | } |
||
2182 | |||
2183 | return _cairo_surface_set_error (dst, |
||
2184 | _cairo_surface_fallback_composite_trapezoids (op, pattern, dst, |
||
2185 | antialias, |
||
2186 | src_x, src_y, |
||
2187 | dst_x, dst_y, |
||
2188 | width, height, |
||
2189 | traps, num_traps, |
||
2190 | clip_region)); |
||
2191 | } |
||
2192 | |||
2193 | cairo_span_renderer_t * |
||
2194 | _cairo_surface_create_span_renderer (cairo_operator_t op, |
||
2195 | const cairo_pattern_t *pattern, |
||
2196 | cairo_surface_t *dst, |
||
2197 | cairo_antialias_t antialias, |
||
2198 | const cairo_composite_rectangles_t *rects, |
||
2199 | cairo_region_t *clip_region) |
||
2200 | { |
||
2201 | assert (dst->snapshot_of == NULL); |
||
2202 | |||
2203 | if (unlikely (dst->status)) |
||
2204 | return _cairo_span_renderer_create_in_error (dst->status); |
||
2205 | |||
2206 | if (unlikely (dst->finished)) |
||
2207 | return _cairo_span_renderer_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); |
||
2208 | |||
2209 | if (dst->backend->create_span_renderer) { |
||
2210 | return dst->backend->create_span_renderer (op, |
||
2211 | pattern, dst, |
||
2212 | antialias, |
||
2213 | rects, |
||
2214 | clip_region); |
||
2215 | } |
||
2216 | ASSERT_NOT_REACHED; |
||
2217 | return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED); |
||
2218 | } |
||
2219 | |||
2220 | cairo_bool_t |
||
2221 | _cairo_surface_check_span_renderer (cairo_operator_t op, |
||
2222 | const cairo_pattern_t *pattern, |
||
2223 | cairo_surface_t *dst, |
||
2224 | cairo_antialias_t antialias) |
||
2225 | { |
||
2226 | assert (dst->snapshot_of == NULL); |
||
2227 | assert (dst->status == CAIRO_STATUS_SUCCESS); |
||
2228 | assert (! dst->finished); |
||
2229 | |||
2230 | /* XXX: Currently we have no mono span renderer */ |
||
2231 | if (antialias == CAIRO_ANTIALIAS_NONE) |
||
2232 | return FALSE; |
||
2233 | |||
2234 | if (dst->backend->check_span_renderer != NULL) |
||
2235 | return dst->backend->check_span_renderer (op, pattern, dst, antialias); |
||
2236 | |||
2237 | return FALSE; |
||
2238 | } |
||
2239 | |||
2240 | /** |
||
2241 | * cairo_surface_copy_page: |
||
2242 | * @surface: a #cairo_surface_t |
||
2243 | * |
||
2244 | * Emits the current page for backends that support multiple pages, |
||
2245 | * but doesn't clear it, so that the contents of the current page will |
||
2246 | * be retained for the next page. Use cairo_surface_show_page() if you |
||
2247 | * want to get an empty page after the emission. |
||
2248 | * |
||
2249 | * There is a convenience function for this that takes a #cairo_t, |
||
2250 | * namely cairo_copy_page(). |
||
2251 | * |
||
2252 | * Since: 1.6 |
||
2253 | */ |
||
2254 | void |
||
2255 | cairo_surface_copy_page (cairo_surface_t *surface) |
||
2256 | { |
||
2257 | cairo_status_t status_ignored; |
||
2258 | |||
2259 | if (surface->status) |
||
2260 | return; |
||
2261 | |||
2262 | assert (surface->snapshot_of == NULL); |
||
2263 | |||
2264 | if (surface->finished) { |
||
2265 | status_ignored = _cairo_surface_set_error (surface, |
||
2266 | CAIRO_STATUS_SURFACE_FINISHED); |
||
2267 | return; |
||
2268 | } |
||
2269 | |||
2270 | /* It's fine if some backends don't implement copy_page */ |
||
2271 | if (surface->backend->copy_page == NULL) |
||
2272 | return; |
||
2273 | |||
2274 | status_ignored = _cairo_surface_set_error (surface, |
||
2275 | surface->backend->copy_page (surface)); |
||
2276 | } |
||
2277 | slim_hidden_def (cairo_surface_copy_page); |
||
2278 | |||
2279 | /** |
||
2280 | * cairo_surface_show_page: |
||
2281 | * @surface: a #cairo_Surface_t |
||
2282 | * |
||
2283 | * Emits and clears the current page for backends that support multiple |
||
2284 | * pages. Use cairo_surface_copy_page() if you don't want to clear the page. |
||
2285 | * |
||
2286 | * There is a convenience function for this that takes a #cairo_t, |
||
2287 | * namely cairo_show_page(). |
||
2288 | * |
||
2289 | * Since: 1.6 |
||
2290 | **/ |
||
2291 | void |
||
2292 | cairo_surface_show_page (cairo_surface_t *surface) |
||
2293 | { |
||
2294 | cairo_status_t status_ignored; |
||
2295 | |||
2296 | if (surface->status) |
||
2297 | return; |
||
2298 | |||
2299 | _cairo_surface_begin_modification (surface); |
||
2300 | |||
2301 | if (surface->finished) { |
||
2302 | status_ignored = _cairo_surface_set_error (surface, |
||
2303 | CAIRO_STATUS_SURFACE_FINISHED); |
||
2304 | return; |
||
2305 | } |
||
2306 | |||
2307 | /* It's fine if some backends don't implement show_page */ |
||
2308 | if (surface->backend->show_page == NULL) |
||
2309 | return; |
||
2310 | |||
2311 | status_ignored = _cairo_surface_set_error (surface, |
||
2312 | surface->backend->show_page (surface)); |
||
2313 | } |
||
2314 | slim_hidden_def (cairo_surface_show_page); |
||
2315 | |||
2316 | /** |
||
2317 | * _cairo_surface_get_extents: |
||
2318 | * @surface: the #cairo_surface_t to fetch extents for |
||
2319 | * |
||
2320 | * This function returns a bounding box for the surface. The surface |
||
2321 | * bounds are defined as a region beyond which no rendering will |
||
2322 | * possibly be recorded, in other words, it is the maximum extent of |
||
2323 | * potentially usable coordinates. |
||
2324 | * |
||
2325 | * For vector surfaces, (PDF, PS, SVG and meta-surfaces), the surface |
||
2326 | * might be conceived as unbounded, but we force the user to provide a |
||
2327 | * maximum size at the time of surface_create. So get_extents uses |
||
2328 | * that size. |
||
2329 | * |
||
2330 | * Note: The coordinates returned are in "backend" space rather than |
||
2331 | * "surface" space. That is, they are relative to the true (0,0) |
||
2332 | * origin rather than the device_transform origin. This might seem a |
||
2333 | * bit inconsistent with other #cairo_surface_t interfaces, but all |
||
2334 | * current callers are within the surface layer where backend space is |
||
2335 | * desired. |
||
2336 | * |
||
2337 | * This behavior would have to be changed is we ever exported a public |
||
2338 | * variant of this function. |
||
2339 | */ |
||
2340 | cairo_bool_t |
||
2341 | _cairo_surface_get_extents (cairo_surface_t *surface, |
||
2342 | cairo_rectangle_int_t *extents) |
||
2343 | { |
||
2344 | cairo_bool_t bounded = FALSE; |
||
2345 | |||
2346 | if (unlikely (surface->status || surface->finished)) |
||
2347 | return TRUE; |
||
2348 | |||
2349 | if (surface->backend->get_extents != NULL) |
||
2350 | bounded = surface->backend->get_extents (surface, extents); |
||
2351 | |||
2352 | if (! bounded) |
||
2353 | _cairo_unbounded_rectangle_init (extents); |
||
2354 | |||
2355 | return bounded; |
||
2356 | } |
||
2357 | |||
2358 | /** |
||
2359 | * cairo_surface_has_show_text_glyphs: |
||
2360 | * @surface: a #cairo_surface_t |
||
2361 | * |
||
2362 | * Returns whether the surface supports |
||
2363 | * sophisticated cairo_show_text_glyphs() operations. That is, |
||
2364 | * whether it actually uses the provided text and cluster data |
||
2365 | * to a cairo_show_text_glyphs() call. |
||
2366 | * |
||
2367 | * Note: Even if this function returns %FALSE, a |
||
2368 | * cairo_show_text_glyphs() operation targeted at @surface will |
||
2369 | * still succeed. It just will |
||
2370 | * act like a cairo_show_glyphs() operation. Users can use this |
||
2371 | * function to avoid computing UTF-8 text and cluster mapping if the |
||
2372 | * target surface does not use it. |
||
2373 | * |
||
2374 | * Return value: %TRUE if @surface supports |
||
2375 | * cairo_show_text_glyphs(), %FALSE otherwise |
||
2376 | * |
||
2377 | * Since: 1.8 |
||
2378 | **/ |
||
2379 | cairo_bool_t |
||
2380 | cairo_surface_has_show_text_glyphs (cairo_surface_t *surface) |
||
2381 | { |
||
2382 | cairo_status_t status_ignored; |
||
2383 | |||
2384 | if (surface->status) |
||
2385 | return FALSE; |
||
2386 | |||
2387 | if (surface->finished) { |
||
2388 | status_ignored = _cairo_surface_set_error (surface, |
||
2389 | CAIRO_STATUS_SURFACE_FINISHED); |
||
2390 | return FALSE; |
||
2391 | } |
||
2392 | |||
2393 | if (surface->backend->has_show_text_glyphs) |
||
2394 | return surface->backend->has_show_text_glyphs (surface); |
||
2395 | else |
||
2396 | return surface->backend->show_text_glyphs != NULL; |
||
2397 | } |
||
2398 | slim_hidden_def (cairo_surface_has_show_text_glyphs); |
||
2399 | |||
2400 | /* Note: the backends may modify the contents of the glyph array as long as |
||
2401 | * they do not return %CAIRO_INT_STATUS_UNSUPPORTED. This makes it possible to |
||
2402 | * avoid copying the array again and again, and edit it in-place. |
||
2403 | * Backends are in fact free to use the array as a generic buffer as they |
||
2404 | * see fit. |
||
2405 | * |
||
2406 | * For show_glyphs backend method, and NOT for show_text_glyphs method, |
||
2407 | * when they do return UNSUPPORTED, they may adjust remaining_glyphs to notify |
||
2408 | * that they have successfully rendered some of the glyphs (from the beginning |
||
2409 | * of the array), but not all. If they don't touch remaining_glyphs, it |
||
2410 | * defaults to all glyphs. |
||
2411 | * |
||
2412 | * See commits 5a9642c5746fd677aed35ce620ce90b1029b1a0c and |
||
2413 | * 1781e6018c17909311295a9cc74b70500c6b4d0a for the rationale. |
||
2414 | */ |
||
2415 | cairo_status_t |
||
2416 | _cairo_surface_show_text_glyphs (cairo_surface_t *surface, |
||
2417 | cairo_operator_t op, |
||
2418 | const cairo_pattern_t *source, |
||
2419 | const char *utf8, |
||
2420 | int utf8_len, |
||
2421 | cairo_glyph_t *glyphs, |
||
2422 | int num_glyphs, |
||
2423 | const cairo_text_cluster_t *clusters, |
||
2424 | int num_clusters, |
||
2425 | cairo_text_cluster_flags_t cluster_flags, |
||
2426 | cairo_scaled_font_t *scaled_font, |
||
2427 | cairo_clip_t *clip) |
||
2428 | { |
||
2429 | cairo_status_t status; |
||
2430 | cairo_scaled_font_t *dev_scaled_font = scaled_font; |
||
2431 | cairo_pattern_union_t dev_source; |
||
2432 | |||
2433 | if (unlikely (surface->status)) |
||
2434 | return surface->status; |
||
2435 | |||
2436 | if (num_glyphs == 0 && utf8_len == 0) |
||
2437 | return CAIRO_STATUS_SUCCESS; |
||
2438 | |||
2439 | if (clip && clip->all_clipped) |
||
2440 | return CAIRO_STATUS_SUCCESS; |
||
2441 | |||
2442 | _cairo_surface_begin_modification (surface); |
||
2443 | |||
2444 | _cairo_surface_copy_pattern_for_destination (&source, surface, |
||
2445 | &dev_source.base); |
||
2446 | |||
2447 | if (_cairo_surface_has_device_transform (surface) && |
||
2448 | ! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL)) |
||
2449 | { |
||
2450 | cairo_font_options_t font_options; |
||
2451 | cairo_matrix_t dev_ctm, font_matrix; |
||
2452 | |||
2453 | cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix); |
||
2454 | cairo_scaled_font_get_ctm (scaled_font, &dev_ctm); |
||
2455 | cairo_matrix_multiply (&dev_ctm, &dev_ctm, &surface->device_transform); |
||
2456 | cairo_scaled_font_get_font_options (scaled_font, &font_options); |
||
2457 | dev_scaled_font = cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaled_font), |
||
2458 | &font_matrix, |
||
2459 | &dev_ctm, |
||
2460 | &font_options); |
||
2461 | } |
||
2462 | status = cairo_scaled_font_status (dev_scaled_font); |
||
2463 | if (unlikely (status)) |
||
2464 | return _cairo_surface_set_error (surface, status); |
||
2465 | |||
2466 | status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
2467 | |||
2468 | /* The logic here is duplicated in _cairo_analysis_surface show_glyphs and |
||
2469 | * show_text_glyphs. Keep in synch. */ |
||
2470 | if (clusters) { |
||
2471 | /* A real show_text_glyphs call. Try show_text_glyphs backend |
||
2472 | * method first */ |
||
2473 | if (surface->backend->show_text_glyphs != NULL) { |
||
2474 | status = surface->backend->show_text_glyphs (surface, op, |
||
2475 | source, |
||
2476 | utf8, utf8_len, |
||
2477 | glyphs, num_glyphs, |
||
2478 | clusters, num_clusters, cluster_flags, |
||
2479 | dev_scaled_font, |
||
2480 | clip); |
||
2481 | } |
||
2482 | if (status == CAIRO_INT_STATUS_UNSUPPORTED && |
||
2483 | surface->backend->show_glyphs) |
||
2484 | { |
||
2485 | int remaining_glyphs = num_glyphs; |
||
2486 | status = surface->backend->show_glyphs (surface, op, |
||
2487 | source, |
||
2488 | glyphs, num_glyphs, |
||
2489 | dev_scaled_font, |
||
2490 | clip, |
||
2491 | &remaining_glyphs); |
||
2492 | glyphs += num_glyphs - remaining_glyphs; |
||
2493 | num_glyphs = remaining_glyphs; |
||
2494 | if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0) |
||
2495 | status = CAIRO_STATUS_SUCCESS; |
||
2496 | } |
||
2497 | } else { |
||
2498 | /* A mere show_glyphs call. Try show_glyphs backend method first */ |
||
2499 | if (surface->backend->show_glyphs != NULL) { |
||
2500 | int remaining_glyphs = num_glyphs; |
||
2501 | status = surface->backend->show_glyphs (surface, op, |
||
2502 | source, |
||
2503 | glyphs, num_glyphs, |
||
2504 | dev_scaled_font, |
||
2505 | clip, |
||
2506 | &remaining_glyphs); |
||
2507 | glyphs += num_glyphs - remaining_glyphs; |
||
2508 | num_glyphs = remaining_glyphs; |
||
2509 | if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0) |
||
2510 | status = CAIRO_STATUS_SUCCESS; |
||
2511 | } else if (surface->backend->show_text_glyphs != NULL) { |
||
2512 | /* Intentionally only try show_text_glyphs method for show_glyphs |
||
2513 | * calls if backend does not have show_glyphs. If backend has |
||
2514 | * both methods implemented, we don't fallback from show_glyphs to |
||
2515 | * show_text_glyphs, and hence the backend can assume in its |
||
2516 | * show_text_glyphs call that clusters is not NULL (which also |
||
2517 | * implies that UTF-8 is not NULL, unless the text is |
||
2518 | * zero-length). |
||
2519 | */ |
||
2520 | status = surface->backend->show_text_glyphs (surface, op, |
||
2521 | source, |
||
2522 | utf8, utf8_len, |
||
2523 | glyphs, num_glyphs, |
||
2524 | clusters, num_clusters, cluster_flags, |
||
2525 | dev_scaled_font, |
||
2526 | clip); |
||
2527 | } |
||
2528 | } |
||
2529 | |||
2530 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
2531 | status = _cairo_surface_fallback_show_glyphs (surface, op, |
||
2532 | source, |
||
2533 | glyphs, num_glyphs, |
||
2534 | dev_scaled_font, |
||
2535 | clip); |
||
2536 | } |
||
2537 | |||
2538 | if (dev_scaled_font != scaled_font) |
||
2539 | cairo_scaled_font_destroy (dev_scaled_font); |
||
2540 | |||
2541 | return _cairo_surface_set_error (surface, status); |
||
2542 | } |
||
2543 | |||
2544 | /* XXX: Previously, we had a function named _cairo_surface_show_glyphs |
||
2545 | * with not-so-useful semantics. We've now got a |
||
2546 | * _cairo_surface_show_text_glyphs with the proper semantics, and its |
||
2547 | * fallback still uses this old function (which still needs to be |
||
2548 | * cleaned up in terms of both semantics and naming). */ |
||
2549 | cairo_status_t |
||
2550 | _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font, |
||
2551 | cairo_operator_t op, |
||
2552 | const cairo_pattern_t *pattern, |
||
2553 | cairo_surface_t *dst, |
||
2554 | int source_x, |
||
2555 | int source_y, |
||
2556 | int dest_x, |
||
2557 | int dest_y, |
||
2558 | unsigned int width, |
||
2559 | unsigned int height, |
||
2560 | cairo_glyph_t *glyphs, |
||
2561 | int num_glyphs, |
||
2562 | cairo_region_t *clip_region) |
||
2563 | { |
||
2564 | cairo_status_t status; |
||
2565 | |||
2566 | if (dst->status) |
||
2567 | return dst->status; |
||
2568 | |||
2569 | assert (_cairo_surface_is_writable (dst)); |
||
2570 | |||
2571 | if (dst->backend->old_show_glyphs) { |
||
2572 | status = dst->backend->old_show_glyphs (scaled_font, |
||
2573 | op, pattern, dst, |
||
2574 | source_x, source_y, |
||
2575 | dest_x, dest_y, |
||
2576 | width, height, |
||
2577 | glyphs, num_glyphs, |
||
2578 | clip_region); |
||
2579 | } else |
||
2580 | status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
2581 | |||
2582 | return _cairo_surface_set_error (dst, status); |
||
2583 | } |
||
2584 | |||
2585 | static cairo_status_t |
||
2586 | _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst, |
||
2587 | cairo_rectangle_int_t *src_rectangle, |
||
2588 | cairo_rectangle_int_t *mask_rectangle, |
||
2589 | int dst_x, |
||
2590 | int dst_y, |
||
2591 | unsigned int width, |
||
2592 | unsigned int height, |
||
2593 | cairo_region_t *clip_region) |
||
2594 | { |
||
2595 | cairo_rectangle_int_t dst_rectangle; |
||
2596 | cairo_region_t clear_region; |
||
2597 | cairo_status_t status; |
||
2598 | |||
2599 | /* The area that was drawn is the area in the destination rectangle but |
||
2600 | * not within the source or the mask. |
||
2601 | */ |
||
2602 | dst_rectangle.x = dst_x; |
||
2603 | dst_rectangle.y = dst_y; |
||
2604 | dst_rectangle.width = width; |
||
2605 | dst_rectangle.height = height; |
||
2606 | |||
2607 | _cairo_region_init_rectangle (&clear_region, &dst_rectangle); |
||
2608 | |||
2609 | if (clip_region != NULL) { |
||
2610 | status = cairo_region_intersect (&clear_region, clip_region); |
||
2611 | if (unlikely (status)) |
||
2612 | goto CLEANUP_REGIONS; |
||
2613 | } |
||
2614 | |||
2615 | if (src_rectangle != NULL) { |
||
2616 | if (! _cairo_rectangle_intersect (&dst_rectangle, src_rectangle)) |
||
2617 | goto EMPTY; |
||
2618 | } |
||
2619 | |||
2620 | if (mask_rectangle != NULL) { |
||
2621 | if (! _cairo_rectangle_intersect (&dst_rectangle, mask_rectangle)) |
||
2622 | goto EMPTY; |
||
2623 | } |
||
2624 | |||
2625 | /* Now compute the area that is in dst but not drawn */ |
||
2626 | status = cairo_region_subtract_rectangle (&clear_region, &dst_rectangle); |
||
2627 | if (unlikely (status)) |
||
2628 | goto CLEANUP_REGIONS; |
||
2629 | |||
2630 | EMPTY: |
||
2631 | status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, |
||
2632 | CAIRO_COLOR_TRANSPARENT, |
||
2633 | &clear_region); |
||
2634 | |||
2635 | CLEANUP_REGIONS: |
||
2636 | _cairo_region_fini (&clear_region); |
||
2637 | |||
2638 | return _cairo_surface_set_error (dst, status); |
||
2639 | } |
||
2640 | |||
2641 | /** |
||
2642 | * _cairo_surface_composite_fixup_unbounded: |
||
2643 | * @dst: the destination surface |
||
2644 | * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface()) |
||
2645 | * @src_width: width of source surface |
||
2646 | * @src_height: height of source surface |
||
2647 | * @mask_attr: mask surface attributes or %NULL if no mask |
||
2648 | * @mask_width: width of mask surface |
||
2649 | * @mask_height: height of mask surface |
||
2650 | * @src_x: @src_x from _cairo_surface_composite() |
||
2651 | * @src_y: @src_y from _cairo_surface_composite() |
||
2652 | * @mask_x: @mask_x from _cairo_surface_composite() |
||
2653 | * @mask_y: @mask_y from _cairo_surface_composite() |
||
2654 | * @dst_x: @dst_x from _cairo_surface_composite() |
||
2655 | * @dst_y: @dst_y from _cairo_surface_composite() |
||
2656 | * @width: @width from _cairo_surface_composite() |
||
2657 | * @height: @height_x from _cairo_surface_composite() |
||
2658 | * |
||
2659 | * Eeek! Too many parameters! This is a helper function to take care of fixing |
||
2660 | * up for bugs in libpixman and RENDER where, when asked to composite an |
||
2661 | * untransformed surface with an unbounded operator (like CLEAR or SOURCE) |
||
2662 | * only the region inside both the source and the mask is affected. |
||
2663 | * This function clears the region that should have been drawn but was wasn't. |
||
2664 | **/ |
||
2665 | cairo_status_t |
||
2666 | _cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, |
||
2667 | cairo_surface_attributes_t *src_attr, |
||
2668 | int src_width, |
||
2669 | int src_height, |
||
2670 | cairo_surface_attributes_t *mask_attr, |
||
2671 | int mask_width, |
||
2672 | int mask_height, |
||
2673 | int src_x, |
||
2674 | int src_y, |
||
2675 | int mask_x, |
||
2676 | int mask_y, |
||
2677 | int dst_x, |
||
2678 | int dst_y, |
||
2679 | unsigned int width, |
||
2680 | unsigned int height, |
||
2681 | cairo_region_t *clip_region) |
||
2682 | { |
||
2683 | cairo_rectangle_int_t src_tmp, mask_tmp; |
||
2684 | cairo_rectangle_int_t *src_rectangle = NULL; |
||
2685 | cairo_rectangle_int_t *mask_rectangle = NULL; |
||
2686 | |||
2687 | if (unlikely (dst->status)) |
||
2688 | return dst->status; |
||
2689 | |||
2690 | assert (_cairo_surface_is_writable (dst)); |
||
2691 | |||
2692 | /* The RENDER/libpixman operators are clipped to the bounds of the untransformed, |
||
2693 | * non-repeating sources and masks. Other sources and masks can be ignored. |
||
2694 | */ |
||
2695 | if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) && |
||
2696 | src_attr->extend == CAIRO_EXTEND_NONE) |
||
2697 | { |
||
2698 | src_tmp.x = (dst_x - (src_x + src_attr->x_offset)); |
||
2699 | src_tmp.y = (dst_y - (src_y + src_attr->y_offset)); |
||
2700 | src_tmp.width = src_width; |
||
2701 | src_tmp.height = src_height; |
||
2702 | |||
2703 | src_rectangle = &src_tmp; |
||
2704 | } |
||
2705 | |||
2706 | if (mask_attr && |
||
2707 | _cairo_matrix_is_integer_translation (&mask_attr->matrix, NULL, NULL) && |
||
2708 | mask_attr->extend == CAIRO_EXTEND_NONE) |
||
2709 | { |
||
2710 | mask_tmp.x = (dst_x - (mask_x + mask_attr->x_offset)); |
||
2711 | mask_tmp.y = (dst_y - (mask_y + mask_attr->y_offset)); |
||
2712 | mask_tmp.width = mask_width; |
||
2713 | mask_tmp.height = mask_height; |
||
2714 | |||
2715 | mask_rectangle = &mask_tmp; |
||
2716 | } |
||
2717 | |||
2718 | return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle, |
||
2719 | dst_x, dst_y, width, height, |
||
2720 | clip_region); |
||
2721 | } |
||
2722 | |||
2723 | /** |
||
2724 | * _cairo_surface_composite_shape_fixup_unbounded: |
||
2725 | * @dst: the destination surface |
||
2726 | * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface()) |
||
2727 | * @src_width: width of source surface |
||
2728 | * @src_height: height of source surface |
||
2729 | * @mask_width: width of mask surface |
||
2730 | * @mask_height: height of mask surface |
||
2731 | * @src_x: @src_x from _cairo_surface_composite() |
||
2732 | * @src_y: @src_y from _cairo_surface_composite() |
||
2733 | * @mask_x: @mask_x from _cairo_surface_composite() |
||
2734 | * @mask_y: @mask_y from _cairo_surface_composite() |
||
2735 | * @dst_x: @dst_x from _cairo_surface_composite() |
||
2736 | * @dst_y: @dst_y from _cairo_surface_composite() |
||
2737 | * @width: @width from _cairo_surface_composite() |
||
2738 | * @height: @height_x from _cairo_surface_composite() |
||
2739 | * |
||
2740 | * Like _cairo_surface_composite_fixup_unbounded(), but instead of |
||
2741 | * handling the case where we have a source pattern and a mask |
||
2742 | * pattern, handle the case where we are compositing a source pattern |
||
2743 | * using a mask we create ourselves, as in |
||
2744 | * _cairo_surface_composite_glyphs() or _cairo_surface_composite_trapezoids() |
||
2745 | **/ |
||
2746 | cairo_status_t |
||
2747 | _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst, |
||
2748 | cairo_surface_attributes_t *src_attr, |
||
2749 | int src_width, |
||
2750 | int src_height, |
||
2751 | int mask_width, |
||
2752 | int mask_height, |
||
2753 | int src_x, |
||
2754 | int src_y, |
||
2755 | int mask_x, |
||
2756 | int mask_y, |
||
2757 | int dst_x, |
||
2758 | int dst_y, |
||
2759 | unsigned int width, |
||
2760 | unsigned int height, |
||
2761 | cairo_region_t *clip_region) |
||
2762 | { |
||
2763 | cairo_rectangle_int_t src_tmp, mask_tmp; |
||
2764 | cairo_rectangle_int_t *src_rectangle = NULL; |
||
2765 | cairo_rectangle_int_t *mask_rectangle = NULL; |
||
2766 | |||
2767 | if (dst->status) |
||
2768 | return dst->status; |
||
2769 | |||
2770 | assert (_cairo_surface_is_writable (dst)); |
||
2771 | |||
2772 | /* The RENDER/libpixman operators are clipped to the bounds of the untransformed, |
||
2773 | * non-repeating sources and masks. Other sources and masks can be ignored. |
||
2774 | */ |
||
2775 | if (_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) && |
||
2776 | src_attr->extend == CAIRO_EXTEND_NONE) |
||
2777 | { |
||
2778 | src_tmp.x = (dst_x - (src_x + src_attr->x_offset)); |
||
2779 | src_tmp.y = (dst_y - (src_y + src_attr->y_offset)); |
||
2780 | src_tmp.width = src_width; |
||
2781 | src_tmp.height = src_height; |
||
2782 | |||
2783 | src_rectangle = &src_tmp; |
||
2784 | } |
||
2785 | |||
2786 | mask_tmp.x = dst_x - mask_x; |
||
2787 | mask_tmp.y = dst_y - mask_y; |
||
2788 | mask_tmp.width = mask_width; |
||
2789 | mask_tmp.height = mask_height; |
||
2790 | |||
2791 | mask_rectangle = &mask_tmp; |
||
2792 | |||
2793 | return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle, |
||
2794 | dst_x, dst_y, width, height, |
||
2795 | clip_region); |
||
2796 | } |
||
2797 | |||
2798 | /** |
||
2799 | * _cairo_surface_copy_pattern_for_destination |
||
2800 | * @pattern: the pattern to copy |
||
2801 | * @destination: the destination surface for which the pattern is being copied |
||
2802 | * @pattern_copy: the location to hold the copy |
||
2803 | * |
||
2804 | * Copies the given pattern, taking into account device scale and offsets |
||
2805 | * of the destination surface. |
||
2806 | */ |
||
2807 | static void |
||
2808 | _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern, |
||
2809 | cairo_surface_t *destination, |
||
2810 | cairo_pattern_t *pattern_copy) |
||
2811 | { |
||
2812 | if (! _cairo_surface_has_device_transform (destination)) |
||
2813 | return; |
||
2814 | |||
2815 | _cairo_pattern_init_static_copy (pattern_copy, *pattern); |
||
2816 | _cairo_pattern_transform (pattern_copy, |
||
2817 | &destination->device_transform_inverse); |
||
2818 | |||
2819 | *pattern = pattern_copy; |
||
2820 | } |
||
2821 | |||
2822 | /** |
||
2823 | * _cairo_surface_set_resolution |
||
2824 | * @surface: the surface |
||
2825 | * @x_res: x resolution, in dpi |
||
2826 | * @y_res: y resolution, in dpi |
||
2827 | * |
||
2828 | * Set the actual surface resolution of @surface to the given x and y DPI. |
||
2829 | * Mainly used for correctly computing the scale factor when fallback |
||
2830 | * rendering needs to take place in the paginated surface. |
||
2831 | */ |
||
2832 | void |
||
2833 | _cairo_surface_set_resolution (cairo_surface_t *surface, |
||
2834 | double x_res, |
||
2835 | double y_res) |
||
2836 | { |
||
2837 | if (surface->status) |
||
2838 | return; |
||
2839 | |||
2840 | surface->x_resolution = x_res; |
||
2841 | surface->y_resolution = y_res; |
||
2842 | } |
||
2843 | |||
2844 | /* Generic methods for determining operation extents. */ |
||
2845 | |||
2846 | static void |
||
2847 | _rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip) |
||
2848 | { |
||
2849 | const cairo_rectangle_int_t *clip_extents; |
||
2850 | cairo_bool_t is_empty; |
||
2851 | |||
2852 | clip_extents = NULL; |
||
2853 | if (clip != NULL) |
||
2854 | clip_extents = _cairo_clip_get_extents (clip); |
||
2855 | |||
2856 | if (clip_extents != NULL) |
||
2857 | is_empty = _cairo_rectangle_intersect (extents, clip_extents); |
||
2858 | } |
||
2859 | |||
2860 | static void |
||
2861 | _cairo_surface_operation_extents (cairo_surface_t *surface, |
||
2862 | cairo_operator_t op, |
||
2863 | const cairo_pattern_t *source, |
||
2864 | cairo_clip_t *clip, |
||
2865 | cairo_rectangle_int_t *extents) |
||
2866 | { |
||
2867 | cairo_bool_t is_empty; |
||
2868 | |||
2869 | is_empty = _cairo_surface_get_extents (surface, extents); |
||
2870 | |||
2871 | if (_cairo_operator_bounded_by_source (op)) { |
||
2872 | cairo_rectangle_int_t source_extents; |
||
2873 | |||
2874 | _cairo_pattern_get_extents (source, &source_extents); |
||
2875 | is_empty = _cairo_rectangle_intersect (extents, &source_extents); |
||
2876 | } |
||
2877 | |||
2878 | _rectangle_intersect_clip (extents, clip); |
||
2879 | } |
||
2880 | |||
2881 | cairo_status_t |
||
2882 | _cairo_surface_paint_extents (cairo_surface_t *surface, |
||
2883 | cairo_operator_t op, |
||
2884 | const cairo_pattern_t *source, |
||
2885 | cairo_clip_t *clip, |
||
2886 | cairo_rectangle_int_t *extents) |
||
2887 | { |
||
2888 | _cairo_surface_operation_extents (surface, op, source, clip, extents); |
||
2889 | return CAIRO_STATUS_SUCCESS; |
||
2890 | } |
||
2891 | |||
2892 | cairo_status_t |
||
2893 | _cairo_surface_mask_extents (cairo_surface_t *surface, |
||
2894 | cairo_operator_t op, |
||
2895 | const cairo_pattern_t *source, |
||
2896 | const cairo_pattern_t *mask, |
||
2897 | cairo_clip_t *clip, |
||
2898 | cairo_rectangle_int_t *extents) |
||
2899 | { |
||
2900 | cairo_bool_t is_empty; |
||
2901 | |||
2902 | _cairo_surface_operation_extents (surface, op, source, clip, extents); |
||
2903 | |||
2904 | if (_cairo_operator_bounded_by_mask (op)) { |
||
2905 | cairo_rectangle_int_t mask_extents; |
||
2906 | |||
2907 | _cairo_pattern_get_extents (mask, &mask_extents); |
||
2908 | is_empty = _cairo_rectangle_intersect (extents, &mask_extents); |
||
2909 | } |
||
2910 | |||
2911 | return CAIRO_STATUS_SUCCESS; |
||
2912 | } |
||
2913 | |||
2914 | cairo_status_t |
||
2915 | _cairo_surface_stroke_extents (cairo_surface_t *surface, |
||
2916 | cairo_operator_t op, |
||
2917 | const cairo_pattern_t *source, |
||
2918 | cairo_path_fixed_t *path, |
||
2919 | cairo_stroke_style_t *style, |
||
2920 | const cairo_matrix_t *ctm, |
||
2921 | const cairo_matrix_t *ctm_inverse, |
||
2922 | double tolerance, |
||
2923 | cairo_antialias_t antialias, |
||
2924 | cairo_clip_t *clip, |
||
2925 | cairo_rectangle_int_t *extents) |
||
2926 | { |
||
2927 | cairo_status_t status; |
||
2928 | cairo_bool_t is_empty; |
||
2929 | |||
2930 | _cairo_surface_operation_extents (surface, op, source, clip, extents); |
||
2931 | |||
2932 | if (_cairo_operator_bounded_by_mask (op)) { |
||
2933 | cairo_rectangle_int_t mask_extents; |
||
2934 | |||
2935 | status = _cairo_path_fixed_stroke_extents (path, style, |
||
2936 | ctm, ctm_inverse, |
||
2937 | tolerance, |
||
2938 | &mask_extents); |
||
2939 | if (unlikely (status)) |
||
2940 | return status; |
||
2941 | |||
2942 | is_empty = _cairo_rectangle_intersect (extents, &mask_extents); |
||
2943 | } |
||
2944 | |||
2945 | return CAIRO_STATUS_SUCCESS; |
||
2946 | } |
||
2947 | |||
2948 | cairo_status_t |
||
2949 | _cairo_surface_fill_extents (cairo_surface_t *surface, |
||
2950 | cairo_operator_t op, |
||
2951 | const cairo_pattern_t *source, |
||
2952 | cairo_path_fixed_t *path, |
||
2953 | cairo_fill_rule_t fill_rule, |
||
2954 | double tolerance, |
||
2955 | cairo_antialias_t antialias, |
||
2956 | cairo_clip_t *clip, |
||
2957 | cairo_rectangle_int_t *extents) |
||
2958 | { |
||
2959 | cairo_bool_t is_empty; |
||
2960 | |||
2961 | _cairo_surface_operation_extents (surface, op, source, clip, extents); |
||
2962 | |||
2963 | if (_cairo_operator_bounded_by_mask (op)) { |
||
2964 | cairo_rectangle_int_t mask_extents; |
||
2965 | |||
2966 | _cairo_path_fixed_fill_extents (path, fill_rule, tolerance, |
||
2967 | &mask_extents); |
||
2968 | is_empty = _cairo_rectangle_intersect (extents, &mask_extents); |
||
2969 | } |
||
2970 | |||
2971 | return CAIRO_STATUS_SUCCESS; |
||
2972 | } |
||
2973 | |||
2974 | cairo_status_t |
||
2975 | _cairo_surface_glyphs_extents (cairo_surface_t *surface, |
||
2976 | cairo_operator_t op, |
||
2977 | const cairo_pattern_t *source, |
||
2978 | cairo_glyph_t *glyphs, |
||
2979 | int num_glyphs, |
||
2980 | cairo_scaled_font_t *scaled_font, |
||
2981 | cairo_clip_t *clip, |
||
2982 | cairo_rectangle_int_t *extents) |
||
2983 | { |
||
2984 | cairo_status_t status; |
||
2985 | cairo_bool_t is_empty; |
||
2986 | |||
2987 | _cairo_surface_operation_extents (surface, op, source, clip, extents); |
||
2988 | |||
2989 | if (_cairo_operator_bounded_by_mask (op)) { |
||
2990 | cairo_rectangle_int_t glyph_extents; |
||
2991 | |||
2992 | status = _cairo_scaled_font_glyph_device_extents (scaled_font, |
||
2993 | glyphs, |
||
2994 | num_glyphs, |
||
2995 | &glyph_extents, |
||
2996 | NULL); |
||
2997 | if (unlikely (status)) |
||
2998 | return status; |
||
2999 | |||
3000 | is_empty = _cairo_rectangle_intersect (extents, &glyph_extents); |
||
3001 | } |
||
3002 | |||
3003 | return CAIRO_STATUS_SUCCESS; |
||
3004 | } |
||
3005 | |||
3006 | cairo_surface_t * |
||
3007 | _cairo_surface_create_in_error (cairo_status_t status) |
||
3008 | { |
||
3009 | switch (status) { |
||
3010 | case CAIRO_STATUS_NO_MEMORY: |
||
3011 | return (cairo_surface_t *) &_cairo_surface_nil; |
||
3012 | case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: |
||
3013 | return (cairo_surface_t *) &_cairo_surface_nil_surface_type_mismatch; |
||
3014 | case CAIRO_STATUS_INVALID_STATUS: |
||
3015 | return (cairo_surface_t *) &_cairo_surface_nil_invalid_status; |
||
3016 | case CAIRO_STATUS_INVALID_CONTENT: |
||
3017 | return (cairo_surface_t *) &_cairo_surface_nil_invalid_content; |
||
3018 | case CAIRO_STATUS_INVALID_FORMAT: |
||
3019 | return (cairo_surface_t *) &_cairo_surface_nil_invalid_format; |
||
3020 | case CAIRO_STATUS_INVALID_VISUAL: |
||
3021 | return (cairo_surface_t *) &_cairo_surface_nil_invalid_visual; |
||
3022 | case CAIRO_STATUS_READ_ERROR: |
||
3023 | return (cairo_surface_t *) &_cairo_surface_nil_read_error; |
||
3024 | case CAIRO_STATUS_WRITE_ERROR: |
||
3025 | return (cairo_surface_t *) &_cairo_surface_nil_write_error; |
||
3026 | case CAIRO_STATUS_FILE_NOT_FOUND: |
||
3027 | return (cairo_surface_t *) &_cairo_surface_nil_file_not_found; |
||
3028 | case CAIRO_STATUS_TEMP_FILE_ERROR: |
||
3029 | return (cairo_surface_t *) &_cairo_surface_nil_temp_file_error; |
||
3030 | case CAIRO_STATUS_INVALID_STRIDE: |
||
3031 | return (cairo_surface_t *) &_cairo_surface_nil_invalid_stride; |
||
3032 | case CAIRO_STATUS_INVALID_SIZE: |
||
3033 | return (cairo_surface_t *) &_cairo_surface_nil_invalid_size; |
||
3034 | case CAIRO_STATUS_SUCCESS: |
||
3035 | case CAIRO_STATUS_LAST_STATUS: |
||
3036 | ASSERT_NOT_REACHED; |
||
3037 | /* fall-through */ |
||
3038 | case CAIRO_STATUS_INVALID_RESTORE: |
||
3039 | case CAIRO_STATUS_INVALID_POP_GROUP: |
||
3040 | case CAIRO_STATUS_NO_CURRENT_POINT: |
||
3041 | case CAIRO_STATUS_INVALID_MATRIX: |
||
3042 | case CAIRO_STATUS_NULL_POINTER: |
||
3043 | case CAIRO_STATUS_INVALID_STRING: |
||
3044 | case CAIRO_STATUS_INVALID_PATH_DATA: |
||
3045 | case CAIRO_STATUS_SURFACE_FINISHED: |
||
3046 | case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: |
||
3047 | case CAIRO_STATUS_INVALID_DASH: |
||
3048 | case CAIRO_STATUS_INVALID_DSC_COMMENT: |
||
3049 | case CAIRO_STATUS_INVALID_INDEX: |
||
3050 | case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: |
||
3051 | case CAIRO_STATUS_FONT_TYPE_MISMATCH: |
||
3052 | case CAIRO_STATUS_USER_FONT_IMMUTABLE: |
||
3053 | case CAIRO_STATUS_USER_FONT_ERROR: |
||
3054 | case CAIRO_STATUS_NEGATIVE_COUNT: |
||
3055 | case CAIRO_STATUS_INVALID_CLUSTERS: |
||
3056 | case CAIRO_STATUS_INVALID_SLANT: |
||
3057 | case CAIRO_STATUS_INVALID_WEIGHT: |
||
3058 | case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: |
||
3059 | default: |
||
3060 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
||
3061 | return (cairo_surface_t *) &_cairo_surface_nil; |
||
3062 | } |
||
3063 | } |
||
3064 | |||
3065 | /* LocalWords: rasterized |
||
3066 | */ |