static cairo_status_t _cairo_recording_surface_finish (void *abstract_surface) { cairo_recording_surface_t *recording_surface = abstract_surface; cairo_command_t **elements; int i, num_elements; num_elements = recording_surface->commands.num_elements; elements = _cairo_array_index (&recording_surface->commands, 0); for (i = 0; i < num_elements; i++) { cairo_command_t *command = elements[i]; switch (command->header.type) { case CAIRO_COMMAND_PAINT: _cairo_pattern_fini (&command->paint.source.base); break; case CAIRO_COMMAND_MASK: _cairo_pattern_fini (&command->mask.source.base); _cairo_pattern_fini (&command->mask.mask.base); 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); break; case CAIRO_COMMAND_FILL: _cairo_pattern_fini (&command->fill.source.base); _cairo_path_fixed_fini (&command->fill.path); 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); break; default: ASSERT_NOT_REACHED; } _cairo_clip_fini (&command->header.clip); free (command); } _cairo_array_fini (&recording_surface->commands); _cairo_clip_fini (&recording_surface->clip); return CAIRO_STATUS_SUCCESS; }
static cairo_int_status_t _cairo_recording_surface_stroke (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, 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_clip_t *clip) { cairo_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; cairo_command_stroke_t *command; command = malloc (sizeof (cairo_command_stroke_t)); if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _command_init (recording_surface, &command->header, CAIRO_COMMAND_STROKE, op, clip); if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_path_fixed_init_copy (&command->path, path); if (unlikely (status)) goto CLEANUP_SOURCE; status = _cairo_stroke_style_init_copy (&command->style, style); if (unlikely (status)) goto CLEANUP_PATH; command->ctm = *ctm; command->ctm_inverse = *ctm_inverse; command->tolerance = tolerance; command->antialias = antialias; status = _cairo_array_append (&recording_surface->commands, &command); if (unlikely (status)) goto CLEANUP_STYLE; return CAIRO_STATUS_SUCCESS; CLEANUP_STYLE: _cairo_stroke_style_fini (&command->style); CLEANUP_PATH: _cairo_path_fixed_fini (&command->path); CLEANUP_SOURCE: _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: _cairo_clip_fini (&command->header.clip); free (command); return status; }
static cairo_int_status_t _cairo_recording_surface_mask (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, cairo_clip_t *clip) { cairo_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; cairo_command_mask_t *command; command = malloc (sizeof (cairo_command_mask_t)); if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _command_init (recording_surface, &command->header, CAIRO_COMMAND_MASK, op, clip); if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->mask.base, mask); if (unlikely (status)) goto CLEANUP_SOURCE; status = _cairo_array_append (&recording_surface->commands, &command); if (unlikely (status)) goto CLEANUP_MASK; return CAIRO_STATUS_SUCCESS; CLEANUP_MASK: _cairo_pattern_fini (&command->mask.base); CLEANUP_SOURCE: _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: _cairo_clip_fini (&command->header.clip); free (command); return status; }
static cairo_int_status_t _cairo_recording_surface_paint (void *abstract_surface, cairo_operator_t op, const cairo_pattern_t *source, cairo_clip_t *clip) { cairo_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; cairo_command_paint_t *command; command = malloc (sizeof (cairo_command_paint_t)); if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _command_init (recording_surface, &command->header, CAIRO_COMMAND_PAINT, op, clip); if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_array_append (&recording_surface->commands, &command); if (unlikely (status)) goto CLEANUP_SOURCE; /* An optimisation that takes care to not replay what was done * before surface is cleared. We don't erase recorded commands * since we may have earlier snapshots of this surface. */ if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) recording_surface->replay_start_idx = recording_surface->commands.num_elements; return CAIRO_STATUS_SUCCESS; CLEANUP_SOURCE: _cairo_pattern_fini (&command->source.base); CLEANUP_COMMAND: _cairo_clip_fini (&command->header.clip); free (command); return status; }
static cairo_int_status_t _cairo_recording_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_status_t status; cairo_recording_surface_t *recording_surface = abstract_surface; cairo_command_show_text_glyphs_t *command; command = malloc (sizeof (cairo_command_show_text_glyphs_t)); if (unlikely (command == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _command_init (recording_surface, &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, op, clip); if (unlikely (status)) goto CLEANUP_COMMAND; status = _cairo_pattern_init_snapshot (&command->source.base, source); if (unlikely (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 (unlikely (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 (unlikely (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 (unlikely (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 (&recording_surface->commands, &command); if (unlikely (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: _cairo_clip_fini (&command->header.clip); free (command); return 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; }
cairo_int_status_t _cairo_meta_surface_replay (cairo_surface_t *surface, cairo_surface_t *target) { cairo_meta_surface_t *meta; cairo_command_t *command, **elements; int i, num_elements; cairo_int_status_t status; cairo_traps_t traps; cairo_clip_t clip; meta = (cairo_meta_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; _cairo_clip_init (&clip, target); num_elements = meta->commands.num_elements; elements = (cairo_command_t **) meta->commands.elements; for (i = 0; i < num_elements; i++) { command = elements[i]; switch (command->type) { case CAIRO_COMMAND_COMPOSITE: status = _cairo_surface_set_clip (target, &clip); if (status) break; status = _cairo_surface_composite (command->composite.operator, &command->composite.src_pattern.base, command->composite.mask_pattern_pointer, target, command->composite.src_x, command->composite.src_y, command->composite.mask_x, command->composite.mask_y, command->composite.dst_x, command->composite.dst_y, command->composite.width, command->composite.height); break; case CAIRO_COMMAND_FILL_RECTANGLES: status = _cairo_surface_set_clip (target, &clip); if (status) break; status = _cairo_surface_fill_rectangles (target, command->fill_rectangles.operator, &command->fill_rectangles.color, command->fill_rectangles.rects, command->fill_rectangles.num_rects); break; case CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS: status = _cairo_surface_set_clip (target, &clip); if (status) break; status = _cairo_surface_composite_trapezoids (command->composite_trapezoids.operator, &command->composite_trapezoids.pattern.base, target, command->composite_trapezoids.antialias, command->composite_trapezoids.x_src, command->composite_trapezoids.y_src, command->composite_trapezoids.x_dst, command->composite_trapezoids.y_dst, command->composite_trapezoids.width, command->composite_trapezoids.height, command->composite_trapezoids.traps, command->composite_trapezoids.num_traps); break; case CAIRO_COMMAND_INTERSECT_CLIP_PATH: /* XXX Meta surface clipping is broken and requires some * cairo-gstate.c rewriting. Work around it for now. */ if (command->intersect_clip_path.path_pointer == NULL) status = _cairo_clip_reset (&clip); else status = _cairo_clip_clip (&clip, command->intersect_clip_path.path_pointer, command->intersect_clip_path.fill_rule, command->intersect_clip_path.tolerance, command->intersect_clip_path.antialias, target); break; case CAIRO_COMMAND_SHOW_GLYPHS: status = _cairo_surface_set_clip (target, &clip); if (status) break; status = _cairo_surface_show_glyphs (command->show_glyphs.scaled_font, command->show_glyphs.operator, &command->show_glyphs.pattern.base, target, command->show_glyphs.source_x, command->show_glyphs.source_y, command->show_glyphs.dest_x, command->show_glyphs.dest_y, command->show_glyphs.width, command->show_glyphs.height, command->show_glyphs.glyphs, command->show_glyphs.num_glyphs); if (status != CAIRO_INT_STATUS_UNSUPPORTED) break; status = (*command->show_glyphs.scaled_font->backend-> show_glyphs) (command->show_glyphs.scaled_font, command->show_glyphs.operator, &command->show_glyphs.pattern.base, target, command->show_glyphs.source_x, command->show_glyphs.source_y, command->show_glyphs.dest_x, command->show_glyphs.dest_y, command->show_glyphs.width, command->show_glyphs.height, command->show_glyphs.glyphs, command->show_glyphs.num_glyphs); break; case CAIRO_COMMAND_FILL_PATH: status = _cairo_surface_set_clip (target, &clip); if (status) break; status = _cairo_surface_fill_path (command->fill_path.operator, &command->fill_path.pattern.base, target, &command->fill_path.path, command->fill_path.fill_rule, command->fill_path.tolerance); if (status != CAIRO_INT_STATUS_UNSUPPORTED) break; _cairo_traps_init (&traps); status = _cairo_path_fixed_fill_to_traps (&command->fill_path.path, command->fill_path.fill_rule, command->fill_path.tolerance, &traps); if (status) { _cairo_traps_fini (&traps); break; } status = _cairo_surface_clip_and_composite_trapezoids (&command->fill_path.pattern.base, command->fill_path.operator, target, &traps, &clip, command->fill_path.antialias); _cairo_traps_fini (&traps); break; default: ASSERT_NOT_REACHED; } if (status) break; } _cairo_clip_fini (&clip); return status; }