cairo_status_t _cairo_clip_rectangle (cairo_clip_t *clip, const cairo_rectangle_int_t *rectangle) { if (clip->all_clipped) return CAIRO_STATUS_SUCCESS; if (rectangle->width == 0 || rectangle->height == 0) { _cairo_clip_set_all_clipped (clip); return CAIRO_STATUS_SUCCESS; } /* if a smaller clip has already been set, ignore the new path */ if (clip->path != NULL) { if (rectangle->x <= clip->path->extents.x && rectangle->y <= clip->path->extents.y && rectangle->x + rectangle->width >= clip->path->extents.x + clip->path->extents.width && rectangle->y + rectangle->height >= clip->path->extents.y + clip->path->extents.height) { return CAIRO_STATUS_SUCCESS; } } return _cairo_clip_intersect_rectangle (clip, rectangle); }
/* XXX consider accepting a matrix, no users yet. */ cairo_status_t _cairo_clip_init_rectangle (cairo_clip_t *clip, const cairo_rectangle_int_t *rect) { _cairo_clip_init (clip); if (rect == NULL) return CAIRO_STATUS_SUCCESS; if (rect->width == 0 || rect->height == 0) { _cairo_clip_set_all_clipped (clip); return CAIRO_STATUS_SUCCESS; } return _cairo_clip_intersect_rectangle (clip, rect); }
static cairo_int_status_t _paint_fallback_image (cairo_paginated_surface_t *surface, cairo_rectangle_int_t *rect) { double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution; double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution; int x, y, width, height; cairo_status_t status; cairo_surface_t *image; cairo_surface_pattern_t pattern; cairo_clip_t *clip; x = rect->x; y = rect->y; width = rect->width; height = rect->height; image = _cairo_paginated_surface_create_image_surface (surface, ceil (width * x_scale), ceil (height * y_scale)); _cairo_surface_set_device_scale (image, x_scale, y_scale); /* set_device_offset just sets the x0/y0 components of the matrix; * so we have to do the scaling manually. */ cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale); status = _cairo_recording_surface_replay (surface->recording_surface, image); if (unlikely (status)) goto CLEANUP_IMAGE; _cairo_pattern_init_for_surface (&pattern, image); cairo_matrix_init (&pattern.base.matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale); /* the fallback should be rendered at native resolution, so disable * filtering (if possible) to avoid introducing potential artifacts. */ pattern.base.filter = CAIRO_FILTER_NEAREST; clip = _cairo_clip_intersect_rectangle (NULL, rect); status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, &pattern.base, clip); _cairo_clip_destroy (clip); _cairo_pattern_fini (&pattern.base); CLEANUP_IMAGE: cairo_surface_destroy (image); return (cairo_int_status_t)status; }
static cairo_clip_t * _cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper, const cairo_clip_t *clip) { cairo_clip_t *copy; copy = _cairo_clip_copy (clip); if (wrapper->has_extents) { copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents); } copy = _cairo_clip_transform (copy, &wrapper->transform); if (! _cairo_matrix_is_identity (&wrapper->target->device_transform)) copy = _cairo_clip_transform (copy, &wrapper->target->device_transform); if (wrapper->clip) copy = _cairo_clip_intersect_clip (copy, wrapper->clip); return copy; }
cairo_clip_t * _cairo_clip_reduce_to_rectangle (const cairo_clip_t *clip, const cairo_rectangle_int_t *r) { cairo_clip_t *copy; if (_cairo_clip_is_all_clipped (clip)) return (cairo_clip_t *) clip; if (_cairo_clip_contains_rectangle (clip, r)) return _cairo_clip_intersect_rectangle (NULL, r); copy = _cairo_clip_copy_intersect_rectangle (clip, r); if (_cairo_clip_is_all_clipped (copy)) return copy; return _cairo_clip_reduce_to_boxes (copy); }
static cairo_clip_t * _cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper, const cairo_clip_t *clip) { cairo_clip_t *copy; cairo_matrix_t m; copy = _cairo_clip_copy (clip); if (wrapper->has_extents) { copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents); } _cairo_surface_wrapper_get_transform (wrapper, &m); copy = _cairo_clip_transform (copy, &m); if (wrapper->clip) copy = _cairo_clip_intersect_clip (copy, wrapper->clip); return copy; }
static cairo_int_status_t render_glyphs_via_mask (cairo_gl_surface_t *dst, int dst_x, int dst_y, cairo_operator_t op, cairo_surface_t *source, cairo_composite_glyphs_info_t *info, cairo_clip_t *clip, cairo_bool_t via_msaa_compositor) { cairo_surface_t *mask; cairo_status_t status; cairo_bool_t has_component_alpha; TRACE ((stderr, "%s\n", __FUNCTION__)); /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */ mask = cairo_gl_surface_create (dst->base.device, CAIRO_CONTENT_COLOR_ALPHA, info->extents.width, info->extents.height); if (unlikely (mask->status)) return mask->status; status = render_glyphs ((cairo_gl_surface_t *) mask, info->extents.x, info->extents.y, CAIRO_OPERATOR_ADD, NULL, info, &has_component_alpha, NULL, via_msaa_compositor); if (likely (status == CAIRO_STATUS_SUCCESS)) { cairo_surface_pattern_t mask_pattern; cairo_surface_pattern_t source_pattern; cairo_rectangle_int_t clip_extents; mask->is_clear = FALSE; _cairo_pattern_init_for_surface (&mask_pattern, mask); mask_pattern.base.has_component_alpha = has_component_alpha; mask_pattern.base.filter = CAIRO_FILTER_NEAREST; mask_pattern.base.extend = CAIRO_EXTEND_NONE; cairo_matrix_init_translate (&mask_pattern.base.matrix, dst_x-info->extents.x, dst_y-info->extents.y); _cairo_pattern_init_for_surface (&source_pattern, source); cairo_matrix_init_translate (&source_pattern.base.matrix, dst_x-info->extents.x, dst_y-info->extents.y); clip = _cairo_clip_copy (clip); clip_extents.x = info->extents.x - dst_x; clip_extents.y = info->extents.y - dst_y; clip_extents.width = info->extents.width; clip_extents.height = info->extents.height; clip = _cairo_clip_intersect_rectangle (clip, &clip_extents); status = _cairo_surface_mask (&dst->base, op, &source_pattern.base, &mask_pattern.base, clip); _cairo_clip_destroy (clip); _cairo_pattern_fini (&mask_pattern.base); _cairo_pattern_fini (&source_pattern.base); } cairo_surface_destroy (mask); return status; }
cairo_status_t _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst, cairo_image_surface_t *src, int src_x, int src_y, int width, int height, int dst_x, int dst_y) { GLenum internal_format, format, type; cairo_bool_t has_alpha, needs_swap; cairo_image_surface_t *clone = NULL; cairo_gl_context_t *ctx; int cpp; cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; status = _cairo_gl_context_acquire (dst->base.device, &ctx); if (unlikely (status)) return status; if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor, src->pixman_format, &internal_format, &format, &type, &has_alpha, &needs_swap)) { cairo_bool_t is_supported; clone = _cairo_image_surface_coerce (src); if (unlikely (status = clone->base.status)) goto FAIL; is_supported = _cairo_gl_get_image_format_and_type (ctx->gl_flavor, clone->pixman_format, &internal_format, &format, &type, &has_alpha, &needs_swap); assert (is_supported); assert (!needs_swap); src = clone; } cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8; status = _cairo_gl_surface_flush (&dst->base); if (unlikely (status)) goto FAIL; if (_cairo_gl_surface_is_texture (dst)) { void *data_start = src->data + src_y * src->stride + src_x * cpp; void *data_start_gles2 = NULL; /* * Due to GL_UNPACK_ROW_LENGTH missing in GLES2 we have to extract the * image data ourselves in some cases. In particular, we must extract * the pixels if: * a. we don't want full-length lines or * b. the row stride cannot be handled by GL itself using a 4 byte * alignment constraint */ if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES && (src->width * cpp < src->stride - 3 || width != src->width)) { glPixelStorei (GL_UNPACK_ALIGNMENT, 1); status = _cairo_gl_surface_extract_image_data (src, src_x, src_y, width, height, &data_start_gles2); if (unlikely (status)) goto FAIL; data_start = data_start_gles2; } else { glPixelStorei (GL_UNPACK_ALIGNMENT, 4); if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp); } _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP); glBindTexture (ctx->tex_target, dst->tex); glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexSubImage2D (ctx->tex_target, 0, dst_x, dst_y, width, height, format, type, data_start); free (data_start_gles2); /* If we just treated some rgb-only data as rgba, then we have to * go back and fix up the alpha channel where we filled in this * texture data. */ if (!has_alpha) { _cairo_gl_surface_fill_alpha_channel (dst, ctx, dst_x, dst_y, width, height); } } else { cairo_surface_t *tmp; tmp = _cairo_gl_surface_create_scratch (ctx, dst->base.content, width, height); if (unlikely (tmp->status)) goto FAIL; status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *) tmp, src, src_x, src_y, width, height, 0, 0); if (status == CAIRO_INT_STATUS_SUCCESS) { cairo_surface_pattern_t tmp_pattern; cairo_rectangle_int_t r; cairo_clip_t *clip; _cairo_pattern_init_for_surface (&tmp_pattern, tmp); cairo_matrix_init_translate (&tmp_pattern.base.matrix, -dst_x, -dst_y); tmp_pattern.base.filter = CAIRO_FILTER_NEAREST; tmp_pattern.base.extend = CAIRO_EXTEND_NONE; r.x = dst_x; r.y = dst_y; r.width = width; r.height = height; clip = _cairo_clip_intersect_rectangle (NULL, &r); status = _cairo_surface_paint (&dst->base, CAIRO_OPERATOR_SOURCE, &tmp_pattern.base, clip); _cairo_clip_destroy (clip); _cairo_pattern_fini (&tmp_pattern.base); } cairo_surface_destroy (tmp); } FAIL: status = _cairo_gl_context_release (ctx, status); if (clone) cairo_surface_destroy (&clone->base); return status; }