summaryrefslogtreecommitdiff
path: root/src/cairo-device.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2010-01-18 21:53:42 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2010-01-22 23:01:50 +0000
commitf617d5fc982f749d0981c81c1de1be8dc3632717 (patch)
treecd188075e8decf98ce40fd1fdd5b59ca6f7935a1 /src/cairo-device.c
parent82f8aa548d70acf51b319000d7a5c176fc73da64 (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.c265
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);
+}