/** * cairo_xcb_surface_set_size: * @surface: a #cairo_surface_t for the XCB backend * @width: the new width of the surface * @height: the new height of the surface * * Informs cairo of the new size of the XCB drawable underlying the * surface. For a surface created for a window (rather than a pixmap), * this function must be called each time the size of the window * changes. (For a subwindow, you are normally resizing the window * yourself, but for a toplevel window, it is necessary to listen for * ConfigureNotify events.) * * A pixmap can never change size, so it is never necessary to call * this function on a surface created for a pixmap. * * If cairo_surface_flush() wasn't called, some pending operations * might be discarded. **/ void cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface, int width, int height) { cairo_xcb_surface_t *surface; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_INVALID_SIZE)); return; } surface = (cairo_xcb_surface_t *) abstract_surface; _drawable_changed(surface); surface->width = width; surface->height = height; }
void cairo_tee_surface_add (cairo_surface_t *abstract_surface, cairo_surface_t *target) { cairo_tee_surface_t *surface; cairo_surface_wrapper_t slave; cairo_status_t status; if (unlikely (abstract_surface->status)) return; if (abstract_surface->backend != &cairo_tee_surface_backend) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } if (unlikely (target->status)) { status = _cairo_surface_set_error (abstract_surface, target->status); return; } surface = (cairo_tee_surface_t *) abstract_surface; _cairo_surface_wrapper_init (&slave, target); status = _cairo_array_append (&surface->slaves, &slave); if (unlikely (status)) { _cairo_surface_wrapper_fini (&slave); status = _cairo_surface_set_error (&surface->base, status); } }
void cairo_gl_surface_set_size (cairo_surface_t *abstract_surface, int width, int height) { cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (! _cairo_surface_is_gl (abstract_surface) || _cairo_gl_surface_is_texture (surface)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } if (surface->width != width || surface->height != height) { surface->needs_update = TRUE; surface->width = width; surface->height = height; } }
/** * cairo_xcb_surface_set_size: * @surface: a #cairo_surface_t for the XCB backend * @width: the new width of the surface * @height: the new height of the surface * * Informs cairo of the new size of the XCB drawable underlying the * surface. For a surface created for a window (rather than a pixmap), * this function must be called each time the size of the window * changes. (For a subwindow, you are normally resizing the window * yourself, but for a toplevel window, it is necessary to listen for * ConfigureNotify events.) * * A pixmap can never change size, so it is never necessary to call * this function on a surface created for a pixmap. **/ void cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface, int width, int height) { cairo_xcb_surface_t *surface; cairo_status_t status_ignored; if (unlikely (abstract_surface->status)) return; if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) { status_ignored = _cairo_surface_set_error (abstract_surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return; } if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) { status_ignored = _cairo_surface_set_error (abstract_surface, CAIRO_STATUS_INVALID_SIZE); return; } surface = (cairo_xcb_surface_t *) abstract_surface; surface->width = width; surface->height = height; }
/** * cairo_xcb_surface_set_drawable: * @surface: a #cairo_surface_t for the XCB backend * @drawable: the new drawable of the surface * @width: the new width of the surface * @height: the new height of the surface * * Informs cairo of the new drawable and size of the XCB drawable underlying the * surface. * * If cairo_surface_flush() wasn't called, some pending operations * might be discarded. **/ void cairo_xcb_surface_set_drawable (cairo_surface_t *abstract_surface, xcb_drawable_t drawable, int width, int height) { cairo_xcb_surface_t *surface; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_INVALID_SIZE)); return; } surface = (cairo_xcb_surface_t *) abstract_surface; /* XXX: and what about this case? */ if (surface->owns_pixmap) return; _drawable_changed (surface); if (surface->drawable != drawable) { cairo_status_t status; status = _cairo_xcb_connection_acquire (surface->connection); if (unlikely (status)) return; if (surface->picture != XCB_NONE) { _cairo_xcb_connection_render_free_picture (surface->connection, surface->picture); surface->picture = XCB_NONE; } _cairo_xcb_connection_release (surface->connection); surface->drawable = drawable; } surface->width = width; surface->height = height; }
static void _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface) { cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface; cairo_image_surface_t *image; cairo_image_surface_t *clone; void *extra; cairo_status_t status; /* We need to make an image copy of the original surface since the * snapshot may exceed the lifetime of the original device, i.e. * when we later need to use the snapshot the data may have already * been lost. */ status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); if (unlikely (status)) { snapshot->target = _cairo_surface_create_in_error (status); status = _cairo_surface_set_error (surface, status); return; } clone = (cairo_image_surface_t *) _cairo_image_surface_create_with_pixman_format (NULL, image->pixman_format, image->width, image->height, 0); if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) { if (clone->stride == image->stride) { memcpy (clone->data, image->data, image->stride * image->height); } else { pixman_image_composite32 (PIXMAN_OP_SRC, image->pixman_image, NULL, clone->pixman_image, 0, 0, 0, 0, 0, 0, image->width, image->height); } clone->base.is_clear = FALSE; snapshot->clone = &clone->base; } else { snapshot->clone = &clone->base; status = _cairo_surface_set_error (surface, clone->base.status); } _cairo_surface_release_source_image (snapshot->target, image, extra); snapshot->target = snapshot->clone; snapshot->base.type = snapshot->target->type; }
static void _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface) { cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface; cairo_image_surface_t *image; cairo_surface_t *clone; void *extra; cairo_status_t status; TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, snapshot->target->unique_id)); /* We need to make an image copy of the original surface since the * snapshot may exceed the lifetime of the original device, i.e. * when we later need to use the snapshot the data may have already * been lost. */ CAIRO_MUTEX_LOCK (snapshot->mutex); if (snapshot->target->backend->snapshot != NULL) { clone = snapshot->target->backend->snapshot (snapshot->target); if (clone != NULL) { assert (clone->status || ! _cairo_surface_is_snapshot (clone)); goto done; } } /* XXX copy to a similar surface, leave acquisition till later? * We should probably leave such decisions to the backend in case we * rely upon devices/connections like Xlib. */ status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); if (unlikely (status)) { snapshot->target = _cairo_surface_create_in_error (status); status = _cairo_surface_set_error (surface, status); goto unlock; } clone = image->base.backend->snapshot (&image->base); _cairo_surface_release_source_image (snapshot->target, image, extra); done: status = _cairo_surface_set_error (surface, clone->status); snapshot->target = snapshot->clone = clone; snapshot->base.type = clone->type; unlock: CAIRO_MUTEX_UNLOCK (snapshot->mutex); }
void cairo_tee_surface_remove (cairo_surface_t *abstract_surface, cairo_surface_t *target) { cairo_tee_surface_t *surface; cairo_surface_wrapper_t *slaves; int n, num_slaves; cairo_status_t status; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (abstract_surface->backend != &cairo_tee_surface_backend) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); return; } surface = (cairo_tee_surface_t *) abstract_surface; if (target == surface->master.target) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_INVALID_INDEX)); return; } num_slaves = _cairo_array_num_elements (&surface->slaves); slaves = _cairo_array_index (&surface->slaves, 0); for (n = 0; n < num_slaves; n++) { if (slaves[n].target == target) break; } if (n == num_slaves) { status = _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_INVALID_INDEX)); return; } _cairo_surface_wrapper_fini (&slaves[n]); for (n++; n < num_slaves; n++) slaves[n-1] = slaves[n]; surface->slaves.num_elements--; /* XXX: cairo_array_remove()? */ }
cairo_status_t _cairo_paginated_surface_set_size (cairo_surface_t *surface, int width, int height) { cairo_paginated_surface_t *paginated_surface; cairo_status_t status; cairo_rectangle_t recording_extents; assert (_cairo_surface_is_paginated (surface)); paginated_surface = (cairo_paginated_surface_t *) surface; recording_extents.x = 0; recording_extents.y = 0; recording_extents.width = width; recording_extents.height = height; cairo_surface_destroy (paginated_surface->recording_surface); paginated_surface->recording_surface = cairo_recording_surface_create (paginated_surface->content, &recording_extents); status = paginated_surface->recording_surface->status; if (unlikely (status)) return (cairo_status_t)_cairo_surface_set_error (surface, (cairo_int_status_t)status); return (cairo_status_t)CAIRO_STATUS_SUCCESS; }
/** * cairo_recording_surface_ink_extents: * @surface: a #cairo_recording_surface_t * @x0: the x-coordinate of the top-left of the ink bounding box * @y0: the y-coordinate of the top-left of the ink bounding box * @width: the width of the ink bounding box * @height: the height of the ink bounding box * * Measures the extents of the operations stored within the recording-surface. * This is useful to compute the required size of an image surface (or * equivalent) into which to replay the full sequence of drawing operations. * * Since: 1.10 **/ void cairo_recording_surface_ink_extents (cairo_surface_t *surface, double *x0, double *y0, double *width, double *height) { cairo_status_t status; cairo_box_t bbox; memset (&bbox, 0, sizeof (bbox)); if (! _cairo_surface_is_recording (surface)) { _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); goto DONE; } status = _recording_surface_get_ink_bbox ((cairo_recording_surface_t *) surface, &bbox, NULL); if (unlikely (status)) status = _cairo_surface_set_error (surface, status); DONE: if (x0) *x0 = _cairo_fixed_to_double (bbox.p1.x); if (y0) *y0 = _cairo_fixed_to_double (bbox.p1.y); if (width) *width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x); if (height) *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y); }
/* This does the necessary fixup when a surface's drawable or size changed. */ static void _drawable_changed (cairo_xcb_surface_t *surface) { _cairo_surface_set_error (&surface->base, _cairo_surface_begin_modification (&surface->base)); _cairo_boxes_clear (&surface->fallback_damage); cairo_surface_destroy (&surface->fallback->base); surface->deferred_clear = FALSE; surface->fallback = NULL; }
static cairo_status_t _start_page (cairo_paginated_surface_t *surface) { if (surface->target->status) return surface->target->status; if (! surface->backend->start_page) return CAIRO_STATUS_SUCCESS; return _cairo_surface_set_error (surface->target, surface->backend->start_page (surface->target)); }
void cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface) { cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface; if (unlikely (abstract_surface->status)) return; if (unlikely (abstract_surface->finished)) { _cairo_surface_set_error (abstract_surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); return; } if (! _cairo_surface_is_gl (abstract_surface)) { _cairo_surface_set_error (abstract_surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return; } if (! _cairo_gl_surface_is_texture (surface)) { cairo_gl_context_t *ctx; cairo_status_t status; status = _cairo_gl_context_acquire (surface->base.device, &ctx); if (unlikely (status)) return; /* For swapping on EGL, at least, we need a valid context/target. */ _cairo_gl_context_set_destination (ctx, surface); /* And in any case we should flush any pending operations. */ _cairo_gl_composite_flush (ctx); ctx->swap_buffers (ctx, surface); status = _cairo_gl_context_release (ctx, status); if (status) status = _cairo_surface_set_error (abstract_surface, status); } }
/** * cairo_xcb_surface_set_size: * @surface: a #cairo_surface_t for the XCB backend * @width: the new width of the surface * @height: the new height of the surface * * Informs cairo of the new size of the XCB drawable underlying the * surface. For a surface created for a window (rather than a pixmap), * this function must be called each time the size of the window * changes. (For a subwindow, you are normally resizing the window * yourself, but for a toplevel window, it is necessary to listen for * ConfigureNotify events.) * * A pixmap can never change size, so it is never necessary to call * this function on a surface created for a pixmap. **/ void cairo_xcb_surface_set_size (cairo_surface_t *surface, int width, int height) { cairo_xcb_surface_t *xcb_surface = (cairo_xcb_surface_t *)surface; if (! _cairo_surface_is_xcb (surface)) { _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); return; } xcb_surface->width = width; xcb_surface->height = height; }
cairo_status_t _cairo_paginated_surface_set_size (cairo_surface_t *surface, int width, int height) { cairo_paginated_surface_t *paginated_surface; cairo_status_t status; assert (_cairo_surface_is_paginated (surface)); paginated_surface = (cairo_paginated_surface_t *) surface; paginated_surface->width = width; paginated_surface->height = height; cairo_surface_destroy (paginated_surface->meta); paginated_surface->meta = _cairo_meta_surface_create (paginated_surface->content, width, height); status = cairo_surface_status (paginated_surface->meta); if (status) return _cairo_surface_set_error (surface, status); return CAIRO_STATUS_SUCCESS; }
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_status_t _cairo_meta_surface_replay_internal (cairo_surface_t *surface, cairo_surface_t *target, cairo_meta_replay_type_t type, cairo_meta_region_type_t region) { cairo_meta_surface_t *meta; cairo_command_t *command, **elements; int i, num_elements; cairo_int_status_t status, status2; cairo_clip_t clip, *old_clip; cairo_bool_t has_device_transform = _cairo_surface_has_device_transform (target); cairo_matrix_t *device_transform = &target->device_transform; cairo_path_fixed_t path_copy, *dev_path; if (surface->status) return surface->status; if (target->status) return _cairo_surface_set_error (surface, target->status); meta = (cairo_meta_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; _cairo_clip_init (&clip, target); old_clip = _cairo_surface_get_clip (target); num_elements = meta->commands.num_elements; elements = _cairo_array_index (&meta->commands, 0); for (i = meta->replay_start_idx; i < num_elements; i++) { command = elements[i]; if (type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) { if (command->header.region != region) continue; } /* For all commands except intersect_clip_path, we have to * ensure the current clip gets set on the surface. */ if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) { status = _cairo_surface_set_clip (target, &clip); if (status) break; } dev_path = _cairo_command_get_path (command); if (dev_path && has_device_transform) { status = _cairo_path_fixed_init_copy (&path_copy, dev_path); if (status) break; _cairo_path_fixed_transform (&path_copy, device_transform); dev_path = &path_copy; } switch (command->header.type) { case CAIRO_COMMAND_PAINT: status = _cairo_surface_paint (target, command->paint.op, &command->paint.source.base); break; case CAIRO_COMMAND_MASK: status = _cairo_surface_mask (target, command->mask.op, &command->mask.source.base, &command->mask.mask.base); break; case CAIRO_COMMAND_STROKE: { cairo_matrix_t dev_ctm = command->stroke.ctm; cairo_matrix_t dev_ctm_inverse = command->stroke.ctm_inverse; if (has_device_transform) { cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform); cairo_matrix_multiply (&dev_ctm_inverse, &target->device_transform_inverse, &dev_ctm_inverse); } status = _cairo_surface_stroke (target, command->stroke.op, &command->stroke.source.base, dev_path, &command->stroke.style, &dev_ctm, &dev_ctm_inverse, command->stroke.tolerance, command->stroke.antialias); break; } case CAIRO_COMMAND_FILL: { cairo_command_t *stroke_command; if (type != CAIRO_META_CREATE_REGIONS) stroke_command = (i < num_elements - 1) ? elements[i + 1] : NULL; else stroke_command = NULL; if (stroke_command != NULL && type == CAIRO_META_REPLAY && region != CAIRO_META_REGION_ALL) { if (stroke_command->header.region != region) stroke_command = NULL; } if (stroke_command != NULL && stroke_command->header.type == CAIRO_COMMAND_STROKE && _cairo_path_fixed_is_equal (dev_path, _cairo_command_get_path (stroke_command))) { cairo_matrix_t dev_ctm; cairo_matrix_t dev_ctm_inverse; dev_ctm = stroke_command->stroke.ctm; dev_ctm_inverse = stroke_command->stroke.ctm_inverse; if (has_device_transform) { cairo_matrix_multiply (&dev_ctm, &dev_ctm, device_transform); cairo_matrix_multiply (&dev_ctm_inverse, &surface->device_transform_inverse, &dev_ctm_inverse); } status = _cairo_surface_fill_stroke (target, command->fill.op, &command->fill.source.base, command->fill.fill_rule, command->fill.tolerance, command->fill.antialias, dev_path, stroke_command->stroke.op, &stroke_command->stroke.source.base, &stroke_command->stroke.style, &dev_ctm, &dev_ctm_inverse, stroke_command->stroke.tolerance, stroke_command->stroke.antialias); i++; } else status = _cairo_surface_fill (target, command->fill.op, &command->fill.source.base, dev_path, command->fill.fill_rule, command->fill.tolerance, command->fill.antialias); break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: { cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs; cairo_glyph_t *dev_glyphs; int i, num_glyphs = command->show_text_glyphs.num_glyphs; /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed * to modify the glyph array that's passed in. We must always * copy the array before handing it to the backend. */ dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (dev_glyphs == NULL) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); break; } if (has_device_transform) { 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 { memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); } status = _cairo_surface_show_text_glyphs (target, command->show_text_glyphs.op, &command->show_text_glyphs.source.base, command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, dev_glyphs, num_glyphs, command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, command->show_text_glyphs.cluster_flags, command->show_text_glyphs.scaled_font); free (dev_glyphs); 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 (dev_path == NULL) _cairo_clip_reset (&clip); else status = _cairo_clip_clip (&clip, dev_path, command->intersect_clip_path.fill_rule, command->intersect_clip_path.tolerance, command->intersect_clip_path.antialias, target); break; default: ASSERT_NOT_REACHED; } if (dev_path == &path_copy) _cairo_path_fixed_fini (&path_copy); if (type == CAIRO_META_CREATE_REGIONS) { if (status == CAIRO_STATUS_SUCCESS) { command->header.region = CAIRO_META_REGION_NATIVE; } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) { command->header.region = CAIRO_META_REGION_IMAGE_FALLBACK; status = CAIRO_STATUS_SUCCESS; } } if (status) break; } _cairo_clip_reset (&clip); status2 = _cairo_surface_set_clip (target, old_clip); if (status == CAIRO_STATUS_SUCCESS) status = status2; return _cairo_surface_set_error (surface, 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_status_t _cairo_recording_surface_replay_internal (cairo_surface_t *surface, const cairo_rectangle_int_t *surface_extents, cairo_surface_t *target, cairo_recording_replay_type_t type, cairo_recording_region_type_t region) { cairo_recording_surface_t *recording_surface; cairo_command_t **elements; int i, num_elements; cairo_int_status_t status; cairo_surface_wrapper_t wrapper; if (unlikely (surface->status)) return surface->status; if (unlikely (target->status)) return target->status; if (unlikely (surface->finished)) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); if (surface->is_clear) return CAIRO_STATUS_SUCCESS; assert (_cairo_surface_is_recording (surface)); _cairo_surface_wrapper_init (&wrapper, target); _cairo_surface_wrapper_set_extents (&wrapper, surface_extents); recording_surface = (cairo_recording_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; num_elements = recording_surface->commands.num_elements; elements = _cairo_array_index (&recording_surface->commands, 0); for (i = recording_surface->replay_start_idx; i < num_elements; i++) { cairo_command_t *command = elements[i]; if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) { if (command->header.region != region) continue; } switch (command->header.type) { case CAIRO_COMMAND_PAINT: status = _cairo_surface_wrapper_paint (&wrapper, command->header.op, &command->paint.source.base, _clip (command)); break; case CAIRO_COMMAND_MASK: status = _cairo_surface_wrapper_mask (&wrapper, command->header.op, &command->mask.source.base, &command->mask.mask.base, _clip (command)); break; case CAIRO_COMMAND_STROKE: { status = _cairo_surface_wrapper_stroke (&wrapper, command->header.op, &command->stroke.source.base, &command->stroke.path, &command->stroke.style, &command->stroke.ctm, &command->stroke.ctm_inverse, command->stroke.tolerance, command->stroke.antialias, _clip (command)); break; } case CAIRO_COMMAND_FILL: { cairo_command_t *stroke_command; stroke_command = NULL; if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1) stroke_command = elements[i + 1]; if (stroke_command != NULL && type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) { if (stroke_command->header.region != region) stroke_command = NULL; } if (stroke_command != NULL && stroke_command->header.type == CAIRO_COMMAND_STROKE && _cairo_path_fixed_is_equal (&command->fill.path, &stroke_command->stroke.path)) { status = _cairo_surface_wrapper_fill_stroke (&wrapper, command->header.op, &command->fill.source.base, command->fill.fill_rule, command->fill.tolerance, command->fill.antialias, &command->fill.path, stroke_command->header.op, &stroke_command->stroke.source.base, &stroke_command->stroke.style, &stroke_command->stroke.ctm, &stroke_command->stroke.ctm_inverse, stroke_command->stroke.tolerance, stroke_command->stroke.antialias, _clip (command)); i++; } else { status = _cairo_surface_wrapper_fill (&wrapper, command->header.op, &command->fill.source.base, &command->fill.path, command->fill.fill_rule, command->fill.tolerance, command->fill.antialias, _clip (command)); } break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: { cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs; cairo_glyph_t *glyphs_copy; int num_glyphs = command->show_text_glyphs.num_glyphs; /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed * to modify the glyph array that's passed in. We must always * copy the array before handing it to the backend. */ glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); if (unlikely (glyphs_copy == NULL)) { status = _cairo_error (CAIRO_STATUS_NO_MEMORY); break; } memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); status = _cairo_surface_wrapper_show_text_glyphs (&wrapper, command->header.op, &command->show_text_glyphs.source.base, command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, glyphs_copy, num_glyphs, command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, command->show_text_glyphs.cluster_flags, command->show_text_glyphs.scaled_font, _clip (command)); free (glyphs_copy); break; } default: ASSERT_NOT_REACHED; } if (type == CAIRO_RECORDING_CREATE_REGIONS) { if (status == CAIRO_STATUS_SUCCESS) { command->header.region = CAIRO_RECORDING_REGION_NATIVE; } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) { command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK; status = CAIRO_STATUS_SUCCESS; } else { assert (_cairo_status_is_error (status)); } } if (unlikely (status)) break; } /* free up any caches */ for (i = recording_surface->replay_start_idx; i < num_elements; i++) { cairo_command_t *command = elements[i]; _cairo_clip_drop_cache (&command->header.clip); } _cairo_surface_wrapper_fini (&wrapper); return _cairo_surface_set_error (surface, status); }
cairo_int_status_t _cairo_recording_surface_get_path (cairo_surface_t *surface, cairo_path_fixed_t *path) { cairo_recording_surface_t *recording_surface; cairo_command_t **elements; int i, num_elements; cairo_int_status_t status; if (surface->status) return surface->status; recording_surface = (cairo_recording_surface_t *) surface; status = CAIRO_STATUS_SUCCESS; num_elements = recording_surface->commands.num_elements; elements = _cairo_array_index (&recording_surface->commands, 0); for (i = recording_surface->replay_start_idx; i < num_elements; i++) { cairo_command_t *command = elements[i]; switch (command->header.type) { case CAIRO_COMMAND_PAINT: case CAIRO_COMMAND_MASK: status = CAIRO_INT_STATUS_UNSUPPORTED; break; case CAIRO_COMMAND_STROKE: { cairo_traps_t traps; _cairo_traps_init (&traps); /* XXX call cairo_stroke_to_path() when that is implemented */ status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path, &command->stroke.style, &command->stroke.ctm, &command->stroke.ctm_inverse, command->stroke.tolerance, &traps); if (status == CAIRO_STATUS_SUCCESS) status = _cairo_traps_path (&traps, path); _cairo_traps_fini (&traps); break; } case CAIRO_COMMAND_FILL: { status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD, 0, 0); break; } case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: { status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font, command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs, path); break; } default: ASSERT_NOT_REACHED; } if (unlikely (status)) break; } return _cairo_surface_set_error (surface, status); }