static cairo_status_t _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface, cairo_box_t *bbox, const cairo_matrix_t *transform) { cairo_surface_t *null_surface; cairo_surface_t *analysis_surface; cairo_status_t status; null_surface = _cairo_null_surface_create (surface->content); analysis_surface = _cairo_analysis_surface_create (null_surface); cairo_surface_destroy (null_surface); status = analysis_surface->status; if (unlikely (status)) return status; if (transform != NULL) _cairo_analysis_surface_set_ctm (analysis_surface, transform); status = _cairo_recording_surface_replay (&surface->base, analysis_surface); _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox); cairo_surface_destroy (analysis_surface); return status; }
static cairo_int_status_t _paint_page (cairo_paginated_surface_t *surface) { cairo_surface_t *analysis; cairo_surface_t *image; cairo_pattern_t *pattern; cairo_status_t status; analysis = _cairo_analysis_surface_create (surface->target, surface->width, surface->height); if (analysis == NULL) return CAIRO_STATUS_NO_MEMORY; surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE); status = _cairo_meta_surface_replay (surface->meta, analysis); surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER); if (status || analysis->status) { if (status == CAIRO_STATUS_SUCCESS) status = analysis->status; cairo_surface_destroy (analysis); return status; } if (_cairo_analysis_surface_has_unsupported (analysis)) { double x_scale = surface->base.x_fallback_resolution / 72.0; double y_scale = surface->base.y_fallback_resolution / 72.0; cairo_matrix_t matrix; image = _cairo_paginated_surface_create_image_surface (surface, surface->width * x_scale, surface->height * y_scale); _cairo_surface_set_device_scale (image, x_scale, y_scale); status = _cairo_meta_surface_replay (surface->meta, image); if (status) goto CLEANUP_IMAGE; pattern = cairo_pattern_create_for_surface (image); cairo_matrix_init_scale (&matrix, x_scale, y_scale); cairo_pattern_set_matrix (pattern, &matrix); status = _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern); cairo_pattern_destroy (pattern); CLEANUP_IMAGE: cairo_surface_destroy (image); } else { status = _cairo_meta_surface_replay (surface->meta, surface->target); } cairo_surface_destroy (analysis); return status; }
static cairo_int_status_t _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, const cairo_pattern_t *pattern) { const cairo_surface_pattern_t *surface_pattern; cairo_analysis_surface_t *tmp; cairo_surface_t *source, *proxy; cairo_matrix_t p2d; cairo_status_t status, analysis_status; assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); surface_pattern = (const cairo_surface_pattern_t *) pattern; assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); source = surface_pattern->surface; proxy = _cairo_surface_has_snapshot (source, &proxy_backend); if (proxy != NULL) { /* nothing untoward found so far */ return CAIRO_STATUS_SUCCESS; } tmp = (cairo_analysis_surface_t *) _cairo_analysis_surface_create (surface->target); if (unlikely (tmp->base.status)) return tmp->base.status; proxy = attach_proxy (source, &tmp->base); p2d = pattern->matrix; status = cairo_matrix_invert (&p2d); assert (status == CAIRO_STATUS_SUCCESS); cairo_matrix_multiply (&tmp->ctm, &p2d, &surface->ctm); tmp->has_ctm = ! _cairo_matrix_is_identity (&tmp->ctm); if (_cairo_surface_is_snapshot (source)) source = _cairo_surface_snapshot_get_target (source); if (_cairo_surface_is_subsurface (source)) source = _cairo_surface_subsurface_get_target (source); status = _cairo_recording_surface_replay_and_create_regions (source, &tmp->base); analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS; detach_proxy (proxy); cairo_surface_destroy (&tmp->base); if (unlikely (status)) return status; return analysis_status; }
static cairo_int_status_t _paint_page (cairo_paginated_surface_t *surface) { cairo_surface_t *analysis; cairo_status_t status; cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback; if (surface->target->status) return surface->target->status; analysis = _cairo_analysis_surface_create (surface->target, surface->width, surface->height); if (analysis->status) return _cairo_surface_set_error (surface->target, analysis->status); surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE); status = _cairo_meta_surface_replay_and_create_regions (surface->meta, analysis); if (status || analysis->status) { if (status == CAIRO_STATUS_SUCCESS) status = analysis->status; goto FAIL; } if (surface->backend->set_bounding_box) { cairo_box_t bbox; _cairo_analysis_surface_get_bounding_box (analysis, &bbox); status = surface->backend->set_bounding_box (surface->target, &bbox); if (status) goto FAIL; } if (surface->backend->set_fallback_images_required) { cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis); status = surface->backend->set_fallback_images_required (surface->target, has_fallbacks); if (status) goto FAIL; } /* Finer grained fallbacks are currently only supported for some * surface types */ switch (surface->target->type) { case CAIRO_SURFACE_TYPE_PDF: case CAIRO_SURFACE_TYPE_PS: case CAIRO_SURFACE_TYPE_WIN32_PRINTING: has_supported = _cairo_analysis_surface_has_supported (analysis); has_page_fallback = FALSE; has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis); break; case CAIRO_SURFACE_TYPE_IMAGE: case CAIRO_SURFACE_TYPE_XLIB: case CAIRO_SURFACE_TYPE_XCB: case CAIRO_SURFACE_TYPE_GLITZ: case CAIRO_SURFACE_TYPE_QUARTZ: case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: case CAIRO_SURFACE_TYPE_WIN32: case CAIRO_SURFACE_TYPE_BEOS: case CAIRO_SURFACE_TYPE_DIRECTFB: case CAIRO_SURFACE_TYPE_SVG: case CAIRO_SURFACE_TYPE_OS2: default: if (_cairo_analysis_surface_has_unsupported (analysis)) { has_supported = FALSE; has_page_fallback = TRUE; } else { has_supported = TRUE; has_page_fallback = FALSE; } has_finegrained_fallback = FALSE; break; } if (has_supported) { surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER); status = _cairo_meta_surface_replay_region (surface->meta, surface->target, CAIRO_META_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); if (status) goto FAIL; } if (has_page_fallback) { cairo_box_int_t box; surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_FALLBACK); box.p1.x = 0; box.p1.y = 0; box.p2.x = surface->width; box.p2.y = surface->height; status = _paint_fallback_image (surface, &box); if (status) goto FAIL; } if (has_finegrained_fallback) { cairo_region_t *region; cairo_box_int_t *boxes; int num_boxes, i; surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_FALLBACK); /* Reset clip region before drawing the fall back images */ status = _cairo_surface_intersect_clip_path (surface->target, NULL, CAIRO_FILL_RULE_WINDING, CAIRO_GSTATE_TOLERANCE_DEFAULT, CAIRO_ANTIALIAS_DEFAULT); if (status) goto FAIL; region = _cairo_analysis_surface_get_unsupported (analysis); status = _cairo_region_get_boxes (region, &num_boxes, &boxes); if (status) goto FAIL; for (i = 0; i < num_boxes; i++) { status = _paint_fallback_image (surface, &boxes[i]); if (status) { _cairo_region_boxes_fini (region, boxes); goto FAIL; } } _cairo_region_boxes_fini (region, boxes); } FAIL: cairo_surface_destroy (analysis); return _cairo_surface_set_error (surface->target, status); }
static cairo_int_status_t _paint_page (cairo_paginated_surface_t *surface) { cairo_surface_t *analysis; cairo_int_status_t status; cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback; if (unlikely (surface->target->status)) return (cairo_int_status_t)surface->target->status; analysis = _cairo_analysis_surface_create (surface->target); if (unlikely (analysis->status)) return (cairo_int_status_t)_cairo_surface_set_error (surface->target, (cairo_int_status_t)analysis->status); surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE); status = (cairo_int_status_t)_cairo_recording_surface_replay_and_create_regions (surface->recording_surface, analysis); if (status) goto FAIL; assert (analysis->status == CAIRO_STATUS_SUCCESS); if (surface->backend->set_bounding_box) { cairo_box_t bbox; _cairo_analysis_surface_get_bounding_box (analysis, &bbox); status = surface->backend->set_bounding_box (surface->target, &bbox); if (unlikely (status)) goto FAIL; } if (surface->backend->set_fallback_images_required) { cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis); status = surface->backend->set_fallback_images_required (surface->target, has_fallbacks); if (unlikely (status)) goto FAIL; } /* Finer grained fallbacks are currently only supported for some * surface types */ if (surface->backend->supports_fine_grained_fallbacks != NULL && surface->backend->supports_fine_grained_fallbacks (surface->target)) { has_supported = _cairo_analysis_surface_has_supported (analysis); has_page_fallback = FALSE; has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis); } else { if (_cairo_analysis_surface_has_unsupported (analysis)) { has_supported = FALSE; has_page_fallback = TRUE; } else { has_supported = TRUE; has_page_fallback = FALSE; } has_finegrained_fallback = FALSE; } if (has_supported) { surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER); status = (cairo_int_status_t)_cairo_recording_surface_replay_region (surface->recording_surface, NULL, surface->target, CAIRO_RECORDING_REGION_NATIVE); assert (status != CAIRO_INT_STATUS_UNSUPPORTED); if (unlikely (status)) goto FAIL; } if (has_page_fallback) { cairo_rectangle_int_t extents; cairo_bool_t is_bounded; surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_FALLBACK); is_bounded = _cairo_surface_get_extents (surface->target, &extents); if (! is_bounded) { status = CAIRO_INT_STATUS_UNSUPPORTED; goto FAIL; } status = _paint_fallback_image (surface, &extents); if (unlikely (status)) goto FAIL; } if (has_finegrained_fallback) { cairo_region_t *region; int num_rects, i; surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_FALLBACK); region = _cairo_analysis_surface_get_unsupported (analysis); num_rects = cairo_region_num_rectangles (region); for (i = 0; i < num_rects; i++) { cairo_rectangle_int_t rect; cairo_region_get_rectangle (region, i, &rect); status = _paint_fallback_image (surface, &rect); if (unlikely (status)) goto FAIL; } } FAIL: cairo_surface_destroy (analysis); return _cairo_surface_set_error (surface->target, status); }
static cairo_int_status_t _cairo_user_scaled_glyph_init (void *abstract_font, cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_glyph_info_t info) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_user_scaled_font_t *scaled_font = abstract_font; cairo_surface_t *meta_surface = scaled_glyph->meta_surface; if (!scaled_glyph->meta_surface) { cairo_user_font_face_t *face = (cairo_user_font_face_t *) scaled_font->base.font_face; cairo_text_extents_t extents = scaled_font->default_glyph_extents; cairo_t *cr; cr = _cairo_user_scaled_font_create_meta_context (scaled_font); if (face->scaled_font_methods.render_glyph) status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font, _cairo_scaled_glyph_index(scaled_glyph), cr, &extents); else status = CAIRO_STATUS_USER_FONT_ERROR; if (status == CAIRO_STATUS_SUCCESS) status = cairo_status (cr); meta_surface = cairo_surface_reference (cairo_get_target (cr)); cairo_destroy (cr); if (status) { cairo_surface_destroy (meta_surface); return status; } _cairo_scaled_glyph_set_meta_surface (scaled_glyph, &scaled_font->base, meta_surface); /* set metrics */ if (extents.width == 0.) { /* Compute extents.x/y/width/height from meta_surface, in font space */ cairo_box_t bbox; double x1, y1, x2, y2; double x_scale, y_scale; cairo_surface_t *null_surface; cairo_surface_t *analysis_surface; null_surface = _cairo_null_surface_create (cairo_surface_get_content (meta_surface)); analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); cairo_surface_destroy (null_surface); _cairo_analysis_surface_set_ctm (analysis_surface, &scaled_font->extent_scale); status = _cairo_meta_surface_replay (meta_surface, analysis_surface); _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); cairo_surface_destroy (analysis_surface); if (status) return status; _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2); x_scale = scaled_font->extent_x_scale; y_scale = scaled_font->extent_y_scale; extents.x_bearing = x1 * x_scale; extents.y_bearing = y1 * y_scale; extents.width = (x2 - x1) * x_scale; extents.height = (y2 - y1) * y_scale; } if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale; extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale; } _cairo_scaled_glyph_set_metrics (scaled_glyph, &scaled_font->base, &extents); } if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) { cairo_surface_t *surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_format_t format; int width, height; /* TODO * extend the glyph cache to support argb glyphs. * need to figure out the semantics and interaction with subpixel * rendering first. */ width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); switch (scaled_font->base.options.antialias) { default: case CAIRO_ANTIALIAS_DEFAULT: case CAIRO_ANTIALIAS_GRAY: format = CAIRO_FORMAT_A8; break; case CAIRO_ANTIALIAS_NONE: format = CAIRO_FORMAT_A1; break; case CAIRO_ANTIALIAS_SUBPIXEL: format = CAIRO_FORMAT_ARGB32; break; } surface = cairo_image_surface_create (format, width, height); cairo_surface_set_device_offset (surface, - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x), - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y)); status = _cairo_meta_surface_replay (meta_surface, surface); if (status) { cairo_surface_destroy(surface); return status; } _cairo_scaled_glyph_set_surface (scaled_glyph, &scaled_font->base, (cairo_image_surface_t *) surface); } if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { cairo_path_fixed_t *path = _cairo_path_fixed_create (); if (!path) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_meta_surface_get_path (meta_surface, path); if (status) { _cairo_path_fixed_destroy (path); return status; } _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, path); } return status; }
static cairo_int_status_t _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, const cairo_pattern_t *pattern, cairo_rectangle_int_t *extents) { const cairo_surface_pattern_t *surface_pattern; cairo_analysis_surface_t *tmp; cairo_surface_t *source, *proxy; cairo_matrix_t p2d; cairo_int_status_t status, analysis_status; cairo_bool_t surface_is_unbounded; cairo_bool_t unused; assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); surface_pattern = (const cairo_surface_pattern_t *) pattern; assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); source = surface_pattern->surface; proxy = _cairo_surface_has_snapshot (source, &proxy_backend); if (proxy != NULL) { /* nothing untoward found so far */ return CAIRO_STATUS_SUCCESS; } tmp = (cairo_analysis_surface_t *) _cairo_analysis_surface_create (surface->target); if (unlikely (tmp->base.status)) { status =tmp->base.status; goto cleanup1; } proxy = attach_proxy (source, &tmp->base); p2d = pattern->matrix; status = cairo_matrix_invert (&p2d); assert (status == CAIRO_INT_STATUS_SUCCESS); _cairo_analysis_surface_set_ctm (&tmp->base, &p2d); source = _cairo_surface_get_source (source, NULL); surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_REFLECT); status = _cairo_recording_surface_replay_and_create_regions (source, &pattern->matrix, &tmp->base, surface_is_unbounded); if (unlikely (status)) goto cleanup2; /* black background or mime data fills entire extents */ if (!(source->content & CAIRO_CONTENT_ALPHA) || _cairo_surface_has_mime_image (source)) { cairo_rectangle_int_t rect; if (_cairo_surface_get_extents (source, &rect)) { cairo_box_t bbox; _cairo_box_from_rectangle (&bbox, &rect); _cairo_matrix_transform_bounding_box_fixed (&p2d, &bbox, NULL); _cairo_box_round_to_rectangle (&bbox, &rect); status = _add_operation (tmp, &rect, CAIRO_INT_STATUS_SUCCESS); if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) status = CAIRO_INT_STATUS_SUCCESS; if (unlikely (status)) goto cleanup2; } } if (tmp->has_supported) { surface->has_supported = TRUE; unused = cairo_region_union (&surface->supported_region, &tmp->supported_region); } if (tmp->has_unsupported) { surface->has_unsupported = TRUE; unused = cairo_region_union (&surface->fallback_region, &tmp->fallback_region); } analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS; if (pattern->extend != CAIRO_EXTEND_NONE) { _cairo_unbounded_rectangle_init (extents); } else { status = cairo_matrix_invert (&tmp->ctm); _cairo_matrix_transform_bounding_box_fixed (&tmp->ctm, &tmp->page_bbox, NULL); _cairo_box_round_to_rectangle (&tmp->page_bbox, extents); } cleanup2: detach_proxy (proxy); cleanup1: cairo_surface_destroy (&tmp->base); if (unlikely (status)) return status; return analysis_status; }