Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | 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.     default:
  160.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  161.         return (cairo_device_t *) &_nil_device;
  162.     }
  163. }
  164.  
  165. void
  166. _cairo_device_init (cairo_device_t *device,
  167.                     const cairo_device_backend_t *backend)
  168. {
  169.     CAIRO_REFERENCE_COUNT_INIT (&device->ref_count, 1);
  170.     device->status = CAIRO_STATUS_SUCCESS;
  171.  
  172.     device->backend = backend;
  173.  
  174.     CAIRO_RECURSIVE_MUTEX_INIT (device->mutex);
  175.     device->mutex_depth = 0;
  176.  
  177.     device->finished = FALSE;
  178.  
  179.     _cairo_user_data_array_init (&device->user_data);
  180. }
  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. cairo_device_reference (cairo_device_t *device)
  199. {
  200.     if (device == NULL ||
  201.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  202.     {
  203.         return device;
  204.     }
  205.  
  206.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
  207.     _cairo_reference_count_inc (&device->ref_count);
  208.  
  209.     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. cairo_device_status (cairo_device_t *device)
  227. {
  228.     if (device == NULL)
  229.         return CAIRO_STATUS_NULL_POINTER;
  230.  
  231.     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. cairo_device_flush (cairo_device_t *device)
  251. {
  252.     cairo_status_t status;
  253.  
  254.     if (device == NULL || device->status)
  255.         return;
  256.  
  257.     if (device->backend->flush != NULL) {
  258.         status = device->backend->flush (device);
  259.         if (unlikely (status))
  260.             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. cairo_device_finish (cairo_device_t *device)
  286. {
  287.     if (device == NULL ||
  288.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  289.     {
  290.         return;
  291.     }
  292.  
  293.     if (device->finished)
  294.         return;
  295.  
  296.     cairo_device_flush (device);
  297.  
  298.     device->finished = TRUE;
  299.  
  300.     if (device->backend->finish != NULL)
  301.         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. cairo_device_destroy (cairo_device_t *device)
  319. {
  320.     cairo_user_data_array_t user_data;
  321.  
  322.     if (device == NULL ||
  323.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  324.     {
  325.         return;
  326.     }
  327.  
  328.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&device->ref_count));
  329.     if (! _cairo_reference_count_dec_and_test (&device->ref_count))
  330.         return;
  331.  
  332.     cairo_device_finish (device);
  333.  
  334.     assert (device->mutex_depth == 0);
  335.     CAIRO_MUTEX_FINI (device->mutex);
  336.  
  337.     user_data = device->user_data;
  338.  
  339.     device->backend->destroy (device);
  340.  
  341.     _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. cairo_device_get_type (cairo_device_t *device)
  359. {
  360.     if (device == NULL ||
  361.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  362.     {
  363.         return (cairo_device_type_t) -1;
  364.     }
  365.  
  366.     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. cairo_device_acquire (cairo_device_t *device)
  401. {
  402.     if (device == NULL)
  403.         return CAIRO_STATUS_SUCCESS;
  404.  
  405.     if (unlikely (device->status))
  406.         return device->status;
  407.  
  408.     if (unlikely (device->finished))
  409.         return _cairo_device_set_error (device, CAIRO_STATUS_SURFACE_FINISHED); /* XXX */
  410.  
  411.     CAIRO_MUTEX_LOCK (device->mutex);
  412.     if (device->mutex_depth++ == 0) {
  413.         if (device->backend->lock != NULL)
  414.             device->backend->lock (device);
  415.     }
  416.  
  417.     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. cairo_device_release (cairo_device_t *device)
  432. {
  433.     if (device == NULL)
  434.         return;
  435.  
  436.     assert (device->mutex_depth > 0);
  437.  
  438.     if (--device->mutex_depth == 0) {
  439.         if (device->backend->unlock != NULL)
  440.             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. _cairo_device_set_error (cairo_device_t *device,
  449.                          cairo_status_t  status)
  450. {
  451.     if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
  452.         return status;
  453.  
  454.     /* Don't overwrite an existing error. This preserves the first
  455.      * error, which is the most significant. */
  456.     _cairo_status_set_error (&device->status, status);
  457.  
  458.     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. cairo_device_get_reference_count (cairo_device_t *device)
  474. {
  475.     if (device == NULL ||
  476.         CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  477.         return 0;
  478.  
  479.     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. cairo_device_get_user_data (cairo_device_t               *device,
  498.                             const cairo_user_data_key_t *key)
  499. {
  500.     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. 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.     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&device->ref_count))
  529.         return device->status;
  530.  
  531.     return _cairo_user_data_array_set_data (&device->user_data,
  532.                                             key, user_data, destroy);
  533. }
  534.