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; }
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; }
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_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; }
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; }
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; }
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_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; }