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); }
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; }
static cairo_int_status_t clip_and_composite_boxes (const cairo_spans_compositor_t *compositor, cairo_composite_rectangles_t *extents, cairo_boxes_t *boxes) { cairo_int_status_t status; cairo_polygon_t polygon; TRACE ((stderr, "%s\n", __FUNCTION__)); status = trim_extents_to_boxes (extents, boxes); if (unlikely (status)) return status; if (boxes->num_boxes == 0) { if (extents->is_bounded) return CAIRO_STATUS_SUCCESS; return fixup_unbounded_boxes (compositor, extents, boxes); } /* Can we reduce drawing through a clip-mask to simply drawing the clip? */ if (extents->clip->path != NULL && extents->is_bounded) { cairo_polygon_t polygon; cairo_fill_rule_t fill_rule; cairo_antialias_t antialias; cairo_clip_t *clip; clip = _cairo_clip_copy (extents->clip); clip = _cairo_clip_intersect_boxes (clip, boxes); if (_cairo_clip_is_all_clipped (clip)) return CAIRO_INT_STATUS_NOTHING_TO_DO; status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias); _cairo_clip_path_destroy (clip->path); clip->path = NULL; if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { cairo_clip_t *saved_clip = extents->clip; extents->clip = clip; status = clip_and_composite_polygon (compositor, extents, &polygon, fill_rule, antialias); clip = extents->clip; extents->clip = saved_clip; _cairo_polygon_fini (&polygon); } _cairo_clip_destroy (clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } if (boxes->is_pixel_aligned) { status = composite_aligned_boxes (compositor, extents, boxes); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } status = composite_boxes (compositor, extents, boxes); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; status = _cairo_polygon_init_boxes (&polygon, boxes); if (unlikely (status)) return status; status = composite_polygon (compositor, extents, &polygon, CAIRO_FILL_RULE_WINDING, CAIRO_ANTIALIAS_DEFAULT); _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); }