Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /* cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2004 Red Hat, Inc
  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 University of Southern
  31.  * California.
  32.  *
  33.  * Contributor(s):
  34.  *      Kristian Høgsberg <krh@redhat.com>
  35.  *      Carl Worth <cworth@cworth.org>
  36.  */
  37.  
  38. #include "cairoint.h"
  39. #include "cairo-error-private.h"
  40.  
  41. /**
  42.  * _cairo_array_init:
  43.  *
  44.  * Initialize a new #cairo_array_t object to store objects each of size
  45.  * @element_size.
  46.  *
  47.  * The #cairo_array_t object provides grow-by-doubling storage. It
  48.  * never interprets the data passed to it, nor does it provide any
  49.  * sort of callback mechanism for freeing resources held onto by
  50.  * stored objects.
  51.  *
  52.  * When finished using the array, _cairo_array_fini() should be
  53.  * called to free resources allocated during use of the array.
  54.  **/
  55. void
  56. _cairo_array_init (cairo_array_t *array, int element_size)
  57. {
  58.     array->size = 0;
  59.     array->num_elements = 0;
  60.     array->element_size = element_size;
  61.     array->elements = NULL;
  62.  
  63.     array->is_snapshot = FALSE;
  64. }
  65.  
  66. /**
  67.  * _cairo_array_init_snapshot:
  68.  * @array: A #cairo_array_t to be initialized as a snapshot
  69.  * @other: The #cairo_array_t from which to create the snapshot
  70.  *
  71.  * Initialize @array as an immutable copy of @other. It is an error to
  72.  * call an array-modifying function (other than _cairo_array_fini) on
  73.  * @array after calling this function.
  74.  **/
  75. void
  76. _cairo_array_init_snapshot (cairo_array_t       *array,
  77.                             const cairo_array_t *other)
  78. {
  79.     array->size = other->size;
  80.     array->num_elements = other->num_elements;
  81.     array->element_size = other->element_size;
  82.     array->elements = other->elements;
  83.  
  84.     array->is_snapshot = TRUE;
  85. }
  86.  
  87. /**
  88.  * _cairo_array_fini:
  89.  * @array: A #cairo_array_t
  90.  *
  91.  * Free all resources associated with @array. After this call, @array
  92.  * should not be used again without a subsequent call to
  93.  * _cairo_array_init() again first.
  94.  **/
  95. void
  96. _cairo_array_fini (cairo_array_t *array)
  97. {
  98.     if (array->is_snapshot)
  99.         return;
  100.  
  101.     if (array->elements) {
  102.         free (* array->elements);
  103.         free (array->elements);
  104.     }
  105. }
  106.  
  107. /**
  108.  * _cairo_array_grow_by:
  109.  * @array: a #cairo_array_t
  110.  *
  111.  * Increase the size of @array (if needed) so that there are at least
  112.  * @additional free spaces in the array. The actual size of the array
  113.  * is always increased by doubling as many times as necessary.
  114.  **/
  115. cairo_status_t
  116. _cairo_array_grow_by (cairo_array_t *array, unsigned int additional)
  117. {
  118.     char *new_elements;
  119.     unsigned int old_size = array->size;
  120.     unsigned int required_size = array->num_elements + additional;
  121.     unsigned int new_size;
  122.  
  123.     assert (! array->is_snapshot);
  124.  
  125.     /* check for integer overflow */
  126.     if (required_size > INT_MAX || required_size < array->num_elements)
  127.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  128.  
  129.     if (CAIRO_INJECT_FAULT ())
  130.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  131.  
  132.     if (required_size <= old_size)
  133.         return CAIRO_STATUS_SUCCESS;
  134.  
  135.     if (old_size == 0)
  136.         new_size = 1;
  137.     else
  138.         new_size = old_size * 2;
  139.  
  140.     while (new_size < required_size)
  141.         new_size = new_size * 2;
  142.  
  143.     if (array->elements == NULL) {
  144.         array->elements = malloc (sizeof (char *));
  145.         if (unlikely (array->elements == NULL))
  146.             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  147.  
  148.         *array->elements = NULL;
  149.     }
  150.  
  151.     array->size = new_size;
  152.     new_elements = _cairo_realloc_ab (*array->elements,
  153.                                       array->size, array->element_size);
  154.  
  155.     if (unlikely (new_elements == NULL)) {
  156.         array->size = old_size;
  157.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  158.     }
  159.  
  160.     *array->elements = new_elements;
  161.  
  162.     return CAIRO_STATUS_SUCCESS;
  163. }
  164.  
  165. /**
  166.  * _cairo_array_truncate:
  167.  * @array: a #cairo_array_t
  168.  *
  169.  * Truncate size of the array to @num_elements if less than the
  170.  * current size. No memory is actually freed. The stored objects
  171.  * beyond @num_elements are simply "forgotten".
  172.  **/
  173. void
  174. _cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
  175. {
  176.     assert (! array->is_snapshot);
  177.  
  178.     if (num_elements < array->num_elements)
  179.         array->num_elements = num_elements;
  180. }
  181.  
  182. /**
  183.  * _cairo_array_index:
  184.  * @array: a #cairo_array_t
  185.  * Returns: A pointer to the object stored at @index.
  186.  *
  187.  * If the resulting value is assigned to a pointer to an object of the same
  188.  * element_size as initially passed to _cairo_array_init() then that
  189.  * pointer may be used for further direct indexing with []. For
  190.  * example:
  191.  *
  192.  * <informalexample><programlisting>
  193.  *      cairo_array_t array;
  194.  *      double *values;
  195.  *
  196.  *      _cairo_array_init (&array, sizeof(double));
  197.  *      ... calls to _cairo_array_append() here ...
  198.  *
  199.  *      values = _cairo_array_index (&array, 0);
  200.  *      for (i = 0; i < _cairo_array_num_elements (&array); i++)
  201.  *          ... use values[i] here ...
  202.  * </programlisting></informalexample>
  203.  **/
  204. void *
  205. _cairo_array_index (cairo_array_t *array, unsigned int index)
  206. {
  207.     /* We allow an index of 0 for the no-elements case.
  208.      * This makes for cleaner calling code which will often look like:
  209.      *
  210.      *    elements = _cairo_array_index (array, num_elements);
  211.      *    for (i=0; i < num_elements; i++) {
  212.      *        ... use elements[i] here ...
  213.      *    }
  214.      *
  215.      * which in the num_elements==0 case gets the NULL pointer here,
  216.      * but never dereferences it.
  217.      */
  218.     if (index == 0 && array->num_elements == 0)
  219.         return NULL;
  220.  
  221.     assert (index < array->num_elements);
  222.  
  223.     return (void *) &(*array->elements)[index * array->element_size];
  224. }
  225.  
  226. /**
  227.  * _cairo_array_copy_element:
  228.  * @array: a #cairo_array_t
  229.  *
  230.  * Copy a single element out of the array from index @index into the
  231.  * location pointed to by @dst.
  232.  **/
  233. void
  234. _cairo_array_copy_element (cairo_array_t *array, int index, void *dst)
  235. {
  236.     memcpy (dst, _cairo_array_index (array, index), array->element_size);
  237. }
  238.  
  239. /**
  240.  * _cairo_array_append:
  241.  * @array: a #cairo_array_t
  242.  *
  243.  * Append a single item onto the array by growing the array by at
  244.  * least one element, then copying element_size bytes from @element
  245.  * into the array. The address of the resulting object within the
  246.  * array can be determined with:
  247.  *
  248.  * _cairo_array_index (array, _cairo_array_num_elements (array) - 1);
  249.  *
  250.  * Return value: %CAIRO_STATUS_SUCCESS if successful or
  251.  * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
  252.  * operation.
  253.  **/
  254. cairo_status_t
  255. _cairo_array_append (cairo_array_t      *array,
  256.                      const void         *element)
  257. {
  258.     assert (! array->is_snapshot);
  259.  
  260.     return _cairo_array_append_multiple (array, element, 1);
  261. }
  262.  
  263. /**
  264.  * _cairo_array_append_multiple:
  265.  * @array: a #cairo_array_t
  266.  *
  267.  * Append one or more items onto the array by growing the array by
  268.  * @num_elements, then copying @num_elements * element_size bytes from
  269.  * @elements into the array.
  270.  *
  271.  * Return value: %CAIRO_STATUS_SUCCESS if successful or
  272.  * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
  273.  * operation.
  274.  **/
  275. cairo_status_t
  276. _cairo_array_append_multiple (cairo_array_t     *array,
  277.                               const void        *elements,
  278.                               int                num_elements)
  279. {
  280.     cairo_status_t status;
  281.     void *dest;
  282.  
  283.     assert (! array->is_snapshot);
  284.  
  285.     status = _cairo_array_allocate (array, num_elements, &dest);
  286.     if (unlikely (status))
  287.         return status;
  288.  
  289.     memcpy (dest, elements, num_elements * array->element_size);
  290.  
  291.     return CAIRO_STATUS_SUCCESS;
  292. }
  293.  
  294. /**
  295.  * _cairo_array_allocate:
  296.  * @array: a #cairo_array_t
  297.  *
  298.  * Allocate space at the end of the array for @num_elements additional
  299.  * elements, providing the address of the new memory chunk in
  300.  * @elements. This memory will be unitialized, but will be accounted
  301.  * for in the return value of _cairo_array_num_elements().
  302.  *
  303.  * Return value: %CAIRO_STATUS_SUCCESS if successful or
  304.  * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
  305.  * operation.
  306.  **/
  307. cairo_status_t
  308. _cairo_array_allocate (cairo_array_t     *array,
  309.                        unsigned int       num_elements,
  310.                        void             **elements)
  311. {
  312.     cairo_status_t status;
  313.  
  314.     assert (! array->is_snapshot);
  315.  
  316.     status = _cairo_array_grow_by (array, num_elements);
  317.     if (unlikely (status))
  318.         return status;
  319.  
  320.     assert (array->num_elements + num_elements <= array->size);
  321.  
  322.     *elements = &(*array->elements)[array->num_elements * array->element_size];
  323.  
  324.     array->num_elements += num_elements;
  325.  
  326.     return CAIRO_STATUS_SUCCESS;
  327. }
  328.  
  329. /**
  330.  * _cairo_array_num_elements:
  331.  * @array: a #cairo_array_t
  332.  * Returns: The number of elements stored in @array.
  333.  *
  334.  * This space was left intentionally blank, but gtk-doc filled it.
  335.  **/
  336. int
  337. _cairo_array_num_elements (cairo_array_t *array)
  338. {
  339.     return array->num_elements;
  340. }
  341.  
  342. /**
  343.  * _cairo_array_size:
  344.  * @array: a #cairo_array_t
  345.  * Returns: The number of elements for which there is currently space
  346.  * allocated in @array.
  347.  *
  348.  * This space was left intentionally blank, but gtk-doc filled it.
  349.  **/
  350. int
  351. _cairo_array_size (cairo_array_t *array)
  352. {
  353.     return array->size;
  354. }
  355.  
  356. /**
  357.  * _cairo_user_data_array_init:
  358.  * @array: a #cairo_user_data_array_t
  359.  *
  360.  * Initializes a #cairo_user_data_array_t structure for future
  361.  * use. After initialization, the array has no keys. Call
  362.  * _cairo_user_data_array_fini() to free any allocated memory
  363.  * when done using the array.
  364.  **/
  365. void
  366. _cairo_user_data_array_init (cairo_user_data_array_t *array)
  367. {
  368.     _cairo_array_init (array, sizeof (cairo_user_data_slot_t));
  369. }
  370.  
  371. /**
  372.  * _cairo_user_data_array_fini:
  373.  * @array: a #cairo_user_data_array_t
  374.  *
  375.  * Destroys all current keys in the user data array and deallocates
  376.  * any memory allocated for the array itself.
  377.  **/
  378. void
  379. _cairo_user_data_array_fini (cairo_user_data_array_t *array)
  380. {
  381.     unsigned int num_slots;
  382.  
  383.     num_slots = array->num_elements;
  384.     if (num_slots) {
  385.         cairo_user_data_slot_t *slots;
  386.  
  387.         slots = _cairo_array_index (array, 0);
  388.         do {
  389.             if (slots->user_data != NULL && slots->destroy != NULL)
  390.                 slots->destroy (slots->user_data);
  391.             slots++;
  392.         } while (--num_slots);
  393.     }
  394.  
  395.     _cairo_array_fini (array);
  396. }
  397.  
  398. /**
  399.  * _cairo_user_data_array_get_data:
  400.  * @array: a #cairo_user_data_array_t
  401.  * @key: the address of the #cairo_user_data_key_t the user data was
  402.  * attached to
  403.  *
  404.  * Returns user data previously attached using the specified
  405.  * key.  If no user data has been attached with the given key this
  406.  * function returns %NULL.
  407.  *
  408.  * Return value: the user data previously attached or %NULL.
  409.  **/
  410. void *
  411. _cairo_user_data_array_get_data (cairo_user_data_array_t     *array,
  412.                                  const cairo_user_data_key_t *key)
  413. {
  414.     int i, num_slots;
  415.     cairo_user_data_slot_t *slots;
  416.  
  417.     /* We allow this to support degenerate objects such as cairo_surface_nil. */
  418.     if (array == NULL)
  419.         return NULL;
  420.  
  421.     num_slots = array->num_elements;
  422.     slots = _cairo_array_index (array, 0);
  423.     for (i = 0; i < num_slots; i++) {
  424.         if (slots[i].key == key)
  425.             return slots[i].user_data;
  426.     }
  427.  
  428.     return NULL;
  429. }
  430.  
  431. /**
  432.  * _cairo_user_data_array_set_data:
  433.  * @array: a #cairo_user_data_array_t
  434.  * @key: the address of a #cairo_user_data_key_t to attach the user data to
  435.  * @user_data: the user data to attach
  436.  * @destroy: a #cairo_destroy_func_t which will be called when the
  437.  * user data array is destroyed or when new user data is attached using the
  438.  * same key.
  439.  *
  440.  * Attaches user data to a user data array.  To remove user data,
  441.  * call this function with the key that was used to set it and %NULL
  442.  * for @data.
  443.  *
  444.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
  445.  * slot could not be allocated for the user data.
  446.  **/
  447. cairo_status_t
  448. _cairo_user_data_array_set_data (cairo_user_data_array_t     *array,
  449.                                  const cairo_user_data_key_t *key,
  450.                                  void                        *user_data,
  451.                                  cairo_destroy_func_t         destroy)
  452. {
  453.     cairo_status_t status;
  454.     int i, num_slots;
  455.     cairo_user_data_slot_t *slots, *slot, new_slot;
  456.  
  457.     if (user_data) {
  458.         new_slot.key = key;
  459.         new_slot.user_data = user_data;
  460.         new_slot.destroy = destroy;
  461.     } else {
  462.         new_slot.key = NULL;
  463.         new_slot.user_data = NULL;
  464.         new_slot.destroy = NULL;
  465.     }
  466.  
  467.     slot = NULL;
  468.     num_slots = array->num_elements;
  469.     slots = _cairo_array_index (array, 0);
  470.     for (i = 0; i < num_slots; i++) {
  471.         if (slots[i].key == key) {
  472.             slot = &slots[i];
  473.             if (slot->destroy && slot->user_data)
  474.                 slot->destroy (slot->user_data);
  475.             break;
  476.         }
  477.         if (user_data && slots[i].user_data == NULL) {
  478.             slot = &slots[i];   /* Have to keep searching for an exact match */
  479.         }
  480.     }
  481.  
  482.     if (slot) {
  483.         *slot = new_slot;
  484.         return CAIRO_STATUS_SUCCESS;
  485.     }
  486.  
  487.     status = _cairo_array_append (array, &new_slot);
  488.     if (unlikely (status))
  489.         return status;
  490.  
  491.     return CAIRO_STATUS_SUCCESS;
  492. }
  493.  
  494. cairo_status_t
  495. _cairo_user_data_array_copy (cairo_user_data_array_t    *dst,
  496.                              cairo_user_data_array_t    *src)
  497. {
  498.     /* discard any existing user-data */
  499.     if (dst->num_elements != 0) {
  500.         _cairo_user_data_array_fini (dst);
  501.         _cairo_user_data_array_init (dst);
  502.     }
  503.  
  504.     if (src->num_elements == 0)
  505.         return CAIRO_STATUS_SUCCESS;
  506.  
  507.     return _cairo_array_append_multiple (dst,
  508.                                          _cairo_array_index (src, 0),
  509.                                          src->num_elements);
  510. }
  511.  
  512. void
  513. _cairo_user_data_array_foreach (cairo_user_data_array_t     *array,
  514.                                 void (*func) (const void *key,
  515.                                               void *elt,
  516.                                               void *closure),
  517.                                 void *closure)
  518. {
  519.     cairo_user_data_slot_t *slots;
  520.     int i, num_slots;
  521.  
  522.     num_slots = array->num_elements;
  523.     slots = _cairo_array_index (array, 0);
  524.     for (i = 0; i < num_slots; i++) {
  525.         if (slots[i].user_data != NULL)
  526.             func (slots[i].key, slots[i].user_data, closure);
  527.     }
  528. }
  529.