コード例 #1
0
/**
 * _cairo_matrix_is_pixman_translation:
 * @matrix: a matrix
 * @filter: the filter to be used on the pattern transformed by @matrix
 * @x_offset: the translation in the X direction
 * @y_offset: the translation in the Y direction
 *
 * Checks if @matrix translated by (x_offset, y_offset) can be
 * represented using just an offset (within the range pixman can
 * accept) and an identity matrix.
 *
 * Passing a non-zero value in x_offset/y_offset has the same effect
 * as applying cairo_matrix_translate(matrix, x_offset, y_offset) and
 * setting x_offset and y_offset to 0.
 *
 * Upon return x_offset and y_offset contain the translation vector if
 * the return value is %TRUE. If the return value is %FALSE, they will
 * not be modified.
 *
 * Return value: %TRUE if @matrix can be represented as a pixman
 * translation, %FALSE otherwise.
 **/
cairo_bool_t
_cairo_matrix_is_pixman_translation (const cairo_matrix_t     *matrix,
				     cairo_filter_t            filter,
				     int                      *x_offset,
				     int                      *y_offset)
{
    double tx, ty;

    if (!_cairo_matrix_is_translation (matrix))
	return FALSE;

    if (matrix->x0 == 0. && matrix->y0 == 0.)
	return TRUE;

    tx = matrix->x0 + *x_offset;
    ty = matrix->y0 + *y_offset;

    if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) {
	tx = _pixman_nearest_sample (tx);
	ty = _pixman_nearest_sample (ty);
    } else if (tx != floor (tx) || ty != floor (ty)) {
	return FALSE;
    }

    if (fabs (tx) > PIXMAN_MAX_INT || fabs (ty) > PIXMAN_MAX_INT)
	return FALSE;

    *x_offset = _cairo_lround (tx);
    *y_offset = _cairo_lround (ty);
    return TRUE;
}
コード例 #2
0
cairo_surface_t *
_cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
					 const cairo_rectangle_int_t *extents)
{
    cairo_surface_subsurface_t *surface;

    if (unlikely (target->status))
	return _cairo_surface_create_in_error (target->status);
    if (unlikely (target->finished))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));

    assert (target->backend->type != CAIRO_SURFACE_TYPE_SUBSURFACE);

    surface = malloc (sizeof (cairo_surface_subsurface_t));
    if (unlikely (surface == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));

    assert (_cairo_matrix_is_translation (&target->device_transform));

    _cairo_surface_init (&surface->base,
			 &_cairo_surface_subsurface_backend,
			 NULL, /* device */
			 target->content);

    surface->extents = *extents;
    surface->extents.x += target->device_transform.x0;
    surface->extents.y += target->device_transform.y0;

    surface->target = cairo_surface_reference (target);
    surface->base.type = surface->target->type;

    surface->snapshot = NULL;

    return &surface->base;
}
コード例 #3
0
/**
 * cairo_surface_create_for_rectangle:
 * @target: an existing surface for which the sub-surface will point to
 * @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units)
 * @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units)
 * @width: width of the sub-surface (in device-space units)
 * @height: height of the sub-surface (in device-space units)
 *
 * Create a new surface that is a rectangle within the target surface.
 * All operations drawn to this surface are then clipped and translated
 * onto the target surface. Nothing drawn via this sub-surface outside of
 * its bounds is drawn onto the target surface, making this a useful method
 * for passing constrained child surfaces to library routines that draw
 * directly onto the parent surface, i.e. with no further backend allocations,
 * double buffering or copies.
 *
 * <note><para>The semantics of subsurfaces have not been finalized yet
 * unless the rectangle is in full device units, is contained within
 * the extents of the target surface, and the target or subsurface's
 * device transforms are not changed.</para></note>
 *
 * Return value: a pointer to the newly allocated surface. The caller
 * owns the surface and should call cairo_surface_destroy() when done
 * with it.
 *
 * This function always returns a valid pointer, but it will return a
 * pointer to a "nil" surface if @other is already in an error state
 * or any other error occurs.
 *
 * Since: 1.10
 **/
cairo_surface_t *
cairo_surface_create_for_rectangle (cairo_surface_t *target,
				    double x, double y,
				    double width, double height)
{
    cairo_surface_subsurface_t *surface;

    if (unlikely (width < 0 || height < 0))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));

    if (unlikely (target->status))
	return _cairo_surface_create_in_error (target->status);
    if (unlikely (target->finished))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));

    surface = malloc (sizeof (cairo_surface_subsurface_t));
    if (unlikely (surface == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));

    assert (_cairo_matrix_is_translation (&target->device_transform));
    x += target->device_transform.x0;
    y += target->device_transform.y0;

    _cairo_surface_init (&surface->base,
			 &_cairo_surface_subsurface_backend,
			 NULL, /* device */
			 target->content);

    /* XXX forced integer alignment */
    surface->extents.x = ceil (x);
    surface->extents.y = ceil (y);
    surface->extents.width = floor (x + width) - surface->extents.x;
    surface->extents.height = floor (y + height) - surface->extents.y;
    if ((surface->extents.width | surface->extents.height) < 0)
	surface->extents.width = surface->extents.height = 0;

    if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
	/* Maintain subsurfaces as 1-depth */
	cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target;
	surface->extents.x += sub->extents.x;
	surface->extents.y += sub->extents.y;
	target = sub->target;
    }

    surface->target = cairo_surface_reference (target);
    surface->base.type = surface->target->type;

    surface->snapshot = NULL;

    return &surface->base;
}
コード例 #4
0
cairo_bool_t
_cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
				      int *itx, int *ity)
{
    if (_cairo_matrix_is_translation (matrix))
    {
        cairo_fixed_t x0_fixed = _cairo_fixed_from_double (matrix->x0);
        cairo_fixed_t y0_fixed = _cairo_fixed_from_double (matrix->y0);

        if (_cairo_fixed_is_integer (x0_fixed) &&
            _cairo_fixed_is_integer (y0_fixed))
        {
            if (itx)
                *itx = _cairo_fixed_integer_part (x0_fixed);
            if (ity)
                *ity = _cairo_fixed_integer_part (y0_fixed);

            return TRUE;
        }
    }

    return FALSE;
}
コード例 #5
0
ファイル: cairo-surface-wrapper.c プロジェクト: igagis/cairo
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,
					 const 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,
					 const cairo_clip_t	    *clip)
{
    cairo_status_t status;
    cairo_clip_t *dev_clip;
    cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)];
    cairo_glyph_t *dev_glyphs = stack_glyphs;
    cairo_scaled_font_t *dev_scaled_font = scaled_font;
    cairo_pattern_union_t source_copy;
    cairo_font_options_t options;

    if (unlikely (wrapper->target->status))
	return wrapper->target->status;

    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
    if (_cairo_clip_is_all_clipped (dev_clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    cairo_surface_get_font_options (wrapper->target, &options);
    cairo_font_options_merge (&options, &scaled_font->options);

    if (wrapper->needs_transform) {
	cairo_matrix_t m;
	int i;

	_cairo_surface_wrapper_get_transform (wrapper, &m);

	if (! _cairo_matrix_is_translation (&wrapper->transform)) {
	    cairo_matrix_t ctm;

	    /* XXX No device-transform? A bug in the tangle of layers? */
	    _cairo_matrix_multiply (&ctm,
				    &wrapper->transform,
				    &scaled_font->ctm);
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
							&scaled_font->font_matrix,
							&ctm, &options);
	}

	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (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 (! cairo_font_options_equal (&options, &scaled_font->options)) {
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
							&scaled_font->font_matrix,
							&scaled_font->ctm,
							&options);
	}

	/* 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.
	 */
	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (dev_glyphs == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto FINISH;
	    }
	}

	memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
    }

    status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
					      utf8, utf8_len,
					      dev_glyphs, num_glyphs,
					      clusters, num_clusters,
					      cluster_flags,
					      dev_scaled_font,
					      dev_clip);
 FINISH:
    _cairo_clip_destroy (dev_clip);
    if (dev_glyphs != stack_glyphs)
	free (dev_glyphs);
    if (dev_scaled_font != scaled_font)
	cairo_scaled_font_destroy (dev_scaled_font);
    return status;
}
コード例 #6
0
ファイル: cairo-path-stroke.c プロジェクト: AliYousuf/cairo
static cairo_int_status_t
_cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t	*path,
				      cairo_stroke_style_t	*stroke_style,
				      const cairo_matrix_t	*ctm,
				      cairo_traps_t		*traps)
{
    cairo_rectilinear_stroker_t rectilinear_stroker;
    cairo_int_status_t status;

    /* This special-case rectilinear stroker only supports
     * miter-joined lines (not curves) and a translation-only matrix
     * (though it could probably be extended to support a matrix with
     * uniform, integer scaling).
     *
     * It also only supports horizontal and vertical line_to
     * elements. But we don't catch that here, but instead return
     * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
     * non-rectilinear line_to is encountered.
     */
    if (path->has_curve_to)
	return CAIRO_INT_STATUS_UNSUPPORTED;
    if (stroke_style->line_join	!= CAIRO_LINE_JOIN_MITER)
	return CAIRO_INT_STATUS_UNSUPPORTED;
    /* If the miter limit turns right angles into bevels, then we
     * can't use this optimization. Remember, the ratio is
     * 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or ⎷2,
     * which we round for safety. */
    if (stroke_style->miter_limit < M_SQRT2)
	return CAIRO_INT_STATUS_UNSUPPORTED;
    if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
	   stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE))
    {
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }
    if (! (_cairo_matrix_is_identity (ctm) ||
	   _cairo_matrix_is_translation (ctm)))
    {
	return CAIRO_INT_STATUS_UNSUPPORTED;
    }

    _cairo_rectilinear_stroker_init (&rectilinear_stroker,
				     stroke_style,
				     ctm,
				     traps);
    if (traps->has_limits) {
	_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
					  &traps->limits);
    }

    status = _cairo_path_fixed_interpret (path,
					  CAIRO_DIRECTION_FORWARD,
					  _cairo_rectilinear_stroker_move_to,
					  rectilinear_stroker.dash.dashed ?
					  _cairo_rectilinear_stroker_line_to_dashed :
					  _cairo_rectilinear_stroker_line_to,
					  NULL,
					  _cairo_rectilinear_stroker_close_path,
					  &rectilinear_stroker);
    if (unlikely (status))
	goto BAIL;

    if (rectilinear_stroker.dash.dashed)
	status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
    else
	status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);

BAIL:
    _cairo_rectilinear_stroker_fini (&rectilinear_stroker);

    if (unlikely (status))
	_cairo_traps_clear (traps);

    return status;
}
コード例 #7
0
void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t	*matrix,
				pixman_transform_t	*pixman_transform,
				double xc,
				double yc)
{
    static const pixman_transform_t pixman_identity_transform = {{
        {1 << 16,        0,       0},
        {       0, 1 << 16,       0},
        {       0,       0, 1 << 16}
    }};

    if (_cairo_matrix_is_identity (matrix)) {
        *pixman_transform = pixman_identity_transform;
    } else {
        cairo_matrix_t inv;
	unsigned max_iterations;

        pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
        pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
        pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);

        pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
        pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
        pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);

        pixman_transform->matrix[2][0] = 0;
        pixman_transform->matrix[2][1] = 0;
        pixman_transform->matrix[2][2] = 1 << 16;

        /* The conversion above breaks cairo's translation invariance:
         * a translation of (a, b) in device space translates to
         * a translation of (xx * a + xy * b, yx * a + yy * b)
         * for cairo, while pixman uses rounded versions of xx ... yy.
         * This error increases as a and b get larger.
         *
         * To compensate for this, we fix the point (xc, yc) in pattern
         * space and adjust pixman's transform to agree with cairo's at
         * that point.
	 */

	if (_cairo_matrix_is_translation (matrix))
	    return;

        /* Note: If we can't invert the transformation, skip the adjustment. */
        inv = *matrix;
        if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
            return;

        /* find the pattern space coordinate that maps to (xc, yc) */
	xc += .5; yc += .5; /* offset for the pixel centre */
	max_iterations = 5;
	do {
	    double x,y;
	    pixman_vector_t vector;
	    cairo_fixed_16_16_t dx, dy;

	    vector.vector[0] = _cairo_fixed_16_16_from_double (xc);
	    vector.vector[1] = _cairo_fixed_16_16_from_double (yc);
	    vector.vector[2] = 1 << 16;

	    if (! pixman_transform_point_3d (pixman_transform, &vector))
		return;

	    x = pixman_fixed_to_double (vector.vector[0]);
	    y = pixman_fixed_to_double (vector.vector[1]);
	    cairo_matrix_transform_point (&inv, &x, &y);

	    /* Ideally, the vector should now be (xc, yc).
	     * We can now compensate for the resulting error.
	     */
	    x -= xc;
	    y -= yc;
	    cairo_matrix_transform_distance (matrix, &x, &y);
	    dx = _cairo_fixed_16_16_from_double (x);
	    dy = _cairo_fixed_16_16_from_double (y);
	    pixman_transform->matrix[0][2] -= dx;
	    pixman_transform->matrix[1][2] -= dy;

	    if (dx == 0 && dy == 0)
		break;
	} while (--max_iterations);
    }
}