Line data Source code
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 *
113 0 : _cairo_device_create_in_error (cairo_status_t status)
114 : {
115 0 : switch (status) {
116 : case CAIRO_STATUS_NO_MEMORY:
117 0 : return (cairo_device_t *) &_nil_device;
118 : case CAIRO_STATUS_DEVICE_ERROR:
119 0 : return (cairo_device_t *) &_invalid_device;
120 : case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
121 0 : return (cairo_device_t *) &_mismatch_device;
122 :
123 : case CAIRO_STATUS_SUCCESS:
124 : case CAIRO_STATUS_LAST_STATUS:
125 0 : 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 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
161 0 : return (cairo_device_t *) &_nil_device;
162 : }
163 : }
164 :
165 : void
166 0 : _cairo_device_init (cairo_device_t *device,
167 : const cairo_device_backend_t *backend)
168 : {
169 0 : CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
170 0 : device->status = CAIRO_STATUS_SUCCESS;
171 :
172 0 : device->backend = backend;
173 :
174 0 : CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
175 0 : device->mutex_depth = 0;
176 :
177 0 : device->finished = FALSE;
178 :
179 0 : _cairo_user_data_array_init (&device->user_data);
180 0 : }
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 *
198 3 : cairo_device_reference (cairo_device_t *device)
199 : {
200 3 : if (device == NULL ||
201 0 : CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
202 : {
203 3 : return device;
204 : }
205 :
206 0 : assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
207 0 : _cairo_reference_count_inc (&device->ref_count);
208 :
209 0 : 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
226 0 : cairo_device_status (cairo_device_t *device)
227 : {
228 0 : if (device == NULL)
229 0 : return CAIRO_STATUS_NULL_POINTER;
230 :
231 0 : 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
250 0 : cairo_device_flush (cairo_device_t *device)
251 : {
252 : cairo_status_t status;
253 :
254 0 : if (device == NULL || device->status)
255 0 : return;
256 :
257 0 : if (device->backend->flush != NULL) {
258 0 : status = device->backend->flush (device);
259 0 : if (unlikely (status))
260 0 : 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
285 0 : cairo_device_finish (cairo_device_t *device)
286 : {
287 0 : if (device == NULL ||
288 0 : CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
289 : {
290 0 : return;
291 : }
292 :
293 0 : if (device->finished)
294 0 : return;
295 :
296 0 : cairo_device_flush (device);
297 :
298 0 : device->finished = TRUE;
299 :
300 0 : if (device->backend->finish != NULL)
301 0 : 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
318 0 : cairo_device_destroy (cairo_device_t *device)
319 : {
320 : cairo_user_data_array_t user_data;
321 :
322 0 : if (device == NULL ||
323 0 : CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
324 : {
325 0 : return;
326 : }
327 :
328 0 : assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
329 0 : if (! _cairo_reference_count_dec_and_test (&device->ref_count))
330 0 : return;
331 :
332 0 : cairo_device_finish (device);
333 :
334 0 : assert (device->mutex_depth == 0);
335 0 : CAIRO_MUTEX_FINI (device->mutex);
336 :
337 0 : user_data = device->user_data;
338 :
339 0 : device->backend->destroy (device);
340 :
341 0 : _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
358 0 : cairo_device_get_type (cairo_device_t *device)
359 : {
360 0 : if (device == NULL ||
361 0 : CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
362 : {
363 0 : return (cairo_device_type_t) -1;
364 : }
365 :
366 0 : 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
400 0 : cairo_device_acquire (cairo_device_t *device)
401 : {
402 0 : if (device == NULL)
403 0 : return CAIRO_STATUS_SUCCESS;
404 :
405 0 : if (unlikely (device->status))
406 0 : return device->status;
407 :
408 0 : if (unlikely (device->finished))
409 0 : return _cairo_device_set_error (device, CAIRO_STATUS_SURFACE_FINISHED); /* XXX */
410 :
411 0 : CAIRO_MUTEX_LOCK (device->mutex);
412 0 : if (device->mutex_depth++ == 0) {
413 0 : if (device->backend->lock != NULL)
414 0 : device->backend->lock (device);
415 : }
416 :
417 0 : 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
431 0 : cairo_device_release (cairo_device_t *device)
432 : {
433 0 : if (device == NULL)
434 0 : return;
435 :
436 0 : assert (device->mutex_depth > 0);
437 :
438 0 : if (--device->mutex_depth == 0) {
439 0 : if (device->backend->unlock != NULL)
440 0 : device->backend->unlock (device);
441 : }
442 :
443 0 : CAIRO_MUTEX_UNLOCK (device->mutex);
444 : }
445 : slim_hidden_def (cairo_device_release);
446 :
447 : cairo_status_t
448 0 : _cairo_device_set_error (cairo_device_t *device,
449 : cairo_status_t status)
450 : {
451 0 : if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
452 0 : return status;
453 :
454 : /* Don't overwrite an existing error. This preserves the first
455 : * error, which is the most significant. */
456 0 : _cairo_status_set_error (&device->status, status);
457 :
458 0 : 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
473 0 : cairo_device_get_reference_count (cairo_device_t *device)
474 : {
475 0 : if (device == NULL ||
476 0 : CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
477 0 : return 0;
478 :
479 0 : 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 *
497 0 : cairo_device_get_user_data (cairo_device_t *device,
498 : const cairo_user_data_key_t *key)
499 : {
500 0 : 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
523 0 : 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 0 : if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
529 0 : return device->status;
530 :
531 0 : return _cairo_user_data_array_set_data (&device->user_data,
532 : key, user_data, destroy);
533 : }
|