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"
41 * SECTION:cairo-device
42 * @Title: cairo_device_t
43 * @Short_Description: interface to underlying rendering system
44 * @See_Also: #cairo_surface_t
46 * Devices are the abstraction Cairo employs for the rendering system
47 * used by a #cairo_surface_t. You can get the device of a surface using
48 * cairo_surface_get_device().
50 * Devices are created using custom functions specific to the rendering
51 * system you want to use. See the documentation for the surface types
52 * for those functions.
54 * An important function that devices fulfill is sharing access to the
55 * rendering system between Cairo and your application. If you want to
56 * access a device directly that you used to draw to with Cairo, you must
57 * first call cairo_device_flush() to ensure that Cairo finishes all
58 * operations on the device and resets it to a clean state.
60 * Cairo also provides the functions cairo_device_acquire() and
61 * cairo_device_release() to synchronize access to the rendering system
62 * in a multithreaded environment. This is done internally, but can also
63 * be used by applications.
65 * Putting this all together, a function that works with devices should
66 * look something like this:
67 * <informalexample><programlisting>
69 * my_device_modifying_function (cairo_device_t *device)
71 * cairo_status_t status;
73 * // Ensure the device is properly reset
74 * cairo_device_flush (device);
75 * // Try to acquire the device
76 * status = cairo_device_acquire (device);
77 * if (status != CAIRO_STATUS_SUCCESS) {
78 * printf ("Failed to acquire the device: %s\n", cairo_status_to_string (status));
82 * // Do the custom operations on the device here.
83 * // But do not call any Cairo functions that might acquire devices.
85 * // Release the device when done.
86 * cairo_device_release (device);
88 * </programlisting></informalexample>
90 * <note><para>Please refer to the documentation of each backend for
91 * additional usage requirements, guarantees provided, and
92 * interactions with existing surface API of the device functions for
93 * surfaces of that type.
97 static const cairo_device_t _nil_device = {
98 CAIRO_REFERENCE_COUNT_INVALID,
99 CAIRO_STATUS_NO_MEMORY,
102 static const cairo_device_t _mismatch_device = {
103 CAIRO_REFERENCE_COUNT_INVALID,
104 CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
107 static const cairo_device_t _invalid_device = {
108 CAIRO_REFERENCE_COUNT_INVALID,
109 CAIRO_STATUS_DEVICE_ERROR,
113 _cairo_device_create_in_error (cairo_status_t status)
116 case CAIRO_STATUS_NO_MEMORY:
117 return (cairo_device_t *) &_nil_device;
118 case CAIRO_STATUS_DEVICE_ERROR:
119 return (cairo_device_t *) &_invalid_device;
120 case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
121 return (cairo_device_t *) &_mismatch_device;
123 case CAIRO_STATUS_SUCCESS:
124 case CAIRO_STATUS_LAST_STATUS:
127 case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
128 case CAIRO_STATUS_INVALID_STATUS:
129 case CAIRO_STATUS_INVALID_FORMAT:
130 case CAIRO_STATUS_INVALID_VISUAL:
131 case CAIRO_STATUS_READ_ERROR:
132 case CAIRO_STATUS_WRITE_ERROR:
133 case CAIRO_STATUS_FILE_NOT_FOUND:
134 case CAIRO_STATUS_TEMP_FILE_ERROR:
135 case CAIRO_STATUS_INVALID_STRIDE:
136 case CAIRO_STATUS_INVALID_SIZE:
137 case CAIRO_STATUS_INVALID_RESTORE:
138 case CAIRO_STATUS_INVALID_POP_GROUP:
139 case CAIRO_STATUS_NO_CURRENT_POINT:
140 case CAIRO_STATUS_INVALID_MATRIX:
141 case CAIRO_STATUS_NULL_POINTER:
142 case CAIRO_STATUS_INVALID_STRING:
143 case CAIRO_STATUS_INVALID_PATH_DATA:
144 case CAIRO_STATUS_SURFACE_FINISHED:
145 case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
146 case CAIRO_STATUS_INVALID_DASH:
147 case CAIRO_STATUS_INVALID_DSC_COMMENT:
148 case CAIRO_STATUS_INVALID_INDEX:
149 case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
150 case CAIRO_STATUS_FONT_TYPE_MISMATCH:
151 case CAIRO_STATUS_USER_FONT_IMMUTABLE:
152 case CAIRO_STATUS_USER_FONT_ERROR:
153 case CAIRO_STATUS_NEGATIVE_COUNT:
154 case CAIRO_STATUS_INVALID_CLUSTERS:
155 case CAIRO_STATUS_INVALID_SLANT:
156 case CAIRO_STATUS_INVALID_WEIGHT:
157 case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
158 case CAIRO_STATUS_INVALID_CONTENT:
159 case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
160 case CAIRO_STATUS_DEVICE_FINISHED:
162 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
163 return (cairo_device_t *) &_nil_device;
168 _cairo_device_init (cairo_device_t *device,
169 const cairo_device_backend_t *backend)
171 CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
172 device->status = CAIRO_STATUS_SUCCESS;
174 device->backend = backend;
176 CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
177 device->mutex_depth = 0;
179 device->finished = FALSE;
181 _cairo_user_data_array_init (&device->user_data);
185 * cairo_device_reference:
186 * @device: a #cairo_device_t
188 * Increases the reference count on @device by one. This prevents
189 * @device from being destroyed until a matching call to
190 * cairo_device_destroy() is made.
192 * The number of references to a #cairo_device_t can be get using
193 * cairo_device_get_reference_count().
195 * Return value: the referenced #cairo_device_t.
200 cairo_device_reference (cairo_device_t *device)
202 if (device == NULL ||
203 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
208 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
209 _cairo_reference_count_inc (&device->ref_count);
213 slim_hidden_def (cairo_device_reference);
216 * cairo_device_status:
217 * @device: a #cairo_device_t
219 * Checks whether an error has previously occurred for this
222 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
223 * the device is in an error state.
228 cairo_device_status (cairo_device_t *device)
231 return CAIRO_STATUS_NULL_POINTER;
233 return device->status;
237 * cairo_device_flush:
238 * @device: a #cairo_device_t
240 * Finish any pending operations for the device and also restore any
241 * temporary modifications cairo has made to the device's state.
242 * This function must be called before switching from using the
243 * device with Cairo to operating on it directly with native APIs.
244 * If the device doesn't support direct access, then this function
247 * This function may acquire devices.
252 cairo_device_flush (cairo_device_t *device)
254 cairo_status_t status;
256 if (device == NULL || device->status)
259 if (device->finished)
262 if (device->backend->flush != NULL) {
263 status = device->backend->flush (device);
264 if (unlikely (status))
265 status = _cairo_device_set_error (device, status);
268 slim_hidden_def (cairo_device_flush);
271 * cairo_device_finish:
272 * @device: the #cairo_device_t to finish
274 * This function finishes the device and drops all references to
275 * external resources. All surfaces, fonts and other objects created
276 * for this @device will be finished, too.
277 * Further operations on the @device will not affect the @device but
278 * will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error.
280 * When the last call to cairo_device_destroy() decreases the
281 * reference count to zero, cairo will call cairo_device_finish() if
282 * it hasn't been called already, before freeing the resources
283 * associated with the device.
285 * This function may acquire devices.
290 cairo_device_finish (cairo_device_t *device)
292 if (device == NULL ||
293 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
298 if (device->finished)
301 cairo_device_flush (device);
303 if (device->backend->finish != NULL)
304 device->backend->finish (device);
306 /* We only finish the device after the backend's callback returns because
307 * the device might still be needed during the callback
308 * (e.g. for cairo_device_acquire ()).
310 device->finished = TRUE;
312 slim_hidden_def (cairo_device_finish);
315 * cairo_device_destroy:
316 * @device: a #cairo_device_t
318 * Decreases the reference count on @device by one. If the result is
319 * zero, then @device and all associated resources are freed. See
320 * cairo_device_reference().
322 * This function may acquire devices if the last reference was dropped.
327 cairo_device_destroy (cairo_device_t *device)
329 cairo_user_data_array_t user_data;
331 if (device == NULL ||
332 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
337 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
338 if (! _cairo_reference_count_dec_and_test (&device->ref_count))
341 cairo_device_finish (device);
343 assert (device->mutex_depth == 0);
344 CAIRO_MUTEX_FINI (device->mutex);
346 user_data = device->user_data;
348 device->backend->destroy (device);
350 _cairo_user_data_array_fini (&user_data);
353 slim_hidden_def (cairo_device_destroy);
356 * cairo_device_get_type:
357 * @device: a #cairo_device_t
359 * This function returns the type of the device. See #cairo_device_type_t
360 * for available types.
362 * Return value: The type of @device.
367 cairo_device_get_type (cairo_device_t *device)
369 if (device == NULL ||
370 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
372 return CAIRO_DEVICE_TYPE_INVALID;
375 return device->backend->type;
379 * cairo_device_acquire:
380 * @device: a #cairo_device_t
382 * Acquires the @device for the current thread. This function will block
383 * until no other thread has acquired the device.
385 * If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the
386 * device. From now on your thread owns the device and no other thread will be
387 * able to acquire it until a matching call to cairo_device_release(). It is
388 * allowed to recursively acquire the device multiple times from the same
391 * <note><para>You must never acquire two different devices at the same time
392 * unless this is explicitly allowed. Otherwise the possibility of deadlocks
395 * As various Cairo functions can acquire devices when called, these functions
396 * may also cause deadlocks when you call them with an acquired device. So you
397 * must not have a device acquired when calling them. These functions are
398 * marked in the documentation.
401 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
402 * the device is in an error state and could not be
403 * acquired. After a successful call to cairo_device_acquire(),
404 * a matching call to cairo_device_release() is required.
409 cairo_device_acquire (cairo_device_t *device)
412 return CAIRO_STATUS_SUCCESS;
414 if (unlikely (device->status))
415 return device->status;
417 if (unlikely (device->finished))
418 return _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_FINISHED);
420 CAIRO_MUTEX_LOCK (device->mutex);
421 if (device->mutex_depth++ == 0) {
422 if (device->backend->lock != NULL)
423 device->backend->lock (device);
426 return CAIRO_STATUS_SUCCESS;
428 slim_hidden_def (cairo_device_acquire);
431 * cairo_device_release:
432 * @device: a #cairo_device_t
434 * Releases a @device previously acquired using cairo_device_acquire(). See
435 * that function for details.
440 cairo_device_release (cairo_device_t *device)
445 assert (device->mutex_depth > 0);
447 if (--device->mutex_depth == 0) {
448 if (device->backend->unlock != NULL)
449 device->backend->unlock (device);
452 CAIRO_MUTEX_UNLOCK (device->mutex);
454 slim_hidden_def (cairo_device_release);
457 _cairo_device_set_error (cairo_device_t *device,
458 cairo_status_t status)
460 if (status == CAIRO_STATUS_SUCCESS)
461 return CAIRO_STATUS_SUCCESS;
463 _cairo_status_set_error (&device->status, status);
465 return _cairo_error (status);
469 * cairo_device_get_reference_count:
470 * @device: a #cairo_device_t
472 * Returns the current reference count of @device.
474 * Return value: the current reference count of @device. If the
475 * object is a nil object, 0 will be returned.
480 cairo_device_get_reference_count (cairo_device_t *device)
482 if (device == NULL ||
483 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
486 return CAIRO_REFERENCE_COUNT_GET_VALUE (&device->ref_count);
490 * cairo_device_get_user_data:
491 * @device: a #cairo_device_t
492 * @key: the address of the #cairo_user_data_key_t the user data was
495 * Return user data previously attached to @device using the
496 * specified key. If no user data has been attached with the given
497 * key this function returns %NULL.
499 * Return value: the user data previously attached or %NULL.
504 cairo_device_get_user_data (cairo_device_t *device,
505 const cairo_user_data_key_t *key)
507 return _cairo_user_data_array_get_data (&device->user_data,
512 * cairo_device_set_user_data:
513 * @device: a #cairo_device_t
514 * @key: the address of a #cairo_user_data_key_t to attach the user data to
515 * @user_data: the user data to attach to the #cairo_device_t
516 * @destroy: a #cairo_destroy_func_t which will be called when the
517 * #cairo_t is destroyed or when new user data is attached using the
520 * Attach user data to @device. To remove user data from a surface,
521 * call this function with the key that was used to set it and %NULL
524 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
525 * slot could not be allocated for the user data.
530 cairo_device_set_user_data (cairo_device_t *device,
531 const cairo_user_data_key_t *key,
533 cairo_destroy_func_t destroy)
535 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
536 return device->status;
538 return _cairo_user_data_array_set_data (&device->user_data,
539 key, user_data, destroy);