Subversion Repositories Kolibri OS

Rev

Rev 1892 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
  2. /* cairo - a vector graphics library with display and print output
  3.  *
  4.  * Copyright © 2005 Red Hat, Inc.
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it either under the terms of the GNU Lesser General Public
  8.  * License version 2.1 as published by the Free Software Foundation
  9.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  10.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  11.  * notice, a recipient may use your version of this file under either
  12.  * the MPL or the LGPL.
  13.  *
  14.  * You should have received a copy of the LGPL along with this library
  15.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  17.  * You should have received a copy of the MPL along with this library
  18.  * in the file COPYING-MPL-1.1
  19.  *
  20.  * The contents of this file are subject to the Mozilla Public License
  21.  * Version 1.1 (the "License"); you may not use this file except in
  22.  * compliance with the License. You may obtain a copy of the License at
  23.  * http://www.mozilla.org/MPL/
  24.  *
  25.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  26.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  27.  * the specific language governing rights and limitations.
  28.  *
  29.  * The Original Code is the cairo graphics library.
  30.  *
  31.  * The Initial Developer of the Original Code is Red Hat, Inc.
  32.  *
  33.  * Contributor(s):
  34.  *      Owen Taylor <otaylor@redhat.com>
  35.  *      Vladimir Vukicevic <vladimir@pobox.com>
  36.  *      Søren Sandmann <sandmann@daimi.au.dk>
  37.  */
  38.  
  39. #include "cairoint.h"
  40.  
  41. #include "cairo-error-private.h"
  42. #include "cairo-region-private.h"
  43.  
  44. /* XXX need to update pixman headers to be const as appropriate */
  45. #define CONST_CAST (pixman_region32_t *)
  46.  
  47. /**
  48.  * SECTION:cairo-region
  49.  * @Title: Regions
  50.  * @Short_Description: Representing a pixel-aligned area
  51.  *
  52.  * Regions are a simple graphical data type representing an area of
  53.  * integer-aligned rectangles. They are often used on raster surfaces
  54.  * to track areas of interest, such as change or clip areas.
  55.  **/
  56.  
  57. static const cairo_region_t _cairo_region_nil = {
  58.     CAIRO_REFERENCE_COUNT_INVALID,      /* ref_count */
  59.     CAIRO_STATUS_NO_MEMORY,             /* status */
  60. };
  61.  
  62. cairo_region_t *
  63. _cairo_region_create_in_error (cairo_status_t status)
  64. {
  65.     switch (status) {
  66.     case CAIRO_STATUS_NO_MEMORY:
  67.         return (cairo_region_t *) &_cairo_region_nil;
  68.  
  69.     case CAIRO_STATUS_SUCCESS:
  70.     case CAIRO_STATUS_LAST_STATUS:
  71.         ASSERT_NOT_REACHED;
  72.         /* fall-through */
  73.     case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
  74.     case CAIRO_STATUS_INVALID_STATUS:
  75.     case CAIRO_STATUS_INVALID_CONTENT:
  76.     case CAIRO_STATUS_INVALID_FORMAT:
  77.     case CAIRO_STATUS_INVALID_VISUAL:
  78.     case CAIRO_STATUS_READ_ERROR:
  79.     case CAIRO_STATUS_WRITE_ERROR:
  80.     case CAIRO_STATUS_FILE_NOT_FOUND:
  81.     case CAIRO_STATUS_TEMP_FILE_ERROR:
  82.     case CAIRO_STATUS_INVALID_STRIDE:
  83.     case CAIRO_STATUS_INVALID_SIZE:
  84.     case CAIRO_STATUS_DEVICE_TYPE_MISMATCH:
  85.     case CAIRO_STATUS_DEVICE_ERROR:
  86.     case CAIRO_STATUS_INVALID_RESTORE:
  87.     case CAIRO_STATUS_INVALID_POP_GROUP:
  88.     case CAIRO_STATUS_NO_CURRENT_POINT:
  89.     case CAIRO_STATUS_INVALID_MATRIX:
  90.     case CAIRO_STATUS_NULL_POINTER:
  91.     case CAIRO_STATUS_INVALID_STRING:
  92.     case CAIRO_STATUS_INVALID_PATH_DATA:
  93.     case CAIRO_STATUS_SURFACE_FINISHED:
  94.     case CAIRO_STATUS_PATTERN_TYPE_MISMATCH:
  95.     case CAIRO_STATUS_INVALID_DASH:
  96.     case CAIRO_STATUS_INVALID_DSC_COMMENT:
  97.     case CAIRO_STATUS_INVALID_INDEX:
  98.     case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE:
  99.     case CAIRO_STATUS_FONT_TYPE_MISMATCH:
  100.     case CAIRO_STATUS_USER_FONT_IMMUTABLE:
  101.     case CAIRO_STATUS_USER_FONT_ERROR:
  102.     case CAIRO_STATUS_NEGATIVE_COUNT:
  103.     case CAIRO_STATUS_INVALID_CLUSTERS:
  104.     case CAIRO_STATUS_INVALID_SLANT:
  105.     case CAIRO_STATUS_INVALID_WEIGHT:
  106.     case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED:
  107.     case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION:
  108.     case CAIRO_STATUS_DEVICE_FINISHED:
  109.     default:
  110.         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
  111.         return (cairo_region_t *) &_cairo_region_nil;
  112.     }
  113. }
  114.  
  115. /**
  116.  * _cairo_region_set_error:
  117.  * @region: a region
  118.  * @status: a status value indicating an error
  119.  *
  120.  * Atomically sets region->status to @status and calls _cairo_error;
  121.  * Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal
  122.  * status values.
  123.  *
  124.  * All assignments of an error status to region->status should happen
  125.  * through _cairo_region_set_error(). Note that due to the nature of
  126.  * the atomic operation, it is not safe to call this function on the
  127.  * nil objects.
  128.  *
  129.  * The purpose of this function is to allow the user to set a
  130.  * breakpoint in _cairo_error() to generate a stack trace for when the
  131.  * user causes cairo to detect an error.
  132.  *
  133.  * Return value: the error status.
  134.  **/
  135. static cairo_status_t
  136. _cairo_region_set_error (cairo_region_t *region,
  137.                          cairo_status_t status)
  138. {
  139.     if (status == CAIRO_STATUS_SUCCESS)
  140.         return CAIRO_STATUS_SUCCESS;
  141.  
  142.     /* Don't overwrite an existing error. This preserves the first
  143.      * error, which is the most significant. */
  144.     _cairo_status_set_error (&region->status, status);
  145.  
  146.     return _cairo_error (status);
  147. }
  148.  
  149. void
  150. _cairo_region_init (cairo_region_t *region)
  151. {
  152.     VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
  153.  
  154.     region->status = CAIRO_STATUS_SUCCESS;
  155.     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
  156.     pixman_region32_init (&region->rgn);
  157. }
  158.  
  159. void
  160. _cairo_region_init_rectangle (cairo_region_t *region,
  161.                               const cairo_rectangle_int_t *rectangle)
  162. {
  163.     VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t)));
  164.  
  165.     region->status = CAIRO_STATUS_SUCCESS;
  166.     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 0);
  167.     pixman_region32_init_rect (&region->rgn,
  168.                                rectangle->x, rectangle->y,
  169.                                rectangle->width, rectangle->height);
  170. }
  171.  
  172. void
  173. _cairo_region_fini (cairo_region_t *region)
  174. {
  175.     assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
  176.     pixman_region32_fini (&region->rgn);
  177.     VG (VALGRIND_MAKE_MEM_NOACCESS (region, sizeof (cairo_region_t)));
  178. }
  179.  
  180. /**
  181.  * cairo_region_create:
  182.  *
  183.  * Allocates a new empty region object.
  184.  *
  185.  * Return value: A newly allocated #cairo_region_t. Free with
  186.  *   cairo_region_destroy(). This function always returns a
  187.  *   valid pointer; if memory cannot be allocated, then a special
  188.  *   error object is returned where all operations on the object do nothing.
  189.  *   You can check for this with cairo_region_status().
  190.  *
  191.  * Since: 1.10
  192.  **/
  193. cairo_region_t *
  194. cairo_region_create (void)
  195. {
  196.     cairo_region_t *region;
  197.  
  198.     region = _cairo_malloc (sizeof (cairo_region_t));
  199.     if (region == NULL)
  200.         return (cairo_region_t *) &_cairo_region_nil;
  201.  
  202.     region->status = CAIRO_STATUS_SUCCESS;
  203.     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
  204.  
  205.     pixman_region32_init (&region->rgn);
  206.  
  207.     return region;
  208. }
  209. slim_hidden_def (cairo_region_create);
  210.  
  211. /**
  212.  * cairo_region_create_rectangles:
  213.  * @rects: an array of @count rectangles
  214.  * @count: number of rectangles
  215.  *
  216.  * Allocates a new region object containing the union of all given @rects.
  217.  *
  218.  * Return value: A newly allocated #cairo_region_t. Free with
  219.  *   cairo_region_destroy(). This function always returns a
  220.  *   valid pointer; if memory cannot be allocated, then a special
  221.  *   error object is returned where all operations on the object do nothing.
  222.  *   You can check for this with cairo_region_status().
  223.  *
  224.  * Since: 1.10
  225.  **/
  226. cairo_region_t *
  227. cairo_region_create_rectangles (const cairo_rectangle_int_t *rects,
  228.                                 int count)
  229. {
  230.     pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
  231.     pixman_box32_t *pboxes = stack_pboxes;
  232.     cairo_region_t *region;
  233.     int i;
  234.  
  235.     region = _cairo_malloc (sizeof (cairo_region_t));
  236.     if (unlikely (region == NULL))
  237.         return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  238.  
  239.     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
  240.     region->status = CAIRO_STATUS_SUCCESS;
  241.  
  242.     if (count == 1) {
  243.         pixman_region32_init_rect (&region->rgn,
  244.                                    rects->x, rects->y,
  245.                                    rects->width, rects->height);
  246.  
  247.         return region;
  248.     }
  249.  
  250.     if (count > ARRAY_LENGTH (stack_pboxes)) {
  251.         pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
  252.         if (unlikely (pboxes == NULL)) {
  253.             free (region);
  254.             return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  255.         }
  256.     }
  257.  
  258.     for (i = 0; i < count; i++) {
  259.         pboxes[i].x1 = rects[i].x;
  260.         pboxes[i].y1 = rects[i].y;
  261.         pboxes[i].x2 = rects[i].x + rects[i].width;
  262.         pboxes[i].y2 = rects[i].y + rects[i].height;
  263.     }
  264.  
  265.     i = pixman_region32_init_rects (&region->rgn, pboxes, count);
  266.  
  267.     if (pboxes != stack_pboxes)
  268.         free (pboxes);
  269.  
  270.     if (unlikely (i == 0)) {
  271.         free (region);
  272.         return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  273.     }
  274.  
  275.     return region;
  276. }
  277. slim_hidden_def (cairo_region_create_rectangles);
  278.  
  279. cairo_region_t *
  280. _cairo_region_create_from_boxes (const cairo_box_t *boxes, int count)
  281. {
  282.     cairo_region_t *region;
  283.  
  284.     region = _cairo_malloc (sizeof (cairo_region_t));
  285.     if (unlikely (region == NULL))
  286.         return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  287.  
  288.     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
  289.     region->status = CAIRO_STATUS_SUCCESS;
  290.  
  291.     if (! pixman_region32_init_rects (&region->rgn,
  292.                                       (pixman_box32_t *)boxes, count)) {
  293.         free (region);
  294.         return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  295.     }
  296.  
  297.     return region;
  298. }
  299.  
  300. cairo_box_t *
  301. _cairo_region_get_boxes (const cairo_region_t *region, int *nbox)
  302. {
  303.     if (region->status) {
  304.         nbox = 0;
  305.         return NULL;
  306.     }
  307.  
  308.     return (cairo_box_t *) pixman_region32_rectangles (CONST_CAST &region->rgn, nbox);
  309. }
  310.  
  311. /**
  312.  * cairo_region_create_rectangle:
  313.  * @rectangle: a #cairo_rectangle_int_t
  314.  *
  315.  * Allocates a new region object containing @rectangle.
  316.  *
  317.  * Return value: A newly allocated #cairo_region_t. Free with
  318.  *   cairo_region_destroy(). This function always returns a
  319.  *   valid pointer; if memory cannot be allocated, then a special
  320.  *   error object is returned where all operations on the object do nothing.
  321.  *   You can check for this with cairo_region_status().
  322.  *
  323.  * Since: 1.10
  324.  **/
  325. cairo_region_t *
  326. cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle)
  327. {
  328.     cairo_region_t *region;
  329.  
  330.     region = _cairo_malloc (sizeof (cairo_region_t));
  331.     if (unlikely (region == NULL))
  332.         return (cairo_region_t *) &_cairo_region_nil;
  333.  
  334.     region->status = CAIRO_STATUS_SUCCESS;
  335.     CAIRO_REFERENCE_COUNT_INIT (&region->ref_count, 1);
  336.  
  337.     pixman_region32_init_rect (&region->rgn,
  338.                                rectangle->x, rectangle->y,
  339.                                rectangle->width, rectangle->height);
  340.  
  341.     return region;
  342. }
  343. slim_hidden_def (cairo_region_create_rectangle);
  344.  
  345. /**
  346.  * cairo_region_copy:
  347.  * @original: a #cairo_region_t
  348.  *
  349.  * Allocates a new region object copying the area from @original.
  350.  *
  351.  * Return value: A newly allocated #cairo_region_t. Free with
  352.  *   cairo_region_destroy(). This function always returns a
  353.  *   valid pointer; if memory cannot be allocated, then a special
  354.  *   error object is returned where all operations on the object do nothing.
  355.  *   You can check for this with cairo_region_status().
  356.  *
  357.  * Since: 1.10
  358.  **/
  359. cairo_region_t *
  360. cairo_region_copy (const cairo_region_t *original)
  361. {
  362.     cairo_region_t *copy;
  363.  
  364.     if (original != NULL && original->status)
  365.         return (cairo_region_t *) &_cairo_region_nil;
  366.  
  367.     copy = cairo_region_create ();
  368.     if (unlikely (copy->status))
  369.         return copy;
  370.  
  371.     if (original != NULL &&
  372.         ! pixman_region32_copy (&copy->rgn, CONST_CAST &original->rgn))
  373.     {
  374.         cairo_region_destroy (copy);
  375.         return (cairo_region_t *) &_cairo_region_nil;
  376.     }
  377.  
  378.     return copy;
  379. }
  380. slim_hidden_def (cairo_region_copy);
  381.  
  382. /**
  383.  * cairo_region_reference:
  384.  * @region: a #cairo_region_t
  385.  *
  386.  * Increases the reference count on @region by one. This prevents
  387.  * @region from being destroyed until a matching call to
  388.  * cairo_region_destroy() is made.
  389.  *
  390.  * Return value: the referenced #cairo_region_t.
  391.  *
  392.  * Since: 1.10
  393.  **/
  394. cairo_region_t *
  395. cairo_region_reference (cairo_region_t *region)
  396. {
  397.     if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
  398.         return NULL;
  399.  
  400.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
  401.  
  402.     _cairo_reference_count_inc (&region->ref_count);
  403.     return region;
  404. }
  405. slim_hidden_def (cairo_region_reference);
  406.  
  407. /**
  408.  * cairo_region_destroy:
  409.  * @region: a #cairo_region_t
  410.  *
  411.  * Destroys a #cairo_region_t object created with
  412.  * cairo_region_create(), cairo_region_copy(), or
  413.  * or cairo_region_create_rectangle().
  414.  *
  415.  * Since: 1.10
  416.  **/
  417. void
  418. cairo_region_destroy (cairo_region_t *region)
  419. {
  420.     if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&region->ref_count))
  421.         return;
  422.  
  423.     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));
  424.  
  425.     if (! _cairo_reference_count_dec_and_test (&region->ref_count))
  426.         return;
  427.  
  428.     _cairo_region_fini (region);
  429.     free (region);
  430. }
  431. slim_hidden_def (cairo_region_destroy);
  432.  
  433. /**
  434.  * cairo_region_num_rectangles:
  435.  * @region: a #cairo_region_t
  436.  *
  437.  * Returns the number of rectangles contained in @region.
  438.  *
  439.  * Return value: The number of rectangles contained in @region.
  440.  *
  441.  * Since: 1.10
  442.  **/
  443. int
  444. cairo_region_num_rectangles (const cairo_region_t *region)
  445. {
  446.     if (region->status)
  447.         return 0;
  448.  
  449.     return pixman_region32_n_rects (CONST_CAST &region->rgn);
  450. }
  451. slim_hidden_def (cairo_region_num_rectangles);
  452.  
  453. /**
  454.  * cairo_region_get_rectangle:
  455.  * @region: a #cairo_region_t
  456.  * @nth: a number indicating which rectangle should be returned
  457.  * @rectangle: return location for a #cairo_rectangle_int_t
  458.  *
  459.  * Stores the @nth rectangle from the region in @rectangle.
  460.  *
  461.  * Since: 1.10
  462.  **/
  463. void
  464. cairo_region_get_rectangle (const cairo_region_t *region,
  465.                             int nth,
  466.                             cairo_rectangle_int_t *rectangle)
  467. {
  468.     pixman_box32_t *pbox;
  469.  
  470.     if (region->status) {
  471.         rectangle->x = rectangle->y = 0;
  472.         rectangle->width = rectangle->height = 0;
  473.         return;
  474.     }
  475.  
  476.     pbox = pixman_region32_rectangles (CONST_CAST &region->rgn, NULL) + nth;
  477.  
  478.     rectangle->x = pbox->x1;
  479.     rectangle->y = pbox->y1;
  480.     rectangle->width = pbox->x2 - pbox->x1;
  481.     rectangle->height = pbox->y2 - pbox->y1;
  482. }
  483. slim_hidden_def (cairo_region_get_rectangle);
  484.  
  485. /**
  486.  * cairo_region_get_extents:
  487.  * @region: a #cairo_region_t
  488.  * @extents: rectangle into which to store the extents
  489.  *
  490.  * Gets the bounding rectangle of @region as a #cairo_rectangle_int_t
  491.  *
  492.  * Since: 1.10
  493.  **/
  494. void
  495. cairo_region_get_extents (const cairo_region_t *region,
  496.                           cairo_rectangle_int_t *extents)
  497. {
  498.     pixman_box32_t *pextents;
  499.  
  500.     if (region->status) {
  501.         extents->x = extents->y = 0;
  502.         extents->width = extents->height = 0;
  503.         return;
  504.     }
  505.  
  506.     pextents = pixman_region32_extents (CONST_CAST &region->rgn);
  507.  
  508.     extents->x = pextents->x1;
  509.     extents->y = pextents->y1;
  510.     extents->width = pextents->x2 - pextents->x1;
  511.     extents->height = pextents->y2 - pextents->y1;
  512. }
  513. slim_hidden_def (cairo_region_get_extents);
  514.  
  515. /**
  516.  * cairo_region_status:
  517.  * @region: a #cairo_region_t
  518.  *
  519.  * Checks whether an error has previous occurred for this
  520.  * region object.
  521.  *
  522.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  523.  *
  524.  * Since: 1.10
  525.  **/
  526. cairo_status_t
  527. cairo_region_status (const cairo_region_t *region)
  528. {
  529.     return region->status;
  530. }
  531. slim_hidden_def (cairo_region_status);
  532.  
  533. /**
  534.  * cairo_region_subtract:
  535.  * @dst: a #cairo_region_t
  536.  * @other: another #cairo_region_t
  537.  *
  538.  * Subtracts @other from @dst and places the result in @dst
  539.  *
  540.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  541.  *
  542.  * Since: 1.10
  543.  **/
  544. cairo_status_t
  545. cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other)
  546. {
  547.     if (dst->status)
  548.         return dst->status;
  549.  
  550.     if (other->status)
  551.         return _cairo_region_set_error (dst, other->status);
  552.  
  553.     if (! pixman_region32_subtract (&dst->rgn,
  554.                                     &dst->rgn,
  555.                                     CONST_CAST &other->rgn))
  556.     {
  557.         return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
  558.     }
  559.  
  560.     return CAIRO_STATUS_SUCCESS;
  561. }
  562. slim_hidden_def (cairo_region_subtract);
  563.  
  564. /**
  565.  * cairo_region_subtract_rectangle:
  566.  * @dst: a #cairo_region_t
  567.  * @rectangle: a #cairo_rectangle_int_t
  568.  *
  569.  * Subtracts @rectangle from @dst and places the result in @dst
  570.  *
  571.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  572.  *
  573.  * Since: 1.10
  574.  **/
  575. cairo_status_t
  576. cairo_region_subtract_rectangle (cairo_region_t *dst,
  577.                                  const cairo_rectangle_int_t *rectangle)
  578. {
  579.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  580.     pixman_region32_t region;
  581.  
  582.     if (dst->status)
  583.         return dst->status;
  584.  
  585.     pixman_region32_init_rect (&region,
  586.                                rectangle->x, rectangle->y,
  587.                                rectangle->width, rectangle->height);
  588.  
  589.     if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region))
  590.         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
  591.  
  592.     pixman_region32_fini (&region);
  593.  
  594.     return status;
  595. }
  596. slim_hidden_def (cairo_region_subtract_rectangle);
  597.  
  598. /**
  599.  * cairo_region_intersect:
  600.  * @dst: a #cairo_region_t
  601.  * @other: another #cairo_region_t
  602.  *
  603.  * Computes the intersection of @dst with @other and places the result in @dst
  604.  *
  605.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  606.  *
  607.  * Since: 1.10
  608.  **/
  609. cairo_status_t
  610. cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other)
  611. {
  612.     if (dst->status)
  613.         return dst->status;
  614.  
  615.     if (other->status)
  616.         return _cairo_region_set_error (dst, other->status);
  617.  
  618.     if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
  619.         return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
  620.  
  621.     return CAIRO_STATUS_SUCCESS;
  622. }
  623. slim_hidden_def (cairo_region_intersect);
  624.  
  625. /**
  626.  * cairo_region_intersect_rectangle:
  627.  * @dst: a #cairo_region_t
  628.  * @rectangle: a #cairo_rectangle_int_t
  629.  *
  630.  * Computes the intersection of @dst with @rectangle and places the
  631.  * result in @dst
  632.  *
  633.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  634.  *
  635.  * Since: 1.10
  636.  **/
  637. cairo_status_t
  638. cairo_region_intersect_rectangle (cairo_region_t *dst,
  639.                                   const cairo_rectangle_int_t *rectangle)
  640. {
  641.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  642.     pixman_region32_t region;
  643.  
  644.     if (dst->status)
  645.         return dst->status;
  646.  
  647.     pixman_region32_init_rect (&region,
  648.                                rectangle->x, rectangle->y,
  649.                                rectangle->width, rectangle->height);
  650.  
  651.     if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, &region))
  652.         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
  653.  
  654.     pixman_region32_fini (&region);
  655.  
  656.     return status;
  657. }
  658. slim_hidden_def (cairo_region_intersect_rectangle);
  659.  
  660. /**
  661.  * cairo_region_union:
  662.  * @dst: a #cairo_region_t
  663.  * @other: another #cairo_region_t
  664.  *
  665.  * Computes the union of @dst with @other and places the result in @dst
  666.  *
  667.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  668.  *
  669.  * Since: 1.10
  670.  **/
  671. cairo_status_t
  672. cairo_region_union (cairo_region_t *dst,
  673.                     const cairo_region_t *other)
  674. {
  675.     if (dst->status)
  676.         return dst->status;
  677.  
  678.     if (other->status)
  679.         return _cairo_region_set_error (dst, other->status);
  680.  
  681.     if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn))
  682.         return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
  683.  
  684.     return CAIRO_STATUS_SUCCESS;
  685. }
  686. slim_hidden_def (cairo_region_union);
  687.  
  688. /**
  689.  * cairo_region_union_rectangle:
  690.  * @dst: a #cairo_region_t
  691.  * @rectangle: a #cairo_rectangle_int_t
  692.  *
  693.  * Computes the union of @dst with @rectangle and places the result in @dst.
  694.  *
  695.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  696.  *
  697.  * Since: 1.10
  698.  **/
  699. cairo_status_t
  700. cairo_region_union_rectangle (cairo_region_t *dst,
  701.                               const cairo_rectangle_int_t *rectangle)
  702. {
  703.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  704.     pixman_region32_t region;
  705.  
  706.     if (dst->status)
  707.         return dst->status;
  708.  
  709.     pixman_region32_init_rect (&region,
  710.                                rectangle->x, rectangle->y,
  711.                                rectangle->width, rectangle->height);
  712.  
  713.     if (! pixman_region32_union (&dst->rgn, &dst->rgn, &region))
  714.         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
  715.  
  716.     pixman_region32_fini (&region);
  717.  
  718.     return status;
  719. }
  720. slim_hidden_def (cairo_region_union_rectangle);
  721.  
  722. /**
  723.  * cairo_region_xor:
  724.  * @dst: a #cairo_region_t
  725.  * @other: another #cairo_region_t
  726.  *
  727.  * Computes the exclusive difference of @dst with @other and places the
  728.  * result in @dst. That is, @dst will be set to contain all areas that
  729.  * are either in @dst or in @other, but not in both.
  730.  *
  731.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  732.  *
  733.  * Since: 1.10
  734.  **/
  735. cairo_status_t
  736. cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other)
  737. {
  738.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  739.     pixman_region32_t tmp;
  740.  
  741.     if (dst->status)
  742.         return dst->status;
  743.  
  744.     if (other->status)
  745.         return _cairo_region_set_error (dst, other->status);
  746.  
  747.     pixman_region32_init (&tmp);
  748.  
  749.     /* XXX: get an xor function into pixman */
  750.     if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) ||
  751.         ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) ||
  752.         ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
  753.         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
  754.  
  755.     pixman_region32_fini (&tmp);
  756.  
  757.     return status;
  758. }
  759. slim_hidden_def (cairo_region_xor);
  760.  
  761. /**
  762.  * cairo_region_xor_rectangle:
  763.  * @dst: a #cairo_region_t
  764.  * @rectangle: a #cairo_rectangle_int_t
  765.  *
  766.  * Computes the exclusive difference of @dst with @rectangle and places the
  767.  * result in @dst. That is, @dst will be set to contain all areas that are
  768.  * either in @dst or in @rectangle, but not in both.
  769.  *
  770.  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
  771.  *
  772.  * Since: 1.10
  773.  **/
  774. cairo_status_t
  775. cairo_region_xor_rectangle (cairo_region_t *dst,
  776.                             const cairo_rectangle_int_t *rectangle)
  777. {
  778.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  779.     pixman_region32_t region, tmp;
  780.  
  781.     if (dst->status)
  782.         return dst->status;
  783.  
  784.     pixman_region32_init_rect (&region,
  785.                                rectangle->x, rectangle->y,
  786.                                rectangle->width, rectangle->height);
  787.     pixman_region32_init (&tmp);
  788.  
  789.     /* XXX: get an xor function into pixman */
  790.     if (! pixman_region32_subtract (&tmp, &region, &dst->rgn) ||
  791.         ! pixman_region32_subtract (&dst->rgn, &dst->rgn, &region) ||
  792.         ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp))
  793.         status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY);
  794.  
  795.     pixman_region32_fini (&tmp);
  796.     pixman_region32_fini (&region);
  797.  
  798.     return status;
  799. }
  800. slim_hidden_def (cairo_region_xor_rectangle);
  801.  
  802. /**
  803.  * cairo_region_is_empty:
  804.  * @region: a #cairo_region_t
  805.  *
  806.  * Checks whether @region is empty.
  807.  *
  808.  * Return value: %TRUE if @region is empty, %FALSE if it isn't.
  809.  *
  810.  * Since: 1.10
  811.  **/
  812. cairo_bool_t
  813. cairo_region_is_empty (const cairo_region_t *region)
  814. {
  815.     if (region->status)
  816.         return TRUE;
  817.  
  818.     return ! pixman_region32_not_empty (CONST_CAST &region->rgn);
  819. }
  820. slim_hidden_def (cairo_region_is_empty);
  821.  
  822. /**
  823.  * cairo_region_translate:
  824.  * @region: a #cairo_region_t
  825.  * @dx: Amount to translate in the x direction
  826.  * @dy: Amount to translate in the y direction
  827.  *
  828.  * Translates @region by (@dx, @dy).
  829.  *
  830.  * Since: 1.10
  831.  **/
  832. void
  833. cairo_region_translate (cairo_region_t *region,
  834.                         int dx, int dy)
  835. {
  836.     if (region->status)
  837.         return;
  838.  
  839.     pixman_region32_translate (&region->rgn, dx, dy);
  840. }
  841. slim_hidden_def (cairo_region_translate);
  842.  
  843. /**
  844.  * cairo_region_overlap_t:
  845.  * @CAIRO_REGION_OVERLAP_IN: The contents are entirely inside the region. (Since 1.10)
  846.  * @CAIRO_REGION_OVERLAP_OUT: The contents are entirely outside the region. (Since 1.10)
  847.  * @CAIRO_REGION_OVERLAP_PART: The contents are partially inside and
  848.  *     partially outside the region. (Since 1.10)
  849.  *
  850.  * Used as the return value for cairo_region_contains_rectangle().
  851.  *
  852.  * Since: 1.10
  853.  **/
  854.  
  855. /**
  856.  * cairo_region_contains_rectangle:
  857.  * @region: a #cairo_region_t
  858.  * @rectangle: a #cairo_rectangle_int_t
  859.  *
  860.  * Checks whether @rectangle is inside, outside or partially contained
  861.  * in @region
  862.  *
  863.  * Return value:
  864.  *   %CAIRO_REGION_OVERLAP_IN if @rectangle is entirely inside @region,
  865.  *   %CAIRO_REGION_OVERLAP_OUT if @rectangle is entirely outside @region, or
  866.  *   %CAIRO_REGION_OVERLAP_PART if @rectangle is partially inside and partially outside @region.
  867.  *
  868.  * Since: 1.10
  869.  **/
  870. cairo_region_overlap_t
  871. cairo_region_contains_rectangle (const cairo_region_t *region,
  872.                                  const cairo_rectangle_int_t *rectangle)
  873. {
  874.     pixman_box32_t pbox;
  875.     pixman_region_overlap_t poverlap;
  876.  
  877.     if (region->status)
  878.         return CAIRO_REGION_OVERLAP_OUT;
  879.  
  880.     pbox.x1 = rectangle->x;
  881.     pbox.y1 = rectangle->y;
  882.     pbox.x2 = rectangle->x + rectangle->width;
  883.     pbox.y2 = rectangle->y + rectangle->height;
  884.  
  885.     poverlap = pixman_region32_contains_rectangle (CONST_CAST &region->rgn,
  886.                                                    &pbox);
  887.     switch (poverlap) {
  888.     default:
  889.     case PIXMAN_REGION_OUT:  return CAIRO_REGION_OVERLAP_OUT;
  890.     case PIXMAN_REGION_IN:   return CAIRO_REGION_OVERLAP_IN;
  891.     case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART;
  892.     }
  893. }
  894. slim_hidden_def (cairo_region_contains_rectangle);
  895.  
  896. /**
  897.  * cairo_region_contains_point:
  898.  * @region: a #cairo_region_t
  899.  * @x: the x coordinate of a point
  900.  * @y: the y coordinate of a point
  901.  *
  902.  * Checks whether (@x, @y) is contained in @region.
  903.  *
  904.  * Return value: %TRUE if (@x, @y) is contained in @region, %FALSE if it is not.
  905.  *
  906.  * Since: 1.10
  907.  **/
  908. cairo_bool_t
  909. cairo_region_contains_point (const cairo_region_t *region,
  910.                              int x, int y)
  911. {
  912.     pixman_box32_t box;
  913.  
  914.     if (region->status)
  915.         return FALSE;
  916.  
  917.     return pixman_region32_contains_point (CONST_CAST &region->rgn, x, y, &box);
  918. }
  919. slim_hidden_def (cairo_region_contains_point);
  920.  
  921. /**
  922.  * cairo_region_equal:
  923.  * @a: a #cairo_region_t or %NULL
  924.  * @b: a #cairo_region_t or %NULL
  925.  *
  926.  * Compares whether region_a is equivalent to region_b. %NULL as an argument
  927.  * is equal to itself, but not to any non-%NULL region.
  928.  *
  929.  * Return value: %TRUE if both regions contained the same coverage,
  930.  * %FALSE if it is not or any region is in an error status.
  931.  *
  932.  * Since: 1.10
  933.  **/
  934. cairo_bool_t
  935. cairo_region_equal (const cairo_region_t *a,
  936.                     const cairo_region_t *b)
  937. {
  938.     /* error objects are never equal */
  939.     if ((a != NULL && a->status) || (b != NULL && b->status))
  940.         return FALSE;
  941.  
  942.     if (a == b)
  943.         return TRUE;
  944.  
  945.     if (a == NULL || b == NULL)
  946.         return FALSE;
  947.  
  948.     return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn);
  949. }
  950. slim_hidden_def (cairo_region_equal);
  951.