static cairo_int_status_t clip_and_composite_polygon (const cairo_spans_compositor_t *compositor, cairo_composite_rectangles_t *extents, cairo_polygon_t *polygon, cairo_fill_rule_t fill_rule, cairo_antialias_t antialias) { cairo_int_status_t status; /* XXX simply uses polygon limits.point extemities, tessellation? */ status = trim_extents_to_polygon (extents, polygon); if (unlikely (status)) return status; if (_cairo_polygon_is_empty (polygon)) { cairo_boxes_t boxes; if (extents->is_bounded) return CAIRO_STATUS_SUCCESS; _cairo_boxes_init (&boxes); extents->bounded.width = extents->bounded.height = 0; return fixup_unbounded_boxes (compositor, extents, &boxes); } if (extents->is_bounded && extents->clip->path) { cairo_polygon_t clipper; cairo_antialias_t clip_antialias; cairo_fill_rule_t clip_fill_rule; status = _cairo_clip_get_polygon (extents->clip, &clipper, &clip_fill_rule, &clip_antialias); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { cairo_clip_t *old_clip; if (clip_antialias == antialias) { /* refresh limits after trimming extents */ _cairo_polygon_limit_to_clip(polygon, extents->clip); status = _cairo_polygon_intersect (polygon, fill_rule, &clipper, clip_fill_rule); _cairo_polygon_fini (&clipper); if (unlikely (status)) return status; old_clip = extents->clip; extents->clip = _cairo_clip_copy_region (extents->clip); _cairo_clip_destroy (old_clip); } else { _cairo_polygon_fini (&clipper); } } } return composite_polygon (compositor, extents, polygon, fill_rule, antialias); }
cairo_status_t _cairo_polygon_intersect_with_boxes (cairo_polygon_t *polygon, cairo_fill_rule_t *winding, cairo_box_t *boxes, int num_boxes) { cairo_polygon_t b; cairo_status_t status; int n; if (num_boxes == 0) { polygon->num_edges = 0; return CAIRO_STATUS_SUCCESS; } for (n = 0; n < num_boxes; n++) { if (polygon->extents.p1.x >= boxes[n].p1.x && polygon->extents.p2.x <= boxes[n].p2.x && polygon->extents.p1.y >= boxes[n].p1.y && polygon->extents.p2.y <= boxes[n].p2.y) { return CAIRO_STATUS_SUCCESS; } } _cairo_polygon_init (&b, NULL, 0); for (n = 0; n < num_boxes; n++) { if (boxes[n].p2.x > polygon->extents.p1.x && boxes[n].p1.x < polygon->extents.p2.x && boxes[n].p2.y > polygon->extents.p1.y && boxes[n].p1.y < polygon->extents.p2.y) { cairo_point_t p1, p2; p1.y = boxes[n].p1.y; p2.y = boxes[n].p2.y; p2.x = p1.x = boxes[n].p1.x; _cairo_polygon_add_external_edge (&b, &p1, &p2); p2.x = p1.x = boxes[n].p2.x; _cairo_polygon_add_external_edge (&b, &p2, &p1); } } status = _cairo_polygon_intersect (polygon, *winding, &b, CAIRO_FILL_RULE_WINDING); _cairo_polygon_fini (&b); *winding = CAIRO_FILL_RULE_WINDING; return status; }
static cairo_int_status_t fixup_unbounded_polygon (const cairo_spans_compositor_t *compositor, const cairo_composite_rectangles_t *extents, cairo_boxes_t *boxes) { cairo_polygon_t polygon, intersect; cairo_composite_rectangles_t composite; cairo_fill_rule_t fill_rule; cairo_antialias_t antialias; cairo_int_status_t status; TRACE((stderr, "%s\n", __FUNCTION__)); /* Can we treat the clip as a regular clear-polygon and use it to fill? */ status = _cairo_clip_get_polygon (extents->clip, &polygon, &fill_rule, &antialias); if (status == CAIRO_INT_STATUS_UNSUPPORTED) return status; status= _cairo_polygon_init_boxes (&intersect, boxes); if (unlikely (status)) goto cleanup_polygon; status = _cairo_polygon_intersect (&polygon, fill_rule, &intersect, CAIRO_FILL_RULE_WINDING); _cairo_polygon_fini (&intersect); if (unlikely (status)) goto cleanup_polygon; status = _cairo_composite_rectangles_init_for_polygon (&composite, extents->surface, CAIRO_OPERATOR_CLEAR, &_cairo_pattern_clear.base, &polygon, NULL); if (unlikely (status)) goto cleanup_polygon; status = composite_polygon (compositor, &composite, &polygon, fill_rule, antialias); _cairo_composite_rectangles_fini (&composite); cleanup_polygon: _cairo_polygon_fini (&polygon); return status; }
cairo_int_status_t _cairo_clip_get_polygon (const cairo_clip_t *clip, cairo_polygon_t *polygon, cairo_fill_rule_t *fill_rule, cairo_antialias_t *antialias) { cairo_status_t status; cairo_clip_path_t *clip_path; if (_cairo_clip_is_all_clipped (clip)) { _cairo_polygon_init (polygon, NULL, 0); return CAIRO_INT_STATUS_SUCCESS; } /* If there is no clip, we need an infinite polygon */ assert (clip && (clip->path || clip->num_boxes)); if (clip->path == NULL) { *fill_rule = CAIRO_FILL_RULE_WINDING; *antialias = CAIRO_ANTIALIAS_DEFAULT; return _cairo_polygon_init_box_array (polygon, clip->boxes, clip->num_boxes); } /* check that residual is all of the same type/tolerance */ if (! can_convert_to_polygon (clip)) return CAIRO_INT_STATUS_UNSUPPORTED; if (clip->num_boxes < 2) _cairo_polygon_init_with_clip (polygon, clip); else _cairo_polygon_init_with_clip (polygon, NULL); clip_path = clip->path; *fill_rule = clip_path->fill_rule; *antialias = clip_path->antialias; status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, polygon); if (unlikely (status)) goto err; if (clip->num_boxes > 1) { status = _cairo_polygon_intersect_with_boxes (polygon, fill_rule, clip->boxes, clip->num_boxes); if (unlikely (status)) goto err; } polygon->limits = NULL; polygon->num_limits = 0; while ((clip_path = clip_path->prev) != NULL) { cairo_polygon_t next; _cairo_polygon_init (&next, NULL, 0); status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &next); if (likely (status == CAIRO_STATUS_SUCCESS)) status = _cairo_polygon_intersect (polygon, *fill_rule, &next, clip_path->fill_rule); _cairo_polygon_fini (&next); if (unlikely (status)) goto err; *fill_rule = CAIRO_FILL_RULE_WINDING; } return CAIRO_STATUS_SUCCESS; err: _cairo_polygon_fini (polygon); return status; }
static cairo_surface_t * get_clip_surface (const cairo_spans_compositor_t *compositor, cairo_surface_t *dst, const cairo_clip_t *clip, const cairo_rectangle_int_t *extents) { cairo_composite_rectangles_t composite; cairo_surface_t *surface; cairo_box_t box; cairo_polygon_t polygon; const cairo_clip_path_t *clip_path; cairo_antialias_t antialias; cairo_fill_rule_t fill_rule; cairo_int_status_t status; assert (clip->path); surface = _cairo_surface_create_similar_solid (dst, CAIRO_CONTENT_ALPHA, extents->width, extents->height, CAIRO_COLOR_TRANSPARENT); _cairo_box_from_rectangle (&box, extents); _cairo_polygon_init (&polygon, &box, 1); clip_path = clip->path; status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &polygon); if (unlikely (status)) goto cleanup_polygon; antialias = clip_path->antialias; fill_rule = clip_path->fill_rule; if (clip->boxes) { cairo_polygon_t intersect; cairo_boxes_t tmp; _cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes); status= _cairo_polygon_init_boxes (&intersect, &tmp); if (unlikely (status)) goto cleanup_polygon; status = _cairo_polygon_intersect (&polygon, fill_rule, &intersect, CAIRO_FILL_RULE_WINDING); _cairo_polygon_fini (&intersect); if (unlikely (status)) goto cleanup_polygon; fill_rule = CAIRO_FILL_RULE_WINDING; } polygon.limits = NULL; polygon.num_limits = 0; clip_path = clip_path->prev; while (clip_path) { if (clip_path->antialias == antialias) { cairo_polygon_t next; _cairo_polygon_init (&next, NULL, 0); status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &next); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = _cairo_polygon_intersect (&polygon, fill_rule, &next, clip_path->fill_rule); _cairo_polygon_fini (&next); if (unlikely (status)) goto cleanup_polygon; fill_rule = CAIRO_FILL_RULE_WINDING; } clip_path = clip_path->prev; } _cairo_polygon_translate (&polygon, -extents->x, -extents->y); status = _cairo_composite_rectangles_init_for_polygon (&composite, surface, CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, &polygon, NULL); if (unlikely (status)) goto cleanup_polygon; status = composite_polygon (compositor, &composite, &polygon, fill_rule, antialias); _cairo_composite_rectangles_fini (&composite); _cairo_polygon_fini (&polygon); if (unlikely (status)) goto error; _cairo_polygon_init (&polygon, &box, 1); clip_path = clip->path; antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT; clip_path = clip_path->prev; while (clip_path) { if (clip_path->antialias == antialias) { if (polygon.num_edges == 0) { status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &polygon); fill_rule = clip_path->fill_rule; polygon.limits = NULL; polygon.num_limits = 0; } else { cairo_polygon_t next; _cairo_polygon_init (&next, NULL, 0); status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &next); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = _cairo_polygon_intersect (&polygon, fill_rule, &next, clip_path->fill_rule); _cairo_polygon_fini (&next); fill_rule = CAIRO_FILL_RULE_WINDING; } if (unlikely (status)) goto error; } clip_path = clip_path->prev; } if (polygon.num_edges) { _cairo_polygon_translate (&polygon, -extents->x, -extents->y); status = _cairo_composite_rectangles_init_for_polygon (&composite, surface, CAIRO_OPERATOR_IN, &_cairo_pattern_white.base, &polygon, NULL); if (unlikely (status)) goto cleanup_polygon; status = composite_polygon (compositor, &composite, &polygon, fill_rule, antialias); _cairo_composite_rectangles_fini (&composite); _cairo_polygon_fini (&polygon); if (unlikely (status)) goto error; } return surface; cleanup_polygon: _cairo_polygon_fini (&polygon); error: cairo_surface_destroy (surface); return _cairo_int_surface_create_in_error (status); }
static cairo_int_status_t clip_and_composite_polygon (const cairo_spans_compositor_t *compositor, cairo_composite_rectangles_t *extents, cairo_polygon_t *polygon, cairo_fill_rule_t fill_rule, cairo_antialias_t antialias) { cairo_int_status_t status; TRACE ((stderr, "%s\n", __FUNCTION__)); /* XXX simply uses polygon limits.point extemities, tessellation? */ status = trim_extents_to_polygon (extents, polygon); if (unlikely (status)) return status; if (_cairo_polygon_is_empty (polygon)) { cairo_boxes_t boxes; if (extents->is_bounded) return CAIRO_STATUS_SUCCESS; _cairo_boxes_init (&boxes); extents->bounded.width = extents->bounded.height = 0; return fixup_unbounded_boxes (compositor, extents, &boxes); } if (extents->is_bounded && extents->clip->path) { cairo_polygon_t clipper; cairo_antialias_t clip_antialias; cairo_fill_rule_t clip_fill_rule; TRACE((stderr, "%s - combining shape with clip polygon\n", __FUNCTION__)); status = _cairo_clip_get_polygon (extents->clip, &clipper, &clip_fill_rule, &clip_antialias); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { cairo_clip_t *old_clip; if (clip_antialias == antialias) { status = _cairo_polygon_intersect (polygon, fill_rule, &clipper, clip_fill_rule); _cairo_polygon_fini (&clipper); if (unlikely (status)) return status; old_clip = extents->clip; extents->clip = _cairo_clip_copy_region (extents->clip); _cairo_clip_destroy (old_clip); status = trim_extents_to_polygon (extents, polygon); if (unlikely (status)) return status; fill_rule = CAIRO_FILL_RULE_WINDING; } else { _cairo_polygon_fini (&clipper); } } } return composite_polygon (compositor, extents, polygon, fill_rule, antialias); }