cairo_status_t _cairo_surface_fallback_fill (cairo_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_status_t status; cairo_traps_t traps; cairo_box_t box; cairo_rectangle_int_t extents; status = _cairo_surface_get_extents (surface, &extents); if (status) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); if (status) return status; _cairo_rectangle_intersect (&extents, &source_extents); } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); if (status) return status; box.p1.x = _cairo_fixed_from_int (extents.x); box.p1.y = _cairo_fixed_from_int (extents.y); box.p2.x = _cairo_fixed_from_int (extents.x + extents.width); box.p2.y = _cairo_fixed_from_int (extents.y + extents.height); _cairo_traps_init (&traps); _cairo_traps_limit (&traps, &box); status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps); if (status) { _cairo_traps_fini (&traps); return status; } status = _clip_and_composite_trapezoids (source, op, surface, &traps, surface->clip, antialias); _cairo_traps_fini (&traps); return status; }
void _cairo_polygon_translate (cairo_polygon_t *polygon, int dx, int dy) { int n; dx = _cairo_fixed_from_int (dx); dy = _cairo_fixed_from_int (dy); polygon->extents.p1.x += dx; polygon->extents.p2.x += dx; polygon->extents.p1.y += dy; polygon->extents.p2.y += dy; for (n = 0; n < polygon->num_edges; n++) { cairo_edge_t *e = &polygon->edges[n]; e->top += dy; e->bottom += dy; e->line.p1.x += dx; e->line.p2.x += dx; e->line.p1.y += dy; e->line.p2.y += dy; } }
static cairo_status_t span_to_traps (void *abstract_renderer, int y, int h, const cairo_half_open_span_t *spans, unsigned num_spans) { struct cairo_trap_renderer *r = abstract_renderer; cairo_fixed_t top, bot; if (num_spans == 0) return CAIRO_STATUS_SUCCESS; top = _cairo_fixed_from_int (y); bot = _cairo_fixed_from_int (y + h); do { if (spans[0].coverage) { cairo_fixed_t x0 = _cairo_fixed_from_int(spans[0].x); cairo_fixed_t x1 = _cairo_fixed_from_int(spans[1].x); cairo_line_t left = { { x0, top }, { x0, bot } }, right = { { x1, top }, { x1, bot } }; _cairo_traps_add_trap (r->traps, top, bot, &left, &right); } spans++; } while (--num_spans > 1); return CAIRO_STATUS_SUCCESS; }
void _cairo_traps_translate (cairo_traps_t *traps, int x, int y) { cairo_fixed_t xoff, yoff; cairo_trapezoid_t *t; int i; /* Ugh. The cairo_composite/(Render) interface doesn't allow an offset for the trapezoids. Need to manually shift all the coordinates to align with the offset origin of the intermediate surface. */ xoff = _cairo_fixed_from_int (x); yoff = _cairo_fixed_from_int (y); for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) { t->top += yoff; t->bottom += yoff; t->left.p1.x += xoff; t->left.p1.y += yoff; t->left.p2.x += xoff; t->left.p2.y += yoff; t->right.p1.x += xoff; t->right.p1.y += yoff; t->right.p2.x += xoff; t->right.p2.y += yoff; } }
void _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents) { if (traps->num_traps == 0) { extents->p1.x = extents->p1.y = _cairo_fixed_from_int (0); extents->p2.x = extents->p2.y = _cairo_fixed_from_int (0); } else *extents = traps->extents; }
void _cairo_box_from_rectangle (cairo_box_t *box, const cairo_rectangle_int_t *rect) { box->p1.x = _cairo_fixed_from_int (rect->x); box->p1.y = _cairo_fixed_from_int (rect->y); box->p2.x = _cairo_fixed_from_int (rect->x + rect->width); box->p2.y = _cairo_fixed_from_int (rect->y + rect->height); }
cairo_status_t _cairo_surface_offset_fill (cairo_surface_t *surface, int x, int y, 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_status_t status; cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; cairo_clip_t *dev_clip = (cairo_clip_t *) clip; cairo_pattern_union_t source_copy; if (unlikely (surface->status)) return surface->status; if (_cairo_clip_is_all_clipped (clip)) return CAIRO_STATUS_SUCCESS; if (x | y) { cairo_matrix_t m; dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; _cairo_path_fixed_translate (&path_copy, _cairo_fixed_from_int (-x), _cairo_fixed_from_int (-y)); dev_path = &path_copy; cairo_matrix_init_translate (&m, x, y); _copy_transformed_pattern (&source_copy.base, source, &m); source = &source_copy.base; } status = _cairo_surface_fill (surface, op, source, dev_path, fill_rule, tolerance, antialias, dev_clip); FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); if (dev_clip != clip) _cairo_clip_destroy (dev_clip); return status; }
cairo_bool_t _cairo_clip_contains_rectangle (const cairo_clip_t *clip, const cairo_rectangle_int_t *rect) { cairo_box_t box; box.p1.x = _cairo_fixed_from_int (rect->x); box.p1.y = _cairo_fixed_from_int (rect->y); box.p2.x = _cairo_fixed_from_int (rect->x + rect->width); box.p2.y = _cairo_fixed_from_int (rect->y + rect->height); return _cairo_clip_contains_rectangle_box (clip, rect, &box); }
static cairo_status_t _cairo_clip_path_reapply_clip_path_translate (cairo_clip_t *clip, cairo_clip_path_t *other_path, int tx, int ty) { cairo_status_t status; cairo_clip_path_t *clip_path; if (other_path->prev != NULL) { status = _cairo_clip_path_reapply_clip_path_translate (clip, other_path->prev, tx, ty); if (unlikely (status)) return status; } clip_path = _cairo_clip_path_create (clip); if (unlikely (clip_path == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_path_fixed_init_copy (&clip_path->path, &other_path->path); if (unlikely (status)) { _cairo_clip_path_destroy (clip_path); return status; } _cairo_path_fixed_translate (&clip_path->path, _cairo_fixed_from_int (tx), _cairo_fixed_from_int (ty)); clip_path->fill_rule = other_path->fill_rule; clip_path->tolerance = other_path->tolerance; clip_path->antialias = other_path->antialias; clip_path->flags = other_path->flags; if (other_path->region != NULL) { clip_path->region = cairo_region_copy (other_path->region); cairo_region_translate (clip_path->region, tx, ty); } clip_path->surface = cairo_surface_reference (other_path->surface); clip_path->extents = other_path->extents; clip_path->extents.x += tx; clip_path->extents.y += ty; return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_surface_fallback_paint (cairo_surface_t *surface, cairo_operator_t op, cairo_pattern_t *source) { cairo_status_t status; cairo_rectangle_int_t extents; cairo_box_t box; cairo_traps_t traps; status = _cairo_surface_get_extents (surface, &extents); if (status) return status; if (_cairo_operator_bounded_by_source (op)) { cairo_rectangle_int_t source_extents; status = _cairo_pattern_get_extents (source, &source_extents); if (status) return status; _cairo_rectangle_intersect (&extents, &source_extents); } status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents); if (status) return status; box.p1.x = _cairo_fixed_from_int (extents.x); box.p1.y = _cairo_fixed_from_int (extents.y); box.p2.x = _cairo_fixed_from_int (extents.x + extents.width); box.p2.y = _cairo_fixed_from_int (extents.y + extents.height); status = _cairo_traps_init_box (&traps, &box); if (status) return status; status = _clip_and_composite_trapezoids (source, op, surface, &traps, surface->clip, CAIRO_ANTIALIAS_NONE); _cairo_traps_fini (&traps); return status; }
static cairo_clip_t * _cairo_clip_reduce_to_boxes (cairo_clip_t *clip) { struct reduce r; cairo_clip_path_t *clip_path; cairo_status_t status; return clip; if (clip->path == NULL) return clip; r.clip = clip; r.extents.p1.x = r.extents.p1.y = INT_MAX; r.extents.p2.x = r.extents.p2.y = INT_MIN; r.inside = FALSE; r.limit.p1.x = _cairo_fixed_from_int (clip->extents.x); r.limit.p1.y = _cairo_fixed_from_int (clip->extents.y); r.limit.p2.x = _cairo_fixed_from_int (clip->extents.x + clip->extents.width); r.limit.p2.y = _cairo_fixed_from_int (clip->extents.y + clip->extents.height); clip_path = clip->path; do { r.current_point.x = 0; r.current_point.y = 0; r.last_move_to = r.current_point; status = _cairo_path_fixed_interpret_flat (&clip_path->path, _reduce_move_to, _reduce_line_to, _reduce_close, &r, clip_path->tolerance); assert (status == CAIRO_STATUS_SUCCESS); _reduce_close (&r); } while ((clip_path = clip_path->prev)); if (! r.inside) { _cairo_clip_path_destroy (clip->path); clip->path = NULL; } return _cairo_clip_intersect_box (clip, &r.extents); }
cairo_clip_t * _cairo_clip_intersect_rectangle (cairo_clip_t *clip, const cairo_rectangle_int_t *r) { cairo_box_t box; if (_cairo_clip_is_all_clipped (clip)) return clip; if (r->width == 0 || r->height == 0) return _cairo_clip_set_all_clipped (clip); box.p1.x = _cairo_fixed_from_int (r->x); box.p1.y = _cairo_fixed_from_int (r->y); box.p2.x = _cairo_fixed_from_int (r->x + r->width); box.p2.y = _cairo_fixed_from_int (r->y + r->height); return _cairo_clip_intersect_rectangle_box (clip, r, &box); }
static cairo_pattern_t * _cairo_default_context_pop_group (void *abstract_cr) { cairo_default_context_t *cr = abstract_cr; cairo_surface_t *group_surface; cairo_pattern_t *group_pattern; cairo_surface_t *parent_surface; cairo_matrix_t group_matrix; cairo_status_t status; /* Verify that we are at the right nesting level */ if (unlikely (! _cairo_gstate_is_group (cr->gstate))) return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_POP_GROUP); /* Get a reference to the active surface before restoring */ group_surface = _cairo_gstate_get_target (cr->gstate); group_surface = cairo_surface_reference (group_surface); status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist); assert (status == CAIRO_STATUS_SUCCESS); parent_surface = _cairo_gstate_get_target (cr->gstate); group_pattern = cairo_pattern_create_for_surface (group_surface); status = group_pattern->status; if (unlikely (status)) goto done; _cairo_gstate_get_matrix (cr->gstate, &group_matrix); cairo_pattern_set_matrix (group_pattern, &group_matrix); /* If we have a current path, we need to adjust it to compensate for * the device offset just removed. */ _cairo_path_fixed_translate (cr->path, _cairo_fixed_from_int (parent_surface->device_transform.x0 - group_surface->device_transform.x0), _cairo_fixed_from_int (parent_surface->device_transform.y0 - group_surface->device_transform.y0)); done: cairo_surface_destroy (group_surface); return group_pattern; }
static cairo_status_t _cairo_clip_intersect_rectangle (cairo_clip_t *clip, const cairo_rectangle_int_t *rect) { cairo_clip_path_t *clip_path; cairo_status_t status; if (clip->path != NULL) { if (rect->x <= clip->path->extents.x && rect->y <= clip->path->extents.y && rect->x + rect->width >= clip->path->extents.x + clip->path->extents.width && rect->y + rect->height >= clip->path->extents.y + clip->path->extents.height) { return CAIRO_STATUS_SUCCESS; } } clip_path = _cairo_clip_path_create (clip); if (unlikely (clip_path == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_path_fixed_init (&clip_path->path); status = _cairo_path_fixed_move_to (&clip_path->path, _cairo_fixed_from_int (rect->x), _cairo_fixed_from_int (rect->y)); assert (status == CAIRO_STATUS_SUCCESS); status = _cairo_path_fixed_rel_line_to (&clip_path->path, _cairo_fixed_from_int (rect->width), _cairo_fixed_from_int (0)); assert (status == CAIRO_STATUS_SUCCESS); status = _cairo_path_fixed_rel_line_to (&clip_path->path, _cairo_fixed_from_int (0), _cairo_fixed_from_int (rect->height)); assert (status == CAIRO_STATUS_SUCCESS); status = _cairo_path_fixed_rel_line_to (&clip_path->path, _cairo_fixed_from_int (-rect->width), _cairo_fixed_from_int (0)); assert (status == CAIRO_STATUS_SUCCESS); status = _cairo_path_fixed_close_path (&clip_path->path); assert (status == CAIRO_STATUS_SUCCESS); clip_path->extents = *rect; clip_path->fill_rule = CAIRO_FILL_RULE_WINDING; clip_path->tolerance = 1; clip_path->antialias = CAIRO_ANTIALIAS_NONE; clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX; /* could preallocate the region if it proves worthwhile */ return CAIRO_STATUS_SUCCESS; }
void _cairo_traps_extents (const cairo_traps_t *traps, cairo_box_t *extents) { if (traps->num_traps == 0) { extents->p1.x = extents->p1.y = _cairo_fixed_from_int (0); extents->p2.x = extents->p2.y = _cairo_fixed_from_int (0); } else { *extents = traps->extents; if (traps->has_limits) { /* clip the traps to the imposed limits */ if (extents->p1.x < traps->limits.p1.x) extents->p1.x = traps->limits.p1.x; if (extents->p2.x > traps->limits.p2.x) extents->p2.x = traps->limits.p2.x; if (extents->p1.y < traps->limits.p1.y) extents->p1.y = traps->limits.p1.y; if (extents->p2.y > traps->limits.p2.y) extents->p2.y = traps->limits.p2.y; } } }
static cairo_status_t span_to_boxes (void *abstract_renderer, int y, int h, const cairo_half_open_span_t *spans, unsigned num_spans) { struct cairo_box_renderer *r = abstract_renderer; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_box_t box; if (num_spans == 0) return CAIRO_STATUS_SUCCESS; box.p1.y = _cairo_fixed_from_int (y); box.p2.y = _cairo_fixed_from_int (y + h); do { if (spans[0].coverage) { box.p1.x = _cairo_fixed_from_int(spans[0].x); box.p2.x = _cairo_fixed_from_int(spans[1].x); status = _cairo_boxes_add (r->boxes, CAIRO_ANTIALIAS_DEFAULT, &box); } spans++; } while (--num_spans > 1 && status == CAIRO_STATUS_SUCCESS); return status; }
cairo_status_t _cairo_surface_offset_stroke (cairo_surface_t *surface, int x, int y, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, const cairo_stroke_style_t*stroke_style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_path_fixed_t path_copy, *dev_path = path; cairo_clip_t clip_copy, *dev_clip = clip; cairo_matrix_t dev_ctm = *ctm; cairo_matrix_t dev_ctm_inverse = *ctm_inverse; cairo_pattern_union_t source_copy; cairo_status_t status; if (unlikely (surface->status)) return surface->status; if (clip && clip->all_clipped) return CAIRO_STATUS_SUCCESS; if (x | y) { cairo_matrix_t m; status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; _cairo_path_fixed_translate (&path_copy, _cairo_fixed_from_int (-x), _cairo_fixed_from_int (-y)); dev_path = &path_copy; cairo_matrix_init_translate (&m, -x, -y); cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); if (clip != NULL) { status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; dev_clip = &clip_copy; } cairo_matrix_init_translate (&m, x, y); _copy_transformed_pattern (&source_copy.base, source, &m); source = &source_copy.base; cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); } status = _cairo_surface_stroke (surface, op, source, dev_path, stroke_style, &dev_ctm, &dev_ctm_inverse, tolerance, antialias, dev_clip); FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); if (dev_clip != clip) _cairo_clip_reset (dev_clip); return status; }
static cairo_int_status_t _cairo_clip_path_to_boxes (cairo_clip_path_t *clip_path, cairo_box_t **boxes, int *count) { int size = -*count; int num_boxes = 0; cairo_status_t status; if (clip_path->region != NULL) { int num_rects, n; num_rects = cairo_region_num_rectangles (clip_path->region); if (num_rects > -size) { cairo_box_t *new_boxes; new_boxes = _cairo_malloc_ab (num_rects, sizeof (cairo_box_t)); if (unlikely (new_boxes == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); *boxes = new_boxes; } for (n = 0; n < num_rects; n++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (clip_path->region, n, &rect); (*boxes)[n].p1.x = _cairo_fixed_from_int (rect.x); (*boxes)[n].p1.y = _cairo_fixed_from_int (rect.y); (*boxes)[n].p2.x = _cairo_fixed_from_int (rect.x + rect.width); (*boxes)[n].p2.y = _cairo_fixed_from_int (rect.y + rect.height); } *count = num_rects; return CAIRO_STATUS_SUCCESS; } /* keep it simple at first */ if (! _clip_paths_are_rectilinear (clip_path)) return CAIRO_INT_STATUS_UNSUPPORTED; assert (-size >= 1); if (_cairo_path_fixed_is_box (&clip_path->path, *boxes)) { num_boxes = 1; } else { status = _rectilinear_clip_to_boxes (&clip_path->path, clip_path->fill_rule, boxes, &num_boxes, &size); if (unlikely (status)) return status; } while (num_boxes > 0 && (clip_path = clip_path->prev) != NULL) { cairo_box_t box; if (clip_path->region != NULL) { status = _region_clip_to_boxes (clip_path->region, boxes, &num_boxes, &size); if (unlikely (status)) return status; break; } else if (_cairo_path_fixed_is_box (&clip_path->path, &box)) { int i, j; for (i = j = 0; i < num_boxes; i++) { if (j != i) (*boxes)[j] = (*boxes)[i]; if (box.p1.x > (*boxes)[j].p1.x) (*boxes)[j].p1.x = box.p1.x; if (box.p2.x < (*boxes)[j].p2.x) (*boxes)[j].p2.x = box.p2.x; if (box.p1.y > (*boxes)[j].p1.y) (*boxes)[j].p1.y = box.p1.y; if (box.p2.y < (*boxes)[j].p2.y) (*boxes)[j].p2.y = box.p2.y; j += (*boxes)[j].p2.x > (*boxes)[j].p1.x && (*boxes)[j].p2.y > (*boxes)[j].p1.y; } num_boxes = j; } else { status = _rectilinear_clip_to_boxes (&clip_path->path, clip_path->fill_rule, boxes, &num_boxes, &size); if (unlikely (status)) return status; } } *count = num_boxes; return CAIRO_STATUS_SUCCESS; }
static cairo_status_t _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content) { cairo_default_context_t *cr = abstract_cr; cairo_surface_t *group_surface; cairo_clip_t *clip; cairo_status_t status; clip = _cairo_gstate_get_clip (cr->gstate); if (_cairo_clip_is_all_clipped (clip)) { group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); status = group_surface->status; if (unlikely (status)) goto bail; } else { cairo_surface_t *parent_surface; cairo_rectangle_int_t extents; cairo_bool_t bounded, is_empty; parent_surface = _cairo_gstate_get_target (cr->gstate); if (unlikely (parent_surface->status)) return parent_surface->status; if (unlikely (parent_surface->finished)) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); /* Get the extents that we'll use in creating our new group surface */ bounded = _cairo_surface_get_extents (parent_surface, &extents); if (clip) /* XXX: This assignment just fixes a compiler warning? */ is_empty = _cairo_rectangle_intersect (&extents, _cairo_clip_get_extents (clip)); if (!bounded) { /* XXX: Generic solution? */ group_surface = cairo_recording_surface_create (content, NULL); extents.x = extents.y = 0; } else { group_surface = _cairo_surface_create_similar_solid (parent_surface, content, extents.width, extents.height, CAIRO_COLOR_TRANSPARENT); } status = group_surface->status; if (unlikely (status)) goto bail; /* Set device offsets on the new surface so that logically it appears at * the same location on the parent surface -- when we pop_group this, * the source pattern will get fixed up for the appropriate target surface * device offsets, so we want to set our own surface offsets from /that/, * and not from the device origin. */ cairo_surface_set_device_offset (group_surface, parent_surface->device_transform.x0 - extents.x, parent_surface->device_transform.y0 - extents.y); /* If we have a current path, we need to adjust it to compensate for * the device offset just applied. */ _cairo_path_fixed_translate (cr->path, _cairo_fixed_from_int (-extents.x), _cairo_fixed_from_int (-extents.y)); } /* create a new gstate for the redirect */ status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist); if (unlikely (status)) goto bail; status = _cairo_gstate_redirect_target (cr->gstate, group_surface); bail: cairo_surface_destroy (group_surface); return status; }
static cairo_status_t _cairo_clip_intersect_path (cairo_clip_t *clip, const cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias) { cairo_clip_path_t *clip_path; cairo_status_t status; cairo_rectangle_int_t extents; cairo_box_t box; cairo_bool_t is_box = FALSE; if (clip->path != NULL) { if (clip->path->fill_rule == fill_rule && (path->is_rectilinear || (tolerance == clip->path->tolerance && antialias == clip->path->antialias)) && _cairo_path_fixed_equal (&clip->path->path, path)) { return CAIRO_STATUS_SUCCESS; } } _cairo_path_fixed_approximate_clip_extents (path, &extents); if (extents.width == 0 || extents.height == 0) { _cairo_clip_set_all_clipped (clip); return CAIRO_STATUS_SUCCESS; } is_box = _cairo_path_fixed_is_box (path, &box); if (clip->path != NULL) { if (! _cairo_rectangle_intersect (&extents, &clip->path->extents)) { _cairo_clip_set_all_clipped (clip); return CAIRO_STATUS_SUCCESS; } /* does this clip wholly subsume the others? */ if (is_box && box.p1.x <= _cairo_fixed_from_int (clip->path->extents.x) && box.p2.x >= _cairo_fixed_from_int (clip->path->extents.x + clip->path->extents.width) && box.p1.y <= _cairo_fixed_from_int (clip->path->extents.y) && box.p2.y >= _cairo_fixed_from_int (clip->path->extents.y + clip->path->extents.height)) { return CAIRO_STATUS_SUCCESS; } } clip_path = _cairo_clip_path_create (clip); if (unlikely (clip_path == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_path_fixed_init_copy (&clip_path->path, path); if (unlikely (status)) { clip->path = clip->path->prev; _cairo_clip_path_destroy (clip_path); return status; } clip_path->extents = extents; clip_path->fill_rule = fill_rule; clip_path->tolerance = tolerance; clip_path->antialias = antialias; if (is_box) clip_path->flags |= CAIRO_CLIP_PATH_IS_BOX; return CAIRO_STATUS_SUCCESS; }
cairo_surface_t * _cairo_clip_get_surface (const cairo_clip_t *clip, cairo_surface_t *target, int *tx, int *ty) { cairo_surface_t *surface; cairo_status_t status; cairo_clip_t *copy, *region; cairo_clip_path_t *copy_path, *clip_path; if (clip->num_boxes) { cairo_path_fixed_t path; int i; surface = _cairo_surface_create_scratch (target, CAIRO_CONTENT_ALPHA, clip->extents.width, clip->extents.height, CAIRO_COLOR_TRANSPARENT); if (unlikely (surface->status)) return surface; _cairo_path_fixed_init (&path); status = CAIRO_STATUS_SUCCESS; for (i = 0; status == CAIRO_STATUS_SUCCESS && i < clip->num_boxes; i++) { status = _cairo_path_fixed_add_box (&path, &clip->boxes[i], -_cairo_fixed_from_int (clip->extents.x), -_cairo_fixed_from_int (clip->extents.y)); } if (status == CAIRO_STATUS_SUCCESS) status = _cairo_surface_fill (surface, CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, &path, CAIRO_FILL_RULE_WINDING, 1., CAIRO_ANTIALIAS_DEFAULT, NULL); _cairo_path_fixed_fini (&path); if (unlikely (status)) { cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); } } else { surface = _cairo_surface_create_scratch (target, CAIRO_CONTENT_ALPHA, clip->extents.width, clip->extents.height, CAIRO_COLOR_WHITE); if (unlikely (surface->status)) return surface; } copy = _cairo_clip_copy_with_translation (clip, -clip->extents.x, -clip->extents.y); copy_path = copy->path; copy->path = NULL; region = copy; if (! _cairo_clip_is_region (copy)) region = _cairo_clip_copy_region (copy); status = CAIRO_STATUS_SUCCESS; clip_path = copy_path; while (status == CAIRO_STATUS_SUCCESS && clip_path) { status = _cairo_surface_fill (surface, CAIRO_OPERATOR_IN, &_cairo_pattern_white.base, &clip_path->path, clip_path->fill_rule, clip_path->tolerance, clip_path->antialias, region); clip_path = clip_path->prev; } copy->path = copy_path; _cairo_clip_destroy (copy); if (region != copy) _cairo_clip_destroy (region); if (unlikely (status)) { cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); } *tx = clip->extents.x; *ty = clip->extents.y; return surface; }
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; }
static cairo_int_status_t _add_operation (cairo_analysis_surface_t *surface, cairo_rectangle_int_t *rect, cairo_int_status_t backend_status) { cairo_int_status_t status; cairo_box_t bbox; if (rect->width == 0 || rect->height == 0) { /* Even though the operation is not visible we must be careful * to not allow unsupported operations to be replayed to the * backend during CAIRO_PAGINATED_MODE_RENDER */ if (backend_status == CAIRO_INT_STATUS_SUCCESS || backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO) { return CAIRO_INT_STATUS_SUCCESS; } else { return CAIRO_INT_STATUS_IMAGE_FALLBACK; } } _cairo_box_from_rectangle (&bbox, rect); if (surface->has_ctm) { int tx, ty; if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) { rect->x += tx; rect->y += ty; tx = _cairo_fixed_from_int (tx); bbox.p1.x += tx; bbox.p2.x += tx; ty = _cairo_fixed_from_int (ty); bbox.p1.y += ty; bbox.p2.y += ty; } else { _cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL); if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) { /* Even though the operation is not visible we must be * careful to not allow unsupported operations to be * replayed to the backend during * CAIRO_PAGINATED_MODE_RENDER */ if (backend_status == CAIRO_INT_STATUS_SUCCESS || backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO) { return CAIRO_INT_STATUS_SUCCESS; } else { return CAIRO_INT_STATUS_IMAGE_FALLBACK; } } _cairo_box_round_to_rectangle (&bbox, rect); } } if (surface->first_op) { surface->first_op = FALSE; surface->page_bbox = bbox; } else _cairo_box_add_box(&surface->page_bbox, &bbox); /* If the operation is completely enclosed within the fallback * region there is no benefit in emitting a native operation as * the fallback image will be painted on top. */ if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN) return CAIRO_INT_STATUS_IMAGE_FALLBACK; if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) { /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates * that the backend only supports this operation if the * transparency removed. If the extents of this operation does * not intersect any other native operation, the operation is * natively supported and the backend will blend the * transparency into the white background. */ if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT) backend_status = CAIRO_INT_STATUS_SUCCESS; } if (backend_status == CAIRO_INT_STATUS_SUCCESS) { /* Add the operation to the supported region. Operations in * this region will be emitted as native operations. */ surface->has_supported = TRUE; return cairo_region_union_rectangle (&surface->supported_region, rect); } /* Add the operation to the unsupported region. This region will * be painted as an image after all native operations have been * emitted. */ surface->has_unsupported = TRUE; status = cairo_region_union_rectangle (&surface->fallback_region, rect); /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate * unsupported operations to the recording surface as using * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to * invoke the cairo-surface-fallback path then return * CAIRO_STATUS_SUCCESS. */ if (status == CAIRO_INT_STATUS_SUCCESS) return CAIRO_INT_STATUS_IMAGE_FALLBACK; else return status; }
static cairo_surface_t * _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path, cairo_surface_t *target) { cairo_surface_t *surface; cairo_pattern_union_t pattern; cairo_status_t status; const cairo_rectangle_int_t *clip_extents = &clip_path->extents; cairo_clip_path_t *prev; cairo_bool_t need_translate; if (clip_path->surface != NULL && clip_path->surface->backend == target->backend) { return cairo_surface_reference (clip_path->surface); } surface = _cairo_surface_create_similar_solid (target, CAIRO_CONTENT_ALPHA, clip_extents->width, clip_extents->height, CAIRO_COLOR_TRANSPARENT, FALSE); if (surface == NULL) { if (clip_path->surface != NULL && clip_path->surface->backend == &_cairo_image_surface_backend) { return cairo_surface_reference (clip_path->surface); } surface = _cairo_image_surface_create_with_content (CAIRO_CONTENT_ALPHA, clip_extents->width, clip_extents->height); } if (unlikely (surface->status)) return surface; _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR); status = _cairo_clip_path_to_region (clip_path); if (unlikely (_cairo_status_is_error (status))) goto BAIL; need_translate = clip_extents->x | clip_extents->y; if (status == CAIRO_STATUS_SUCCESS) { if (need_translate) { cairo_region_translate (clip_path->region, -clip_extents->x, -clip_extents->y); } status = _cairo_surface_fill_region (surface, CAIRO_OPERATOR_SOURCE, CAIRO_COLOR_WHITE, clip_path->region); if (need_translate) { cairo_region_translate (clip_path->region, clip_extents->x, clip_extents->y); } if (unlikely (status)) goto BAIL; goto DONE; } else { if (need_translate) { _cairo_path_fixed_translate (&clip_path->path, _cairo_fixed_from_int (-clip_extents->x), _cairo_fixed_from_int (-clip_extents->y)); } status = _cairo_surface_fill (surface, CAIRO_OPERATOR_OVER, &pattern.base, &clip_path->path, clip_path->fill_rule, clip_path->tolerance, clip_path->antialias, NULL); if (need_translate) { _cairo_path_fixed_translate (&clip_path->path, _cairo_fixed_from_int (clip_extents->x), _cairo_fixed_from_int (clip_extents->y)); } if (unlikely (status)) goto BAIL; } prev = clip_path->prev; NEXT_PATH: if (prev != NULL) { status = _cairo_clip_path_to_region (prev); if (unlikely (_cairo_status_is_error (status))) goto BAIL; if (status == CAIRO_STATUS_SUCCESS) { status = _combine_region (surface, prev->region, clip_extents); if (unlikely (status)) goto BAIL; } else if (prev->flags & CAIRO_CLIP_PATH_IS_BOX) { /* a simple box only affects the extents */ } else if (prev->path.is_rectilinear) { if (need_translate) { _cairo_path_fixed_translate (&prev->path, _cairo_fixed_from_int (-clip_extents->x), _cairo_fixed_from_int (-clip_extents->y)); } status = _cairo_surface_fill (surface, CAIRO_OPERATOR_IN, &pattern.base, &prev->path, prev->fill_rule, prev->tolerance, prev->antialias, NULL); if (need_translate) { _cairo_path_fixed_translate (&prev->path, _cairo_fixed_from_int (clip_extents->x), _cairo_fixed_from_int (clip_extents->y)); } if (unlikely (status)) goto BAIL; prev = prev->prev; goto NEXT_PATH; } else { cairo_surface_t *prev_surface; prev_surface = _cairo_clip_path_get_surface (prev, target); _cairo_pattern_init_for_surface (&pattern.surface, prev_surface); cairo_surface_destroy (prev_surface); cairo_matrix_init_translate (&pattern.base.matrix, -prev->extents.x + clip_extents->x, -prev->extents.y + clip_extents->y); status = _cairo_surface_paint (surface, CAIRO_OPERATOR_IN, &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); if (unlikely (status)) goto BAIL; } } DONE: cairo_surface_destroy (clip_path->surface); return clip_path->surface = cairo_surface_reference (surface); BAIL: cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); }
cairo_status_t _cairo_clip_combine_with_surface (cairo_clip_t *clip, cairo_surface_t *dst, const cairo_rectangle_int_t *extents) { cairo_pattern_union_t pattern; cairo_clip_path_t *clip_path = clip->path; cairo_bool_t need_translate; cairo_status_t status; assert (clip_path != NULL); if (clip_path->surface != NULL && clip_path->surface->backend == dst->backend) { _cairo_pattern_init_for_surface (&pattern.surface, clip_path->surface); cairo_matrix_init_translate (&pattern.base.matrix, extents->x - clip_path->extents.x, extents->y - clip_path->extents.y); status = _cairo_surface_paint (dst, CAIRO_OPERATOR_IN, &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); return status; } _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR); need_translate = extents->x | extents->y; do { status = _cairo_clip_path_to_region (clip_path); if (unlikely (_cairo_status_is_error (status))) return status; if (status == CAIRO_STATUS_SUCCESS) return _combine_region (dst, clip_path->region, extents); if (clip_path->surface != NULL && clip_path->surface->backend == dst->backend) { _cairo_pattern_init_for_surface (&pattern.surface, clip_path->surface); cairo_matrix_init_translate (&pattern.base.matrix, extents->x - clip_path->extents.x, extents->y - clip_path->extents.y); status = _cairo_surface_paint (dst, CAIRO_OPERATOR_IN, &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); return status; } if (clip_path->flags & CAIRO_CLIP_PATH_IS_BOX) { cairo_region_t clip_region; _cairo_region_init_rectangle (&clip_region, &clip_path->extents); status = _combine_region (dst, &clip_region, extents); } else { if (need_translate) { _cairo_path_fixed_translate (&clip_path->path, _cairo_fixed_from_int (-extents->x), _cairo_fixed_from_int (-extents->y)); } status = _cairo_surface_fill (dst, CAIRO_OPERATOR_IN, &pattern.base, &clip_path->path, clip_path->fill_rule, clip_path->tolerance, clip_path->antialias, NULL); if (need_translate) { _cairo_path_fixed_translate (&clip_path->path, _cairo_fixed_from_int (extents->x), _cairo_fixed_from_int (extents->y)); } } if (unlikely (status)) return status; } while ((clip_path = clip_path->prev) != NULL); return CAIRO_STATUS_SUCCESS; }
cairo_int_status_t i965_surface_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_glyph_t *g, int num_glyphs, cairo_scaled_font_t *scaled_font, cairo_clip_t *clip, int *num_remaining) { i965_surface_t *surface = abstract_surface; i965_surface_t *mask = NULL; i965_device_t *device; i965_glyphs_t glyphs; cairo_composite_rectangles_t extents; cairo_clip_t local_clip; cairo_bool_t have_clip = FALSE; cairo_bool_t overlap; cairo_region_t *clip_region = NULL; intel_bo_t *last_bo = NULL; cairo_scaled_glyph_t *glyph_cache[64]; cairo_status_t status; int mask_x = 0, mask_y = 0; int i = 0; *num_remaining = 0; status = _cairo_composite_rectangles_init_for_glyphs (&extents, surface->intel.drm.width, surface->intel.drm.height, op, source, scaled_font, g, num_glyphs, clip, &overlap); if (unlikely (status)) return status; if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents.mask)) clip = NULL; if (clip != NULL && extents.is_bounded) { clip = _cairo_clip_init_copy (&local_clip, clip); status = _cairo_clip_rectangle (clip, &extents.bounded); if (unlikely (status)) return status; have_clip = TRUE; } if (overlap || ! extents.is_bounded) { cairo_format_t format; format = CAIRO_FORMAT_A8; if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL) format = CAIRO_FORMAT_ARGB32; mask = (i965_surface_t *) i965_surface_create_internal (&i965_device (surface)->intel.base, format, extents.bounded.width, extents.bounded.height, I965_TILING_DEFAULT, TRUE); if (unlikely (mask->intel.drm.base.status)) return mask->intel.drm.base.status; status = _cairo_surface_paint (&mask->intel.drm.base, CAIRO_OPERATOR_CLEAR, &_cairo_pattern_clear.base, NULL); if (unlikely (status)) { cairo_surface_destroy (&mask->intel.drm.base); return status; } i965_shader_init (&glyphs.shader, mask, CAIRO_OPERATOR_ADD); status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source, &_cairo_pattern_white.base, &extents.bounded); if (unlikely (status)) { cairo_surface_destroy (&mask->intel.drm.base); return status; } mask_x = -extents.bounded.x; mask_y = -extents.bounded.y; } else { i965_shader_init (&glyphs.shader, surface, op); status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source, source, &extents.bounded); if (unlikely (status)) return status; if (clip != NULL) { status = _cairo_clip_get_region (clip, &clip_region); assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED); if (status == CAIRO_INT_STATUS_UNSUPPORTED) i965_shader_set_clip (&glyphs.shader, clip); } } glyphs.head.next = NULL; glyphs.head.bo = NULL; glyphs.head.count = 0; glyphs.tail = &glyphs.head; device = i965_device (surface); if (mask != NULL || clip_region == NULL) { glyphs.get_rectangle = i965_glyphs_emit_rectangle; } else { glyphs.get_rectangle = i965_glyphs_accumulate_rectangle; glyphs.head.bo = intel_bo_create (&device->intel, I965_VERTEX_SIZE, I965_VERTEX_SIZE, FALSE, I915_TILING_NONE, 0); if (unlikely (glyphs.head.bo == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); glyphs.vbo_base = intel_bo_map (&device->intel, glyphs.head.bo); } glyphs.vbo_offset = 0; status = cairo_device_acquire (&device->intel.base.base); if (unlikely (status)) goto CLEANUP_GLYPHS; _cairo_scaled_font_freeze_cache (scaled_font); //private = _cairo_scaled_font_get_device (scaled_font, device); if (scaled_font->surface_private == NULL) { scaled_font->surface_private = device; scaled_font->surface_backend = surface->intel.drm.base.backend; cairo_list_add (&scaled_font->link, &device->intel.fonts); } memset (glyph_cache, 0, sizeof (glyph_cache)); for (i = 0; i < num_glyphs; i++) { cairo_scaled_glyph_t *scaled_glyph; int x, y, x1, x2, y1, y2; int cache_index = g[i].index % ARRAY_LENGTH (glyph_cache); intel_glyph_t *glyph; scaled_glyph = glyph_cache[cache_index]; if (scaled_glyph == NULL || _cairo_scaled_glyph_index (scaled_glyph) != g[i].index) { status = _cairo_scaled_glyph_lookup (scaled_font, g[i].index, CAIRO_SCALED_GLYPH_INFO_METRICS, &scaled_glyph); if (unlikely (status)) goto FINISH; glyph_cache[cache_index] = scaled_glyph; } if (unlikely (scaled_glyph->metrics.width == 0 || scaled_glyph->metrics.height == 0)) { continue; } /* XXX glyph images are snapped to pixel locations */ x = _cairo_lround (g[i].x); y = _cairo_lround (g[i].y); x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x); y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y); if (x2 < extents.bounded.x || y2 < extents.bounded.y || x1 > extents.bounded.x + extents.bounded.width || y1 > extents.bounded.y + extents.bounded.height) { continue; } if (scaled_glyph->surface_private == NULL) { status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph); if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) { status = CAIRO_STATUS_SUCCESS; continue; } if (unlikely (status)) goto FINISH; } glyph = intel_glyph_pin (scaled_glyph->surface_private); if (glyph->cache->buffer.bo != last_bo) { intel_buffer_cache_t *cache = glyph->cache; glyphs.shader.mask.type.vertex = VS_GLYPHS; glyphs.shader.mask.type.fragment = FS_GLYPHS; glyphs.shader.mask.type.pattern = PATTERN_BASE; glyphs.shader.mask.base.bo = cache->buffer.bo; glyphs.shader.mask.base.format = cache->buffer.format; glyphs.shader.mask.base.width = cache->buffer.width; glyphs.shader.mask.base.height = cache->buffer.height; glyphs.shader.mask.base.stride = cache->buffer.stride; glyphs.shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST); glyphs.shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE); glyphs.shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */ glyphs.shader.committed = FALSE; status = i965_shader_commit (&glyphs.shader, device); if (unlikely (status)) goto FINISH; last_bo = cache->buffer.bo; } x2 = x1 + glyph->width; y2 = y1 + glyph->height; if (mask_x) x1 += mask_x, x2 += mask_x; if (mask_y) y1 += mask_y, y2 += mask_y; i965_add_glyph_rectangle (&glyphs, x1, y1, x2, y2, glyph); } if (mask != NULL && clip_region != NULL) i965_clipped_vertices (device, &glyphs.head, clip_region); status = CAIRO_STATUS_SUCCESS; FINISH: _cairo_scaled_font_thaw_cache (scaled_font); cairo_device_release (surface->intel.drm.base.device); CLEANUP_GLYPHS: i965_shader_fini (&glyphs.shader); if (glyphs.head.bo != NULL) { struct i965_vbo *vbo, *next; intel_bo_destroy (&device->intel, glyphs.head.bo); for (vbo = glyphs.head.next; vbo != NULL; vbo = next) { next = vbo->next; intel_bo_destroy (&device->intel, vbo->bo); free (vbo); } } if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) { cairo_path_fixed_t path; _cairo_path_fixed_init (&path); status = _cairo_scaled_font_glyph_path (scaled_font, g + i, num_glyphs - i, &path); if (mask_x | mask_y) { _cairo_path_fixed_translate (&path, _cairo_fixed_from_int (mask_x), _cairo_fixed_from_int (mask_y)); } if (likely (status == CAIRO_STATUS_SUCCESS)) { status = surface->intel.drm.base.backend->fill (glyphs.shader.target, glyphs.shader.op, mask != NULL ? &_cairo_pattern_white.base : source, &path, CAIRO_FILL_RULE_WINDING, 0, scaled_font->options.antialias, clip); } _cairo_path_fixed_fini (&path); } if (mask != NULL) { if (likely (status == CAIRO_STATUS_SUCCESS)) { status = i965_surface_mask_internal (surface, op, source, mask, clip, &extents); } cairo_surface_finish (&mask->intel.drm.base); cairo_surface_destroy (&mask->intel.drm.base); } if (have_clip) _cairo_clip_fini (&local_clip); return status; }
/* XXX there is likely a faster method! ;-) */ static cairo_status_t _region_clip_to_boxes (const cairo_region_t *region, cairo_box_t **boxes, int *num_boxes, int *size_boxes) { cairo_traps_t traps; cairo_status_t status; int n, num_rects; _cairo_traps_init (&traps); _cairo_traps_limit (&traps, *boxes, *num_boxes); traps.is_rectilinear = TRUE; traps.is_rectangular = TRUE; num_rects = cairo_region_num_rectangles (region); for (n = 0; n < num_rects; n++) { cairo_rectangle_int_t rect; cairo_point_t p1, p2; cairo_region_get_rectangle (region, n, &rect); p1.x = _cairo_fixed_from_int (rect.x); p1.y = _cairo_fixed_from_int (rect.y); p2.x = _cairo_fixed_from_int (rect.x + rect.width); p2.y = _cairo_fixed_from_int (rect.y + rect.height); status = _cairo_traps_tessellate_rectangle (&traps, &p1, &p2); if (unlikely (status)) goto CLEANUP; } status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps, CAIRO_FILL_RULE_WINDING); if (unlikely (status)) goto CLEANUP; n = *size_boxes; if (n < 0) n = -n; if (traps.num_traps > n) { cairo_box_t *new_boxes; new_boxes = _cairo_malloc_ab (traps.num_traps, sizeof (cairo_box_t)); if (unlikely (new_boxes == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP; } if (*size_boxes > 0) free (*boxes); *boxes = new_boxes; *size_boxes = traps.num_traps; } for (n = 0; n < traps.num_traps; n++) { (*boxes)[n].p1.x = traps.traps[n].left.p1.x; (*boxes)[n].p1.y = traps.traps[n].top; (*boxes)[n].p2.x = traps.traps[n].right.p1.x; (*boxes)[n].p2.y = traps.traps[n].bottom; } *num_boxes = n; CLEANUP: _cairo_traps_fini (&traps); return status; }