static cairo_int_status_t _cairo_xcb_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; cairo_composite_rectangles_t composite; cairo_int_status_t status; status = _cairo_composite_rectangles_init_for_stroke (&composite, &surface->base, op, source, path, style, ctm, clip); if (unlikely (status)) return status; if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_stroke (surface, op, source, path, style, ctm, ctm_inverse, tolerance, antialias, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto done; status = _cairo_xcb_surface_render_stroke (surface, op, source, path, style, ctm, ctm_inverse, tolerance, antialias, &composite); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto done; } status = _cairo_surface_stroke (_cairo_xcb_surface_fallback (surface, &composite), op, source, path, style, ctm, ctm_inverse, tolerance, antialias, clip); done: _cairo_composite_rectangles_fini (&composite); return status; }
cairo_int_status_t _cairo_compositor_stroke (const cairo_compositor_t *compositor, cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; cairo_int_status_t status; TRACE ((stderr, "%s\n", __FUNCTION__)); if (_cairo_pen_vertices_needed (tolerance, style->line_width/2, ctm) <= 1) return CAIRO_INT_STATUS_NOTHING_TO_DO; status = _cairo_composite_rectangles_init_for_stroke (&extents, surface, op, source, path, style, ctm, clip); if (unlikely (status)) return status; do { while (compositor->stroke == XNULL) compositor = compositor->delegate; status = compositor->stroke (compositor, &extents, path, style, ctm, ctm_inverse, tolerance, antialias); compositor = compositor->delegate; } while (status == CAIRO_INT_STATUS_UNSUPPORTED); if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) { TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n", __FUNCTION__, extents.unbounded.x, extents.unbounded.y, extents.unbounded.width, extents.unbounded.height)); surface->damage = _cairo_damage_add_rectangle (surface->damage, &extents.unbounded); } _cairo_composite_rectangles_fini (&extents); return status; }
static cairo_int_status_t _cairo_xcb_surface_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; cairo_composite_rectangles_t composite; cairo_int_status_t status; cairo_bool_t overlap; status = _cairo_composite_rectangles_init_for_glyphs (&composite, &surface->base, op, source, scaled_font, glyphs, num_glyphs, clip, &overlap); if (unlikely (status)) return status; if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_glyphs (surface, op, source, scaled_font, glyphs, num_glyphs, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto done; status = _cairo_xcb_surface_render_glyphs (surface, op, source, scaled_font, glyphs, num_glyphs, &composite, overlap); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto done; } status = _cairo_surface_show_text_glyphs (_cairo_xcb_surface_fallback (surface, &composite), op, source, NULL, 0, glyphs, num_glyphs, NULL, 0, 0, scaled_font, clip); done: _cairo_composite_rectangles_fini (&composite); 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; }
static cairo_int_status_t _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents, const cairo_clip_t *clip) { if ((!_cairo_rectangle_intersect (&extents->bounded, &extents->mask)) && (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)) return CAIRO_INT_STATUS_NOTHING_TO_DO; if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE)) { extents->unbounded = extents->bounded; } else if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) { if (!_cairo_rectangle_intersect (&extents->unbounded, &extents->mask)) return CAIRO_INT_STATUS_NOTHING_TO_DO; } extents->clip = _cairo_clip_reduce_for_composite (clip, extents); if (_cairo_clip_is_all_clipped (extents->clip)) return CAIRO_INT_STATUS_NOTHING_TO_DO; if (! _cairo_rectangle_intersect (&extents->unbounded, _cairo_clip_get_extents (extents->clip))) return CAIRO_INT_STATUS_NOTHING_TO_DO; if (! _cairo_rectangle_intersect (&extents->bounded, _cairo_clip_get_extents (extents->clip)) && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) { return CAIRO_INT_STATUS_NOTHING_TO_DO; } if (extents->source_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) _cairo_pattern_sampled_area (&extents->source_pattern.base, &extents->bounded, &extents->source_sample_area); if (extents->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) { _cairo_pattern_sampled_area (&extents->mask_pattern.base, &extents->bounded, &extents->mask_sample_area); if (extents->mask_sample_area.width == 0 || extents->mask_sample_area.height == 0) { _cairo_composite_rectangles_fini (extents); return CAIRO_INT_STATUS_NOTHING_TO_DO; } } return CAIRO_STATUS_SUCCESS; }
cairo_int_status_t _cairo_compositor_glyphs (const cairo_compositor_t *compositor, cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_glyph_t *glyphs, int num_glyphs, cairo_scaled_font_t *scaled_font, const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; cairo_bool_t overlap; cairo_int_status_t status; TRACE ((stderr, "%s\n", __FUNCTION__)); status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface, op, source, scaled_font, glyphs, num_glyphs, clip, &overlap); if (unlikely (status)) return status; do { while (compositor->glyphs == NULL) compositor = compositor->delegate; status = compositor->glyphs (compositor, &extents, scaled_font, glyphs, num_glyphs, overlap); compositor = compositor->delegate; } while (status == CAIRO_INT_STATUS_UNSUPPORTED); if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) { TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n", __FUNCTION__, extents.unbounded.x, extents.unbounded.y, extents.unbounded.width, extents.unbounded.height)); surface->damage = _cairo_damage_add_rectangle (surface->damage, &extents.unbounded); } _cairo_composite_rectangles_fini (&extents); return status; }
cairo_int_status_t _cairo_compositor_fill (const cairo_compositor_t *compositor, cairo_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, const cairo_clip_t *clip) { cairo_composite_rectangles_t extents; cairo_int_status_t status; TRACE ((stderr, "%s\n", __FUNCTION__)); status = _cairo_composite_rectangles_init_for_fill (&extents, surface, op, source, path, clip); if (unlikely (status)) return status; do { while (compositor->fill == XNULL) compositor = compositor->delegate; status = compositor->fill (compositor, &extents, path, fill_rule, tolerance, antialias); compositor = compositor->delegate; } while (status == CAIRO_INT_STATUS_UNSUPPORTED); if (status == CAIRO_INT_STATUS_SUCCESS && surface->damage) { TRACE ((stderr, "%s: applying damage (%d,%d)x(%d, %d)\n", __FUNCTION__, extents.unbounded.x, extents.unbounded.y, extents.unbounded.width, extents.unbounded.height)); surface->damage = _cairo_damage_add_rectangle (surface->damage, &extents.unbounded); } _cairo_composite_rectangles_fini (&extents); return status; }
static cairo_int_status_t fixup_unbounded_mask (const cairo_spans_compositor_t *compositor, const cairo_composite_rectangles_t *extents, cairo_boxes_t *boxes) { cairo_composite_rectangles_t composite; cairo_surface_t *clip; cairo_int_status_t status; TRACE((stderr, "%s\n", __FUNCTION__)); clip = get_clip_surface (compositor, extents->surface, extents->clip, &extents->unbounded); if (unlikely (clip->status)) { if ((cairo_int_status_t)clip->status == CAIRO_INT_STATUS_NOTHING_TO_DO) return CAIRO_STATUS_SUCCESS; return clip->status; } status = _cairo_composite_rectangles_init_for_boxes (&composite, extents->surface, CAIRO_OPERATOR_CLEAR, &_cairo_pattern_clear.base, boxes, NULL); if (unlikely (status)) goto cleanup_clip; _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip); composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST; composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE; status = composite_boxes (compositor, &composite, boxes); _cairo_pattern_fini (&composite.mask_pattern.base); _cairo_composite_rectangles_fini (&composite); cleanup_clip: cairo_surface_destroy (clip); return status; }
static cairo_int_status_t _cairo_xcb_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; cairo_composite_rectangles_t composite; cairo_int_status_t status; status = _cairo_composite_rectangles_init_for_mask (&composite, &surface->base, op, source, mask, clip); if (unlikely (status)) return status; if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_mask (surface, op, source, mask, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto done; status = _cairo_xcb_surface_render_mask (surface, op, source, mask, &composite); if (status != CAIRO_INT_STATUS_UNSUPPORTED) goto done; } status = _cairo_surface_mask (_cairo_xcb_surface_fallback (surface, &composite), op, source, mask, clip); done: _cairo_composite_rectangles_fini (&composite); 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 fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor, const cairo_composite_rectangles_t *extents, cairo_boxes_t *boxes) { cairo_boxes_t tmp, clear; cairo_box_t box; cairo_int_status_t status; assert (boxes->is_pixel_aligned); TRACE ((stderr, "%s\n", __FUNCTION__)); if (extents->bounded.width == extents->unbounded.width && extents->bounded.height == extents->unbounded.height) { return CAIRO_STATUS_SUCCESS; } /* subtract the drawn boxes from the unbounded area */ _cairo_boxes_init (&clear); box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); box.p1.y = _cairo_fixed_from_int (extents->unbounded.y); box.p2.x = _cairo_fixed_from_int (extents->unbounded.x); box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height); if (boxes->num_boxes) { _cairo_boxes_init (&tmp); status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box); assert (status == CAIRO_INT_STATUS_SUCCESS); tmp.chunks.next = &boxes->chunks; tmp.num_boxes += boxes->num_boxes; status = _cairo_bentley_ottmann_tessellate_boxes (&tmp, CAIRO_FILL_RULE_WINDING, &clear); tmp.chunks.next = NULL; if (unlikely (status)) goto error; } else { box.p1.x = _cairo_fixed_from_int (extents->unbounded.x); box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box); assert (status == CAIRO_INT_STATUS_SUCCESS); } /* If we have a clip polygon, we need to intersect with that as well */ if (extents->clip->path) { status = fixup_unbounded_polygon (compositor, extents, &clear); if (status == CAIRO_INT_STATUS_UNSUPPORTED) status = fixup_unbounded_mask (compositor, extents, &clear); } else { /* Otherwise just intersect with the clip boxes */ if (extents->clip->num_boxes) { _cairo_boxes_init_for_array (&tmp, extents->clip->boxes, extents->clip->num_boxes); status = _cairo_boxes_intersect (&clear, &tmp, &clear); if (unlikely (status)) goto error; } if (clear.is_pixel_aligned) { status = compositor->fill_boxes (extents->surface, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, &clear); } else { cairo_composite_rectangles_t composite; status = _cairo_composite_rectangles_init_for_boxes (&composite, extents->surface, CAIRO_OPERATOR_CLEAR, &_cairo_pattern_clear.base, &clear, NULL); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { status = composite_boxes (compositor, &composite, &clear); _cairo_composite_rectangles_fini (&composite); } } } error: _cairo_boxes_fini (&clear); return status; }