|             Line data    Source code 
       1              : /*
       2              :   +----------------------------------------------------------------------+
       3              :   | For PHP Version 8                                                    |
       4              :   +----------------------------------------------------------------------+
       5              :   | Copyright (c) 2015 Elizabeth M Smith                                 |
       6              :   +----------------------------------------------------------------------+
       7              :   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
       8              :   | Also available in LICENSE                                            |
       9              :   +----------------------------------------------------------------------+
      10              :   | Authors: Elizabeth M Smith <auroraeosrose@gmail.com>                 |
      11              :   |          Swen Zanon <swen.zanon@geoglis.de>                          |
      12              :   +----------------------------------------------------------------------+
      13              : */
      14              : 
      15              : #ifdef HAVE_CONFIG_H
      16              : #include "config.h"
      17              : #endif
      18              : 
      19              : #include <cairo.h>
      20              : #include <php.h>
      21              : #include <zend_exceptions.h>
      22              : 
      23              : #include "php_cairo.h"
      24              : #include "php_cairo_internal.h"
      25              : #include "region_arginfo.h"
      26              : 
      27              : zend_class_entry *ce_cairo_region;
      28              : zend_class_entry *ce_cairo_region_overlap;
      29              : 
      30              : static zend_object_handlers cairo_region_object_handlers;
      31              : 
      32              : typedef struct _cairo_region_object {
      33              :     cairo_region_t *region;
      34              :     zend_object std;
      35              : } cairo_region_object;
      36              : 
      37          197 : static inline cairo_region_object *cairo_region_fetch_object(zend_object *object)
      38              : {
      39          197 :     return (cairo_region_object *) ((char*)(object) - XtOffsetOf(cairo_region_object, std));
      40              : }
      41              : 
      42              : #define Z_CAIRO_REGION_P(zv) cairo_region_fetch_object(Z_OBJ_P(zv))
      43              : 
      44           92 : cairo_region_object *cairo_region_object_get(zval *zv)
      45              : {
      46           92 :     cairo_region_object *object = Z_CAIRO_REGION_P(zv);
      47           92 :     if (object->region == NULL) {
      48            0 :         zend_throw_exception_ex(ce_cairo_exception, 0,
      49              :             "Internal region object missing in %s, you must call parent::__construct in extended classes.",
      50            0 :             ZSTR_VAL(Z_OBJCE_P(zv)->name));
      51            0 :         return NULL;
      52              :     }
      53           92 :     return object;
      54              : }
      55              : 
      56              : /* ----------------------------------------------------------------
      57              :     \Cairo\Region Object management
      58              : ------------------------------------------------------------------*/
      59              : 
      60              : /* {{{ */
      61           47 : static void cairo_region_free_obj(zend_object *object)
      62              : {
      63           47 :     cairo_region_object *intern = cairo_region_fetch_object(object);
      64              : 
      65           47 :     if (!intern) {
      66            0 :         return;
      67              :     }
      68              : 
      69           47 :     if (intern->region) {
      70           44 :         cairo_region_destroy(intern->region);
      71           44 :         intern->region = NULL;
      72              :     }
      73              : 
      74           47 :     zend_object_std_dtor(&intern->std);
      75              : }
      76              : 
      77              : /* {{{ */
      78           47 : static zend_object* cairo_region_obj_ctor(zend_class_entry *ce, cairo_region_object **intern)
      79              : {
      80           47 :     cairo_region_object *object = ecalloc(1, sizeof(cairo_region_object) + zend_object_properties_size(ce));
      81              : 
      82           47 :     object->region = NULL;
      83              : 
      84           47 :     zend_object_std_init(&object->std, ce);
      85           47 :     object->std.handlers = &cairo_region_object_handlers;
      86           47 :     *intern = object;
      87              : 
      88           47 :     return &object->std;
      89              : }
      90              : /* }}} */
      91              : 
      92              : /* {{{ */
      93           45 : static zend_object* cairo_region_create_object(zend_class_entry *ce)
      94              : {
      95           45 :     cairo_region_object *region_obj = NULL;
      96           45 :     zend_object *return_value = cairo_region_obj_ctor(ce, ®ion_obj);
      97              : 
      98           45 :     object_properties_init(®ion_obj->std, ce);
      99           45 :     return return_value;
     100              : }
     101              : /* }}} */
     102              : 
     103              : /* {{{ */
     104            2 : static zend_object* cairo_region_clone_obj(zend_object *old_object)
     105              : {
     106              :     cairo_region_object *new_region;
     107            2 :     cairo_region_object *old_region = cairo_region_fetch_object(old_object);
     108            2 :     zend_object *return_value = cairo_region_obj_ctor(old_object->ce, &new_region);
     109              : 
     110            2 :     new_region->region = old_region->region;
     111            2 :     cairo_region_reference(old_region->region);
     112              : 
     113            2 :     zend_objects_clone_members(&new_region->std, &old_region->std);
     114              : 
     115            2 :     return return_value;
     116              : }
     117              : /* }}} */
     118              : 
     119              : 
     120              : /* ----------------------------------------------------------------
     121              :     \Cairo\Region Class API
     122              : ------------------------------------------------------------------ */
     123              : 
     124              : /* {{{ proto void __contruct([void | Cairo\Rectangle $rect | array Cairo\Rectangle $rects])
     125              :     Creates a new region - optionally with a single or union of multiple rectangles inside */
     126           45 : PHP_METHOD(Cairo_Region, __construct)
     127              : {
     128              :     cairo_region_object *region_object;
     129           45 :     zval *rectangles_zval = NULL;
     130           45 :     long num_rectangles = 0;
     131              :     HashTable *rectangles_hash;
     132              :     cairo_rectangle_t *rectangle;
     133              :     cairo_rectangle_int_t *rectangles_array;
     134              :     cairo_rectangle_int_t int_rect;
     135           45 :     int i = 0;
     136              :     zval *pzval;
     137              : 
     138           45 :     ZEND_PARSE_PARAMETERS_START(0, 1)
     139           44 :         Z_PARAM_OPTIONAL
     140           44 :         Z_PARAM_ZVAL(rectangles_zval)
     141           47 :     ZEND_PARSE_PARAMETERS_END();
     142              : 
     143           88 :     region_object = Z_CAIRO_REGION_P(getThis());
     144           44 :     if (!region_object) {
     145            0 :         RETURN_NULL();
     146              :     }
     147              : 
     148           44 :     if (rectangles_zval == NULL) {
     149           17 :         region_object->region = cairo_region_create();
     150           54 :     } else if (Z_TYPE_P(rectangles_zval) == IS_OBJECT) {
     151           19 :         rectangle = cairo_rectangle_object_get_rect(rectangles_zval);
     152           19 :         cairo_expand_to_rectangle_int(rectangle, &int_rect);
     153           19 :         region_object->region = cairo_region_create_rectangle(&int_rect);
     154           16 :     } else if (Z_TYPE_P(rectangles_zval) == IS_ARRAY) {
     155              : 
     156              :         /* Grab the zend hash and see how big our array will be */
     157            7 :         rectangles_hash = Z_ARRVAL_P(rectangles_zval);
     158            7 :         num_rectangles = zend_hash_num_elements(rectangles_hash);
     159            7 :         rectangles_array = ecalloc(num_rectangles, sizeof(cairo_rectangle_int_t));
     160              : 
     161              :         /* iterate over the array*/
     162           34 :         ZEND_HASH_FOREACH_VAL(rectangles_hash, pzval) {
     163           14 :             if (Z_TYPE_P(pzval) != IS_OBJECT || Z_OBJCE_P(pzval) != ce_cairo_rectangle) {
     164            1 :                 zend_throw_exception(zend_ce_type_error, "Cairo\\Region::__construct(): Argument #1 ($rectangle) must be empty, a Cairo\\Rectangle object, or an array of Cairo\\Rectangle objects.", 0);
     165            1 :                 efree(rectangles_array);
     166            1 :                 RETURN_THROWS();
     167              :             }
     168           13 :             cairo_expand_to_rectangle_int(cairo_rectangle_object_get_rect(pzval), &int_rect);
     169           13 :             rectangles_array[i++] = int_rect;
     170              :         } ZEND_HASH_FOREACH_END();
     171              : 
     172            6 :         region_object->region = cairo_region_create_rectangles(rectangles_array, i);
     173            6 :         efree(rectangles_array);
     174              : 
     175              :     } else {
     176            1 :         zend_throw_exception(zend_ce_type_error, "Cairo\\Region::__construct(): Argument #1 ($rectangle) must be empty, a Cairo\\Rectangle object, or an array of Cairo\\Rectangle objects.", 0);
     177            1 :         RETURN_THROWS();
     178              :     }
     179              : 
     180           42 :     if (php_cairo_throw_exception(cairo_region_status(region_object->region))) {
     181            0 :         RETURN_THROWS();
     182              :     }
     183              : }
     184              : /* }}} */
     185              : 
     186              : /* {{{ proto \Cairo\Status \Cairo\Region::getStatus()
     187              :    Checks whether an error has previous occurred for this region object. Returns CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY */
     188            2 : PHP_METHOD(Cairo_Region, getStatus)
     189              : {
     190              :     cairo_region_object *region_object;
     191              :     zval status_case;
     192              : 
     193            3 :     ZEND_PARSE_PARAMETERS_NONE();
     194              : 
     195            2 :     region_object = cairo_region_object_get(getThis());
     196            1 :     if (!region_object) {
     197            0 :         RETURN_THROWS();
     198              :     }
     199              : 
     200            1 :     status_case = php_enum_from_cairo_c_enum(
     201              :         ce_cairo_status,
     202            1 :         cairo_region_status(region_object->region)
     203              :     );
     204              : 
     205            1 :     if (Z_TYPE(status_case) == IS_OBJECT) {
     206            2 :         RETURN_ZVAL(&status_case, 1, 1);
     207              :     }
     208              : }
     209              : /* }}} */
     210              : 
     211              : /* {{{ proto long \Cairo\Region::getExtents()
     212              :    Gets the bounding rectangle of a region. Returns a \Cairo\Rectangle. */
     213           27 : PHP_METHOD(Cairo_Region, getExtents)
     214              : {
     215              :     cairo_region_object *region_object;
     216              :     cairo_rectangle_object *rectangle_object;
     217              :     cairo_rectangle_int_t int_rect;
     218              : 
     219           27 :     ZEND_PARSE_PARAMETERS_NONE();
     220              : 
     221           52 :     region_object = cairo_region_object_get(getThis());
     222           26 :     if (!region_object) {
     223            0 :         RETURN_THROWS();
     224              :     }
     225              : 
     226           26 :     cairo_region_get_extents(region_object->region, &int_rect);
     227              : 
     228           26 :     object_init_ex(return_value, php_cairo_get_rectangle_ce());
     229           26 :     rectangle_object = Z_CAIRO_RECTANGLE_P(return_value);
     230           26 :     cairo_rectangle_int_to_double(&int_rect, rectangle_object->rect);
     231              : }
     232              : /* }}} */
     233              : 
     234              : /* {{{ proto long \Cairo\Region::getNumRectangles()
     235              :    Returns the number of rectangles contained in region. */
     236           27 : PHP_METHOD(Cairo_Region, getNumRectangles)
     237              : {
     238              :     cairo_region_object *region_object;
     239              : 
     240           27 :     ZEND_PARSE_PARAMETERS_NONE();
     241              : 
     242           52 :     region_object = cairo_region_object_get(getThis());
     243           26 :     if (!region_object) {
     244            0 :         RETURN_THROWS();
     245              :     }
     246              : 
     247           26 :     RETVAL_LONG(cairo_region_num_rectangles(region_object->region));
     248              : }
     249              : /* }}} */
     250              : 
     251              : /* {{{ proto long \Cairo\Region::getRectangle(int number).
     252              :    Returns the nth rectangle in region or false if rectangle does not exist. */
     253            5 : PHP_METHOD(Cairo_Region, getRectangle)
     254              : {
     255              :     zend_long rect_id;
     256              :     cairo_region_object *region_object;
     257              :     cairo_rectangle_object *rectangle_object;
     258              :     cairo_rectangle_int_t int_rect;
     259              : 
     260            5 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     261           10 :         Z_PARAM_LONG(rect_id)
     262            5 :     ZEND_PARSE_PARAMETERS_END();
     263              : 
     264            8 :     region_object = cairo_region_object_get(getThis());
     265            4 :     if (!region_object) {
     266            0 :         RETURN_THROWS();
     267              :     }
     268              : 
     269            4 :     if ((int) rect_id > cairo_region_num_rectangles(region_object->region) - 1) {
     270            1 :         RETURN_FALSE;
     271              :     }
     272              : 
     273            3 :     cairo_region_get_rectangle(region_object->region, (int) rect_id, &int_rect);
     274              : 
     275            3 :     object_init_ex(return_value, php_cairo_get_rectangle_ce());
     276            3 :     rectangle_object = Z_CAIRO_RECTANGLE_P(return_value);
     277            3 :     cairo_rectangle_int_to_double(&int_rect, rectangle_object->rect);
     278              : }
     279              : /* }}} */
     280              : 
     281              : /* {{{ proto bool \Cairo\Region::isEmpty()
     282              :    Checks whether region is empty. Returns TRUE if region is empty, FALSE if it isn't. */
     283            2 : PHP_METHOD(Cairo_Region, isEmpty)
     284              : {
     285              :     cairo_region_object *region_object;
     286              : 
     287            2 :     ZEND_PARSE_PARAMETERS_NONE();
     288              : 
     289            2 :     region_object = cairo_region_object_get(getThis());
     290            1 :     if (!region_object) {
     291            0 :         RETURN_THROWS();
     292              :     }
     293              : 
     294            1 :     RETVAL_BOOL(cairo_region_is_empty(region_object->region));
     295              : }
     296              : /* }}} */
     297              : 
     298              : /* {{{ proto long \Cairo\Region::containsPoint(long x, long y)
     299              :    Checks whether (x, y) is contained in region. Returns TRUE if (x, y) is contained in region, FALSE if it is not. */
     300           11 : PHP_METHOD(Cairo_Region, containsPoint)
     301              : {
     302              :     zend_long x, y;
     303              :     cairo_region_object *region_object;
     304              : 
     305           11 :     ZEND_PARSE_PARAMETERS_START(2, 2)
     306           18 :         Z_PARAM_LONG(x)
     307           18 :         Z_PARAM_LONG(y)
     308           11 :     ZEND_PARSE_PARAMETERS_END();
     309              : 
     310           18 :     region_object = cairo_region_object_get(getThis());
     311            9 :     if (!region_object) {
     312            0 :         RETURN_THROWS();
     313              :     }
     314              : 
     315            9 :     RETVAL_BOOL(cairo_region_contains_point(region_object->region, (int) x, (int) y));
     316              : }
     317              : /* }}} */
     318              : 
     319              : /* {{{ proto \Cairo\Region\Overlap \Cairo\Region::containsRectangle(Cairo\Rectangle $rect)
     320              :    Checks whether rectangle is inside, outside or partially contained in region.
     321              :    Returns OVERLAP::IN if rectangle is entirely inside region,
     322              :    OVERLAP::OUT if rectangle is entirely outside region, or
     323              :    OVERLAP::PART if rectangle is partially inside and partially outside region. */
     324            7 : PHP_METHOD(Cairo_Region, containsRectangle)
     325              : {
     326              :     cairo_rectangle_object *rectangle_object;
     327              :     cairo_region_object *region_object;
     328              :     zval *rectangle_zval;
     329              :     zval region_overlap_case;
     330              :     cairo_rectangle_int_t int_rect;
     331              : 
     332            7 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     333           10 :         Z_PARAM_OBJECT_OF_CLASS(rectangle_zval, ce_cairo_rectangle)
     334           11 :     ZEND_PARSE_PARAMETERS_END();
     335              : 
     336            8 :     region_object = cairo_region_object_get(getThis());
     337            4 :     if (!region_object) {
     338            0 :         RETURN_THROWS();
     339              :     }
     340              : 
     341            4 :     rectangle_object = Z_CAIRO_RECTANGLE_P(rectangle_zval);
     342            4 :     if (!rectangle_object) {
     343            0 :         RETURN_NULL();
     344              :     }
     345              : 
     346            4 :     cairo_expand_to_rectangle_int(rectangle_object->rect, &int_rect);
     347              : 
     348            4 :     region_overlap_case = php_enum_from_cairo_c_enum(
     349              :         ce_cairo_region_overlap,
     350            4 :         cairo_region_contains_rectangle(region_object->region, &int_rect)
     351              :     );
     352              : 
     353            4 :     if (Z_TYPE(region_overlap_case) == IS_OBJECT) {
     354            8 :         RETURN_ZVAL(®ion_overlap_case, 1, 1);
     355              :     }
     356              : }
     357              : /* }}} */
     358              : 
     359              : /* {{{ proto long \Cairo\Region::equal(\Cairo\Region region)
     360              :    Compares whether region_a is equivalent to region_b. NULL as an argument is equal to itself, but not to any non-NULL region. */
     361            7 : PHP_METHOD(Cairo_Region, equal)
     362              : {
     363            7 :     zval *other_region = NULL;
     364              :     cairo_region_object *region_obj, *other_region_obj;
     365              : 
     366            7 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     367           12 :         Z_PARAM_OBJECT_OF_CLASS_OR_NULL(other_region, ce_cairo_region)
     368            8 :     ZEND_PARSE_PARAMETERS_END();
     369              : 
     370           10 :     region_obj = cairo_region_object_get(getThis());
     371            5 :     if (!region_obj) {
     372            0 :         RETURN_THROWS();
     373              :     }
     374              : 
     375            5 :     if (other_region == NULL) {
     376            1 :         RETURN_TRUE;
     377              :     }
     378              : 
     379            4 :     other_region_obj = Z_CAIRO_REGION_P(other_region);
     380            4 :     RETVAL_BOOL(cairo_region_equal(region_obj->region, other_region_obj->region));
     381              : }
     382              : /* }}} */
     383              : 
     384              : /* {{{ proto long \Cairo\Region::translate(long dx, long dy)
     385              :    Translates region by (dx, dy). */
     386            5 : PHP_METHOD(Cairo_Region, translate)
     387              : {
     388              :     zend_long dx, dy;
     389              :     cairo_region_object *region_object;
     390              : 
     391            5 :     ZEND_PARSE_PARAMETERS_START(2, 2)
     392            4 :         Z_PARAM_LONG(dx)
     393            4 :         Z_PARAM_LONG(dy)
     394            5 :     ZEND_PARSE_PARAMETERS_END();
     395              : 
     396            4 :     region_object = cairo_region_object_get(getThis());
     397            2 :     if (!region_object) {
     398            0 :         RETURN_THROWS();
     399              :     }
     400              : 
     401            2 :     cairo_region_translate(region_object->region, (int) dx, (int) dy);
     402            2 :     if (php_cairo_throw_exception(cairo_region_status(region_object->region))) {
     403            0 :         RETURN_THROWS();
     404              :     }
     405              : }
     406              : /* }}} */
     407              : 
     408              : /* {{{ proto \Cairo\Status \Cairo\Region::intersect(\Cairo\Region other_region)
     409              :    Computes the intersection with other_region and stores the result. */
     410            4 : PHP_METHOD(Cairo_Region, intersect)
     411              : {
     412              :     cairo_region_object *region_obj, *other_region_obj;
     413              :     zval *other_region;
     414              :     zval status_case;
     415              : 
     416            4 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     417            6 :         Z_PARAM_OBJECT_OF_CLASS(other_region, ce_cairo_region)
     418            6 :     ZEND_PARSE_PARAMETERS_END();
     419              : 
     420            4 :     region_obj = cairo_region_object_get(getThis());
     421            2 :     if (!region_obj) {
     422            0 :         RETURN_THROWS();
     423              :     }
     424              : 
     425            2 :     other_region_obj = Z_CAIRO_REGION_P(other_region);
     426              : 
     427            2 :     status_case = php_enum_from_cairo_c_enum(
     428              :         ce_cairo_status,
     429            2 :         cairo_region_intersect(region_obj->region, other_region_obj->region)
     430              :     );
     431              : 
     432            2 :     if (Z_TYPE(status_case) == IS_OBJECT) {
     433            4 :         RETURN_ZVAL(&status_case, 1, 1);
     434              :     }
     435              : }
     436              : /* }}} */
     437              : 
     438              : /* {{{ proto \Cairo\Status \Cairo\Region::intersectRectangle(Cairo\Rectangle $rect)
     439              :    Computes the intersection with rectangle and stores the result. */
     440            3 : PHP_METHOD(Cairo_Region, intersectRectangle)
     441              : {
     442              :     cairo_rectangle_object *rectangle_object;
     443              :     cairo_region_object *region_object;
     444              :     zval *rectangle_zval;
     445              :     zval status_case;
     446              :     cairo_rectangle_int_t int_rect;
     447              : 
     448            3 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     449            4 :         Z_PARAM_OBJECT_OF_CLASS(rectangle_zval, ce_cairo_rectangle)
     450            4 :     ZEND_PARSE_PARAMETERS_END();
     451              : 
     452            2 :     region_object = cairo_region_object_get(getThis());
     453            1 :     if (!region_object) {
     454            0 :         RETURN_THROWS();
     455              :     }
     456              : 
     457            1 :     rectangle_object = Z_CAIRO_RECTANGLE_P(rectangle_zval);
     458            1 :     if (!rectangle_object) {
     459            0 :         RETURN_NULL();
     460              :     }
     461              : 
     462            1 :     cairo_expand_to_rectangle_int(rectangle_object->rect, &int_rect);
     463              : 
     464            1 :     status_case = php_enum_from_cairo_c_enum(
     465              :         ce_cairo_status,
     466            1 :         cairo_region_intersect_rectangle(region_object->region, &int_rect)
     467              :     );
     468              : 
     469            1 :     if (Z_TYPE(status_case) == IS_OBJECT) {
     470            2 :         RETURN_ZVAL(&status_case, 1, 1);
     471              :     }
     472              : }
     473              : /* }}} */
     474              : 
     475              : /* {{{ proto \Cairo\Status \Cairo\Region::subtract(\Cairo\Region other_region)
     476              :    Subtracts other_region and stores the result. */
     477            4 : PHP_METHOD(Cairo_Region, subtract)
     478              : {
     479              :     zval *other_region;
     480              :     cairo_region_object *region_obj, *other_region_obj;
     481              :     zval status_case;
     482              : 
     483            4 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     484            6 :         Z_PARAM_OBJECT_OF_CLASS(other_region, ce_cairo_region)
     485            6 :     ZEND_PARSE_PARAMETERS_END();
     486              : 
     487            4 :     region_obj = cairo_region_object_get(getThis());
     488            2 :     if (!region_obj) {
     489            0 :         RETURN_THROWS();
     490              :     }
     491              : 
     492            2 :     other_region_obj = Z_CAIRO_REGION_P(other_region);
     493              : 
     494            2 :     status_case = php_enum_from_cairo_c_enum(
     495              :         ce_cairo_status,
     496            2 :         cairo_region_subtract(region_obj->region, other_region_obj->region)
     497              :     );
     498              : 
     499            2 :     if (Z_TYPE(status_case) == IS_OBJECT) {
     500            4 :         RETURN_ZVAL(&status_case, 1, 1);
     501              :     }
     502              : }
     503              : /* }}} */
     504              : 
     505              : /* {{{ proto \Cairo\Status \Cairo\Region::subtractRectangle(Cairo\Rectangle $rect)
     506              :    Subtracts rectangle from region and stores the result. */
     507            3 : PHP_METHOD(Cairo_Region, subtractRectangle)
     508              : {
     509              :     zval *rectangle_zval;
     510              :     cairo_rectangle_object *rectangle_object;
     511              :     cairo_region_object *region_object;
     512              :     zval status_case;
     513              :     cairo_rectangle_int_t int_rect;
     514              : 
     515            3 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     516            4 :         Z_PARAM_OBJECT_OF_CLASS(rectangle_zval, ce_cairo_rectangle)
     517            4 :     ZEND_PARSE_PARAMETERS_END();
     518              : 
     519            2 :     region_object = cairo_region_object_get(getThis());
     520            1 :     if (!region_object) {
     521            0 :         RETURN_THROWS();
     522              :     }
     523              : 
     524            1 :     rectangle_object = Z_CAIRO_RECTANGLE_P(rectangle_zval);
     525            1 :     if (!rectangle_object) {
     526            0 :         RETURN_NULL();
     527              :     }
     528              : 
     529            1 :     cairo_expand_to_rectangle_int(rectangle_object->rect, &int_rect);
     530              : 
     531            1 :     status_case = php_enum_from_cairo_c_enum(
     532              :         ce_cairo_status,
     533            1 :         cairo_region_subtract_rectangle(region_object->region, &int_rect)
     534              :     );
     535              : 
     536            1 :     if (Z_TYPE(status_case) == IS_OBJECT) {
     537            2 :         RETURN_ZVAL(&status_case, 1, 1);
     538              :     }
     539              : }
     540              : /* }}} */
     541              : 
     542              : /* {{{ proto \Cairo\Status \Cairo\Region::union(\Cairo\Region other_region)
     543              :    Computes the union with other_region and stores the result. */
     544            4 : PHP_METHOD(Cairo_Region, union)
     545              : {
     546              :     zval *other_region;
     547              :     cairo_region_object *region_obj, *other_region_obj;
     548              :     zval status_case;
     549              : 
     550            4 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     551            6 :         Z_PARAM_OBJECT_OF_CLASS(other_region, ce_cairo_region)
     552            6 :     ZEND_PARSE_PARAMETERS_END();
     553              : 
     554            4 :     region_obj = cairo_region_object_get(getThis());
     555            2 :     if (!region_obj) {
     556            0 :         RETURN_THROWS();
     557              :     }
     558              : 
     559            2 :     other_region_obj = Z_CAIRO_REGION_P(other_region);
     560              : 
     561            2 :     status_case = php_enum_from_cairo_c_enum(
     562              :         ce_cairo_status,
     563            2 :         cairo_region_union(region_obj->region, other_region_obj->region)
     564              :     );
     565              : 
     566            2 :     if (Z_TYPE(status_case) == IS_OBJECT) {
     567            4 :         RETURN_ZVAL(&status_case, 1, 1);
     568              :     }
     569              : }
     570              : /* }}} */
     571              : 
     572              : /* {{{ proto \Cairo\Status \Cairo\Region::unionRectangle(Cairo\Rectangle $rect)
     573              :    Computes the union of region with rectangle and stores the result. */
     574            4 : PHP_METHOD(Cairo_Region, unionRectangle)
     575              : {
     576              :     zval *rectangle_zval;
     577              :     cairo_rectangle_object *rectangle_object;
     578              :     cairo_region_object *region_object;
     579              :     zval status_case;
     580              :     cairo_rectangle_int_t int_rect;
     581              : 
     582            4 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     583            6 :         Z_PARAM_OBJECT_OF_CLASS(rectangle_zval, ce_cairo_rectangle)
     584            6 :     ZEND_PARSE_PARAMETERS_END();
     585              : 
     586            4 :     region_object = cairo_region_object_get(getThis());
     587            2 :     if (!region_object) {
     588            0 :         RETURN_THROWS();
     589              :     }
     590              : 
     591            2 :     rectangle_object = Z_CAIRO_RECTANGLE_P(rectangle_zval);
     592            2 :     if (!rectangle_object) {
     593            0 :         RETURN_NULL();
     594              :     }
     595              : 
     596            2 :     cairo_expand_to_rectangle_int(rectangle_object->rect, &int_rect);
     597              : 
     598            2 :     status_case = php_enum_from_cairo_c_enum(
     599              :         ce_cairo_status,
     600            2 :         cairo_region_union_rectangle(region_object->region, &int_rect)
     601              :     );
     602              : 
     603            2 :     if (Z_TYPE(status_case) == IS_OBJECT) {
     604            4 :         RETURN_ZVAL(&status_case, 1, 1);
     605              :     }
     606              : }
     607              : /* }}} */
     608              : 
     609              : /* {{{ proto \Cairo\Status \Cairo\Region::xor(\Cairo\Region other_region)
     610              :    Computes the exclusive difference with other_region and stores the result.
     611              :    That is, region will be set to contain all areas that are either in region or in other_region, but not in both. */
     612            4 : PHP_METHOD(Cairo_Region, xor)
     613              : {
     614              :     zval *other_region;
     615              :     cairo_region_object *region_obj, *other_region_obj;
     616              :     zval status_case;
     617              : 
     618            4 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     619            6 :         Z_PARAM_OBJECT_OF_CLASS(other_region, ce_cairo_region)
     620            6 :     ZEND_PARSE_PARAMETERS_END();
     621              : 
     622            4 :     region_obj = cairo_region_object_get(getThis());
     623            2 :     if (!region_obj) {
     624            0 :         RETURN_THROWS();
     625              :     }
     626              : 
     627            2 :     other_region_obj = Z_CAIRO_REGION_P(other_region);
     628              : 
     629            2 :     status_case = php_enum_from_cairo_c_enum(
     630              :         ce_cairo_status,
     631            2 :         cairo_region_xor(region_obj->region, other_region_obj->region)
     632              :     );
     633              : 
     634            2 :     if (Z_TYPE(status_case) == IS_OBJECT) {
     635            4 :         RETURN_ZVAL(&status_case, 1, 1);
     636              :     }
     637              : }
     638              : /* }}} */
     639              : 
     640              : /* {{{ proto \Cairo\Status \Cairo\Region::xorRectangle(Cairo\Rectangle $rect)
     641              :    Computes the exclusive difference of region with rectangle and stores the result.
     642              :    That is, region will be set to contain all areas that are either in region or in rectangle, but not in both. */
     643            4 : PHP_METHOD(Cairo_Region, xorRectangle)
     644              : {
     645              :     zval *rectangle_zval;
     646              :     cairo_rectangle_object *rectangle_object;
     647              :     cairo_region_object *region_object;
     648              :     zval status_case;
     649              :     cairo_rectangle_int_t int_rect;
     650              : 
     651            4 :     ZEND_PARSE_PARAMETERS_START(1, 1)
     652            6 :         Z_PARAM_OBJECT_OF_CLASS(rectangle_zval, ce_cairo_rectangle)
     653            6 :     ZEND_PARSE_PARAMETERS_END();
     654              : 
     655            4 :     region_object = cairo_region_object_get(getThis());
     656            2 :     if (!region_object) {
     657            0 :         RETURN_THROWS();
     658              :     }
     659              : 
     660            2 :     rectangle_object = Z_CAIRO_RECTANGLE_P(rectangle_zval);
     661            2 :     if (!rectangle_object) {
     662            0 :         RETURN_NULL();
     663              :     }
     664              : 
     665            2 :     cairo_expand_to_rectangle_int(rectangle_object->rect, &int_rect);
     666              : 
     667            2 :     status_case = php_enum_from_cairo_c_enum(
     668              :         ce_cairo_status,
     669            2 :         cairo_region_xor_rectangle(region_object->region, &int_rect)
     670              :     );
     671              : 
     672            2 :     if (Z_TYPE(status_case) == IS_OBJECT) {
     673            4 :         RETURN_ZVAL(&status_case, 1, 1);
     674              :     }
     675              : }
     676              : /* }}} */
     677              : 
     678              : 
     679              : /* ----------------------------------------------------------------
     680              :     \Cairo\Region Definition and registration
     681              : ------------------------------------------------------------------*/
     682              : 
     683              : 
     684              : /* {{{ PHP_MINIT_FUNCTION */
     685          433 : PHP_MINIT_FUNCTION(cairo_region)
     686              : {
     687          433 :     memcpy(
     688              :         &cairo_region_object_handlers,
     689              :         zend_get_std_object_handlers(),
     690              :         sizeof(zend_object_handlers)
     691              :     );
     692              : 
     693          433 :     cairo_region_object_handlers.offset = XtOffsetOf(cairo_region_object, std);
     694          433 :     cairo_region_object_handlers.free_obj = cairo_region_free_obj;
     695          433 :     cairo_region_object_handlers.clone_obj = cairo_region_clone_obj;
     696              : 
     697          433 :     ce_cairo_region = register_class_Cairo_Region();
     698          433 :     ce_cairo_region->create_object = cairo_region_create_object;
     699              : 
     700              :     /* Region\Overlap */
     701          433 :     ce_cairo_region_overlap = register_class_Cairo_Region_Overlap();
     702              : 
     703          433 :     return SUCCESS;
     704              : }
         |