Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. _cairo_device_create_in_error (cairo_status_t status)
  114. {
  115.     switch (status) {
  116.     case CAIRO_STATUS_NO_MEMORY:
  117.         return (cairo_device_t *) &_nil_device;
  118.     case CAIRO_STATUS_DEVICE_ERROR:
  119.         return (cairo_device_t *) &_invalid_device;
  120.     case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
  121.         return (cairo_device_t *) &_mismatch_device;
  122.  
  123.     case CAIRO_STATUS_SUCCESS:
  124.     case CAIRO_STATUS_LAST_STATUS:
  125.         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.     case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
  160.     case CAIRO_STATUS_DEVICE_FINISHED:
  161.     default:
  162.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  163.         return (cairo_device_t *) &_nil_device;
  164.     }
  165. }
  166.  
  167. void
  168. _cairo_device_init (cairo_device_t *device,
  169.                     const cairo_device_backend_t *backend)
  170. {
  171.     CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
  172.     device->status = CAIRO_STATUS_SUCCESS;
  173.  
  174.     device->backend = backend;
  175.  
  176.     CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
  177.     device->mutex_depth = 0;
  178.  
  179.     device->finished = FALSE;
  180.  
  181.     _cairo_user_data_array_init (&device->user_data);
  182. }
  183.  
  184. /**
  185.  * cairo_device_reference:
  186.  * @device: a #cairo_device_t
  187.  *
  188.  * Increases the reference count on @device by one. This prevents
  189.  * @device from being destroyed until a matching call to
  190.  * cairo_device_destroy() is made.
  191.  *
  192.  * The number of references to a #cairo_device_t can be get using
  193.  * cairo_device_get_reference_count().
  194.  *
  195.  * Return value: the referenced #cairo_device_t.
  196.  *
  197.  * Since: 1.10
  198.  **/
  199. cairo_device_t *
  200. cairo_device_reference (cairo_device_t *device)
  201. {
  202.     if (device == NULL ||
  203.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  204.     {
  205.         return device;
  206.     }
  207.  
  208.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
  209.     _cairo_reference_count_inc (&device->ref_count);
  210.  
  211.     return device;
  212. }
  213. slim_hidden_def (cairo_device_reference);
  214.  
  215. /**
  216.  * cairo_device_status:
  217.  * @device: a #cairo_device_t
  218.  *
  219.  * Checks whether an error has previously occurred for this
  220.  * device.
  221.  *
  222.  * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
  223.  *               the device is in an error state.
  224.  *
  225.  * Since: 1.10
  226.  **/
  227. cairo_status_t
  228. cairo_device_status (cairo_device_t *device)
  229. {
  230.     if (device == NULL)
  231.         return CAIRO_STATUS_NULL_POINTER;
  232.  
  233.     return device->status;
  234. }
  235.  
  236. /**
  237.  * cairo_device_flush:
  238.  * @device: a #cairo_device_t
  239.  *
  240.  * Finish any pending operations for the device and also restore any
  241.  * temporary modifications cairo has made to the device's state.
  242.  * This function must be called before switching from using the
  243.  * device with Cairo to operating on it directly with native APIs.
  244.  * If the device doesn't support direct access, then this function
  245.  * does nothing.
  246.  *
  247.  * This function may acquire devices.
  248.  *
  249.  * Since: 1.10
  250.  **/
  251. void
  252. cairo_device_flush (cairo_device_t *device)
  253. {
  254.     cairo_status_t status;
  255.  
  256.     if (device == NULL || device->status)
  257.         return;
  258.  
  259.     if (device->finished)
  260.         return;
  261.  
  262.     if (device->backend->flush != NULL) {
  263.         status = device->backend->flush (device);
  264.         if (unlikely (status))
  265.             status = _cairo_device_set_error (device, status);
  266.     }
  267. }
  268. slim_hidden_def (cairo_device_flush);
  269.  
  270. /**
  271.  * cairo_device_finish:
  272.  * @device: the #cairo_device_t to finish
  273.  *
  274.  * This function finishes the device and drops all references to
  275.  * external resources. All surfaces, fonts and other objects created
  276.  * for this @device will be finished, too.
  277.  * Further operations on the @device will not affect the @device but
  278.  * will instead trigger a %CAIRO_STATUS_DEVICE_FINISHED error.
  279.  *
  280.  * When the last call to cairo_device_destroy() decreases the
  281.  * reference count to zero, cairo will call cairo_device_finish() if
  282.  * it hasn't been called already, before freeing the resources
  283.  * associated with the device.
  284.  *
  285.  * This function may acquire devices.
  286.  *
  287.  * Since: 1.10
  288.  **/
  289. void
  290. cairo_device_finish (cairo_device_t *device)
  291. {
  292.     if (device == NULL ||
  293.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  294.     {
  295.         return;
  296.     }
  297.  
  298.     if (device->finished)
  299.         return;
  300.  
  301.     cairo_device_flush (device);
  302.  
  303.     if (device->backend->finish != NULL)
  304.         device->backend->finish (device);
  305.  
  306.     /* We only finish the device after the backend's callback returns because
  307.      * the device might still be needed during the callback
  308.      * (e.g. for cairo_device_acquire ()).
  309.      */
  310.     device->finished = TRUE;
  311. }
  312. slim_hidden_def (cairo_device_finish);
  313.  
  314. /**
  315.  * cairo_device_destroy:
  316.  * @device: a #cairo_device_t
  317.  *
  318.  * Decreases the reference count on @device by one. If the result is
  319.  * zero, then @device and all associated resources are freed.  See
  320.  * cairo_device_reference().
  321.  *
  322.  * This function may acquire devices if the last reference was dropped.
  323.  *
  324.  * Since: 1.10
  325.  **/
  326. void
  327. cairo_device_destroy (cairo_device_t *device)
  328. {
  329.     cairo_user_data_array_t user_data;
  330.  
  331.     if (device == NULL ||
  332.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  333.     {
  334.         return;
  335.     }
  336.  
  337.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
  338.     if (! _cairo_reference_count_dec_and_test (&device->ref_count))
  339.         return;
  340.  
  341.     cairo_device_finish (device);
  342.  
  343.     assert (device->mutex_depth == 0);
  344.     CAIRO_MUTEX_FINI (device->mutex);
  345.  
  346.     user_data = device->user_data;
  347.  
  348.     device->backend->destroy (device);
  349.  
  350.     _cairo_user_data_array_fini (&user_data);
  351.  
  352. }
  353. slim_hidden_def (cairo_device_destroy);
  354.  
  355. /**
  356.  * cairo_device_get_type:
  357.  * @device: a #cairo_device_t
  358.  *
  359.  * This function returns the type of the device. See #cairo_device_type_t
  360.  * for available types.
  361.  *
  362.  * Return value: The type of @device.
  363.  *
  364.  * Since: 1.10
  365.  **/
  366. cairo_device_type_t
  367. cairo_device_get_type (cairo_device_t *device)
  368. {
  369.     if (device == NULL ||
  370.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  371.     {
  372.         return CAIRO_DEVICE_TYPE_INVALID;
  373.     }
  374.  
  375.     return device->backend->type;
  376. }
  377.  
  378. /**
  379.  * cairo_device_acquire:
  380.  * @device: a #cairo_device_t
  381.  *
  382.  * Acquires the @device for the current thread. This function will block
  383.  * until no other thread has acquired the device.
  384.  *
  385.  * If the return value is %CAIRO_STATUS_SUCCESS, you successfully acquired the
  386.  * device. From now on your thread owns the device and no other thread will be
  387.  * able to acquire it until a matching call to cairo_device_release(). It is
  388.  * allowed to recursively acquire the device multiple times from the same
  389.  * thread.
  390.  *
  391.  * <note><para>You must never acquire two different devices at the same time
  392.  * unless this is explicitly allowed. Otherwise the possibility of deadlocks
  393.  * exist.
  394.  *
  395.  * As various Cairo functions can acquire devices when called, these functions
  396.  * may also cause deadlocks when you call them with an acquired device. So you
  397.  * must not have a device acquired when calling them. These functions are
  398.  * marked in the documentation.
  399.  * </para></note>
  400.  *
  401.  * Return value: %CAIRO_STATUS_SUCCESS on success or an error code if
  402.  *               the device is in an error state and could not be
  403.  *               acquired. After a successful call to cairo_device_acquire(),
  404.  *               a matching call to cairo_device_release() is required.
  405.  *
  406.  * Since: 1.10
  407.  **/
  408. cairo_status_t
  409. cairo_device_acquire (cairo_device_t *device)
  410. {
  411.     if (device == NULL)
  412.         return CAIRO_STATUS_SUCCESS;
  413.  
  414.     if (unlikely (device->status))
  415.         return device->status;
  416.  
  417.     if (unlikely (device->finished))
  418.         return _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_FINISHED);
  419.  
  420.     CAIRO_MUTEX_LOCK (device->mutex);
  421.     if (device->mutex_depth++ == 0) {
  422.         if (device->backend->lock != NULL)
  423.             device->backend->lock (device);
  424.     }
  425.  
  426.     return CAIRO_STATUS_SUCCESS;
  427. }
  428. slim_hidden_def (cairo_device_acquire);
  429.  
  430. /**
  431.  * cairo_device_release:
  432.  * @device: a #cairo_device_t
  433.  *
  434.  * Releases a @device previously acquired using cairo_device_acquire(). See
  435.  * that function for details.
  436.  *
  437.  * Since: 1.10
  438.  **/
  439. void
  440. cairo_device_release (cairo_device_t *device)
  441. {
  442.     if (device == NULL)
  443.         return;
  444.  
  445.     assert (device->mutex_depth > 0);
  446.  
  447.     if (--device->mutex_depth == 0) {
  448.         if (device->backend->unlock != NULL)
  449.             device->backend->unlock (device);
  450.     }
  451.  
  452.     CAIRO_MUTEX_UNLOCK (device->mutex);
  453. }
  454. slim_hidden_def (cairo_device_release);
  455.  
  456. cairo_status_t
  457. _cairo_device_set_error (cairo_device_t *device,
  458.                          cairo_status_t  status)
  459. {
  460.     if (status == CAIRO_STATUS_SUCCESS)
  461.         return CAIRO_STATUS_SUCCESS;
  462.  
  463.     _cairo_status_set_error (&device->status, status);
  464.  
  465.     return _cairo_error (status);
  466. }
  467.  
  468. /**
  469.  * cairo_device_get_reference_count:
  470.  * @device: a #cairo_device_t
  471.  *
  472.  * Returns the current reference count of @device.
  473.  *
  474.  * Return value: the current reference count of @device.  If the
  475.  * object is a nil object, 0 will be returned.
  476.  *
  477.  * Since: 1.10
  478.  **/
  479. unsigned int
  480. cairo_device_get_reference_count (cairo_device_t *device)
  481. {
  482.     if (device == NULL ||
  483.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  484.         return 0;
  485.  
  486.     return CAIRO_REFERENCE_COUNT_GET_VALUE (&device->ref_count);
  487. }
  488.  
  489. /**
  490.  * cairo_device_get_user_data:
  491.  * @device: a #cairo_device_t
  492.  * @key: the address of the #cairo_user_data_key_t the user data was
  493.  * attached to
  494.  *
  495.  * Return user data previously attached to @device using the
  496.  * specified key.  If no user data has been attached with the given
  497.  * key this function returns %NULL.
  498.  *
  499.  * Return value: the user data previously attached or %NULL.
  500.  *
  501.  * Since: 1.10
  502.  **/
  503. void *
  504. cairo_device_get_user_data (cairo_device_t               *device,
  505.                             const cairo_user_data_key_t *key)
  506. {
  507.     return _cairo_user_data_array_get_data (&device->user_data,
  508.                                             key);
  509. }
  510.  
  511. /**
  512.  * cairo_device_set_user_data:
  513.  * @device: a #cairo_device_t
  514.  * @key: the address of a #cairo_user_data_key_t to attach the user data to
  515.  * @user_data: the user data to attach to the #cairo_device_t
  516.  * @destroy: a #cairo_destroy_func_t which will be called when the
  517.  * #cairo_t is destroyed or when new user data is attached using the
  518.  * same key.
  519.  *
  520.  * Attach user data to @device.  To remove user data from a surface,
  521.  * call this function with the key that was used to set it and %NULL
  522.  * for @data.
  523.  *
  524.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
  525.  * slot could not be allocated for the user data.
  526.  *
  527.  * Since: 1.10
  528.  **/
  529. cairo_status_t
  530. cairo_device_set_user_data (cairo_device_t               *device,
  531.                             const cairo_user_data_key_t *key,
  532.                             void                         *user_data,
  533.                             cairo_destroy_func_t          destroy)
  534. {
  535.     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  536.         return device->status;
  537.  
  538.     return _cairo_user_data_array_set_data (&device->user_data,
  539.                                             key, user_data, destroy);
  540. }
  541.