LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-device.c (source / functions) Found Hit Coverage
Test: app.info Lines: 95 3 3.2 %
Date: 2012-06-02 Functions: 20 1 5.0 %

       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                 :     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              65 : cairo_device_reference (cairo_device_t *device)
     199                 : {
     200              65 :     if (device == NULL ||
     201               0 :         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
     202                 :     {
     203              65 :         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                 :     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                 :     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                 :     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.7