/** * _cairo_traps_extract_region: * @traps: a #cairo_traps_t * @region: a #cairo_region_t * * Determines if a set of trapezoids are exactly representable as a * cairo region. If so, the passed-in region is initialized to * the area representing the given traps. It should be finalized * with cairo_region_fini(). If not, %CAIRO_INT_STATUS_UNSUPPORTED * is returned. * * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED * or %CAIRO_STATUS_NO_MEMORY **/ cairo_int_status_t _cairo_traps_extract_region (cairo_traps_t *traps, cairo_antialias_t antialias, cairo_region_t **region) { cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; cairo_rectangle_int_t *rects = stack_rects; cairo_int_status_t status; int i, rect_count; /* we only treat this a hint... */ if (antialias != CAIRO_ANTIALIAS_NONE && ! traps->maybe_region) return CAIRO_INT_STATUS_UNSUPPORTED; if (! _traps_are_pixel_aligned (traps, antialias)) { traps->maybe_region = FALSE; return CAIRO_INT_STATUS_UNSUPPORTED; } if (traps->num_traps > ARRAY_LENGTH (stack_rects)) { rects = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_rectangle_int_t)); if (unlikely (rects == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } rect_count = 0; for (i = 0; i < traps->num_traps; i++) { int x1, y1, x2, y2; if (antialias == CAIRO_ANTIALIAS_NONE) { x1 = _cairo_fixed_integer_round_down (traps->traps[i].left.p1.x); y1 = _cairo_fixed_integer_round_down (traps->traps[i].top); x2 = _cairo_fixed_integer_round_down (traps->traps[i].right.p1.x); y2 = _cairo_fixed_integer_round_down (traps->traps[i].bottom); } else { x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x); y1 = _cairo_fixed_integer_part (traps->traps[i].top); x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x); y2 = _cairo_fixed_integer_part (traps->traps[i].bottom); } if (x2 > x1 && y2 > y1) { rects[rect_count].x = x1; rects[rect_count].y = y1; rects[rect_count].width = x2 - x1; rects[rect_count].height = y2 - y1; rect_count++; } } *region = cairo_region_create_rectangles (rects, rect_count); status = (*region)->status; if (rects != stack_rects) free (rects); return status; }
static void update_shape (GtkWidget* window, gint radius, gint shadow_size) { if (g_composited) { /* remove any current shape-mask */ gtk_widget_input_shape_combine_region (window, NULL); return; } int width; int height; gtk_widget_get_size_request (window, &width, &height); const cairo_rectangle_int_t rects[] = {{2, 0, width - 4, height}, {1, 1, width - 2, height - 2}, {0, 2, width, height - 4}}; cairo_region_t* region = NULL; region = cairo_region_create_rectangles (rects, 3); if (cairo_region_status (region) == CAIRO_STATUS_SUCCESS) { gtk_widget_shape_combine_region (window, NULL); gtk_widget_shape_combine_region (window, region); } }
cairo_region_t * meta_region_transform (cairo_region_t *region, MetaMonitorTransform transform, int width, int height) { int n_rects, i; cairo_rectangle_int_t *rects; cairo_region_t *transformed_region; if (transform == META_MONITOR_TRANSFORM_NORMAL) return cairo_region_copy (region); n_rects = cairo_region_num_rectangles (region); rects = g_new0 (cairo_rectangle_int_t, n_rects); for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rects[i]); meta_rectangle_transform (&rects[i], transform, width, height, &rects[i]); } transformed_region = cairo_region_create_rectangles (rects, n_rects); g_free (rects); return transformed_region; }
cairo_region_t * meta_region_scale (cairo_region_t *region, int scale) { int n_rects, i; cairo_rectangle_int_t *rects; cairo_region_t *scaled_region; if (scale == 1) return cairo_region_copy (region); n_rects = cairo_region_num_rectangles (region); rects = g_malloc (sizeof(cairo_rectangle_int_t) * n_rects); for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rects[i]); rects[i].x *= scale; rects[i].y *= scale; rects[i].width *= scale; rects[i].height *= scale; } scaled_region = cairo_region_create_rectangles (rects, n_rects); g_free (rects); return scaled_region; }
cairo_region_t * meta_region_scale_double (cairo_region_t *region, double scale, MetaRoundingStrategy rounding_strategy) { int n_rects, i; cairo_rectangle_int_t *rects; cairo_region_t *scaled_region; g_return_val_if_fail (scale > 0.0, NULL); if (scale == 1.0) return cairo_region_copy (region); n_rects = cairo_region_num_rectangles (region); rects = g_malloc (sizeof(cairo_rectangle_int_t) * n_rects); for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rects[i]); meta_rectangle_scale_double (&rects[i], scale, rounding_strategy, &rects[i]); } scaled_region = cairo_region_create_rectangles (rects, n_rects); g_free (rects); return scaled_region; }
cairo_region_t * meta_region_crop_and_scale (cairo_region_t *region, ClutterRect *src_rect, int dst_width, int dst_height) { int n_rects, i; cairo_rectangle_int_t *rects; cairo_region_t *viewport_region; if (src_rect->size.width == dst_width && src_rect->size.height == dst_height && roundf (src_rect->origin.x) == src_rect->origin.x && roundf (src_rect->origin.y) == src_rect->origin.y) { viewport_region = cairo_region_copy (region); if (src_rect->origin.x != 0 || src_rect->origin.y != 0) { cairo_region_translate (viewport_region, (int) src_rect->origin.x, (int) src_rect->origin.y); } return viewport_region; } n_rects = cairo_region_num_rectangles (region); rects = g_new0 (cairo_rectangle_int_t, n_rects); for (i = 0; i < n_rects; i++) { cairo_region_get_rectangle (region, i, &rects[i]); meta_rectangle_crop_and_scale (&rects[i], src_rect, dst_width, dst_height, &rects[i]); } viewport_region = cairo_region_create_rectangles (rects, n_rects); g_free (rects); return viewport_region; }
static cairo_region_t * region_from_rects (BroadwayRect *rects, int n_rects) { cairo_region_t *region; cairo_rectangle_int_t *cairo_rects; int i; cairo_rects = g_new (cairo_rectangle_int_t, n_rects); for (i = 0; i < n_rects; i++) { cairo_rects[i].x = rects[i].x; cairo_rects[i].y = rects[i].y; cairo_rects[i].width = rects[i].width; cairo_rects[i].height = rects[i].height; } region = cairo_region_create_rectangles (cairo_rects, n_rects); g_free (cairo_rects); return region; }
/* This special-case filler supports only a path that describes a * device-axis aligned rectangle. It exists to avoid the overhead of * the general tessellator when drawing very common rectangles. * * If the path described anything but a device-axis aligned rectangle, * this function will abort. */ cairo_region_t * _cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, const cairo_rectangle_int_t *extents) { cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; cairo_box_t box; cairo_region_t *region = NULL; assert (path->maybe_fill_region); assert (! path->is_empty_fill); if (_cairo_path_fixed_is_box (path, &box)) { rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x); rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y); rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) - rectangle_stack[0].x; rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) - rectangle_stack[0].y; if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents)) region = cairo_region_create (); else region = cairo_region_create_rectangle (&rectangle_stack[0]); } else if (fill_rule == CAIRO_FILL_RULE_WINDING) { cairo_rectangle_int_t *rects = rectangle_stack; cairo_path_fixed_iter_t iter; int last_cw = -1; int size = ARRAY_LENGTH (rectangle_stack); int count = 0; /* Support a series of rectangles as can be expected to describe a * GdkRegion clip region during exposes. */ _cairo_path_fixed_iter_init (&iter, path); while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { int cw = 0; if (box.p1.x > box.p2.x) { cairo_fixed_t t; t = box.p1.x; box.p1.x = box.p2.x; box.p2.x = t; cw = ! cw; } if (box.p1.y > box.p2.y) { cairo_fixed_t t; t = box.p1.y; box.p1.y = box.p2.y; box.p2.y = t; cw = ! cw; } if (last_cw < 0) last_cw = cw; else if (last_cw != cw) goto TESSELLATE; if (count == size) { cairo_rectangle_int_t *new_rects; size *= 4; if (rects == rectangle_stack) { new_rects = _cairo_malloc_ab (size, sizeof (cairo_rectangle_int_t)); if (unlikely (new_rects == NULL)) { /* XXX _cairo_region_nil */ break; } memcpy (new_rects, rects, sizeof (rectangle_stack)); } else { new_rects = _cairo_realloc_ab (rects, size, sizeof (cairo_rectangle_int_t)); if (unlikely (new_rects == NULL)) { /* XXX _cairo_region_nil */ break; } } rects = new_rects; } rects[count].x = _cairo_fixed_integer_part (box.p1.x); rects[count].y = _cairo_fixed_integer_part (box.p1.y); rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x; rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y; if (_cairo_rectangle_intersect (&rects[count], extents)) count++; } if (_cairo_path_fixed_iter_at_end (&iter)) region = cairo_region_create_rectangles (rects, count); TESSELLATE: if (rects != rectangle_stack) free (rects); } if (region == NULL) { /* Hmm, complex polygon */ region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path, fill_rule, extents); } return region; }
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; }