diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-01-18 21:53:42 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-01-22 23:01:50 +0000 |
commit | f617d5fc982f749d0981c81c1de1be8dc3632717 (patch) | |
tree | cd188075e8decf98ce40fd1fdd5b59ca6f7935a1 /src/cairo-device.c | |
parent | 82f8aa548d70acf51b319000d7a5c176fc73da64 (diff) |
Add cairo_device_t
The device is a generic method for accessing the underlying interface
with the native graphics subsystem, typically the X connection or
perhaps the GL context. By exposing a cairo_device_t on a surface and
its various methods we enable finer control over interoperability with
external interactions of the device by applications. The use case in
mind is, for example, a multi-threaded gstreamer which needs to serialise
its own direct access to the device along with Cairo's across many
threads.
Secondly, the cairo_device_t is a unifying API for the mismash of
backend specific methods for controlling creation of surfaces with
explicit devices and a convenient hook for debugging and introspection.
The principal components of the API are the memory management of:
cairo_device_reference(),
cairo_device_finish() and
cairo_device_destroy();
along with a pair of routines for serialising interaction:
cairo_device_acquire() and
cairo_device_release()
and a method to flush any outstanding accesses:
cairo_device_flush().
The device for a particular surface may be retrieved using:
cairo_surface_get_device().
The device returned is owned by the surface.
Diffstat (limited to 'src/cairo-device.c')
-rw-r--r-- | src/cairo-device.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/src/cairo-device.c b/src/cairo-device.c new file mode 100644 index 00000000..f0614eac --- /dev/null +++ b/src/cairo-device.c @@ -0,0 +1,265 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributors(s): + * Chris Wilson <chris@chris-wilson.co.uk> + */ + +#include "cairoint.h" +#include "cairo-device-private.h" +#include "cairo-error-private.h" + +static const cairo_device_t _nil_device = { + CAIRO_REFERENCE_COUNT_INVALID, + CAIRO_STATUS_NO_MEMORY, +}; + +static const cairo_device_t _mismatch_device = { + CAIRO_REFERENCE_COUNT_INVALID, + CAIRO_STATUS_DEVICE_TYPE_MISMATCH, +}; + +static const cairo_device_t _invalid_device = { + CAIRO_REFERENCE_COUNT_INVALID, + CAIRO_STATUS_DEVICE_ERROR, +}; + +cairo_device_t * +_cairo_device_create_in_error (cairo_status_t status) +{ + switch (status) { + case CAIRO_STATUS_NO_MEMORY: + return (cairo_device_t *) &_nil_device; + case CAIRO_STATUS_DEVICE_ERROR: + return (cairo_device_t *) &_invalid_device; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: + return (cairo_device_t *) &_mismatch_device; + + case CAIRO_STATUS_SUCCESS: + case CAIRO_STATUS_LAST_STATUS: + ASSERT_NOT_REACHED; + /* fall-through */ + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_STATUS: + case CAIRO_STATUS_INVALID_FORMAT: + case CAIRO_STATUS_INVALID_VISUAL: + case CAIRO_STATUS_READ_ERROR: + case CAIRO_STATUS_WRITE_ERROR: + case CAIRO_STATUS_FILE_NOT_FOUND: + case CAIRO_STATUS_TEMP_FILE_ERROR: + case CAIRO_STATUS_INVALID_STRIDE: + case CAIRO_STATUS_INVALID_SIZE: + case CAIRO_STATUS_INVALID_RESTORE: + case CAIRO_STATUS_INVALID_POP_GROUP: + case CAIRO_STATUS_NO_CURRENT_POINT: + case CAIRO_STATUS_INVALID_MATRIX: + case CAIRO_STATUS_NULL_POINTER: + case CAIRO_STATUS_INVALID_STRING: + case CAIRO_STATUS_INVALID_PATH_DATA: + case CAIRO_STATUS_SURFACE_FINISHED: + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_DASH: + case CAIRO_STATUS_INVALID_DSC_COMMENT: + case CAIRO_STATUS_INVALID_INDEX: + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: + case CAIRO_STATUS_FONT_TYPE_MISMATCH: + case CAIRO_STATUS_USER_FONT_IMMUTABLE: + case CAIRO_STATUS_USER_FONT_ERROR: + case CAIRO_STATUS_NEGATIVE_COUNT: + case CAIRO_STATUS_INVALID_CLUSTERS: + case CAIRO_STATUS_INVALID_SLANT: + case CAIRO_STATUS_INVALID_WEIGHT: + case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: + case CAIRO_STATUS_INVALID_CONTENT: + default: + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_device_t *) &_nil_device; + } +} + +void +_cairo_device_init (cairo_device_t *device, + const cairo_device_backend_t *backend) +{ + CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1); + device->status = CAIRO_STATUS_SUCCESS; + + device->backend = backend; + + CAIRO_RECURSIVE_MUTEX_INIT (device->mutex); + device->mutex_depth = 0; + + device->finished = FALSE; +} + +cairo_device_t * +cairo_device_reference (cairo_device_t *device) +{ + if (device == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + { + return device; + } + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count)); + _cairo_reference_count_inc (&device->ref_count); + + return device; +} +slim_hidden_def (cairo_device_reference); + +cairo_status_t +cairo_device_status (cairo_device_t *device) +{ + if (device == NULL) + return CAIRO_STATUS_NULL_POINTER; + + return device->status; +} + +void +cairo_device_flush (cairo_device_t *device) +{ + if (device == NULL || device->status) + return; + + if (device->backend->flush != NULL) + device->backend->flush (device); +} +slim_hidden_def (cairo_device_flush); + +void +cairo_device_finish (cairo_device_t *device) +{ + if (device == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + { + return; + } + + if (device->finished) + return; + + device->finished = TRUE; + + cairo_device_flush (device); + + if (device->backend->finish != NULL) + device->backend->finish (device); +} +slim_hidden_def (cairo_device_finish); + +void +cairo_device_destroy (cairo_device_t *device) +{ + if (device == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + { + return; + } + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count)); + if (! _cairo_reference_count_dec_and_test (&device->ref_count)) + return; + + cairo_device_finish (device); + + assert (device->mutex_depth == 0); + CAIRO_MUTEX_FINI (device->mutex); + + device->backend->destroy (device); +} +slim_hidden_def (cairo_device_destroy); + +cairo_device_type_t +cairo_device_get_type (cairo_device_t *device) +{ + if (device == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count)) + { + return (cairo_device_type_t) -1; + } + + return device->backend->type; +} + +cairo_status_t +cairo_device_acquire (cairo_device_t *device) +{ + if (device == NULL) + return CAIRO_STATUS_SUCCESS; + + if (unlikely (device->status)) + return device->status; + + if (unlikely (device->finished)) + return _cairo_device_set_error (device, CAIRO_STATUS_SURFACE_FINISHED); /* XXX */ + + CAIRO_MUTEX_LOCK (device->mutex); + if (device->mutex_depth++ == 0) { + if (device->backend->lock != NULL) + device->backend->lock (device); + } + + return CAIRO_STATUS_SUCCESS; +} +slim_hidden_def (cairo_device_acquire); + +void +cairo_device_release (cairo_device_t *device) +{ + if (device == NULL) + return; + + assert (device->mutex_depth > 0); + + if (--device->mutex_depth == 0) { + if (device->backend->unlock != NULL) + device->backend->unlock (device); + } + + CAIRO_MUTEX_UNLOCK (device->mutex); +} +slim_hidden_def (cairo_device_release); + +cairo_status_t +_cairo_device_set_error (cairo_device_t *device, + cairo_status_t status) +{ + if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + /* Don't overwrite an existing error. This preserves the first + * error, which is the most significant. */ + _cairo_status_set_error (&device->status, status); + + return _cairo_error (status); +} |