static VALUE
cr_clip_rectangle_list (VALUE self)
{
  VALUE rb_rectangles;
  cairo_rectangle_list_t *rectangles;
  int i;

  rectangles = cairo_copy_clip_rectangle_list (_SELF);
  rb_cairo_check_status (rectangles->status);

  rb_rectangles = rb_ary_new2 (rectangles->num_rectangles);
  for (i = 0; i < rectangles->num_rectangles; i++) {
    VALUE argv[4];
    cairo_rectangle_t rectangle = rectangles->rectangles[i];

    argv[0] = rb_float_new (rectangle.x);
    argv[1] = rb_float_new (rectangle.y);
    argv[2] = rb_float_new (rectangle.width);
    argv[3] = rb_float_new (rectangle.height);
    rb_ary_push (rb_rectangles,
                 rb_class_new_instance (4, argv, rb_cCairo_Rectangle));
  }
  cairo_rectangle_list_destroy (rectangles);

  return rb_rectangles;
}
Example #2
0
static PyObject *
pycairo_copy_clip_rectangle_list (PycairoContext *o) {
  int i;
  PyObject *rv = NULL;
  cairo_rectangle_t *r;
  cairo_rectangle_list_t *rlist = cairo_copy_clip_rectangle_list (o->ctx);
  if (rlist->status != CAIRO_STATUS_SUCCESS) {
    Pycairo_Check_Status (rlist->status);
    goto exit;
  }

  rv = PyTuple_New(rlist->num_rectangles);
  if (rv == NULL)
    goto exit;

  for (i = 0, r = rlist->rectangles; i < rlist->num_rectangles; i++, r++) {
    PyObject *py_rect = Py_BuildValue("(dddd)", r->x, r->y,
				      r->width, r->height);
    if (py_rect == NULL) {
      Py_CLEAR(rv);
      goto exit;
    }
    PyTuple_SET_ITEM (rv, i, py_rect);
  }
 exit:
  cairo_rectangle_list_destroy(rlist);
  return rv;
}
Example #3
0
bool
gfxContext::ClipContainsRect(const gfxRect& aRect)
{
    cairo_rectangle_list_t *clip =
        cairo_copy_clip_rectangle_list(mCairo);

    bool result = false;

    if (clip->status == CAIRO_STATUS_SUCCESS) {
        for (int i = 0; i < clip->num_rectangles; i++) {
            gfxRect rect(clip->rectangles[i].x, clip->rectangles[i].y,
                         clip->rectangles[i].width, clip->rectangles[i].height);
            if (rect.Contains(aRect)) {
                result = PR_TRUE;
                break;
            }
        }
    }

   cairo_rectangle_list_destroy(clip);
   return result;
}
static bool
_get_rectangular_clip (cairo_t *cr,
                       const nsIntRect& bounds,
                       bool *need_clip,
                       nsIntRect *rectangles, int max_rectangles,
                       int *num_rectangles)
{
    cairo_rectangle_list_t *cliplist;
    cairo_rectangle_t *clips;
    int i;
    bool retval = true;

    cliplist = cairo_copy_clip_rectangle_list (cr);
    if (cliplist->status != CAIRO_STATUS_SUCCESS) {
        retval = false;
        NATIVE_DRAWING_NOTE("FALLBACK: non-rectangular clip");
        goto FINISH;
    }

    /* the clip is always in surface backend coordinates (i.e. native backend coords) */
    clips = cliplist->rectangles;

    for (i = 0; i < cliplist->num_rectangles; ++i) {
        
        nsIntRect rect;
        if (!_convert_coord_to_int (clips[i].x, &rect.x) ||
            !_convert_coord_to_int (clips[i].y, &rect.y) ||
            !_convert_coord_to_int (clips[i].width, &rect.width) ||
            !_convert_coord_to_int (clips[i].height, &rect.height))
        {
            retval = false;
            NATIVE_DRAWING_NOTE("FALLBACK: non-integer clip");
            goto FINISH;
        }

        if (rect.IsEqualInterior(bounds)) {
            /* the bounds are entirely inside the clip region so we don't need to clip. */
            *need_clip = false;
            goto FINISH;
        }            

        NS_ASSERTION(bounds.Contains(rect),
                     "Was expecting to be clipped to bounds");

        if (i >= max_rectangles) {
            retval = false;
            NATIVE_DRAWING_NOTE("FALLBACK: unsupported clip rectangle count");
            goto FINISH;
        }

        rectangles[i] = rect;
    }
  
    *need_clip = true;
    *num_rectangles = cliplist->num_rectangles;

FINISH:
    cairo_rectangle_list_destroy (cliplist);

    return retval;
}
static void
gimp_display_shell_canvas_draw_image (GimpDisplayShell *shell,
                                      cairo_t          *cr)
{
  cairo_rectangle_list_t *clip_rectangles;
  cairo_rectangle_int_t   image_rect;

  image_rect.x = - shell->offset_x;
  image_rect.y = - shell->offset_y;
  gimp_display_shell_scale_get_image_size (shell,
                                           &image_rect.width,
                                           &image_rect.height);


  /*  first, clear the exposed part of the region that is outside the
   *  image, which is the exposed region minus the image rectangle
   */

  cairo_save (cr);

  if (shell->rotate_transform)
    cairo_transform (cr, shell->rotate_transform);

  cairo_rectangle (cr,
                   image_rect.x,
                   image_rect.y,
                   image_rect.width,
                   image_rect.height);

  cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
  cairo_clip (cr);

  if (gdk_cairo_get_clip_rectangle (cr, NULL))
    gimp_display_shell_draw_background (shell, cr);

  cairo_restore (cr);


  /*  then, draw the exposed part of the region that is inside the
   *  image
   */

  cairo_save (cr);
  clip_rectangles = cairo_copy_clip_rectangle_list (cr);

  if (shell->rotate_transform)
    cairo_transform (cr, shell->rotate_transform);

  cairo_rectangle (cr,
                   image_rect.x,
                   image_rect.y,
                   image_rect.width,
                   image_rect.height);
  cairo_clip (cr);

  if (gdk_cairo_get_clip_rectangle (cr, NULL))
    {
      gint i;

      cairo_save (cr);
      gimp_display_shell_draw_checkerboard (shell, cr);
      cairo_restore (cr);

      for (i = 0; i < clip_rectangles->num_rectangles; i++)
        {
          cairo_rectangle_t rect = clip_rectangles->rectangles[i];

          gimp_display_shell_draw_image (shell, cr,
                                         floor (rect.x),
                                         floor (rect.y),
                                         ceil (rect.width),
                                         ceil (rect.height));
        }
    }

  cairo_rectangle_list_destroy (clip_rectangles);
  cairo_restore (cr);


  /*  finally, draw all the remaining image window stuff on top
   */

  /* draw canvas items */
  cairo_save (cr);

  if (shell->rotate_transform)
    cairo_transform (cr, shell->rotate_transform);

  gimp_canvas_item_draw (shell->canvas_item, cr);

  cairo_restore (cr);

  gimp_canvas_item_draw (shell->unrotated_item, cr);

  /* restart (and recalculate) the selection boundaries */
  gimp_display_shell_selection_restart (shell);
}
Example #6
0
static cairo_test_status_t
preamble (cairo_test_context_t *ctx)
{
    cairo_surface_t        *surface;
    cairo_t                *cr;
    cairo_rectangle_list_t *rectangle_list;
    const char             *phase;
    cairo_status_t          status;

    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
    cr = cairo_create (surface);
    cairo_surface_destroy (surface);


    /* first, test basic stuff. This should not be clipped, it should
       return the surface rectangle. */
    phase = "No clip set";
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
    if (! check_count (ctx, phase, rectangle_list, 1) ||
        ! check_clip_extents (ctx, phase, cr, 0, 0, 100, 100) ||
        ! check_rectangles_contain (ctx, phase, rectangle_list, 0, 0, 100, 100))
    {
	goto FAIL;
    }
    cairo_rectangle_list_destroy (rectangle_list);

    /* Test simple clip rect. */
    phase = "Simple clip rect";
    cairo_save (cr);
    cairo_rectangle (cr, 10, 10, 80, 80);
    cairo_clip (cr);
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
    if (! check_count (ctx, phase, rectangle_list, 1) ||
        ! check_clip_extents (ctx, phase, cr, 10, 10, 80, 80) ||
        ! check_rectangles_contain (ctx, phase, rectangle_list, 10, 10, 80, 80))
    {
	goto FAIL;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr);

    /* Test everything clipped out. */
    phase = "All clipped out";
    cairo_save (cr);
    cairo_clip (cr);
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
    if (! check_count (ctx, phase, rectangle_list, 0))
    {
	goto FAIL;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr);

    /* test two clip rects */
    phase = "Two clip rects";
    cairo_save (cr);
    cairo_rectangle (cr, 10, 10, 10, 10);
    cairo_rectangle (cr, 20, 20, 10, 10);
    cairo_clip (cr);
    cairo_rectangle (cr, 15, 15, 10, 10);
    cairo_clip (cr);
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
    if (! check_count (ctx, phase, rectangle_list, 2) ||
        ! check_clip_extents (ctx, phase, cr, 15, 15, 10, 10) ||
        ! check_rectangles_contain (ctx, phase, rectangle_list, 15, 15, 5, 5) ||
        ! check_rectangles_contain (ctx, phase, rectangle_list, 20, 20, 5, 5))
    {
	goto FAIL;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr);

    /* test non-rectangular clip */
    phase = "Nonrectangular clip";
    cairo_save (cr);
    cairo_move_to (cr, 0, 0);
    cairo_line_to (cr, 100, 100);
    cairo_line_to (cr, 100, 0);
    cairo_close_path (cr);
    cairo_clip (cr);
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
     /* can't get this in one tight user-space rectangle */
    if (! check_unrepresentable (ctx, phase, rectangle_list) ||
        ! check_clip_extents (ctx, phase, cr, 0, 0, 100, 100))
    {
	goto FAIL;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr);

    phase = "User space, simple scale, getting clip with same transform";
    cairo_save (cr);
    cairo_scale (cr, 2, 2);
    cairo_rectangle (cr, 5, 5, 40, 40);
    cairo_clip (cr);
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
    if (! check_count (ctx, phase, rectangle_list, 1) ||
        ! check_clip_extents (ctx, phase, cr, 5, 5, 40, 40) ||
        ! check_rectangles_contain (ctx, phase, rectangle_list, 5, 5, 40, 40))
    {
	goto FAIL;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr);

    phase = "User space, simple scale, getting clip with no transform";
    cairo_save (cr);
    cairo_save (cr);
    cairo_scale (cr, 2, 2);
    cairo_rectangle (cr, 5, 5, 40, 40);
    cairo_restore (cr);
    cairo_clip (cr);
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
    if (! check_count (ctx, phase, rectangle_list, 1) ||
        ! check_clip_extents (ctx, phase, cr, 10, 10, 80, 80) ||
        ! check_rectangles_contain (ctx, phase, rectangle_list, 10, 10, 80, 80))
    {
	goto FAIL;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr);

    phase = "User space, rotation, getting clip with no transform";
    cairo_save (cr);
    cairo_save (cr);
    cairo_rotate (cr, 12);
    cairo_rectangle (cr, 5, 5, 40, 40);
    cairo_restore (cr);
    cairo_clip (cr);
    rectangle_list = cairo_copy_clip_rectangle_list (cr);
    if (! check_unrepresentable (ctx, phase, rectangle_list))
	goto FAIL;

FAIL:
    cairo_rectangle_list_destroy (rectangle_list);
    status = cairo_status (cr);
    cairo_destroy (cr);

    return cairo_test_status_from_status (ctx, status);
}
Example #7
0
static gboolean
goc_canvas_draw (GtkWidget *widget, cairo_t *cr)
{
	double x0, y0, x1, y1;
	double ax0, ay0, ax1, ay1;
	double clip_x1, clip_y1, clip_x2, clip_y2;
	GocCanvas *canvas = GOC_CANVAS (widget);
	GdkEventExpose *event = (GdkEventExpose *) gtk_get_current_event ();
	GocCanvasPrivate *priv = (GocCanvasPrivate *) canvas->priv;
	cairo_rectangle_list_t *l = cairo_copy_clip_rectangle_list (cr);
	int i, x, y;

	if (GOC_IS_ITEM (priv->invalidated_item) && priv->invalid_region) {
		/* evaluate the cairo clipped region and compare with the saved one */
		cairo_region_t *region;
		cairo_rectangle_int_t rect[l->num_rectangles];
	    for (i= 0; i  < l->num_rectangles; i++) {
			rect[i].x = l->rectangles[i].x;
			rect[i].y = l->rectangles[i].y;
			rect[i].width = l->rectangles[i].width;
			rect[i].height = l->rectangles[i].height;
		}
		region = cairo_region_create_rectangles (rect, l->num_rectangles);
		if (cairo_region_equal (priv->invalid_region, region)) {
			cairo_rectangle_list_destroy (l);
			cairo_region_destroy (region);
			/* looks like each time we call gtk_widget_queue_draw*,
			   the draw event is fired twice */
			if (priv->done) {
				priv->invalidated_item = NULL;
				cairo_region_destroy (priv->invalid_region);
				priv->invalid_region = NULL;
			} else {
				goc_item_draw (priv->invalidated_item, cr);
				priv->done = TRUE;
			}
			return TRUE;
		}

		cairo_region_destroy (region);
	}

	x = gtk_adjustment_get_value (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas)));
	y = gtk_adjustment_get_value (gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas)));
	cairo_translate (cr, -x, -y);
	goc_item_get_bounds (GOC_ITEM (canvas->root),&x0, &y0, &x1, &y1);
	for (i= 0; i  < l->num_rectangles; i++) {
		cairo_save (cr);
		cairo_rectangle (cr, l->rectangles[i].x, l->rectangles[i].y,
		                 l->rectangles[i].width, l->rectangles[i].height);
		cairo_clip (cr);
		clip_x1 = l->rectangles[i].x;
		clip_y1 = l->rectangles[i].y;
		clip_x2 = clip_x1 + l->rectangles[i].width;
		clip_y2 = clip_y1 + l->rectangles[i].height;

		if (canvas->direction == GOC_DIRECTION_RTL) {
			ax1 = (double) (canvas->width - clip_x1) / canvas->pixels_per_unit + canvas->scroll_x1;
			ax0 = (double) (canvas->width - clip_x2) / canvas->pixels_per_unit + canvas->scroll_x1;
		} else {
			ax0 = (double) clip_x1 / canvas->pixels_per_unit + canvas->scroll_x1;
			ax1 = ((double) clip_x1 + event->area.width) / canvas->pixels_per_unit + canvas->scroll_x1;
		}
		ay0 = (double) clip_y1 / canvas->pixels_per_unit + canvas->scroll_y1;
		ay1 = (double) clip_y2 / canvas->pixels_per_unit + canvas->scroll_y1;
		if (x0 <= ax1 && x1 >= ax0 && y0 <= ay1 && y1 >= ay0) {
			canvas->cur_event = (GdkEvent *) event;
			goc_item_draw_region (GOC_ITEM (canvas->root), cr, ax0, ay0, ax1, ay1);
		}
		cairo_restore (cr);
	}
	cairo_rectangle_list_destroy (l);
	return TRUE;
}
Example #8
0
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
    const cairo_test_context_t *ctx = cairo_test_get_context (cr);
    cairo_surface_t        *surface;
    cairo_t                *cr2;
    cairo_rectangle_list_t *rectangle_list;
    const char             *phase;
    cairo_bool_t            uses_clip_rects;
    
    surface = cairo_surface_create_similar (cairo_get_group_target (cr),
                                            CAIRO_CONTENT_COLOR, 100, 100);
    /* don't use cr accidentally */
    cr = NULL;
    cr2 = cairo_create (surface);
    cairo_surface_destroy (surface);

    /* Check the surface type so we ignore cairo_copy_clip_rectangle_list failures
     * on surface types that don't use rectangle lists for clipping.
     * Default to FALSE for the internal surface types, (meta, test-fallback, etc.)
     */
    switch (cairo_surface_get_type (surface)) {
    case CAIRO_SURFACE_TYPE_IMAGE:
    case CAIRO_SURFACE_TYPE_XLIB:
    case CAIRO_SURFACE_TYPE_XCB:
    case CAIRO_SURFACE_TYPE_GLITZ:
    case CAIRO_SURFACE_TYPE_WIN32:
    case CAIRO_SURFACE_TYPE_BEOS:
    case CAIRO_SURFACE_TYPE_DIRECTFB:
        uses_clip_rects = TRUE;
	break;
    case CAIRO_SURFACE_TYPE_QUARTZ:
    case CAIRO_SURFACE_TYPE_PDF:
    case CAIRO_SURFACE_TYPE_PS:
    case CAIRO_SURFACE_TYPE_SVG:
    case CAIRO_SURFACE_TYPE_OS2:
    default:
        uses_clip_rects = FALSE;
        break;
    }

    /* first, test basic stuff. This should not be clipped, it should
       return the surface rectangle. */
    phase = "No clip set";
    rectangle_list = cairo_copy_clip_rectangle_list (cr2);
    if (!check_count (ctx, phase, uses_clip_rects, rectangle_list, 1) ||
        !check_clip_extents (ctx, phase, cr2, 0, 0, 100, 100) ||
        !check_rectangles_contain (ctx, phase, uses_clip_rects, rectangle_list, 0, 0, 100, 100)) {
        cairo_rectangle_list_destroy (rectangle_list);
	return CAIRO_TEST_FAILURE;
    }
    cairo_rectangle_list_destroy (rectangle_list);

    /* Test simple clip rect. */
    phase = "Simple clip rect";
    cairo_save (cr2);
    cairo_rectangle (cr2, 10, 10, 80, 80);
    cairo_clip (cr2);
    rectangle_list = cairo_copy_clip_rectangle_list (cr2);
    if (!check_count (ctx, phase, uses_clip_rects, rectangle_list, 1) ||
        !check_clip_extents (ctx, phase, cr2, 10, 10, 80, 80) ||
        !check_rectangles_contain (ctx, phase, uses_clip_rects, rectangle_list, 10, 10, 80, 80)) {
        cairo_rectangle_list_destroy (rectangle_list);
	return CAIRO_TEST_FAILURE;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr2);

    /* Test everything clipped out. */
    phase = "All clipped out";
    cairo_save (cr2);
    cairo_clip (cr2);
    rectangle_list = cairo_copy_clip_rectangle_list (cr2);
    if (!check_count (ctx, phase, uses_clip_rects, rectangle_list, 0)) {
        cairo_rectangle_list_destroy (rectangle_list);
	return CAIRO_TEST_FAILURE;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr2);
    
    /* test two clip rects */
    phase = "Two clip rects";
    cairo_save (cr2);
    cairo_rectangle (cr2, 10, 10, 10, 10);
    cairo_rectangle (cr2, 20, 20, 10, 10);
    cairo_clip (cr2);
    cairo_rectangle (cr2, 15, 15, 10, 10);
    cairo_clip (cr2);
    rectangle_list = cairo_copy_clip_rectangle_list (cr2);
    if (!check_count (ctx, phase, uses_clip_rects, rectangle_list, 2) ||
        !check_clip_extents (ctx, phase, cr2, 15, 15, 10, 10) ||
        !check_rectangles_contain (ctx, phase, uses_clip_rects, rectangle_list, 15, 15, 5, 5) ||
        !check_rectangles_contain (ctx, phase, uses_clip_rects, rectangle_list, 20, 20, 5, 5)) {
        cairo_rectangle_list_destroy (rectangle_list);
	return CAIRO_TEST_FAILURE;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr2);

    /* test non-rectangular clip */
    phase = "Nonrectangular clip";
    cairo_save (cr2);
    cairo_move_to (cr2, 0, 0);
    cairo_line_to (cr2, 100, 100);
    cairo_line_to (cr2, 100, 0);
    cairo_close_path (cr2);
    cairo_clip (cr2);
    rectangle_list = cairo_copy_clip_rectangle_list (cr2);
     /* can't get this in one tight user-space rectangle */
    if (!check_unrepresentable (ctx, phase, rectangle_list) ||
        !check_clip_extents (ctx, phase, cr2, 0, 0, 100, 100)) {
        cairo_rectangle_list_destroy (rectangle_list);
	return CAIRO_TEST_FAILURE;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr2);
    
    phase = "User space, simple scale, getting clip with same transform";
    cairo_save (cr2);
    cairo_scale (cr2, 2, 2);
    cairo_rectangle (cr2, 5, 5, 40, 40);
    cairo_clip (cr2);
    rectangle_list = cairo_copy_clip_rectangle_list (cr2);
    if (!check_count (ctx, phase, uses_clip_rects, rectangle_list, 1) ||
        !check_clip_extents (ctx, phase, cr2, 5, 5, 40, 40) ||
        !check_rectangles_contain (ctx, phase, uses_clip_rects, rectangle_list, 5, 5, 40, 40)) {
        cairo_rectangle_list_destroy (rectangle_list);
	return CAIRO_TEST_FAILURE;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr2);

    phase = "User space, simple scale, getting clip with no transform";
    cairo_save (cr2);
    cairo_save (cr2);
    cairo_scale (cr2, 2, 2);
    cairo_rectangle (cr2, 5, 5, 40, 40);
    cairo_restore (cr2);
    cairo_clip (cr2);
    rectangle_list = cairo_copy_clip_rectangle_list (cr2);
    if (!check_count (ctx, phase, uses_clip_rects, rectangle_list, 1) ||
        !check_clip_extents (ctx, phase, cr2, 10, 10, 80, 80) ||
        !check_rectangles_contain (ctx, phase, uses_clip_rects, rectangle_list, 10, 10, 80, 80)) {
        cairo_rectangle_list_destroy (rectangle_list);
	return CAIRO_TEST_FAILURE;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr2);

    phase = "User space, rotation, getting clip with no transform";
    cairo_save (cr2);
    cairo_save (cr2);
    cairo_rotate (cr2, 12);
    cairo_rectangle (cr2, 5, 5, 40, 40);
    cairo_restore (cr2);
    cairo_clip (cr2);
    rectangle_list = cairo_copy_clip_rectangle_list (cr2);
    if (!check_unrepresentable (ctx, phase, rectangle_list)) {
        cairo_rectangle_list_destroy (rectangle_list);
	return CAIRO_TEST_FAILURE;
    }
    cairo_rectangle_list_destroy (rectangle_list);
    cairo_restore (cr2);

    cairo_destroy (cr2);
    return CAIRO_TEST_SUCCESS;
}
static cairo_bool_t
_get_rectangular_clip (cairo_t *cr,
                       int bounds_x, int bounds_y,
                       int bounds_width, int bounds_height,
                       cairo_bool_t *need_clip,
                       XRectangle *rectangles, int max_rectangles,
                       int *num_rectangles)
{
    cairo_rectangle_list_t *cliplist;
    cairo_rectangle_t *clips;
    int i;
    double b_x = bounds_x;
    double b_y = bounds_y;
    double b_x_most = bounds_x + bounds_width;
    double b_y_most = bounds_y + bounds_height;
    int rect_count = 0;
    cairo_bool_t retval = True;

    cliplist = cairo_copy_clip_rectangle_list (cr);
    if (cliplist->status != CAIRO_STATUS_SUCCESS) {
        retval = False;
        goto FINISH;
    }

    if (cliplist->num_rectangles == 0) {
        *num_rectangles = 0;
        *need_clip = True;
        goto FINISH;
    }

    clips = cliplist->rectangles;

    for (i = 0; i < cliplist->num_rectangles; ++i) {
        double intersect_x, intersect_y, intersect_x_most, intersect_y_most;
        
        /* the clip is always in surface backend coordinates (i.e. native backend coords) */
        if (b_x >= clips[i].x && b_x_most <= clips[i].x + clips[i].width &&
            b_y >= clips[i].y && b_y_most <= clips[i].y + clips[i].height) {
            /* the bounds are entirely inside the clip region so we don't need to clip. */
            *need_clip = False;
            goto FINISH;
        }
        
        if (_intersect_interval (b_x, b_x_most, clips[i].x, clips[i].x + clips[i].width,
                                 &intersect_x, &intersect_x_most) &&
            _intersect_interval (b_y, b_y_most, clips[i].y, clips[i].y + clips[i].height,
                                 &intersect_y, &intersect_y_most)) {
            XRectangle *rect = &rectangles[rect_count];

            if (rect_count >= max_rectangles) {
                retval = False;
                goto FINISH;
            }

            if (!_convert_coord_to_short (intersect_x, &rect->x) ||
                !_convert_coord_to_short (intersect_y, &rect->y) ||
                !_convert_coord_to_unsigned_short (intersect_x_most - intersect_x, &rect->width) ||
                !_convert_coord_to_unsigned_short (intersect_y_most - intersect_y, &rect->height))
            {
                retval = False;
                goto FINISH;
            }

            ++rect_count;
        }
    }
  
    *need_clip = True;
    *num_rectangles = rect_count;

FINISH:
    cairo_rectangle_list_destroy (cliplist);

    return retval;
}