LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-device.c (source / functions) Hit Total Coverage
Test: output.info Lines: 3 99 3.0 %
Date: 2017-07-14 16:53:18 Functions: 1 14 7.1 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13