1 /* Cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Intel Corporation.
33 * Chris Wilson <chris@chris-wilson.co.uk>
37 #include "cairo-device-private.h"
38 #include "cairo-error-private.h"
39 #include "cairo-list-inline.h"
42 * SECTION:cairo-device
43 * @Title: cairo_device_t
44 * @Short_Description: interface to underlying rendering system
45 * @See_Also: #cairo_surface_t
47 * Devices are the abstraction Cairo employs for the rendering system
48 * used by a #cairo_surface_t. You can get the device of a surface using
49 * cairo_surface_get_device().
51 * Devices are created using custom functions specific to the rendering
52 * system you want to use. See the documentation for the surface types
53 * for those functions.
55 * An important function that devices fulfill is sharing access to the
56 * rendering system between Cairo and your application. If you want to
57 * access a device directly that you used to draw to with Cairo, you must
58 * first call cairo_device_flush() to ensure that Cairo finishes all
59 * operations on the device and resets it to a clean state.
61 * Cairo also provides the functions cairo_device_acquire() and
62 * cairo_device_release() to synchronize access to the rendering system
63 * in a multithreaded environment. This is done internally, but can also
64 * be used by applications.
66 * Putting this all together, a function that works with devices should
67 * look something like this:
68 * <informalexample><programlisting>
70 * my_device_modifying_function (cairo_device_t *device)
72 * cairo_status_t status;
74 * // Ensure the device is properly reset
75 * cairo_device_flush (device);
76 * // Try to acquire the device
77 * status = cairo_device_acquire (device);
78 * if (status != CAIRO_STATUS_SUCCESS) {
79 * printf ("Failed to acquire the device: %s\n", cairo_status_to_string (status));
83 * // Do the custom operations on the device here.
84 * // But do not call any Cairo functions that might acquire devices.
86 * // Release the device when done.
87 * cairo_device_release (device);
89 * </programlisting></informalexample>
91 * <note><para>Please refer to the documentation of each backend for
92 * additional usage requirements, guarantees provided, and
93 * interactions with existing surface API of the device functions for
94 * surfaces of that type.
98 static const cairo_device_t _nil_device = {
99 CAIRO_REFERENCE_COUNT_INVALID,
100 CAIRO_STATUS_NO_MEMORY,
103 static const cairo_device_t _mismatch_device = {
104 CAIRO_REFERENCE_COUNT_INVALID,
105 CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
108 static const cairo_device_t _invalid_device = {
109 CAIRO_REFERENCE_COUNT_INVALID,
110 CAIRO_STATUS_DEVICE_ERROR,
114 _cairo_device_create_in_error (cairo_status_t status)
117 case CAIRO_STATUS_NO_MEMORY:
118 return (cairo_device_t *) &_nil_device;
119 case CAIRO_STATUS_DEVICE_ERROR:
120 return (cairo_device_t *) &_invalid_device;
121 case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
122 return (cairo_device_t *) &_mismatch_device;
124 case CAIRO_STATUS_SUCCESS:
125 case CAIRO_STATUS_LAST_STATUS:
128 case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
129 case CAIRO_STATUS_INVALID_STATUS:
130 case CAIRO_STATUS_INVALID_FORMAT:
131 case CAIRO_STATUS_INVALID_VISUAL:
132 case CAIRO_STATUS_READ_ERROR:
133 case CAIRO_STATUS_WRITE_ERROR:
134 case CAIRO_STATUS_FILE_NOT_FOUND:
135 case CAIRO_STATUS_TEMP_FILE_ERROR:
136 case CAIRO_STATUS_INVALID_STRIDE:
137 case CAIRO_STATUS_INVALID_SIZE:
138 case CAIRO_STATUS_INVALID_RESTORE:
139 case CAIRO_STATUS_INVALID_POP_GROUP:
140 case CAIRO_STATUS_NO_CURRENT_POINT:
141 case CAIRO_STATUS_INVALID_MATRIX:
142 case CAIRO_STATUS_NULL_POINTER:
143 case CAIRO_STATUS_INVALID_STRING:
144 case CAIRO_STATUS_INVALID_PATH_DATA:
145 case CAIRO_STATUS_SURFACE_FINISHED:
146 case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
147 case CAIRO_STATUS_INVALID_DASH:
148 case CAIRO_STATUS_INVALID_DSC_COMMENT:
149 case CAIRO_STATUS_INVALID_INDEX:
150 case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
151 case CAIRO_STATUS_FONT_TYPE_MISMATCH:
152 case CAIRO_STATUS_USER_FONT_IMMUTABLE:
153 case CAIRO_STATUS_USER_FONT_ERROR:
154 case CAIRO_STATUS_NEGATIVE_COUNT:
155 case CAIRO_STATUS_INVALID_CLUSTERS:
156 case CAIRO_STATUS_INVALID_SLANT:
157 case CAIRO_STATUS_INVALID_WEIGHT:
158 case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
159 case CAIRO_STATUS_INVALID_CONTENT:
160 case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
161 case CAIRO_STATUS_DEVICE_FINISHED:
163 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
164 return (cairo_device_t *) &_nil_device;
169 _cairo_device_init (cairo_device_t *device,
170 const cairo_device_backend_t *backend)
172 CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
173 device->status = CAIRO_STATUS_SUCCESS;
175 device->backend = backend;
177 CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
178 device->mutex_depth = 0;
180 device->finished = FALSE;
182 _cairo_user_data_array_init (&device->user_data);
184 cairo_list_init (&device->shadow_caches);
185 device->shadow_caches_size = 0;
189 * cairo_device_reference:
190 * @device: a #cairo_device_t
192 * Increases the reference count on @device by one. This prevents
193 * @device from being destroyed until a matching call to
194 * cairo_device_destroy() is made.
196 * The number of references to a #cairo_device_t can be get using
197 * cairo_device_get_reference_count().
199 * Return value: the referenced #cairo_device_t.
204 cairo_device_reference (cairo_device_t *device)
206 if (device == NULL ||
207 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
212 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
213 _cairo_reference_count_inc (&device->ref_count);
217 slim_hidden_def (cairo_device_reference);
220 * cairo_device_status:
221 * @device: a #cairo_device_t
223 * Checks whether an error has previously occurred for this
226 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
227 * the device is in an error state.
232 cairo_device_status (cairo_device_t *device)
235 return CAIRO_STATUS_NULL_POINTER;
237 return device->status;
241 * cairo_device_flush:
242 * @device: a #cairo_device_t
244 * Finish any pending operations for the device and also restore any
245 * temporary modifications cairo has made to the device's state.
246 * This function must be called before switching from using the
247 * device with Cairo to operating on it directly with native APIs.
248 * If the device doesn't support direct access, then this function
251 * This function may acquire devices.
256 cairo_device_flush (cairo_device_t *device)
258 cairo_status_t status;
260 if (device == NULL || device->status)
263 if (device->finished)
266 if (device->backend->flush != NULL) {
267 status = device->backend->flush (device);
268 if (unlikely (status))
269 status = _cairo_device_set_error (device, status);
272 slim_hidden_def (cairo_device_flush);
275 * cairo_device_finish:
276 * @device: the #cairo_device_t to finish
278 * This function finishes the device and drops all references to
279 * external resources. All surfaces, fonts and other objects created
280 * for this @device will be finished, too.
281 * Further operations on the @device will not affect the @device but
282 * will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error.
284 * When the last call to cairo_device_destroy() decreases the
285 * reference count to zero, cairo will call cairo_device_finish() if
286 * it hasn't been called already, before freeing the resources
287 * associated with the device.
289 * This function may acquire devices.
294 cairo_device_finish (cairo_device_t *device)
296 if (device == NULL ||
297 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
302 if (device->finished)
305 cairo_device_flush (device);
307 if (device->backend->finish != NULL)
308 device->backend->finish (device);
310 /* We only finish the device after the backend's callback returns because
311 * the device might still be needed during the callback
312 * (e.g. for cairo_device_acquire ()).
314 device->finished = TRUE;
316 slim_hidden_def (cairo_device_finish);
319 * cairo_device_destroy:
320 * @device: a #cairo_device_t
322 * Decreases the reference count on @device by one. If the result is
323 * zero, then @device and all associated resources are freed. See
324 * cairo_device_reference().
326 * This function may acquire devices if the last reference was dropped.
331 cairo_device_destroy (cairo_device_t *device)
333 cairo_user_data_array_t user_data;
335 if (device == NULL ||
336 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
341 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
342 if (! _cairo_reference_count_dec_and_test (&device->ref_count))
345 while (! cairo_list_is_empty (&device->shadow_caches)) {
346 cairo_shadow_cache_t *shadow;
348 shadow = cairo_list_first_entry (&device->shadow_caches,
349 cairo_shadow_cache_t,
352 cairo_list_del (&shadow->link);
353 cairo_surface_destroy (shadow->surface);
356 device->shadow_caches_size = 0;
358 cairo_device_finish (device);
360 assert (device->mutex_depth == 0);
361 CAIRO_MUTEX_FINI (device->mutex);
363 user_data = device->user_data;
365 device->backend->destroy (device);
367 _cairo_user_data_array_fini (&user_data);
370 slim_hidden_def (cairo_device_destroy);
373 * cairo_device_get_type:
374 * @device: a #cairo_device_t
376 * This function returns the type of the device. See #cairo_device_type_t
377 * for available types.
379 * Return value: The type of @device.
384 cairo_device_get_type (cairo_device_t *device)
386 if (device == NULL ||
387 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
389 return CAIRO_DEVICE_TYPE_INVALID;
392 return device->backend->type;
396 * cairo_device_acquire:
397 * @device: a #cairo_device_t
399 * Acquires the @device for the current thread. This function will block
400 * until no other thread has acquired the device.
402 * If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the
403 * device. From now on your thread owns the device and no other thread will be
404 * able to acquire it until a matching call to cairo_device_release(). It is
405 * allowed to recursively acquire the device multiple times from the same
408 * <note><para>You must never acquire two different devices at the same time
409 * unless this is explicitly allowed. Otherwise the possibility of deadlocks
412 * As various Cairo functions can acquire devices when called, these functions
413 * may also cause deadlocks when you call them with an acquired device. So you
414 * must not have a device acquired when calling them. These functions are
415 * marked in the documentation.
418 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
419 * the device is in an error state and could not be
420 * acquired. After a successful call to cairo_device_acquire(),
421 * a matching call to cairo_device_release() is required.
426 cairo_device_acquire (cairo_device_t *device)
429 return CAIRO_STATUS_SUCCESS;
431 if (unlikely (device->status))
432 return device->status;
434 if (unlikely (device->finished))
435 return _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_FINISHED);
437 CAIRO_MUTEX_LOCK (device->mutex);
438 if (device->mutex_depth++ == 0) {
439 if (device->backend->lock != NULL)
440 device->backend->lock (device);
443 return CAIRO_STATUS_SUCCESS;
445 slim_hidden_def (cairo_device_acquire);
448 * cairo_device_release:
449 * @device: a #cairo_device_t
451 * Releases a @device previously acquired using cairo_device_acquire(). See
452 * that function for details.
457 cairo_device_release (cairo_device_t *device)
462 assert (device->mutex_depth > 0);
464 if (--device->mutex_depth == 0) {
465 if (device->backend->unlock != NULL)
466 device->backend->unlock (device);
469 CAIRO_MUTEX_UNLOCK (device->mutex);
471 slim_hidden_def (cairo_device_release);
474 _cairo_device_set_error (cairo_device_t *device,
475 cairo_status_t status)
477 if (status == CAIRO_STATUS_SUCCESS)
478 return CAIRO_STATUS_SUCCESS;
480 _cairo_status_set_error (&device->status, status);
482 return _cairo_error (status);
486 * cairo_device_get_reference_count:
487 * @device: a #cairo_device_t
489 * Returns the current reference count of @device.
491 * Return value: the current reference count of @device. If the
492 * object is a nil object, 0 will be returned.
497 cairo_device_get_reference_count (cairo_device_t *device)
499 if (device == NULL ||
500 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
503 return CAIRO_REFERENCE_COUNT_GET_VALUE (&device->ref_count);
507 * cairo_device_get_user_data:
508 * @device: a #cairo_device_t
509 * @key: the address of the #cairo_user_data_key_t the user data was
512 * Return user data previously attached to @device using the
513 * specified key. If no user data has been attached with the given
514 * key this function returns %NULL.
516 * Return value: the user data previously attached or %NULL.
521 cairo_device_get_user_data (cairo_device_t *device,
522 const cairo_user_data_key_t *key)
524 return _cairo_user_data_array_get_data (&device->user_data,
529 * cairo_device_set_user_data:
530 * @device: a #cairo_device_t
531 * @key: the address of a #cairo_user_data_key_t to attach the user data to
532 * @user_data: the user data to attach to the #cairo_device_t
533 * @destroy: a #cairo_destroy_func_t which will be called when the
534 * #cairo_t is destroyed or when new user data is attached using the
537 * Attach user data to @device. To remove user data from a surface,
538 * call this function with the key that was used to set it and %NULL
541 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
542 * slot could not be allocated for the user data.
547 cairo_device_set_user_data (cairo_device_t *device,
548 const cairo_user_data_key_t *key,
550 cairo_destroy_func_t destroy)
552 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
553 return device->status;
555 return _cairo_user_data_array_set_data (&device->user_data,
556 key, user_data, destroy);