1 /* Cairo - a vector graphics library with display and print output
2 *
3 * Copyright © 2009 Intel Corporation
4 *
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.
12 *
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
18 *
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/
23 *
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.
27 *
28 * The Original Code is the cairo graphics library.
29 *
30 * The Initial Developer of the Original Code is Intel Corporation.
31 *
32 * Contributors(s):
33 * Chris Wilson <chris@chris-wilson.co.uk>
34 */
35
36 #include "cairoint.h"
37 #include "cairo-device-private.h"
38 #include "cairo-error-private.h"
39
40 /**
41 * SECTION:cairo-device
42 * @Title: cairo_device_t
43 * @Short_Description: interface to underlying rendering system
44 * @See_Also: #cairo_surface_t
45 *
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().
49 *
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.
53 *
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.
59 *
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.
64 *
65 * Putting this all together, a function that works with devices should
66 * look something like this:
67 * <informalexample><programlisting>
68 * void
69 * my_device_modifying_function (cairo_device_t *device)
70 * {
71 * cairo_status_t status;
72 *
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));
79 * return;
80 * }
81 *
82 * // Do the custom operations on the device here.
83 * // But do not call any Cairo functions that might acquire devices.
84 *
85 * // Release the device when done.
86 * cairo_device_release (device);
87 * }
88 * </programlisting></informalexample>
89 *
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.
94 * </para></note>
95 */
96
97 static const cairo_device_t _nil_device = {
98 CAIRO_REFERENCE_COUNT_INVALID,
99 CAIRO_STATUS_NO_MEMORY,
100 };
101
102 static const cairo_device_t _mismatch_device = {
103 CAIRO_REFERENCE_COUNT_INVALID,
104 CAIRO_STATUS_DEVICE_TYPE_MISMATCH,
105 };
106
107 static const cairo_device_t _invalid_device = {
108 CAIRO_REFERENCE_COUNT_INVALID,
109 CAIRO_STATUS_DEVICE_ERROR,
110 };
111
112 cairo_device_t *
_cairo_device_create_in_error(cairo_status_t status)113 _cairo_device_create_in_error (cairo_status_t status)
114 {
115 switch (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;
122
123 case CAIRO_STATUS_SUCCESS:
124 case CAIRO_STATUS_LAST_STATUS:
125 ASSERT_NOT_REACHED;
126 /* fall-through */
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 default:
160 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
161 return (cairo_device_t *) &_nil_device;
162 }
163 }
164
165 void
_cairo_device_init(cairo_device_t * device,const cairo_device_backend_t * backend)166 _cairo_device_init (cairo_device_t *device,
167 const cairo_device_backend_t *backend)
168 {
169 CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
170 device->status = CAIRO_STATUS_SUCCESS;
171
172 device->backend = backend;
173
174 CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
175 device->mutex_depth = 0;
176
177 device->finished = FALSE;
178
179 _cairo_user_data_array_init (&device->user_data);
180 }
181
182 /**
183 * cairo_device_reference:
184 * @device: a #cairo_device_t
185 *
186 * Increases the reference count on @device by one. This prevents
187 * @device from being destroyed until a matching call to
188 * cairo_device_destroy() is made.
189 *
190 * The number of references to a #cairo_device_t can be get using
191 * cairo_device_get_reference_count().
192 *
193 * Return value: the referenced #cairo_device_t.
194 *
195 * Since: 1.10
196 **/
197 cairo_device_t *
cairo_device_reference(cairo_device_t * device)198 cairo_device_reference (cairo_device_t *device)
199 {
200 if (device == NULL ||
201 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
202 {
203 return device;
204 }
205
206 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
207 _cairo_reference_count_inc (&device->ref_count);
208
209 return device;
210 }
211 slim_hidden_def (cairo_device_reference);
212
213 /**
214 * cairo_device_status:
215 * @device: a #cairo_device_t
216 *
217 * Checks whether an error has previously occurred for this
218 * device.
219 *
220 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
221 * the device is in an error state.
222 *
223 * Since: 1.10
224 **/
225 cairo_status_t
cairo_device_status(cairo_device_t * device)226 cairo_device_status (cairo_device_t *device)
227 {
228 if (device == NULL)
229 return CAIRO_STATUS_NULL_POINTER;
230
231 return device->status;
232 }
233
234 /**
235 * cairo_device_flush:
236 * @device: a #cairo_device_t
237 *
238 * Finish any pending operations for the device and also restore any
239 * temporary modifications cairo has made to the device's state.
240 * This function must be called before switching from using the
241 * device with Cairo to operating on it directly with native APIs.
242 * If the device doesn't support direct access, then this function
243 * does nothing.
244 *
245 * This function may acquire devices.
246 *
247 * Since: 1.10
248 **/
249 void
cairo_device_flush(cairo_device_t * device)250 cairo_device_flush (cairo_device_t *device)
251 {
252 cairo_status_t status;
253
254 if (device == NULL || device->status)
255 return;
256
257 if (device->backend->flush != NULL) {
258 status = device->backend->flush (device);
259 if (unlikely (status))
260 status = _cairo_device_set_error (device, status);
261 }
262 }
263 slim_hidden_def (cairo_device_flush);
264
265 /**
266 * cairo_device_finish:
267 * @device: the #cairo_device_t to finish
268 *
269 * This function finishes the device and drops all references to
270 * external resources. All surfaces, fonts and other objects created
271 * for this @device will be finished, too.
272 * Further operations on the @device will not affect the @device but
273 * will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error.
274 *
275 * When the last call to cairo_device_destroy() decreases the
276 * reference count to zero, cairo will call cairo_device_finish() if
277 * it hasn't been called already, before freeing the resources
278 * associated with the device.
279 *
280 * This function may acquire devices.
281 *
282 * Since: 1.10
283 **/
284 void
cairo_device_finish(cairo_device_t * device)285 cairo_device_finish (cairo_device_t *device)
286 {
287 if (device == NULL ||
288 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
289 {
290 return;
291 }
292
293 if (device->finished)
294 return;
295
296 cairo_device_flush (device);
297
298 device->finished = TRUE;
299
300 if (device->backend->finish != NULL)
301 device->backend->finish (device);
302 }
303 slim_hidden_def (cairo_device_finish);
304
305 /**
306 * cairo_device_destroy:
307 * @device: a #cairo_device_t
308 *
309 * Decreases the reference count on @device by one. If the result is
310 * zero, then @device and all associated resources are freed. See
311 * cairo_device_reference().
312 *
313 * This function may acquire devices if the last reference was dropped.
314 *
315 * Since: 1.10
316 **/
317 void
cairo_device_destroy(cairo_device_t * device)318 cairo_device_destroy (cairo_device_t *device)
319 {
320 cairo_user_data_array_t user_data;
321
322 if (device == NULL ||
323 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
324 {
325 return;
326 }
327
328 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
329 if (! _cairo_reference_count_dec_and_test (&device->ref_count))
330 return;
331
332 cairo_device_finish (device);
333
334 assert (device->mutex_depth == 0);
335 CAIRO_MUTEX_FINI (device->mutex);
336
337 user_data = device->user_data;
338
339 device->backend->destroy (device);
340
341 _cairo_user_data_array_fini (&user_data);
342
343 }
344 slim_hidden_def (cairo_device_destroy);
345
346 /**
347 * cairo_device_get_type:
348 * @device: a #cairo_device_t
349 *
350 * This function returns the type of the device. See #cairo_device_type_t
351 * for available types.
352 *
353 * Return value: The type of @device.
354 *
355 * Since: 1.10
356 **/
357 cairo_device_type_t
cairo_device_get_type(cairo_device_t * device)358 cairo_device_get_type (cairo_device_t *device)
359 {
360 if (device == NULL ||
361 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
362 {
363 return (cairo_device_type_t) -1;
364 }
365
366 return device->backend->type;
367 }
368
369 /**
370 * cairo_device_acquire:
371 * @device: a #cairo_device_t
372 *
373 * Acquires the @device for the current thread. This function will block
374 * until no other thread has acquired the device.
375 *
376 * If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the
377 * device. From now on your thread owns the device and no other thread will be
378 * able to acquire it until a matching call to cairo_device_release(). It is
379 * allowed to recursively acquire the device multiple times from the same
380 * thread.
381 *
382 * <note><para>You must never acquire two different devices at the same time
383 * unless this is explicitly allowed. Otherwise the possibility of deadlocks
384 * exist.
385 *
386 * As various Cairo functions can acquire devices when called, these functions
387 * may also cause deadlocks when you call them with an acquired device. So you
388 * must not have a device acquired when calling them. These functions are
389 * marked in the documentation.
390 * </para></note>
391 *
392 * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
393 * the device is in an error state and could not be
394 * acquired. After a successful call to cairo_device_acquire(),
395 * a matching call to cairo_device_release() is required.
396 *
397 * Since: 1.10
398 **/
399 cairo_status_t
cairo_device_acquire(cairo_device_t * device)400 cairo_device_acquire (cairo_device_t *device)
401 {
402 if (device == NULL)
403 return CAIRO_STATUS_SUCCESS;
404
405 if (unlikely (device->status))
406 return device->status;
407
408 if (unlikely (device->finished))
409 return _cairo_device_set_error (device, CAIRO_STATUS_SURFACE_FINISHED); /* XXX */
410
411 CAIRO_MUTEX_LOCK (device->mutex);
412 if (device->mutex_depth++ == 0) {
413 if (device->backend->lock != NULL)
414 device->backend->lock (device);
415 }
416
417 return CAIRO_STATUS_SUCCESS;
418 }
419 slim_hidden_def (cairo_device_acquire);
420
421 /**
422 * cairo_device_release:
423 * @device: a #cairo_device_t
424 *
425 * Releases a @device previously acquired using cairo_device_acquire(). See
426 * that function for details.
427 *
428 * Since: 1.10
429 **/
430 void
cairo_device_release(cairo_device_t * device)431 cairo_device_release (cairo_device_t *device)
432 {
433 if (device == NULL)
434 return;
435
436 assert (device->mutex_depth > 0);
437
438 if (--device->mutex_depth == 0) {
439 if (device->backend->unlock != NULL)
440 device->backend->unlock (device);
441 }
442
443 CAIRO_MUTEX_UNLOCK (device->mutex);
444 }
445 slim_hidden_def (cairo_device_release);
446
447 cairo_status_t
_cairo_device_set_error(cairo_device_t * device,cairo_status_t status)448 _cairo_device_set_error (cairo_device_t *device,
449 cairo_status_t status)
450 {
451 if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
452 return status;
453
454 /* Don't overwrite an existing error. This preserves the first
455 * error, which is the most significant. */
456 _cairo_status_set_error (&device->status, status);
457
458 return _cairo_error (status);
459 }
460
461 /**
462 * cairo_device_get_reference_count:
463 * @device: a #cairo_device_t
464 *
465 * Returns the current reference count of @device.
466 *
467 * Return value: the current reference count of @device. If the
468 * object is a nil object, 0 will be returned.
469 *
470 * Since: 1.10
471 **/
472 unsigned int
cairo_device_get_reference_count(cairo_device_t * device)473 cairo_device_get_reference_count (cairo_device_t *device)
474 {
475 if (device == NULL ||
476 CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
477 return 0;
478
479 return CAIRO_REFERENCE_COUNT_GET_VALUE (&device->ref_count);
480 }
481
482 /**
483 * cairo_device_get_user_data:
484 * @device: a #cairo_device_t
485 * @key: the address of the #cairo_user_data_key_t the user data was
486 * attached to
487 *
488 * Return user data previously attached to @device using the
489 * specified key. If no user data has been attached with the given
490 * key this function returns %NULL.
491 *
492 * Return value: the user data previously attached or %NULL.
493 *
494 * Since: 1.10
495 **/
496 void *
cairo_device_get_user_data(cairo_device_t * device,const cairo_user_data_key_t * key)497 cairo_device_get_user_data (cairo_device_t *device,
498 const cairo_user_data_key_t *key)
499 {
500 return _cairo_user_data_array_get_data (&device->user_data,
501 key);
502 }
503
504 /**
505 * cairo_device_set_user_data:
506 * @device: a #cairo_device_t
507 * @key: the address of a #cairo_user_data_key_t to attach the user data to
508 * @user_data: the user data to attach to the #cairo_device_t
509 * @destroy: a #cairo_destroy_func_t which will be called when the
510 * #cairo_t is destroyed or when new user data is attached using the
511 * same key.
512 *
513 * Attach user data to @device. To remove user data from a surface,
514 * call this function with the key that was used to set it and %NULL
515 * for @data.
516 *
517 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
518 * slot could not be allocated for the user data.
519 *
520 * Since: 1.10
521 **/
522 cairo_status_t
cairo_device_set_user_data(cairo_device_t * device,const cairo_user_data_key_t * key,void * user_data,cairo_destroy_func_t destroy)523 cairo_device_set_user_data (cairo_device_t *device,
524 const cairo_user_data_key_t *key,
525 void *user_data,
526 cairo_destroy_func_t destroy)
527 {
528 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
529 return device->status;
530
531 return _cairo_user_data_array_set_data (&device->user_data,
532 key, user_data, destroy);
533 }
534