cairo_status_t _cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, cairo_clip_t *clip) { cairo_status_t status; cairo_bool_t clear; /* XXX as we cache a reference to the path, and compare every time, * we may in future need to install a notification if the clip->path * is every modified (e.g. cairo_clip_translate). */ if (clip == NULL && clipper->clip.path == NULL) return CAIRO_STATUS_SUCCESS; if (clip != NULL && clip->path == clipper->clip.path) return CAIRO_STATUS_SUCCESS; if (clip != NULL && clipper->clip.path != NULL && _cairo_path_fixed_equal (&clip->path->path, &clipper->clip.path->path)) { return CAIRO_STATUS_SUCCESS; } /* all clipped out state should never propagate this far */ assert (clip == NULL || clip->path != NULL); /* Check whether this clip is a continuation of the previous. * If not, we have to remove the current clip and rebuild. */ clear = clip == NULL || clip->path->prev != clipper->clip.path; _cairo_clip_reset (&clipper->clip); _cairo_clip_init_copy (&clipper->clip, clip); if (clear) { clipper->is_clipped = FALSE; status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0); if (unlikely (status)) return status; if (clip != NULL && clip->path != NULL) { status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper, clip->path); clipper->is_clipped = TRUE; } } else { cairo_clip_path_t *path = clip->path; clipper->is_clipped = TRUE; status = clipper->intersect_clip_path (clipper, &path->path, path->fill_rule, path->tolerance, path->antialias); } return status; }
cairo_status_t _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, cairo_clip_t *clip) { cairo_status_t status; cairo_matrix_t device_transform; cairo_path_fixed_t path_copy, *dev_path = path; cairo_clip_t clip_copy, *dev_clip = clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; if (clip && clip->all_clipped) return CAIRO_STATUS_SUCCESS; if (_cairo_surface_wrapper_needs_device_transform (wrapper, &device_transform)) { status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; _cairo_path_fixed_transform (&path_copy, &device_transform); dev_path = &path_copy; if (clip != NULL) { status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &device_transform); if (unlikely (status)) goto FINISH; dev_clip = &clip_copy; } } else { if (clip != NULL) { dev_clip = &clip_copy; _cairo_clip_init_copy (&clip_copy, clip); } } status = _cairo_surface_fill (wrapper->target, 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_reset (dev_clip); return status; }
cairo_status_t _cairo_clip_init_copy_transformed (cairo_clip_t *clip, cairo_clip_t *other, const cairo_matrix_t *matrix) { cairo_status_t status = CAIRO_STATUS_SUCCESS; int tx, ty; if (other == NULL) { _cairo_clip_init (clip); return CAIRO_STATUS_SUCCESS; } if (other->all_clipped) { _cairo_clip_init (clip); clip->all_clipped = TRUE; return CAIRO_STATUS_SUCCESS; } if (_cairo_matrix_is_identity (matrix)) { _cairo_clip_init_copy (clip, other); return CAIRO_STATUS_SUCCESS; } if (other->path != NULL) { _cairo_clip_init (clip); /* if we only need to translate, so we can reuse the caches... */ /* XXX we still loose the benefit of constructs when the copy is * deleted though. Indirect clip_paths? */ if (_cairo_matrix_is_integer_translation (matrix, &tx, &ty)) { status = _cairo_clip_path_reapply_clip_path_translate (clip, other->path, tx, ty); } else { status = _cairo_clip_path_reapply_clip_path_transform (clip, other->path, matrix); if (clip->path->extents.width == 0 && clip->path->extents.height == 0) { _cairo_clip_set_all_clipped (clip); } } } return status; }
static cairo_status_t _command_init (cairo_recording_surface_t *recording_surface, cairo_command_header_t *command, cairo_command_type_t type, cairo_operator_t op, cairo_clip_t *clip) { cairo_status_t status = CAIRO_STATUS_SUCCESS; command->type = type; command->op = op; command->region = CAIRO_RECORDING_REGION_ALL; _cairo_clip_init_copy (&command->clip, clip); if (recording_surface->clip.path != NULL) status = _cairo_clip_apply_clip (&command->clip, &recording_surface->clip); return status; }
cairo_status_t _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, cairo_clip_t *clip) { cairo_status_t status; cairo_matrix_t device_transform; cairo_clip_t clip_copy, *dev_clip = clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; if (clip && clip->all_clipped) return CAIRO_STATUS_SUCCESS; if (clip != NULL) { if (_cairo_surface_wrapper_needs_device_transform (wrapper, &device_transform)) { status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &device_transform); if (unlikely (status)) goto FINISH; } else { _cairo_clip_init_copy (&clip_copy, clip); } dev_clip = &clip_copy; } status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip); FINISH: if (dev_clip != clip) _cairo_clip_reset (dev_clip); return status; }
/** * _cairo_recording_surface_snapshot * @surface: a #cairo_surface_t which must be a recording surface * * Make an immutable copy of @surface. It is an error to call a * surface-modifying function on the result of this function. * * The caller owns the return value and should call * cairo_surface_destroy() when finished with it. This function will not * return %NULL, but will return a nil surface instead. * * Return value: The snapshot surface. **/ static cairo_surface_t * _cairo_recording_surface_snapshot (void *abstract_other) { cairo_recording_surface_t *other = abstract_other; cairo_recording_surface_t *recording_surface; cairo_status_t status; recording_surface = malloc (sizeof (cairo_recording_surface_t)); if (unlikely (recording_surface == NULL)) return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _cairo_surface_init (&recording_surface->base, &cairo_recording_surface_backend, NULL, /* device */ other->base.content); recording_surface->extents_pixels = other->extents_pixels; recording_surface->extents = other->extents; recording_surface->unbounded = other->unbounded; recording_surface->content = other->content; _cairo_clip_init_copy (&recording_surface->clip, &other->clip); /* XXX We should in theory be able to reuse the original array, but we * need to handle reference cycles during subsurface and self-copy. */ recording_surface->replay_start_idx = 0; recording_surface->base.is_clear = TRUE; _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *)); status = _cairo_recording_surface_replay (&other->base, &recording_surface->base); if (unlikely (status)) { cairo_surface_destroy (&recording_surface->base); return _cairo_surface_create_in_error (status); } return &recording_surface->base; }
cairo_status_t _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, 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_matrix_t device_transform; cairo_clip_t clip_copy, *dev_clip = clip; cairo_glyph_t *dev_glyphs = glyphs; if (unlikely (wrapper->target->status)) return wrapper->target->status; if (glyphs == NULL || num_glyphs == 0) return CAIRO_STATUS_SUCCESS; if (clip && clip->all_clipped) return CAIRO_STATUS_SUCCESS; if (_cairo_surface_wrapper_needs_device_transform (wrapper, &device_transform)) { int i; if (clip != NULL) { dev_clip = &clip_copy; status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &device_transform); if (unlikely (status)) goto FINISH; } dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (dev_glyphs == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto FINISH; } for (i = 0; i < num_glyphs; i++) { dev_glyphs[i] = glyphs[i]; cairo_matrix_transform_point (&device_transform, &dev_glyphs[i].x, &dev_glyphs[i].y); } } else { if (clip != NULL) { dev_clip = &clip_copy; _cairo_clip_init_copy (&clip_copy, clip); } } status = _cairo_surface_show_text_glyphs (wrapper->target, op, source, utf8, utf8_len, dev_glyphs, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, dev_clip); FINISH: if (dev_clip != clip) _cairo_clip_reset (dev_clip); if (dev_glyphs != glyphs) free (dev_glyphs); return status; }
cairo_status_t _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, cairo_operator_t fill_op, const cairo_pattern_t *fill_source, cairo_fill_rule_t fill_rule, double fill_tolerance, cairo_antialias_t fill_antialias, cairo_path_fixed_t *path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, cairo_stroke_style_t *stroke_style, cairo_matrix_t *stroke_ctm, cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, cairo_clip_t *clip) { cairo_status_t status; cairo_matrix_t device_transform; cairo_path_fixed_t path_copy, *dev_path = path; cairo_clip_t clip_copy, *dev_clip = clip; cairo_matrix_t dev_ctm = *stroke_ctm; cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; if (unlikely (wrapper->target->status)) return wrapper->target->status; if (clip && clip->all_clipped) return CAIRO_STATUS_SUCCESS; if (_cairo_surface_wrapper_needs_device_transform (wrapper, &device_transform)) { status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; _cairo_path_fixed_transform (&path_copy, &device_transform); dev_path = &path_copy; if (clip != NULL) { status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &device_transform); if (unlikely (status)) goto FINISH; dev_clip = &clip_copy; } cairo_matrix_multiply (&dev_ctm, &dev_ctm, &device_transform); status = cairo_matrix_invert (&device_transform); assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_multiply (&dev_ctm_inverse, &device_transform, &dev_ctm_inverse); } else { if (clip != NULL) { dev_clip = &clip_copy; _cairo_clip_init_copy (&clip_copy, clip); } } status = _cairo_surface_fill_stroke (wrapper->target, fill_op, fill_source, fill_rule, fill_tolerance, fill_antialias, dev_path, stroke_op, stroke_source, stroke_style, &dev_ctm, &dev_ctm_inverse, stroke_tolerance, stroke_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 bool _cairo_qt_fast_fill (cairo_qt_surface_t *qs, const cairo_pattern_t *source, const cairo_path_fixed_t *path = NULL, cairo_fill_rule_t fill_rule = CAIRO_FILL_RULE_WINDING, double tolerance = 0.0, cairo_antialias_t antialias = CAIRO_ANTIALIAS_NONE) { #if ENABLE_FAST_FILL QImage *qsSrc_image = NULL; QPixmap *qsSrc_pixmap = NULL; std::auto_ptr<QImage> qsSrc_image_d; if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t*) source; if (spattern->surface->type == CAIRO_SURFACE_TYPE_QT) { cairo_qt_surface_t *p = (cairo_qt_surface_t*) spattern->surface; qsSrc_image = p->image; qsSrc_pixmap = p->pixmap; } else if (spattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) { cairo_image_surface_t *p = (cairo_image_surface_t*) spattern->surface; qsSrc_image = new QImage((const uchar*) p->data, p->width, p->height, p->stride, _qimage_format_from_cairo_format(p->format)); qsSrc_image_d.reset(qsSrc_image); } } if (!qsSrc_image && !qsSrc_pixmap) return false; // We can only drawTiledPixmap; there's no drawTiledImage if (! qsSrc_pixmap && (source->extend == CAIRO_EXTEND_REPEAT || source->extend == CAIRO_EXTEND_REFLECT)) { return false; } QMatrix sourceMatrix = _qmatrix_from_cairo_matrix (source->matrix); // We can draw this faster by clipping and calling drawImage/drawPixmap. // Use our own clipping function so that we can get the // region handling to end up with the fastest possible clip. // // XXX Antialiasing will fail pretty hard here, since we can't clip with AA // with QPainter. qs->p->save(); if (path) { cairo_int_status_t status; cairo_clip_t clip, old_clip = qs->clipper.clip; _cairo_clip_init_copy (&clip, &qs->clipper.clip); status = (cairo_int_status_t) _cairo_clip_clip (&clip, path, fill_rule, tolerance, antialias); if (unlikely (status)) { qs->p->restore(); return false; } status = _cairo_qt_surface_set_clip (qs, &clip); if (unlikely (status)) { qs->p->restore(); return false; } _cairo_clip_reset (&clip); qs->clipper.clip = old_clip; } qs->p->setWorldMatrix (sourceMatrix.inverted(), true); switch (source->extend) { case CAIRO_EXTEND_REPEAT: // XXX handle reflect by tiling 4 times first case CAIRO_EXTEND_REFLECT: { assert (qsSrc_pixmap); // Render the tiling to cover the entire destination window (because // it'll be clipped). Transform the window rect by the inverse // of the current world transform so that the device coordinates // end up as the right thing. QRectF dest = qs->p->worldTransform().inverted().mapRect(QRectF(qs->window)); QPointF origin = sourceMatrix.map(QPointF(0.0, 0.0)); qs->p->drawTiledPixmap (dest, *qsSrc_pixmap, origin); } break; case CAIRO_EXTEND_NONE: case CAIRO_EXTEND_PAD: // XXX not exactly right, but good enough default: if (qsSrc_image) qs->p->drawImage (0, 0, *qsSrc_image); else if (qsSrc_pixmap) qs->p->drawPixmap (0, 0, *qsSrc_pixmap); break; } qs->p->restore(); return true; #else return false; #endif }
cairo_status_t _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, cairo_operator_t op, const cairo_pattern_t *source, cairo_clip_t *clip) { cairo_status_t status; cairo_clip_t clip_copy, *dev_clip = clip; cairo_pattern_union_t source_copy; cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; if (wrapper->has_extents) { _cairo_clip_init_copy (&target_clip, clip); status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); if (unlikely (status)) goto FINISH; dev_clip = clip = &target_clip; } if (clip && clip->all_clipped) { status = CAIRO_STATUS_SUCCESS; goto FINISH; } if (_cairo_surface_wrapper_needs_device_transform (wrapper) || _cairo_surface_wrapper_needs_extents_transform (wrapper)) { cairo_matrix_t m; cairo_matrix_init_identity (&m); if (_cairo_surface_wrapper_needs_extents_transform (wrapper)) cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y); if (_cairo_surface_wrapper_needs_device_transform (wrapper)) cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); if (clip != NULL) { status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; dev_clip = &clip_copy; } status = cairo_matrix_invert (&m); assert (status == CAIRO_STATUS_SUCCESS); _copy_transformed_pattern (&source_copy.base, source, &m); source = &source_copy.base; } status = _cairo_surface_paint (wrapper->target, op, source, dev_clip); FINISH: if (wrapper->has_extents) _cairo_clip_reset (&target_clip); if (dev_clip != clip) _cairo_clip_reset (dev_clip); return status; }
cairo_status_t _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, 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_clip_t clip_copy, *dev_clip = clip; cairo_glyph_t *dev_glyphs = glyphs; cairo_pattern_union_t source_copy; cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; if (glyphs == NULL || num_glyphs == 0) return CAIRO_STATUS_SUCCESS; if (wrapper->has_extents) { _cairo_clip_init_copy (&target_clip, clip); status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); if (unlikely (status)) goto FINISH; dev_clip = clip = &target_clip; } if (clip && clip->all_clipped) { status = CAIRO_STATUS_SUCCESS; goto FINISH; } if (_cairo_surface_wrapper_needs_device_transform (wrapper) || _cairo_surface_wrapper_needs_extents_transform (wrapper)) { cairo_matrix_t m; int i; cairo_matrix_init_identity (&m); if (_cairo_surface_wrapper_needs_extents_transform (wrapper)) cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y); if (_cairo_surface_wrapper_needs_device_transform (wrapper)) cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); if (clip != NULL) { status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; dev_clip = &clip_copy; } dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (dev_glyphs == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); goto FINISH; } for (i = 0; i < num_glyphs; i++) { dev_glyphs[i] = glyphs[i]; cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y); } status = cairo_matrix_invert (&m); assert (status == CAIRO_STATUS_SUCCESS); _copy_transformed_pattern (&source_copy.base, source, &m); source = &source_copy.base; } else { if (clip != NULL) { dev_clip = &clip_copy; _cairo_clip_init_copy (&clip_copy, clip); } } status = _cairo_surface_show_text_glyphs (wrapper->target, op, source, utf8, utf8_len, dev_glyphs, num_glyphs, clusters, num_clusters, cluster_flags, scaled_font, dev_clip); FINISH: if (dev_clip != clip) _cairo_clip_reset (dev_clip); if (wrapper->has_extents) _cairo_clip_reset (&target_clip); if (dev_glyphs != glyphs) free (dev_glyphs); return status; }
cairo_status_t _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, cairo_operator_t fill_op, const cairo_pattern_t *fill_source, cairo_fill_rule_t fill_rule, double fill_tolerance, cairo_antialias_t fill_antialias, cairo_path_fixed_t *path, cairo_operator_t stroke_op, const cairo_pattern_t *stroke_source, const cairo_stroke_style_t *stroke_style, const cairo_matrix_t *stroke_ctm, const cairo_matrix_t *stroke_ctm_inverse, double stroke_tolerance, cairo_antialias_t stroke_antialias, cairo_clip_t *clip) { cairo_status_t status; cairo_path_fixed_t path_copy, *dev_path = path; cairo_clip_t clip_copy, *dev_clip = clip; cairo_matrix_t dev_ctm = *stroke_ctm; cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; cairo_pattern_union_t stroke_source_copy; cairo_pattern_union_t fill_source_copy; cairo_clip_t target_clip; if (unlikely (wrapper->target->status)) return wrapper->target->status; if (wrapper->has_extents) { _cairo_clip_init_copy (&target_clip, clip); status = _cairo_clip_rectangle (&target_clip, &wrapper->extents); if (unlikely (status)) goto FINISH; dev_clip = clip = &target_clip; } if (clip && clip->all_clipped) { status = CAIRO_STATUS_SUCCESS; goto FINISH; } if (_cairo_surface_wrapper_needs_device_transform (wrapper) || _cairo_surface_wrapper_needs_extents_transform (wrapper)) { cairo_matrix_t m; cairo_matrix_init_identity (&m); if (_cairo_surface_wrapper_needs_extents_transform (wrapper)) cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y); if (_cairo_surface_wrapper_needs_device_transform (wrapper)) cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m); status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (unlikely (status)) goto FINISH; _cairo_path_fixed_transform (&path_copy, &m); dev_path = &path_copy; if (clip != NULL) { status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m); if (unlikely (status)) goto FINISH; dev_clip = &clip_copy; } cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); status = cairo_matrix_invert (&m); assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m); stroke_source = &stroke_source_copy.base; _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m); fill_source = &fill_source_copy.base; } else { if (clip != NULL) { dev_clip = &clip_copy; _cairo_clip_init_copy (&clip_copy, clip); } } status = _cairo_surface_fill_stroke (wrapper->target, fill_op, fill_source, fill_rule, fill_tolerance, fill_antialias, dev_path, stroke_op, stroke_source, stroke_style, &dev_ctm, &dev_ctm_inverse, stroke_tolerance, stroke_antialias, dev_clip); FINISH: if (dev_path != path) _cairo_path_fixed_fini (dev_path); if (wrapper->has_extents) _cairo_clip_reset (&target_clip); if (dev_clip != clip) _cairo_clip_reset (dev_clip); 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; }