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
:
161 case CAIRO_STATUS_JBIG2_GLOBAL_MISSING
:
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
);
186 * cairo_device_reference:
187 * @device: a #cairo_device_t
189 * Increases the reference count on @device by one. This prevents
190 * @device from being destroyed until a matching call to
191 * cairo_device_destroy() is made.
193 * The number of references to a #cairo_device_t can be get using
194 * cairo_device_get_reference_count().
196 * Return value: the referenced #cairo_device_t.
201 cairo_device_reference (cairo_device_t
*device
)
203 if (device
== NULL
||
204 CAIRO_REFERENCE_COUNT_IS_INVALID (&device
->ref_count
))
209 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device
->ref_count
));
210 _cairo_reference_count_inc (&device
->ref_count
);
214 slim_hidden_def (cairo_device_reference
);
217 * cairo_device_status:
218 * @device: a #cairo_device_t
220 * Checks whether an error has previously occurred for this
223 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
224 * the device is in an error state.
229 cairo_device_status (cairo_device_t
*device
)
232 return CAIRO_STATUS_NULL_POINTER
;
234 return device
->status
;
238 * cairo_device_flush:
239 * @device: a #cairo_device_t
241 * Finish any pending operations for the device and also restore any
242 * temporary modifications cairo has made to the device's state.
243 * This function must be called before switching from using the
244 * device with Cairo to operating on it directly with native APIs.
245 * If the device doesn't support direct access, then this function
248 * This function may acquire devices.
253 cairo_device_flush (cairo_device_t
*device
)
255 cairo_status_t status
;
257 if (device
== NULL
|| device
->status
)
260 if (device
->finished
)
263 if (device
->backend
->flush
!= NULL
) {
264 status
= device
->backend
->flush (device
);
265 if (unlikely (status
))
266 status
= _cairo_device_set_error (device
, status
);
269 slim_hidden_def (cairo_device_flush
);
272 * cairo_device_finish:
273 * @device: the #cairo_device_t to finish
275 * This function finishes the device and drops all references to
276 * external resources. All surfaces, fonts and other objects created
277 * for this @device will be finished, too.
278 * Further operations on the @device will not affect the @device but
279 * will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error.
281 * When the last call to cairo_device_destroy() decreases the
282 * reference count to zero, cairo will call cairo_device_finish() if
283 * it hasn't been called already, before freeing the resources
284 * associated with the device.
286 * This function may acquire devices.
291 cairo_device_finish (cairo_device_t
*device
)
293 if (device
== NULL
||
294 CAIRO_REFERENCE_COUNT_IS_INVALID (&device
->ref_count
))
299 if (device
->finished
)
302 cairo_device_flush (device
);
304 if (device
->backend
->finish
!= NULL
)
305 device
->backend
->finish (device
);
307 /* We only finish the device after the backend's callback returns because
308 * the device might still be needed during the callback
309 * (e.g. for cairo_device_acquire ()).
311 device
->finished
= TRUE
;
313 slim_hidden_def (cairo_device_finish
);
316 * cairo_device_destroy:
317 * @device: a #cairo_device_t
319 * Decreases the reference count on @device by one. If the result is
320 * zero, then @device and all associated resources are freed. See
321 * cairo_device_reference().
323 * This function may acquire devices if the last reference was dropped.
328 cairo_device_destroy (cairo_device_t
*device
)
330 cairo_user_data_array_t user_data
;
332 if (device
== NULL
||
333 CAIRO_REFERENCE_COUNT_IS_INVALID (&device
->ref_count
))
338 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device
->ref_count
));
339 if (! _cairo_reference_count_dec_and_test (&device
->ref_count
))
342 cairo_device_finish (device
);
344 assert (device
->mutex_depth
== 0);
345 CAIRO_MUTEX_FINI (device
->mutex
);
347 user_data
= device
->user_data
;
349 device
->backend
->destroy (device
);
351 _cairo_user_data_array_fini (&user_data
);
354 slim_hidden_def (cairo_device_destroy
);
357 * cairo_device_get_type:
358 * @device: a #cairo_device_t
360 * This function returns the type of the device. See #cairo_device_type_t
361 * for available types.
363 * Return value: The type of @device.
368 cairo_device_get_type (cairo_device_t
*device
)
370 if (device
== NULL
||
371 CAIRO_REFERENCE_COUNT_IS_INVALID (&device
->ref_count
))
373 return CAIRO_DEVICE_TYPE_INVALID
;
376 return device
->backend
->type
;
380 * cairo_device_acquire:
381 * @device: a #cairo_device_t
383 * Acquires the @device for the current thread. This function will block
384 * until no other thread has acquired the device.
386 * If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the
387 * device. From now on your thread owns the device and no other thread will be
388 * able to acquire it until a matching call to cairo_device_release(). It is
389 * allowed to recursively acquire the device multiple times from the same
392 * <note><para>You must never acquire two different devices at the same time
393 * unless this is explicitly allowed. Otherwise the possibility of deadlocks
396 * As various Cairo functions can acquire devices when called, these functions
397 * may also cause deadlocks when you call them with an acquired device. So you
398 * must not have a device acquired when calling them. These functions are
399 * marked in the documentation.
402 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
403 * the device is in an error state and could not be
404 * acquired. After a successful call to cairo_device_acquire(),
405 * a matching call to cairo_device_release() is required.
410 cairo_device_acquire (cairo_device_t
*device
)
413 return CAIRO_STATUS_SUCCESS
;
415 if (unlikely (device
->status
))
416 return device
->status
;
418 if (unlikely (device
->finished
))
419 return _cairo_device_set_error (device
, CAIRO_STATUS_DEVICE_FINISHED
);
421 CAIRO_MUTEX_LOCK (device
->mutex
);
422 if (device
->mutex_depth
++ == 0) {
423 if (device
->backend
->lock
!= NULL
)
424 device
->backend
->lock (device
);
427 return CAIRO_STATUS_SUCCESS
;
429 slim_hidden_def (cairo_device_acquire
);
432 * cairo_device_release:
433 * @device: a #cairo_device_t
435 * Releases a @device previously acquired using cairo_device_acquire(). See
436 * that function for details.
441 cairo_device_release (cairo_device_t
*device
)
446 assert (device
->mutex_depth
> 0);
448 if (--device
->mutex_depth
== 0) {
449 if (device
->backend
->unlock
!= NULL
)
450 device
->backend
->unlock (device
);
453 CAIRO_MUTEX_UNLOCK (device
->mutex
);
455 slim_hidden_def (cairo_device_release
);
458 _cairo_device_set_error (cairo_device_t
*device
,
459 cairo_status_t status
)
461 if (status
== CAIRO_STATUS_SUCCESS
)
462 return CAIRO_STATUS_SUCCESS
;
464 _cairo_status_set_error (&device
->status
, status
);
466 return _cairo_error (status
);
470 * cairo_device_get_reference_count:
471 * @device: a #cairo_device_t
473 * Returns the current reference count of @device.
475 * Return value: the current reference count of @device. If the
476 * object is a nil object, 0 will be returned.
481 cairo_device_get_reference_count (cairo_device_t
*device
)
483 if (device
== NULL
||
484 CAIRO_REFERENCE_COUNT_IS_INVALID (&device
->ref_count
))
487 return CAIRO_REFERENCE_COUNT_GET_VALUE (&device
->ref_count
);
491 * cairo_device_get_user_data:
492 * @device: a #cairo_device_t
493 * @key: the address of the #cairo_user_data_key_t the user data was
496 * Return user data previously attached to @device using the
497 * specified key. If no user data has been attached with the given
498 * key this function returns %NULL.
500 * Return value: the user data previously attached or %NULL.
505 cairo_device_get_user_data (cairo_device_t
*device
,
506 const cairo_user_data_key_t
*key
)
508 return _cairo_user_data_array_get_data (&device
->user_data
,
513 * cairo_device_set_user_data:
514 * @device: a #cairo_device_t
515 * @key: the address of a #cairo_user_data_key_t to attach the user data to
516 * @user_data: the user data to attach to the #cairo_device_t
517 * @destroy: a #cairo_destroy_func_t which will be called when the
518 * #cairo_t is destroyed or when new user data is attached using the
521 * Attach user data to @device. To remove user data from a surface,
522 * call this function with the key that was used to set it and %NULL
525 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
526 * slot could not be allocated for the user data.
531 cairo_device_set_user_data (cairo_device_t
*device
,
532 const cairo_user_data_key_t
*key
,
534 cairo_destroy_func_t destroy
)
536 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device
->ref_count
))
537 return device
->status
;
539 return _cairo_user_data_array_set_data (&device
->user_data
,
540 key
, user_data
, destroy
);