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_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); 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; }
/* Handles compositing with a clip surface when we have to do the operation * in two pieces and combine them together. */ static cairo_status_t _clip_and_composite_combine (cairo_clip_t *clip, cairo_operator_t op, cairo_pattern_t *src, cairo_draw_func_t draw_func, void *draw_closure, cairo_surface_t *dst, const cairo_rectangle_int16_t *extents) { cairo_surface_t *intermediate; cairo_surface_pattern_t dst_pattern; cairo_surface_pattern_t intermediate_pattern; cairo_status_t status; /* We'd be better off here creating a surface identical in format * to dst, but we have no way of getting that information. * A CAIRO_CONTENT_CLONE or something might be useful. * cairo_surface_create_similar() also unnecessarily clears the surface. */ intermediate = cairo_surface_create_similar (dst, CAIRO_CONTENT_COLOR_ALPHA, extents->width, extents->height); if (intermediate->status) return CAIRO_STATUS_NO_MEMORY; /* Initialize the intermediate surface from the destination surface */ _cairo_pattern_init_for_surface (&dst_pattern, dst); status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, &dst_pattern.base, NULL, intermediate, extents->x, extents->y, 0, 0, 0, 0, extents->width, extents->height); _cairo_pattern_fini (&dst_pattern.base); if (status) goto CLEANUP_SURFACE; status = (*draw_func) (draw_closure, op, src, intermediate, extents->x, extents->y, extents); if (status) goto CLEANUP_SURFACE; /* Combine that with the clip */ status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN, intermediate, extents->x, extents->y, extents); if (status) goto CLEANUP_SURFACE; /* Punch the clip out of the destination */ status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT, dst, 0, 0, extents); if (status) goto CLEANUP_SURFACE; /* Now add the two results together */ _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate); status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, &intermediate_pattern.base, NULL, dst, 0, 0, 0, 0, extents->x, extents->y, extents->width, extents->height); _cairo_pattern_fini (&intermediate_pattern.base); CLEANUP_SURFACE: cairo_surface_destroy (intermediate); return status; }
/* Composites a region representing a set of trapezoids. */ static cairo_status_t _composite_trap_region (cairo_clip_t *clip, cairo_pattern_t *src, cairo_operator_t op, cairo_surface_t *dst, pixman_region16_t *trap_region, cairo_rectangle_int16_t *extents) { cairo_status_t status; cairo_pattern_union_t solid_pattern; cairo_pattern_union_t mask; int num_rects = pixman_region_num_rects (trap_region); unsigned int clip_serial; cairo_surface_t *clip_surface = clip ? clip->surface : NULL; if (clip_surface && op == CAIRO_OPERATOR_CLEAR) { _cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE); src = &solid_pattern.base; op = CAIRO_OPERATOR_DEST_OUT; } if (num_rects == 0) return CAIRO_STATUS_SUCCESS; if (num_rects > 1) { if (_cairo_surface_get_clip_mode (dst) != CAIRO_CLIP_MODE_REGION) return CAIRO_INT_STATUS_UNSUPPORTED; clip_serial = _cairo_surface_allocate_clip_serial (dst); status = _cairo_surface_set_clip_region (dst, trap_region, clip_serial); if (status) return status; } if (clip_surface) _cairo_pattern_init_for_surface (&mask.surface, clip_surface); status = _cairo_surface_composite (op, src, clip_surface ? &mask.base : NULL, dst, extents->x, extents->y, extents->x - (clip_surface ? clip->surface_rect.x : 0), extents->y - (clip_surface ? clip->surface_rect.y : 0), extents->x, extents->y, extents->width, extents->height); /* Restore the original clip if we modified it temporarily. */ if (num_rects >1) _cairo_surface_set_clip (dst, clip); if (clip_surface) _cairo_pattern_fini (&mask.base); if (src == &solid_pattern.base) _cairo_pattern_fini (&solid_pattern.base); 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; }
cairo_warn cairo_int_status_t _cairo_dwrite_scaled_show_glyphs(void *scaled_font, cairo_operator_t op, const cairo_pattern_t *pattern, cairo_surface_t *generic_surface, int source_x, int source_y, int dest_x, int dest_y, unsigned int width, unsigned int height, cairo_glyph_t *glyphs, int num_glyphs, cairo_region_t *clip_region, int *remaining_glyphs) { cairo_win32_surface_t *surface = (cairo_win32_surface_t *)generic_surface; cairo_int_status_t status; if (width == 0 || height == 0) return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; if (_cairo_surface_is_win32 (generic_surface) && surface->format == CAIRO_FORMAT_RGB24 && op == CAIRO_OPERATOR_OVER) { //XXX: we need to set the clip region here status = (cairo_int_status_t)_cairo_dwrite_show_glyphs_on_surface (surface, op, pattern, glyphs, num_glyphs, (cairo_scaled_font_t*)scaled_font, NULL); return status; } else { cairo_dwrite_scaled_font_t *dwritesf = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font); UINT16 *indices = new UINT16[num_glyphs]; DWRITE_GLYPH_OFFSET *offsets = new DWRITE_GLYPH_OFFSET[num_glyphs]; FLOAT *advances = new FLOAT[num_glyphs]; BOOL transform = FALSE; DWRITE_GLYPH_RUN run; run.bidiLevel = 0; run.fontFace = ((cairo_dwrite_font_face_t*)dwritesf->base.font_face)->dwriteface; run.glyphIndices = indices; run.glyphCount = num_glyphs; run.isSideways = FALSE; run.glyphOffsets = offsets; run.glyphAdvances = advances; IDWriteGlyphRunAnalysis *analysis; if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 && dwritesf->mat.xx == dwritesf->base.font_matrix.xx && dwritesf->mat.yy == dwritesf->base.font_matrix.yy) { for (int i = 0; i < num_glyphs; i++) { indices[i] = (WORD) glyphs[i].index; // Since we will multiply by our ctm matrix later for rotation effects // and such, adjust positions by the inverse matrix now. offsets[i].ascenderOffset = (FLOAT)dest_y - (FLOAT)glyphs[i].y; offsets[i].advanceOffset = (FLOAT)glyphs[i].x - dest_x; advances[i] = 0.0; } run.fontEmSize = (FLOAT)dwritesf->base.font_matrix.yy; } else { transform = TRUE; for (int i = 0; i < num_glyphs; i++) { indices[i] = (WORD) glyphs[i].index; double x = glyphs[i].x - dest_x; double y = glyphs[i].y - dest_y; cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y); // Since we will multiply by our ctm matrix later for rotation effects // and such, adjust positions by the inverse matrix now. offsets[i].ascenderOffset = -(FLOAT)y; offsets[i].advanceOffset = (FLOAT)x; advances[i] = 0.0; } run.fontEmSize = 1.0f; } if (!transform) { DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run, 1.0f, NULL, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, DWRITE_MEASURING_MODE_NATURAL, 0, 0, &analysis); } else { DWRITE_MATRIX dwmatrix = _cairo_dwrite_matrix_from_matrix(&dwritesf->mat); DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run, 1.0f, &dwmatrix, DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, DWRITE_MEASURING_MODE_NATURAL, 0, 0, &analysis); } RECT r; r.left = 0; r.top = 0; r.right = width; r.bottom = height; BYTE *surface = new BYTE[width * height * 3]; analysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &r, surface, width * height * 3); cairo_image_surface_t *mask_surface = (cairo_image_surface_t*)cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_surface_flush(&mask_surface->base); for (unsigned int y = 0; y < height; y++) { for (unsigned int x = 0; x < width; x++) { mask_surface->data[y * mask_surface->stride + x * 4] = surface[y * width * 3 + x * 3 + 1]; mask_surface->data[y * mask_surface->stride + x * 4 + 1] = surface[y * width * 3 + x * 3 + 1]; mask_surface->data[y * mask_surface->stride + x * 4 + 2] = surface[y * width * 3 + x * 3 + 1]; mask_surface->data[y * mask_surface->stride + x * 4 + 3] = surface[y * width * 3 + x * 3 + 1]; } } cairo_surface_mark_dirty(&mask_surface->base); pixman_image_set_component_alpha(mask_surface->pixman_image, 1); cairo_surface_pattern_t mask; _cairo_pattern_init_for_surface (&mask, &mask_surface->base); status = (cairo_int_status_t)_cairo_surface_composite (op, pattern, &mask.base, generic_surface, source_x, source_y, 0, 0, dest_x, dest_y, width, height, clip_region); _cairo_pattern_fini (&mask.base); analysis->Release(); delete [] surface; delete [] indices; delete [] offsets; delete [] advances; cairo_surface_destroy (&mask_surface->base); *remaining_glyphs = 0; return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; } }
static cairo_int_status_t traps_to_operand (void *_dst, const cairo_rectangle_int_t *extents, cairo_antialias_t antialias, cairo_traps_t *traps, cairo_gl_operand_t *operand, int dst_x, int dst_y) { pixman_format_code_t pixman_format; pixman_image_t *pixman_image; cairo_surface_t *image, *mask; cairo_surface_pattern_t pattern; cairo_status_t status; pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1; pixman_image = pixman_image_create_bits (pixman_format, extents->width, extents->height, NULL, 0); if (unlikely (pixman_image == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps); image = _cairo_image_surface_create_for_pixman_image (pixman_image, pixman_format); if (unlikely (image->status)) { pixman_image_unref (pixman_image); return image->status; } /* GLES2 only supports RGB/RGBA when uploading */ if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) { cairo_surface_pattern_t pattern; cairo_surface_t *rgba_image; /* XXX perform this fixup inside _cairo_gl_draw_image() */ rgba_image = _cairo_image_surface_create_with_pixman_format (NULL, _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8, extents->width, extents->height, 0); if (unlikely (rgba_image->status)) return rgba_image->status; _cairo_pattern_init_for_surface (&pattern, image); status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); cairo_surface_destroy (image); image = rgba_image; if (unlikely (status)) { cairo_surface_destroy (image); return status; } } mask = _cairo_surface_create_similar_scratch (_dst, CAIRO_CONTENT_COLOR_ALPHA, extents->width, extents->height); if (unlikely (mask->status)) { cairo_surface_destroy (image); return mask->status; } status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask, (cairo_image_surface_t *)image, 0, 0, extents->width, extents->height, 0, 0); cairo_surface_destroy (image); if (unlikely (status)) goto error; _cairo_pattern_init_for_surface (&pattern, mask); cairo_matrix_init_translate (&pattern.base.matrix, -extents->x+dst_x, -extents->y+dst_y); pattern.base.filter = CAIRO_FILTER_NEAREST; pattern.base.extend = CAIRO_EXTEND_NONE; status = _cairo_gl_operand_init (operand, &pattern.base, _dst, &_cairo_unbounded_rectangle, &_cairo_unbounded_rectangle); _cairo_pattern_fini (&pattern.base); if (unlikely (status)) goto error; operand->texture.owns_surface = mask; return CAIRO_STATUS_SUCCESS; error: cairo_surface_destroy (mask); return status; }
cairo_status_t _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, cairo_operator_t op, cairo_pattern_t *pattern, cairo_surface_t *surface, int source_x, int source_y, int dest_x, int dest_y, unsigned int width, unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs) { cairo_status_t status; cairo_surface_t *mask = NULL; int i; /* These operators aren't interpreted the same way by the backends; * they are implemented in terms of other operators in cairo-gstate.c */ assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR); if (scaled_font->status) return scaled_font->status; if (scaled_font->backend->show_glyphs != NULL) { status = scaled_font->backend->show_glyphs (scaled_font, op, pattern, surface, source_x, source_y, dest_x, dest_y, width, height, glyphs, num_glyphs); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } /* Font display routine either does not exist or failed. */ status = CAIRO_STATUS_SUCCESS; _cairo_cache_freeze (scaled_font->glyphs); for (i = 0; i < num_glyphs; i++) { int x, y; cairo_surface_pattern_t glyph_pattern; cairo_image_surface_t *glyph_surface; cairo_scaled_glyph_t *scaled_glyph; status = _cairo_scaled_glyph_lookup (scaled_font, glyphs[i].index, CAIRO_SCALED_GLYPH_INFO_SURFACE, &scaled_glyph); if (status) goto CLEANUP_MASK; glyph_surface = scaled_glyph->surface; /* Create the mask using the format from the first glyph */ if (mask == NULL) { mask = cairo_image_surface_create (glyph_surface->format, width, height); if (mask->status) { status = mask->status; goto CLEANUP_MASK; } status = _cairo_surface_fill_rectangle (mask, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, 0, 0, width, height); if (status) goto CLEANUP_MASK; if (glyph_surface->format == CAIRO_FORMAT_ARGB32) pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)-> pixman_image, TRUE); } /* round glyph locations to the nearest pixel */ x = (int) floor (glyphs[i].x + glyph_surface->base.device_x_offset + 0.5); y = (int) floor (glyphs[i].y + glyph_surface->base.device_y_offset + 0.5); _cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base); status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, &glyph_pattern.base, NULL, mask, 0, 0, 0, 0, x - dest_x, y - dest_y, glyph_surface->width, glyph_surface->height); _cairo_pattern_fini (&glyph_pattern.base); if (status) break; } if (mask != NULL) { cairo_surface_pattern_t mask_pattern; _cairo_pattern_init_for_surface (&mask_pattern, mask); status = _cairo_surface_composite (op, pattern, &mask_pattern.base, surface, source_x, source_y, 0, 0, dest_x, dest_y, width, height); _cairo_pattern_fini (&mask_pattern.base); } CLEANUP_MASK: _cairo_cache_thaw (scaled_font->glyphs); if (mask != NULL) cairo_surface_destroy (mask); return status; }
static cairo_int_status_t _cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor, cairo_composite_rectangles_t *extents, 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) { cairo_surface_t *mask; cairo_surface_pattern_t pattern; cairo_int_status_t status; cairo_clip_t *clip; if (! extents->is_bounded) return CAIRO_INT_STATUS_UNSUPPORTED; TRACE ((stderr, "%s\n", __FUNCTION__)); mask = _cairo_surface_create_scratch (extents->surface, CAIRO_CONTENT_ALPHA, extents->bounded.width, extents->bounded.height, NULL); if (unlikely (mask->status)) return mask->status; clip = extents->clip; if (! _cairo_clip_is_region (clip)) clip = _cairo_clip_copy_region (clip); if (! mask->is_clear) { status = _cairo_surface_offset_paint (mask, extents->bounded.x, extents->bounded.y, CAIRO_OPERATOR_CLEAR, &_cairo_pattern_clear.base, clip); if (unlikely (status)) goto error; } status = _cairo_surface_offset_stroke (mask, extents->bounded.x, extents->bounded.y, CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, path, style, ctm, ctm_inverse, tolerance, antialias, clip); if (unlikely (status)) goto error; if (clip != extents->clip) { status = _cairo_clip_combine_with_surface (extents->clip, mask, extents->bounded.x, extents->bounded.y); if (unlikely (status)) goto error; } _cairo_pattern_init_for_surface (&pattern, mask); cairo_matrix_init_translate (&pattern.base.matrix, -extents->bounded.x, -extents->bounded.y); pattern.base.filter = CAIRO_FILTER_NEAREST; pattern.base.extend = CAIRO_EXTEND_NONE; if (extents->op == CAIRO_OPERATOR_SOURCE) { status = _cairo_surface_mask (extents->surface, CAIRO_OPERATOR_DEST_OUT, &_cairo_pattern_white.base, &pattern.base, clip); if ((status == CAIRO_INT_STATUS_SUCCESS)) { status = _cairo_surface_mask (extents->surface, CAIRO_OPERATOR_ADD, &extents->source_pattern.base, &pattern.base, clip); } } else { status = _cairo_surface_mask (extents->surface, extents->op, &extents->source_pattern.base, &pattern.base, clip); } _cairo_pattern_fini (&pattern.base); error: cairo_surface_destroy (mask); if (clip != extents->clip) _cairo_clip_destroy (clip); return status; }
static cairo_int_status_t _cairo_tee_surface_show_text_glyphs (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const char *utf8, int utf8_len, cairo_glyph_t *glyphs, int num_glyphs, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font, cairo_clip_t *clip) { cairo_tee_surface_t *surface = abstract_surface; cairo_surface_wrapper_t *slaves; int n, num_slaves; cairo_status_t status; cairo_glyph_t *glyphs_copy; const cairo_pattern_t *matched_source; cairo_surface_pattern_t temp; /* XXX: This copying is ugly. */ glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (unlikely (glyphs_copy == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp); status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op, matched_source, utf8, utf8_len, glyphs_copy, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, clip); if (matched_source == &temp.base) { _cairo_pattern_fini (&temp.base); } if (unlikely (status)) goto CLEANUP; num_slaves = _cairo_array_num_elements (&surface->slaves); slaves = _cairo_array_index (&surface->slaves, 0); for (n = 0; n < num_slaves; n++) { memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp); status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], op, matched_source, utf8, utf8_len, glyphs_copy, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, clip); if (matched_source == &temp.base) { _cairo_pattern_fini (&temp.base); } if (unlikely (status)) goto CLEANUP; } CLEANUP: free (glyphs_copy); return status; }
static cairo_int_status_t _cairo_meta_surface_show_text_glyphs (void *abstract_surface, cairo_operator_t op, cairo_pattern_t *source, const char *utf8, int utf8_len, cairo_glyph_t *glyphs, int num_glyphs, const cairo_text_cluster_t *clusters, int num_clusters, cairo_text_cluster_flags_t cluster_flags, cairo_scaled_font_t *scaled_font) { cairo_status_t status; cairo_meta_surface_t *meta = abstract_surface; cairo_command_show_text_glyphs_t *command; command = malloc (sizeof (cairo_command_show_text_glyphs_t)); if (command == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); command->header.type = CAIRO_COMMAND_SHOW_TEXT_GLYPHS; command->header.region = CAIRO_META_REGION_ALL; command->op = op; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (status) goto CLEANUP_COMMAND; command->utf8 = NULL; command->utf8_len = utf8_len; command->glyphs = NULL; command->num_glyphs = num_glyphs; command->clusters = NULL; command->num_clusters = num_clusters; if (utf8_len) { command->utf8 = malloc (utf8_len); if (command->utf8 == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_ARRAYS; } memcpy (command->utf8, utf8, utf8_len); } if (num_glyphs) { command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0])); if (command->glyphs == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_ARRAYS; } memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs); } if (num_clusters) { command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0])); if (command->clusters == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto CLEANUP_ARRAYS; } memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters); } command->cluster_flags = cluster_flags; command->scaled_font = cairo_scaled_font_reference (scaled_font); status = _cairo_array_append (&meta->commands, &command); if (status) goto CLEANUP_SCALED_FONT; return CAIRO_STATUS_SUCCESS; CLEANUP_SCALED_FONT: cairo_scaled_font_destroy (command->scaled_font); CLEANUP_ARRAYS: free (command->utf8); free (command->glyphs); free (command->clusters); _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: free (command); return status; }
static cairo_status_t _cairo_meta_surface_finish (void *abstract_surface) { cairo_meta_surface_t *meta = abstract_surface; cairo_command_t *command; cairo_command_t **elements; int i, num_elements; if (meta->commands_owner) { cairo_surface_destroy (meta->commands_owner); return CAIRO_STATUS_SUCCESS; } num_elements = meta->commands.num_elements; elements = _cairo_array_index (&meta->commands, 0); for (i = 0; i < num_elements; i++) { command = elements[i]; switch (command->header.type) { /* 5 basic drawing operations */ case CAIRO_COMMAND_PAINT: _cairo_pattern_fini (&command->paint.source.base); free (command); break; case CAIRO_COMMAND_MASK: _cairo_pattern_fini (&command->mask.source.base); _cairo_pattern_fini (&command->mask.mask.base); free (command); break; case CAIRO_COMMAND_STROKE: _cairo_pattern_fini (&command->stroke.source.base); _cairo_path_fixed_fini (&command->stroke.path); _cairo_stroke_style_fini (&command->stroke.style); free (command); break; case CAIRO_COMMAND_FILL: _cairo_pattern_fini (&command->fill.source.base); _cairo_path_fixed_fini (&command->fill.path); free (command); break; case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: _cairo_pattern_fini (&command->show_text_glyphs.source.base); free (command->show_text_glyphs.utf8); free (command->show_text_glyphs.glyphs); free (command->show_text_glyphs.clusters); cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font); free (command); break; /* Other junk. */ case CAIRO_COMMAND_INTERSECT_CLIP_PATH: if (command->intersect_clip_path.path_pointer) _cairo_path_fixed_fini (&command->intersect_clip_path.path); free (command); break; default: ASSERT_NOT_REACHED; } } _cairo_array_fini (&meta->commands); return CAIRO_STATUS_SUCCESS; }
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); }
static cairo_status_t _cairo_clip_intersect_mask (cairo_clip_t *clip, cairo_traps_t *traps, cairo_antialias_t antialias, cairo_surface_t *target) { cairo_pattern_union_t pattern; cairo_box_t extents; cairo_rectangle_t surface_rect, target_rect; cairo_surface_t *surface; cairo_status_t status; /* Represent the clip as a mask surface. We create a new surface * the size of the intersection of the old mask surface and the * extents of the new clip path. */ _cairo_traps_extents (traps, &extents); _cairo_box_round_to_rectangle (&extents, &surface_rect); if (clip->surface != NULL) _cairo_rectangle_intersect (&surface_rect, &clip->surface_rect); /* Intersect with the target surface rectangle so we don't use * more memory and time than we need to. */ status = _cairo_surface_get_extents (target, &target_rect); if (!status) _cairo_rectangle_intersect (&surface_rect, &target_rect); surface = _cairo_surface_create_similar_solid (target, CAIRO_CONTENT_ALPHA, surface_rect.width, surface_rect.height, CAIRO_COLOR_WHITE); if (surface->status) return CAIRO_STATUS_NO_MEMORY; /* Render the new clipping path into the new mask surface. */ _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y); _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE); status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, &pattern.base, surface, antialias, 0, 0, 0, 0, surface_rect.width, surface_rect.height, traps->traps, traps->num_traps); _cairo_pattern_fini (&pattern.base); if (status) { cairo_surface_destroy (surface); return status; } /* If there was a clip surface already, combine it with the new * mask surface using the IN operator, so we get the intersection * of the old and new clipping paths. */ if (clip->surface != NULL) { _cairo_pattern_init_for_surface (&pattern.surface, clip->surface); status = _cairo_surface_composite (CAIRO_OPERATOR_IN, &pattern.base, NULL, surface, surface_rect.x - clip->surface_rect.x, surface_rect.y - clip->surface_rect.y, 0, 0, 0, 0, surface_rect.width, surface_rect.height); _cairo_pattern_fini (&pattern.base); if (status) { cairo_surface_destroy (surface); return status; } cairo_surface_destroy (clip->surface); } clip->surface = surface; clip->surface_rect = surface_rect; clip->serial = _cairo_surface_allocate_clip_serial (target); return status; }