コード例 #1
0
static cairo_surface_t *
_cairo_tee_surface_snapshot (void *abstract_surface)
{
    cairo_tee_surface_t *surface = abstract_surface;
    cairo_surface_wrapper_t *slaves;
    int num_slaves, n;

    /* we prefer to use a recording surface for our snapshots */
    if (_cairo_surface_is_recording (surface->master.target))
	return _cairo_surface_wrapper_snapshot (&surface->master);

    num_slaves = _cairo_array_num_elements (&surface->slaves);
    slaves = _cairo_array_index (&surface->slaves, 0);
    for (n = 0; n < num_slaves; n++) {
	if (_cairo_surface_is_recording (slaves[n].target))
	    return _cairo_surface_wrapper_snapshot (&slaves[n]);
    }

    return _cairo_surface_wrapper_snapshot (&surface->master);
}
コード例 #2
0
static cairo_bool_t
is_recording_pattern (const cairo_pattern_t *pattern)
{
    cairo_surface_t *surface;

    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
	return FALSE;

    surface = ((const cairo_surface_pattern_t *) pattern)->surface;
    return _cairo_surface_is_recording (surface);
}
コード例 #3
0
cairo_status_t
cairo_xml_for_recording_surface (cairo_device_t	 *device,
				 cairo_surface_t *recording_surface)
{
    cairo_box_t bbox;
    cairo_rectangle_int_t extents;
    cairo_surface_t *surface;
    cairo_xml_t *xml;
    cairo_status_t status;

    if (unlikely (device->status))
	return device->status;

    if (unlikely (recording_surface->status))
	return recording_surface->status;

    if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
	return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);

    if (unlikely (! _cairo_surface_is_recording (recording_surface)))
	return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);

    status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
						&bbox, NULL);
    if (unlikely (status))
	return status;

    _cairo_box_round_to_rectangle (&bbox, &extents);
    surface = _cairo_xml_surface_create_internal (device,
						  recording_surface->content,
						  extents.width,
						  extents.height);
    if (unlikely (surface->status))
	return surface->status;

    xml = (cairo_xml_t *) device;

    _cairo_xml_printf (xml,
		       "<surface content='%s' width='%d' height='%d'>",
		       _content_to_string (recording_surface->content),
		       extents.width, extents.height);
    _cairo_xml_indent (xml, 2);

    cairo_surface_set_device_offset (surface, -extents.x, -extents.y);
    status = _cairo_recording_surface_replay (recording_surface, surface);
    cairo_surface_destroy (surface);

    _cairo_xml_indent (xml, -2);
    _cairo_xml_printf (xml, "</surface>");

    return status;
}
コード例 #4
0
static cairo_int_status_t
_cairo_analysis_surface_mask (void			*abstract_surface,
			      cairo_operator_t		 op,
			      const cairo_pattern_t	*source,
			      const cairo_pattern_t	*mask,
			      const cairo_clip_t		*clip)
{
    cairo_analysis_surface_t *surface = abstract_surface;
    cairo_int_status_t	      backend_status;
    cairo_rectangle_int_t   extents;

    if (surface->target->backend->mask == NULL) {
	backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
    } else {
	backend_status =
	    surface->target->backend->mask (surface->target,
					    op, source, mask, clip);
	if (_cairo_int_status_is_error (backend_status))
	    return backend_status;
    }

    if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
	cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
	cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;

	if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
	    cairo_surface_t *src_surface = ((cairo_surface_pattern_t *)source)->surface;
	    src_surface = _cairo_surface_get_source (src_surface, NULL);
	    if (_cairo_surface_is_recording (src_surface)) {
		backend_source_status =
		    _analyze_recording_surface_pattern (surface, source);
		if (_cairo_int_status_is_error (backend_source_status))
		    return backend_source_status;
	    }
	}

	if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
	    cairo_surface_t *mask_surface = ((cairo_surface_pattern_t *)mask)->surface;
	    mask_surface = _cairo_surface_get_source (mask_surface, NULL);
	    if (_cairo_surface_is_recording (mask_surface)) {
		backend_mask_status =
		    _analyze_recording_surface_pattern (surface, mask);
		if (_cairo_int_status_is_error (backend_mask_status))
		    return backend_mask_status;
	    }
	}

	backend_status =
	    _cairo_analysis_surface_merge_status (backend_source_status,
						  backend_mask_status);
    }

    _cairo_analysis_surface_operation_extents (surface,
					       op, source, clip,
					       &extents);

    if (_cairo_operator_bounded_by_mask (op)) {
	cairo_rectangle_int_t mask_extents;

	_cairo_pattern_get_extents (mask, &mask_extents);
	_cairo_rectangle_intersect (&extents, &mask_extents);
    }

    return _add_operation (surface, &extents, backend_status);
}
コード例 #5
0
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);
}