Ejemplo n.º 1
0
static cairo_bool_t
_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
{
    return
	(wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y)) ||
	! _cairo_matrix_is_identity (&wrapper->transform) ||
	! _cairo_matrix_is_identity (&wrapper->target->device_transform);
}
Ejemplo n.º 2
0
static void
_cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t *wrapper,
				      cairo_matrix_t *m)
{
    cairo_matrix_init_identity (m);

    if (! _cairo_matrix_is_identity (&wrapper->transform))
	cairo_matrix_multiply (m, &wrapper->transform, m);

    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
	cairo_matrix_multiply (m, &wrapper->target->device_transform, m);
}
Ejemplo n.º 3
0
static void
_cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t *wrapper,
				      cairo_matrix_t *m)
{
    cairo_matrix_init_identity (m);

    if (wrapper->has_extents && (wrapper->extents.x || wrapper->extents.y))
	cairo_matrix_translate (m, -wrapper->extents.x, -wrapper->extents.y);

    if (! _cairo_matrix_is_identity (&wrapper->transform))
	cairo_matrix_multiply (m, &wrapper->transform, m);

    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
	cairo_matrix_multiply (m, &wrapper->target->device_transform, m);
}
Ejemplo n.º 4
0
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
				 cairo_matrix_t  *ctm)
{
    cairo_analysis_surface_t	*surface = (cairo_analysis_surface_t *) abstract_surface;

    surface->ctm = *ctm;
    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
}
Ejemplo n.º 5
0
static void
_copy_transformed_pattern (cairo_pattern_t *pattern,
			   const cairo_pattern_t *original,
			   const cairo_matrix_t  *ctm_inverse)
{
    _cairo_pattern_init_static_copy (pattern, original);

    if (! _cairo_matrix_is_identity (ctm_inverse))
	_cairo_pattern_transform (pattern, ctm_inverse);
}
Ejemplo n.º 6
0
static void
_cairo_surface_wrapper_get_inverse_transform (cairo_surface_wrapper_t *wrapper,
					      cairo_matrix_t *m)
{
    cairo_matrix_init_identity (m);

    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform_inverse))
	cairo_matrix_multiply (m, &wrapper->target->device_transform_inverse, m);

    if (! _cairo_matrix_is_identity (&wrapper->transform)) {
	cairo_matrix_t inv;
	cairo_status_t status;

	inv = wrapper->transform;
	status = cairo_matrix_invert (&inv);
	assert (status == CAIRO_STATUS_SUCCESS);
	cairo_matrix_multiply (m, &inv, m);
    }
}
static cairo_bool_t
_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper,
					       cairo_matrix_t *matrix)
{
    if (_cairo_matrix_is_identity (&wrapper->target->device_transform))
	return FALSE;

    *matrix = wrapper->target->device_transform;
    return TRUE;
}
Ejemplo n.º 8
0
static cairo_int_status_t
_analyze_meta_surface_pattern (cairo_analysis_surface_t	*surface,
			       const cairo_pattern_t *pattern)
{
    cairo_surface_t *analysis = &surface->base;
    const cairo_surface_pattern_t *surface_pattern;
    cairo_status_t status;
    cairo_bool_t old_has_ctm;
    cairo_matrix_t old_ctm, p2d;
    cairo_rectangle_int_t old_clip;
    cairo_rectangle_int_t meta_extents;
    int old_width;
    int old_height;

    assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
    surface_pattern = (const cairo_surface_pattern_t *) pattern;
    assert (_cairo_surface_is_meta (surface_pattern->surface));

    old_width = surface->width;
    old_height = surface->height;
    old_clip = surface->current_clip;
    status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents);
    if (_cairo_status_is_error (status))
	return status;

    surface->width = meta_extents.width;
    surface->height = meta_extents.height;
    surface->current_clip.x = 0;
    surface->current_clip.y = 0;
    surface->current_clip.width = surface->width;
    surface->current_clip.height = surface->height;
    old_ctm = surface->ctm;
    old_has_ctm = surface->has_ctm;
    p2d = pattern->matrix;
    status = cairo_matrix_invert (&p2d);
    /* _cairo_pattern_set_matrix guarantees invertibility */
    assert (status == CAIRO_STATUS_SUCCESS);

    cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);

    status = _cairo_meta_surface_replay_and_create_regions (surface_pattern->surface,
							    analysis);
    if (status == CAIRO_STATUS_SUCCESS)
	status = analysis->status;

    surface->ctm = old_ctm;
    surface->has_ctm = old_has_ctm;
    surface->current_clip = old_clip;
    surface->width = old_width;
    surface->height = old_height;

    return status;
}
Ejemplo n.º 9
0
static void
_cairo_xml_emit_matrix (cairo_xml_t *xml,
			const cairo_matrix_t *matrix)
{
    if (! _cairo_matrix_is_identity (matrix)) {
	_cairo_xml_printf (xml, "<matrix>%f %f %f %f %f %f</matrix>",
			   matrix->xx, matrix->yx,
			   matrix->xy, matrix->yy,
			   matrix->x0, matrix->y0);
    }
}
Ejemplo n.º 10
0
void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
				 cairo_matrix_t  *ctm)
{
    cairo_analysis_surface_t	*surface;

    if (abstract_surface->status)
	return;

    surface = (cairo_analysis_surface_t *) abstract_surface;

    surface->ctm = *ctm;
    surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
}
Ejemplo n.º 11
0
static cairo_int_status_t
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
				    const cairo_pattern_t    *pattern)
{
    const cairo_surface_pattern_t *surface_pattern;
    cairo_analysis_surface_t *tmp;
    cairo_surface_t *source, *proxy;
    cairo_matrix_t p2d;
    cairo_status_t status, analysis_status;

    assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
    surface_pattern = (const cairo_surface_pattern_t *) pattern;
    assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
    source = surface_pattern->surface;

    proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
    if (proxy != NULL) {
	/* nothing untoward found so far */
	return CAIRO_STATUS_SUCCESS;
    }

    tmp = (cairo_analysis_surface_t *)
	_cairo_analysis_surface_create (surface->target);
    if (unlikely (tmp->base.status))
	return tmp->base.status;
    proxy = attach_proxy (source, &tmp->base);

    p2d = pattern->matrix;
    status = cairo_matrix_invert (&p2d);
    assert (status == CAIRO_STATUS_SUCCESS);

    cairo_matrix_multiply (&tmp->ctm, &p2d, &surface->ctm);
    tmp->has_ctm = ! _cairo_matrix_is_identity (&tmp->ctm);

    if (_cairo_surface_is_snapshot (source))
	source = _cairo_surface_snapshot_get_target (source);
    if (_cairo_surface_is_subsurface (source))
	source = _cairo_surface_subsurface_get_target (source);

    status = _cairo_recording_surface_replay_and_create_regions (source,
								 &tmp->base);
    analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS;
    detach_proxy (proxy);
    cairo_surface_destroy (&tmp->base);

    if (unlikely (status))
	return status;

    return analysis_status;
}
Ejemplo n.º 12
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;
}
Ejemplo n.º 13
0
void
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
			     cairo_surface_t *target)
{
    wrapper->target = cairo_surface_reference (target);
    cairo_matrix_init_identity (&wrapper->transform);
    wrapper->has_extents = FALSE;
    wrapper->extents.x = wrapper->extents.y = 0;
    wrapper->clip = NULL;

    wrapper->needs_transform = FALSE;
    if (target) {
	wrapper->needs_transform =
	    ! _cairo_matrix_is_identity (&target->device_transform);
    }
}
Ejemplo n.º 14
0
static cairo_clip_t *
_cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
				 const cairo_clip_t *clip)
{
    cairo_clip_t *copy;

    copy = _cairo_clip_copy (clip);
    if (wrapper->has_extents) {
	copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents);
    }
    copy = _cairo_clip_transform (copy, &wrapper->transform);
    if (! _cairo_matrix_is_identity (&wrapper->target->device_transform))
	copy = _cairo_clip_transform (copy, &wrapper->target->device_transform);
    if (wrapper->clip)
	copy = _cairo_clip_intersect_clip (copy, wrapper->clip);

    return copy;
}
Ejemplo n.º 15
0
void
_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper,
					      const cairo_matrix_t *transform)
{
    cairo_status_t status;

    if (transform == NULL || _cairo_matrix_is_identity (transform)) {
	cairo_matrix_init_identity (&wrapper->transform);

	wrapper->needs_transform =
	    _cairo_surface_wrapper_needs_device_transform (wrapper);
    } else {
	wrapper->transform = *transform;
	status = cairo_matrix_invert (&wrapper->transform);
	/* should always be invertible unless given pathological input */
	assert (status == CAIRO_STATUS_SUCCESS);

	wrapper->needs_transform = TRUE;
    }
}
Ejemplo n.º 16
0
static void _cairo_matrix_to_render_matrix (const cairo_matrix_t *matrix, s_render_matrix_t *render_matrix)
{
	static const s_render_matrix_t render_identity_matrix = {{
		{1 << 16,        0,       0},
		{       0, 1 << 16,       0},
		{       0,       0, 1 << 16}
	}};
	if (_cairo_matrix_is_identity(matrix)) {
		*render_matrix = render_identity_matrix;
	} else {
		render_matrix->matrix[0][0] = _cairo_fixed_from_double(matrix->xx);
		render_matrix->matrix[0][1] = _cairo_fixed_from_double(matrix->xy);
		render_matrix->matrix[0][2] = _cairo_fixed_from_double(matrix->x0);
		render_matrix->matrix[1][0] = _cairo_fixed_from_double(matrix->yx);
		render_matrix->matrix[1][1] = _cairo_fixed_from_double(matrix->yy);
		render_matrix->matrix[1][2] = _cairo_fixed_from_double(matrix->y0);
		render_matrix->matrix[2][0] = 0;
		render_matrix->matrix[2][1] = 0;
		render_matrix->matrix[2][2] = 1 << 16;
	}
}
Ejemplo n.º 17
0
static inline QPainterPath
path_to_qt (const cairo_path_fixed_t *path,
	    const cairo_matrix_t *ctm_inverse = NULL)
{
    qpainter_path_data data;
    cairo_status_t status;

    if (ctm_inverse && _cairo_matrix_is_identity (ctm_inverse))
	ctm_inverse = NULL;
    data.ctm_inverse = ctm_inverse;

    status = _cairo_path_fixed_interpret (path,
					  _cairo_path_to_qpainterpath_move_to,
					  _cairo_path_to_qpainterpath_line_to,
					  _cairo_path_to_qpainterpath_curve_to,
					  _cairo_path_to_qpainterpath_close_path,
					  &data);
    assert (status == CAIRO_STATUS_SUCCESS);

    return data.path;
}
Ejemplo n.º 18
0
static inline SkPath
path_to_sk (cairo_path_fixed_t *path,
	    cairo_matrix_t *mat = NULL)
{
    struct cpc data;
    cairo_status_t status;

    if (mat && _cairo_matrix_is_identity (mat))
	mat = NULL;
    data.matrix = mat;

    status = _cairo_path_fixed_interpret (path,
					  cpc_move_to,
					  cpc_line_to,
					  cpc_curve_to,
					  cpc_close_path,
					  &data);
    assert (status == CAIRO_STATUS_SUCCESS);

    return data.skPath;
}
Ejemplo n.º 19
0
static void
_copy_transformed_pattern (cairo_pattern_t *pattern,
			   const cairo_pattern_t *original,
			   const cairo_matrix_t  *ctm_inverse)
{
    _cairo_pattern_init_static_copy (pattern, original);

    /* apply device_transform first so that it is transformed by ctm_inverse */
    if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
	cairo_surface_pattern_t *surface_pattern;
	cairo_surface_t *surface;

        surface_pattern = (cairo_surface_pattern_t *) original;
        surface = surface_pattern->surface;

	if (_cairo_surface_has_device_transform (surface))
	    _cairo_pattern_transform (pattern, &surface->device_transform);
    }

    if (! _cairo_matrix_is_identity (ctm_inverse))
	_cairo_pattern_transform (pattern, ctm_inverse);
}
Ejemplo n.º 20
0
static void
compute_face (const cairo_point_t *point,
              const cairo_slope_t *dev_slope,
              struct stroker *stroker,
              cairo_stroke_face_t *face)
{
    double face_dx, face_dy;
    cairo_point_t offset_ccw, offset_cw;
    double slope_dx, slope_dy;

    slope_dx = _cairo_fixed_to_double (dev_slope->dx);
    slope_dy = _cairo_fixed_to_double (dev_slope->dy);
    face->length = normalize_slope (&slope_dx, &slope_dy);
    face->dev_slope.x = slope_dx;
    face->dev_slope.y = slope_dy;

    /*
     * rotate to get a line_width/2 vector along the face, note that
     * the vector must be rotated the right direction in device space,
     * but by 90° in user space. So, the rotation depends on
     * whether the ctm reflects or not, and that can be determined
     * by looking at the determinant of the matrix.
     */
    if (! _cairo_matrix_is_identity (stroker->ctm_inverse)) {
        /* Normalize the matrix! */
        cairo_matrix_transform_distance (stroker->ctm_inverse,
                                         &slope_dx, &slope_dy);
        normalize_slope (&slope_dx, &slope_dy);

        if (stroker->ctm_det_positive) {
            face_dx = - slope_dy * (stroker->style.line_width / 2.0);
            face_dy = slope_dx * (stroker->style.line_width / 2.0);
        } else {
            face_dx = slope_dy * (stroker->style.line_width / 2.0);
            face_dy = - slope_dx * (stroker->style.line_width / 2.0);
        }

        /* back to device space */
        cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
    } else {
        face_dx = - slope_dy * (stroker->style.line_width / 2.0);
        face_dy = slope_dx * (stroker->style.line_width / 2.0);
    }

    offset_ccw.x = _cairo_fixed_from_double (face_dx);
    offset_ccw.y = _cairo_fixed_from_double (face_dy);
    offset_cw.x = -offset_ccw.x;
    offset_cw.y = -offset_ccw.y;

    face->ccw = *point;
    translate_point (&face->ccw, &offset_ccw);

    face->point = *point;

    face->cw = *point;
    translate_point (&face->cw, &offset_cw);

    face->usr_vector.x = slope_dx;
    face->usr_vector.y = slope_dy;

    face->dev_vector = *dev_slope;
}
Ejemplo n.º 21
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_has_unity_scale (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);
    }
}
Ejemplo n.º 22
0
void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t	*matrix,
				pixman_transform_t	*pixman_transform)
{
    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 = *matrix;
        double x = 0, y = 0;
        pixman_vector_t vector;

        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 (0, 0) in pattern
         * space and adjust pixman's transform to agree with cairo's at
         * that point. */

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

        /* find the device space coordinate that maps to (0, 0) */
        cairo_matrix_transform_point (&inv, &x, &y);

        /* transform the resulting device space coordinate back
         * to the pattern space, using pixman's transform */
        vector.vector[0] = _cairo_fixed_16_16_from_double (x);
        vector.vector[1] = _cairo_fixed_16_16_from_double (y);
        vector.vector[2] = 1 << 16;

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

        /* Ideally, the vector should now be (0, 0). We can now compensate
         * for the resulting error */
        pixman_transform->matrix[0][2] -= vector.vector[0];
        pixman_transform->matrix[1][2] -= vector.vector[1];
    }
}
Ejemplo n.º 23
0
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;
}
Ejemplo n.º 24
0
static inline cairo_bool_t
_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
{
    return ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
}
Ejemplo n.º 25
0
static cairo_status_t
_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
                                 const cairo_pattern_t *pattern,
				 cairo_gl_surface_t *dst,
				 cairo_bool_t use_texgen)
{
    const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
    cairo_status_t status;

    assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
	    gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);

    if (! _cairo_gl_device_has_glsl (dst->base.device))
	return CAIRO_INT_STATUS_UNSUPPORTED;

    status = _cairo_gl_create_gradient_texture (dst,
						gradient,
						&operand->gradient.gradient);
    if (unlikely (status))
	return status;

    if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
	cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
	double x0, y0, dx, dy, sf, offset;

	dx = linear->pd2.x - linear->pd1.x;
	dy = linear->pd2.y - linear->pd1.y;
	sf = 1.0 / (dx * dx + dy * dy);
	dx *= sf;
	dy *= sf;

	x0 = linear->pd1.x;
	y0 = linear->pd1.y;
	offset = dx * x0 + dy * y0;

	operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;

	cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
	if (! _cairo_matrix_is_identity (&pattern->matrix)) {
	    cairo_matrix_multiply (&operand->gradient.m,
				   &pattern->matrix,
				   &operand->gradient.m);
	}
    } else {
	cairo_matrix_t m;
	cairo_circle_double_t circles[2];
	double x0, y0, r0, dx, dy, dr;

	/*
	 * Some fragment shader implementations use half-floats to
	 * represent numbers, so the maximum number they can represent
	 * is about 2^14. Some intermediate computations used in the
	 * radial gradient shaders can produce results of up to 2*k^4.
	 * Setting k=8 makes the maximum result about 8192 (assuming
	 * that the extreme circles are not much smaller than the
	 * destination image).
	 */
	_cairo_gradient_pattern_fit_to_range (gradient, 8.,
					      &operand->gradient.m, circles);

	x0 = circles[0].center.x;
	y0 = circles[0].center.y;
	r0 = circles[0].radius;
	dx = circles[1].center.x - x0;
	dy = circles[1].center.y - y0;
	dr = circles[1].radius   - r0;

	operand->gradient.a = dx * dx + dy * dy - dr * dr;
	operand->gradient.radius_0 = r0;
	operand->gradient.circle_d.center.x = dx;
	operand->gradient.circle_d.center.y = dy;
	operand->gradient.circle_d.radius   = dr;

	if (operand->gradient.a == 0)
	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
	else if (pattern->extend == CAIRO_EXTEND_NONE)
	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE;
	else
	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT;

	cairo_matrix_init_translate (&m, -x0, -y0);
	cairo_matrix_multiply (&operand->gradient.m,
			       &operand->gradient.m,
			       &m);
    }

    operand->gradient.extend = pattern->extend;
    operand->gradient.texgen = use_texgen;

    return CAIRO_STATUS_SUCCESS;
}
static SkShader*
source_to_sk_shader (cairo_skia_context_t *cr,
		     const cairo_pattern_t *pattern)
{
    SkShader *shader = NULL;

    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
	cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
	return new SkColorShader (color_to_sk (solid->color));
    } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
	cairo_surface_t *surface = surface_from_pattern (pattern);

	cr->source = cairo_surface_reference (surface);

	if (surface->type == CAIRO_SURFACE_TYPE_SKIA) {
	    cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface;

	    shader = SkShader::CreateBitmapShader (*esurf->bitmap,
						   extend_to_sk (pattern->extend),
						   extend_to_sk (pattern->extend));
	} else {
	    SkBitmap bitmap;

	    if (! _cairo_surface_is_image (surface)) {
		cairo_status_t status;

		status = _cairo_surface_acquire_source_image (surface,
							      &cr->source_image,
							      &cr->source_extra);
		if (status)
		    return NULL;

		surface = &cr->source_image->base;
	    }

	    if (unlikely (! surface_to_sk_bitmap (surface, bitmap)))
		return NULL;

	    shader = SkShader::CreateBitmapShader (bitmap,
						   extend_to_sk (pattern->extend),
						   extend_to_sk (pattern->extend));
	}
    } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR
	       /* || pattern->type == CAIRO_PATTERN_TYPE_RADIAL */)
    {
	cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
	SkColor colors_stack[10];
	SkScalar pos_stack[10];
	SkColor *colors = colors_stack;
	SkScalar *pos = pos_stack;

	if (gradient->n_stops > 10) {
	    colors = new SkColor[gradient->n_stops];
	    pos = new SkScalar[gradient->n_stops];
	}

	for (unsigned int i = 0; i < gradient->n_stops; i++) {
	    pos[i] = CAIRO_FIXED_TO_SK_SCALAR (gradient->stops[i].offset);
	    colors[i] = color_stop_to_sk (gradient->stops[i].color);
	}

	if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
	    cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
	    SkPoint points[2];

	    points[0].set (SkFloatToScalar (linear->pd1.x),
			   SkFloatToScalar (linear->pd1.y));
	    points[1].set (SkFloatToScalar (linear->pd2.x),
			   SkFloatToScalar (linear->pd2.y));
	    shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops,
						     extend_to_sk (pattern->extend));
	} else {
	    // XXX todo -- implement real radial shaders in Skia
	}

	if (gradient->n_stops > 10) {
	    delete [] colors;
	    delete [] pos;
	}
    }

    if (shader && ! _cairo_matrix_is_identity (&pattern->matrix))
	shader->setLocalMatrix (matrix_inverse_to_sk (pattern->matrix));

    return shader;
}
Ejemplo n.º 27
0
    PatternToBrushConverter (const cairo_pattern_t *pattern) :
	mAcquiredImageParent(0),
	mAcquiredImage(0),
	mAcquiredImageExtra(0)
    {
	if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
	    cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern;
	    QColor color;
	    color.setRgbF(solid->color.red,
			  solid->color.green,
			  solid->color.blue,
			  solid->color.alpha);

	    mBrush = QBrush(color);
	} else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
	    cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t*) pattern;
	    cairo_surface_t *surface = spattern->surface;

	    if (surface->type == CAIRO_SURFACE_TYPE_QT) {
		cairo_qt_surface_t *qs = (cairo_qt_surface_t*) surface;

		if (qs->image) {
		    mBrush = QBrush(*qs->image);
		} else if (qs->pixmap) {
		    mBrush = QBrush(*qs->pixmap);
		} else {
		    // do something smart
		    mBrush = QBrush(0xff0000ff);
		}
	    } else {
		cairo_image_surface_t *isurf = NULL;

		if (surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
		    isurf = (cairo_image_surface_t*) surface;
		} else {
		    void *image_extra;

		    if (_cairo_surface_acquire_source_image (surface, &isurf, &image_extra) == CAIRO_STATUS_SUCCESS) {
			mAcquiredImageParent = surface;
			mAcquiredImage = isurf;
			mAcquiredImageExtra = image_extra;
		    } else {
			isurf = NULL;
		    }
		}

		if (isurf) {
		    mBrush = QBrush (QImage ((const uchar *) isurf->data,
						 isurf->width,
						 isurf->height,
						 isurf->stride,
						 _qimage_format_from_cairo_format (isurf->format)));
		} else {
		    mBrush = QBrush(0x0000ffff);
		}
	    }
	} else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
		   pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
	{
	    QGradient *grad;
	    cairo_bool_t reverse_stops = FALSE;
	    cairo_bool_t emulate_reflect = FALSE;
	    double offset = 0.0;

	    cairo_extend_t extend = pattern->extend;

	    cairo_gradient_pattern_t *gpat = (cairo_gradient_pattern_t *) pattern;

	    if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
		cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t *) pattern;
		grad = new QLinearGradient (lpat->pd1.x, lpat->pd1.y,
					    lpat->pd2.x, lpat->pd2.y);
	    } else if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
		cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t *) pattern;

		/* Based on the SVG surface code */

		cairo_circle_double_t *c0, *c1;
		double x0, y0, r0, x1, y1, r1;

		if (rpat->cd1.radius < rpat->cd2.radius) {
		    c0 = &rpat->cd1;
		    c1 = &rpat->cd2;
		    reverse_stops = FALSE;
		} else {
		    c0 = &rpat->cd2;
		    c1 = &rpat->cd1;
		    reverse_stops = TRUE;
		}

		x0 = c0->center.x;
		y0 = c0->center.y;
		r0 = c0->radius;
		x1 = c1->center.x;
		y1 = c1->center.y;
		r1 = c1->radius;

		if (r0 == r1) {
		    grad = new QRadialGradient (x1, y1, r1, x1, y1);
		} else {
		    double fx = (r1 * x0 - r0 * x1) / (r1 - r0);
		    double fy = (r1 * y0 - r0 * y1) / (r1 - r0);

		    /* QPainter doesn't support the inner circle and use instead a gradient focal.
		     * That means we need to emulate the cairo behaviour by processing the
		     * cairo gradient stops.
		     * The CAIRO_EXTENT_NONE and CAIRO_EXTENT_PAD modes are quite easy to handle,
		     * it's just a matter of stop position translation and calculation of
		     * the corresponding SVG radial gradient focal.
		     * The CAIRO_EXTENT_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new
		     * radial gradient, with an new outer circle, equal to r1 - r0 in the CAIRO_EXTEND_REPEAT
		     * case, and 2 * (r1 - r0) in the CAIRO_EXTENT_REFLECT case, and a new gradient stop
		     * list that maps to the original cairo stop list.
		     */
		    if ((extend == CAIRO_EXTEND_REFLECT || extend == CAIRO_EXTEND_REPEAT) && r0 > 0.0) {
			double r_org = r1;
			double r, x, y;

			if (extend == CAIRO_EXTEND_REFLECT) {
			    r1 = 2 * r1 - r0;
			    emulate_reflect = TRUE;
			}

			offset = fmod (r1, r1 - r0) / (r1 - r0) - 1.0;
			r = r1 - r0;

			/* New position of outer circle. */
			x = r * (x1 - fx) / r_org + fx;
			y = r * (y1 - fy) / r_org + fy;

			x1 = x;
			y1 = y;
			r1 = r;
			r0 = 0.0;
		    } else {
			offset = r0 / r1;
		    }

		    grad = new QRadialGradient (x1, y1, r1, fx, fy);

		    if (extend == CAIRO_EXTEND_NONE && r0 != 0.0)
			grad->setColorAt (r0 / r1, Qt::transparent);
		}
	    }

	    switch (extend) {
		case CAIRO_EXTEND_NONE:
		case CAIRO_EXTEND_PAD:
		    grad->setSpread(QGradient::PadSpread);

		    grad->setColorAt (0.0, Qt::transparent);
		    grad->setColorAt (1.0, Qt::transparent);
		    break;

		case CAIRO_EXTEND_REFLECT:
		    grad->setSpread(QGradient::ReflectSpread);
		    break;

		case CAIRO_EXTEND_REPEAT:
		    grad->setSpread(QGradient::RepeatSpread);
		    break;
	    }

	    for (unsigned int i = 0; i < gpat->n_stops; i++) {
		int index = i;
		if (reverse_stops)
		    index = gpat->n_stops - i - 1;

		double offset = gpat->stops[i].offset;
		QColor color;
		color.setRgbF (gpat->stops[i].color.red,
			       gpat->stops[i].color.green,
			       gpat->stops[i].color.blue,
			       gpat->stops[i].color.alpha);

		if (emulate_reflect) {
		    offset = offset / 2.0;
		    grad->setColorAt (1.0 - offset, color);
		}

		grad->setColorAt (offset, color);
	    }

	    mBrush = QBrush(*grad);

	    delete grad;
	}

	if (mBrush.style() != Qt::NoBrush  &&
            pattern->type != CAIRO_PATTERN_TYPE_SOLID &&
            ! _cairo_matrix_is_identity (&pattern->matrix))
	{
	    cairo_matrix_t pm = pattern->matrix;
	    cairo_status_t status = cairo_matrix_invert (&pm);
	    assert (status == CAIRO_STATUS_SUCCESS);
	    mBrush.setMatrix (_qmatrix_from_cairo_matrix (pm));
	}
    }