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;
}
示例#3
0
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
}
示例#10
0
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;
}
示例#11
0
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;
}
示例#12
0
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;
}
示例#13
0
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;
}