0,0 → 1,1478 |
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ |
/* cairo - a vector graphics library with display and print output |
* |
* Copyright © 2002 University of Southern California |
* Copyright © 2005 Red Hat, Inc. |
* Copyright © 2011 Intel Corporation |
* |
* This library is free software; you can redistribute it and/or |
* modify it either under the terms of the GNU Lesser General Public |
* License version 2.1 as published by the Free Software Foundation |
* (the "LGPL") or, at your option, under the terms of the Mozilla |
* Public License Version 1.1 (the "MPL"). If you do not alter this |
* notice, a recipient may use your version of this file under either |
* the MPL or the LGPL. |
* |
* You should have received a copy of the LGPL along with this library |
* in the file COPYING-LGPL-2.1; if not, write to the Free Software |
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
* You should have received a copy of the MPL along with this library |
* in the file COPYING-MPL-1.1 |
* |
* The contents of this file are subject to the Mozilla Public License |
* Version 1.1 (the "License"); you may not use this file except in |
* compliance with the License. You may obtain a copy of the License at |
* http://www.mozilla.org/MPL/ |
* |
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
* OF ANY KIND, either express or implied. See the LGPL or the MPL for |
* the specific language governing rights and limitations. |
* |
* The Original Code is the cairo graphics library. |
* |
* The Initial Developer of the Original Code is University of Southern |
* California. |
* |
* Contributor(s): |
* Carl D. Worth <cworth@cworth.org> |
* Chris Wilson <chris@chris-wilson.co.uk> |
*/ |
|
#include "cairoint.h" |
|
#include "cairo-private.h" |
#include "cairo-arc-private.h" |
#include "cairo-backend-private.h" |
#include "cairo-clip-inline.h" |
#include "cairo-default-context-private.h" |
#include "cairo-error-private.h" |
#include "cairo-freed-pool-private.h" |
#include "cairo-path-private.h" |
#include "cairo-pattern-private.h" |
|
#define CAIRO_TOLERANCE_MINIMUM _cairo_fixed_to_double(1) |
|
#if !defined(INFINITY) |
#define INFINITY HUGE_VAL |
#endif |
|
static freed_pool_t context_pool; |
|
void |
_cairo_default_context_reset_static_data (void) |
{ |
_freed_pool_reset (&context_pool); |
} |
|
void |
_cairo_default_context_fini (cairo_default_context_t *cr) |
{ |
while (cr->gstate != &cr->gstate_tail[0]) { |
if (_cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist)) |
break; |
} |
|
_cairo_gstate_fini (cr->gstate); |
cr->gstate_freelist = cr->gstate_freelist->next; /* skip over tail[1] */ |
while (cr->gstate_freelist != NULL) { |
cairo_gstate_t *gstate = cr->gstate_freelist; |
cr->gstate_freelist = gstate->next; |
free (gstate); |
} |
|
_cairo_path_fixed_fini (cr->path); |
|
_cairo_fini (&cr->base); |
} |
|
static void |
_cairo_default_context_destroy (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_default_context_fini (cr); |
|
/* mark the context as invalid to protect against misuse */ |
cr->base.status = CAIRO_STATUS_NULL_POINTER; |
_freed_pool_put (&context_pool, cr); |
} |
|
static cairo_surface_t * |
_cairo_default_context_get_original_target (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_original_target (cr->gstate); |
} |
|
static cairo_surface_t * |
_cairo_default_context_get_current_target (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_target (cr->gstate); |
} |
|
static cairo_status_t |
_cairo_default_context_save (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist); |
} |
|
static cairo_status_t |
_cairo_default_context_restore (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
if (unlikely (_cairo_gstate_is_group (cr->gstate))) |
return _cairo_error (CAIRO_STATUS_INVALID_RESTORE); |
|
return _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist); |
} |
|
static cairo_status_t |
_cairo_default_context_push_group (void *abstract_cr, cairo_content_t content) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_surface_t *group_surface; |
cairo_clip_t *clip; |
cairo_status_t status; |
|
clip = _cairo_gstate_get_clip (cr->gstate); |
if (_cairo_clip_is_all_clipped (clip)) { |
group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); |
status = group_surface->status; |
if (unlikely (status)) |
goto bail; |
} else { |
cairo_surface_t *parent_surface; |
cairo_rectangle_int_t extents; |
cairo_bool_t bounded, is_empty; |
|
parent_surface = _cairo_gstate_get_target (cr->gstate); |
|
if (unlikely (parent_surface->status)) |
return parent_surface->status; |
if (unlikely (parent_surface->finished)) |
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); |
|
/* Get the extents that we'll use in creating our new group surface */ |
bounded = _cairo_surface_get_extents (parent_surface, &extents); |
if (clip) |
/* XXX: This assignment just fixes a compiler warning? */ |
is_empty = _cairo_rectangle_intersect (&extents, |
_cairo_clip_get_extents (clip)); |
|
if (!bounded) { |
/* XXX: Generic solution? */ |
group_surface = cairo_recording_surface_create (content, NULL); |
extents.x = extents.y = 0; |
} else { |
group_surface = _cairo_surface_create_similar_solid (parent_surface, |
content, |
extents.width, |
extents.height, |
CAIRO_COLOR_TRANSPARENT); |
} |
status = group_surface->status; |
if (unlikely (status)) |
goto bail; |
|
/* Set device offsets on the new surface so that logically it appears at |
* the same location on the parent surface -- when we pop_group this, |
* the source pattern will get fixed up for the appropriate target surface |
* device offsets, so we want to set our own surface offsets from /that/, |
* and not from the device origin. */ |
cairo_surface_set_device_offset (group_surface, |
parent_surface->device_transform.x0 - extents.x, |
parent_surface->device_transform.y0 - extents.y); |
|
/* If we have a current path, we need to adjust it to compensate for |
* the device offset just applied. */ |
_cairo_path_fixed_translate (cr->path, |
_cairo_fixed_from_int (-extents.x), |
_cairo_fixed_from_int (-extents.y)); |
} |
|
/* create a new gstate for the redirect */ |
status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist); |
if (unlikely (status)) |
goto bail; |
|
status = _cairo_gstate_redirect_target (cr->gstate, group_surface); |
|
bail: |
cairo_surface_destroy (group_surface); |
return status; |
} |
|
static cairo_pattern_t * |
_cairo_default_context_pop_group (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_surface_t *group_surface; |
cairo_pattern_t *group_pattern; |
cairo_matrix_t group_matrix, device_transform_matrix; |
cairo_status_t status; |
|
/* Verify that we are at the right nesting level */ |
if (unlikely (! _cairo_gstate_is_group (cr->gstate))) |
return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_POP_GROUP); |
|
/* Get a reference to the active surface before restoring */ |
group_surface = _cairo_gstate_get_target (cr->gstate); |
group_surface = cairo_surface_reference (group_surface); |
|
status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist); |
assert (status == CAIRO_STATUS_SUCCESS); |
|
group_pattern = cairo_pattern_create_for_surface (group_surface); |
status = group_pattern->status; |
if (unlikely (status)) |
goto done; |
|
_cairo_gstate_get_matrix (cr->gstate, &group_matrix); |
/* Transform by group_matrix centered around device_transform so that when |
* we call _cairo_gstate_copy_transformed_pattern the result is a pattern |
* with a matrix equivalent to the device_transform of group_surface. */ |
if (_cairo_surface_has_device_transform (group_surface)) { |
cairo_pattern_set_matrix (group_pattern, &group_surface->device_transform); |
_cairo_pattern_transform (group_pattern, &group_matrix); |
_cairo_pattern_transform (group_pattern, &group_surface->device_transform_inverse); |
} else { |
cairo_pattern_set_matrix (group_pattern, &group_matrix); |
} |
|
/* If we have a current path, we need to adjust it to compensate for |
* the device offset just removed. */ |
cairo_matrix_multiply (&device_transform_matrix, |
&_cairo_gstate_get_target (cr->gstate)->device_transform, |
&group_surface->device_transform_inverse); |
_cairo_path_fixed_transform (cr->path, &device_transform_matrix); |
|
done: |
cairo_surface_destroy (group_surface); |
|
return group_pattern; |
} |
|
static cairo_status_t |
_cairo_default_context_set_source (void *abstract_cr, |
cairo_pattern_t *source) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_source (cr->gstate, source); |
} |
|
static cairo_bool_t |
_current_source_matches_solid (const cairo_pattern_t *pattern, |
double red, |
double green, |
double blue, |
double alpha) |
{ |
cairo_color_t color; |
|
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) |
return FALSE; |
|
red = _cairo_restrict_value (red, 0.0, 1.0); |
green = _cairo_restrict_value (green, 0.0, 1.0); |
blue = _cairo_restrict_value (blue, 0.0, 1.0); |
alpha = _cairo_restrict_value (alpha, 0.0, 1.0); |
|
_cairo_color_init_rgba (&color, red, green, blue, alpha); |
return _cairo_color_equal (&color, |
&((cairo_solid_pattern_t *) pattern)->color); |
} |
|
static cairo_status_t |
_cairo_default_context_set_source_rgba (void *abstract_cr, double red, double green, double blue, double alpha) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_pattern_t *pattern; |
cairo_status_t status; |
|
if (_current_source_matches_solid (cr->gstate->source, |
red, green, blue, alpha)) |
return CAIRO_STATUS_SUCCESS; |
|
/* push the current pattern to the freed lists */ |
_cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black); |
|
pattern = cairo_pattern_create_rgba (red, green, blue, alpha); |
if (unlikely (pattern->status)) |
return pattern->status; |
|
status = _cairo_default_context_set_source (cr, pattern); |
cairo_pattern_destroy (pattern); |
|
return status; |
} |
|
static cairo_status_t |
_cairo_default_context_set_source_surface (void *abstract_cr, |
cairo_surface_t *surface, |
double x, |
double y) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_pattern_t *pattern; |
cairo_matrix_t matrix; |
cairo_status_t status; |
|
/* push the current pattern to the freed lists */ |
_cairo_default_context_set_source (cr, (cairo_pattern_t *) &_cairo_pattern_black); |
|
pattern = cairo_pattern_create_for_surface (surface); |
if (unlikely (pattern->status)) |
return pattern->status; |
|
cairo_matrix_init_translate (&matrix, -x, -y); |
cairo_pattern_set_matrix (pattern, &matrix); |
|
status = _cairo_default_context_set_source (cr, pattern); |
cairo_pattern_destroy (pattern); |
|
return status; |
} |
|
static cairo_pattern_t * |
_cairo_default_context_get_source (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_source (cr->gstate); |
} |
|
static cairo_status_t |
_cairo_default_context_set_tolerance (void *abstract_cr, |
double tolerance) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
if (tolerance < CAIRO_TOLERANCE_MINIMUM) |
tolerance = CAIRO_TOLERANCE_MINIMUM; |
|
return _cairo_gstate_set_tolerance (cr->gstate, tolerance); |
} |
|
static cairo_status_t |
_cairo_default_context_set_operator (void *abstract_cr, cairo_operator_t op) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_operator (cr->gstate, op); |
} |
|
static cairo_status_t |
_cairo_default_context_set_opacity (void *abstract_cr, double opacity) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_opacity (cr->gstate, opacity); |
} |
|
static cairo_status_t |
_cairo_default_context_set_antialias (void *abstract_cr, |
cairo_antialias_t antialias) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_antialias (cr->gstate, antialias); |
} |
|
static cairo_status_t |
_cairo_default_context_set_fill_rule (void *abstract_cr, |
cairo_fill_rule_t fill_rule) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_fill_rule (cr->gstate, fill_rule); |
} |
|
static cairo_status_t |
_cairo_default_context_set_line_width (void *abstract_cr, |
double line_width) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_line_width (cr->gstate, line_width); |
} |
|
static cairo_status_t |
_cairo_default_context_set_line_cap (void *abstract_cr, |
cairo_line_cap_t line_cap) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_line_cap (cr->gstate, line_cap); |
} |
|
static cairo_status_t |
_cairo_default_context_set_line_join (void *abstract_cr, |
cairo_line_join_t line_join) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_line_join (cr->gstate, line_join); |
} |
|
static cairo_status_t |
_cairo_default_context_set_dash (void *abstract_cr, |
const double *dashes, |
int num_dashes, |
double offset) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_dash (cr->gstate, |
dashes, num_dashes, offset); |
} |
|
static cairo_status_t |
_cairo_default_context_set_miter_limit (void *abstract_cr, |
double limit) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_miter_limit (cr->gstate, limit); |
} |
|
static cairo_antialias_t |
_cairo_default_context_get_antialias (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_antialias (cr->gstate); |
} |
|
static void |
_cairo_default_context_get_dash (void *abstract_cr, |
double *dashes, |
int *num_dashes, |
double *offset) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_get_dash (cr->gstate, dashes, num_dashes, offset); |
} |
|
static cairo_fill_rule_t |
_cairo_default_context_get_fill_rule (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_fill_rule (cr->gstate); |
} |
|
static double |
_cairo_default_context_get_line_width (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_line_width (cr->gstate); |
} |
|
static cairo_line_cap_t |
_cairo_default_context_get_line_cap (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_line_cap (cr->gstate); |
} |
|
static cairo_line_join_t |
_cairo_default_context_get_line_join (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_line_join (cr->gstate); |
} |
|
static double |
_cairo_default_context_get_miter_limit (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_miter_limit (cr->gstate); |
} |
|
static cairo_operator_t |
_cairo_default_context_get_operator (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_operator (cr->gstate); |
} |
|
static double |
_cairo_default_context_get_opacity (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_opacity (cr->gstate); |
} |
|
static double |
_cairo_default_context_get_tolerance (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_tolerance (cr->gstate); |
} |
|
|
/* Current tranformation matrix */ |
|
static cairo_status_t |
_cairo_default_context_translate (void *abstract_cr, |
double tx, |
double ty) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_translate (cr->gstate, tx, ty); |
} |
|
static cairo_status_t |
_cairo_default_context_scale (void *abstract_cr, |
double sx, |
double sy) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_scale (cr->gstate, sx, sy); |
} |
|
static cairo_status_t |
_cairo_default_context_rotate (void *abstract_cr, |
double theta) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_rotate (cr->gstate, theta); |
} |
|
static cairo_status_t |
_cairo_default_context_transform (void *abstract_cr, |
const cairo_matrix_t *matrix) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_transform (cr->gstate, matrix); |
} |
|
static cairo_status_t |
_cairo_default_context_set_matrix (void *abstract_cr, |
const cairo_matrix_t *matrix) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_matrix (cr->gstate, matrix); |
} |
|
static cairo_status_t |
_cairo_default_context_set_identity_matrix (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_identity_matrix (cr->gstate); |
return CAIRO_STATUS_SUCCESS; |
} |
|
static void |
_cairo_default_context_get_matrix (void *abstract_cr, |
cairo_matrix_t *matrix) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_get_matrix (cr->gstate, matrix); |
} |
|
static void |
_cairo_default_context_user_to_device (void *abstract_cr, |
double *x, |
double *y) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_user_to_device (cr->gstate, x, y); |
} |
|
static void |
_cairo_default_context_user_to_device_distance (void *abstract_cr, double *dx, double *dy) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_user_to_device_distance (cr->gstate, dx, dy); |
} |
|
static void |
_cairo_default_context_device_to_user (void *abstract_cr, |
double *x, |
double *y) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_device_to_user (cr->gstate, x, y); |
} |
|
static void |
_cairo_default_context_device_to_user_distance (void *abstract_cr, |
double *dx, |
double *dy) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_device_to_user_distance (cr->gstate, dx, dy); |
} |
|
static void |
_cairo_default_context_backend_to_user (void *abstract_cr, |
double *x, |
double *y) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_backend_to_user (cr->gstate, x, y); |
} |
|
static void |
_cairo_default_context_backend_to_user_distance (void *abstract_cr, double *dx, double *dy) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_backend_to_user_distance (cr->gstate, dx, dy); |
} |
|
static void |
_cairo_default_context_user_to_backend (void *abstract_cr, |
double *x, |
double *y) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_user_to_backend (cr->gstate, x, y); |
} |
|
static void |
_cairo_default_context_user_to_backend_distance (void *abstract_cr, |
double *dx, |
double *dy) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_user_to_backend_distance (cr->gstate, dx, dy); |
} |
|
/* Path constructor */ |
|
static cairo_status_t |
_cairo_default_context_new_path (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_path_fixed_fini (cr->path); |
_cairo_path_fixed_init (cr->path); |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_status_t |
_cairo_default_context_new_sub_path (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_path_fixed_new_sub_path (cr->path); |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_status_t |
_cairo_default_context_move_to (void *abstract_cr, double x, double y) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_fixed_t x_fixed, y_fixed; |
|
_cairo_gstate_user_to_backend (cr->gstate, &x, &y); |
x_fixed = _cairo_fixed_from_double (x); |
y_fixed = _cairo_fixed_from_double (y); |
|
return _cairo_path_fixed_move_to (cr->path, x_fixed, y_fixed); |
} |
|
static cairo_status_t |
_cairo_default_context_line_to (void *abstract_cr, double x, double y) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_fixed_t x_fixed, y_fixed; |
|
_cairo_gstate_user_to_backend (cr->gstate, &x, &y); |
x_fixed = _cairo_fixed_from_double (x); |
y_fixed = _cairo_fixed_from_double (y); |
|
return _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed); |
} |
|
static cairo_status_t |
_cairo_default_context_curve_to (void *abstract_cr, |
double x1, double y1, |
double x2, double y2, |
double x3, double y3) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_fixed_t x1_fixed, y1_fixed; |
cairo_fixed_t x2_fixed, y2_fixed; |
cairo_fixed_t x3_fixed, y3_fixed; |
|
_cairo_gstate_user_to_backend (cr->gstate, &x1, &y1); |
_cairo_gstate_user_to_backend (cr->gstate, &x2, &y2); |
_cairo_gstate_user_to_backend (cr->gstate, &x3, &y3); |
|
x1_fixed = _cairo_fixed_from_double (x1); |
y1_fixed = _cairo_fixed_from_double (y1); |
|
x2_fixed = _cairo_fixed_from_double (x2); |
y2_fixed = _cairo_fixed_from_double (y2); |
|
x3_fixed = _cairo_fixed_from_double (x3); |
y3_fixed = _cairo_fixed_from_double (y3); |
|
return _cairo_path_fixed_curve_to (cr->path, |
x1_fixed, y1_fixed, |
x2_fixed, y2_fixed, |
x3_fixed, y3_fixed); |
} |
|
static cairo_status_t |
_cairo_default_context_arc (void *abstract_cr, |
double xc, double yc, double radius, |
double angle1, double angle2, |
cairo_bool_t forward) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_status_t status; |
|
/* Do nothing, successfully, if radius is <= 0 */ |
if (radius <= 0.0) { |
cairo_fixed_t x_fixed, y_fixed; |
|
_cairo_gstate_user_to_backend (cr->gstate, &xc, &yc); |
x_fixed = _cairo_fixed_from_double (xc); |
y_fixed = _cairo_fixed_from_double (yc); |
status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed); |
if (unlikely (status)) |
return status; |
|
status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed); |
if (unlikely (status)) |
return status; |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
status = _cairo_default_context_line_to (cr, |
xc + radius * cos (angle1), |
yc + radius * sin (angle1)); |
|
if (unlikely (status)) |
return status; |
|
if (forward) |
_cairo_arc_path (&cr->base, xc, yc, radius, angle1, angle2); |
else |
_cairo_arc_path_negative (&cr->base, xc, yc, radius, angle1, angle2); |
|
return CAIRO_STATUS_SUCCESS; /* any error will have already been set on cr */ |
} |
|
static cairo_status_t |
_cairo_default_context_rel_move_to (void *abstract_cr, double dx, double dy) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_fixed_t dx_fixed, dy_fixed; |
|
_cairo_gstate_user_to_backend_distance (cr->gstate, &dx, &dy); |
|
dx_fixed = _cairo_fixed_from_double (dx); |
dy_fixed = _cairo_fixed_from_double (dy); |
|
return _cairo_path_fixed_rel_move_to (cr->path, dx_fixed, dy_fixed); |
} |
|
static cairo_status_t |
_cairo_default_context_rel_line_to (void *abstract_cr, double dx, double dy) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_fixed_t dx_fixed, dy_fixed; |
|
_cairo_gstate_user_to_backend_distance (cr->gstate, &dx, &dy); |
|
dx_fixed = _cairo_fixed_from_double (dx); |
dy_fixed = _cairo_fixed_from_double (dy); |
|
return _cairo_path_fixed_rel_line_to (cr->path, dx_fixed, dy_fixed); |
} |
|
|
static cairo_status_t |
_cairo_default_context_rel_curve_to (void *abstract_cr, |
double dx1, double dy1, |
double dx2, double dy2, |
double dx3, double dy3) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_fixed_t dx1_fixed, dy1_fixed; |
cairo_fixed_t dx2_fixed, dy2_fixed; |
cairo_fixed_t dx3_fixed, dy3_fixed; |
|
_cairo_gstate_user_to_backend_distance (cr->gstate, &dx1, &dy1); |
_cairo_gstate_user_to_backend_distance (cr->gstate, &dx2, &dy2); |
_cairo_gstate_user_to_backend_distance (cr->gstate, &dx3, &dy3); |
|
dx1_fixed = _cairo_fixed_from_double (dx1); |
dy1_fixed = _cairo_fixed_from_double (dy1); |
|
dx2_fixed = _cairo_fixed_from_double (dx2); |
dy2_fixed = _cairo_fixed_from_double (dy2); |
|
dx3_fixed = _cairo_fixed_from_double (dx3); |
dy3_fixed = _cairo_fixed_from_double (dy3); |
|
return _cairo_path_fixed_rel_curve_to (cr->path, |
dx1_fixed, dy1_fixed, |
dx2_fixed, dy2_fixed, |
dx3_fixed, dy3_fixed); |
} |
|
static cairo_status_t |
_cairo_default_context_close_path (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_path_fixed_close_path (cr->path); |
} |
|
static cairo_status_t |
_cairo_default_context_rectangle (void *abstract_cr, |
double x, double y, |
double width, double height) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_status_t status; |
|
status = _cairo_default_context_move_to (cr, x, y); |
if (unlikely (status)) |
return status; |
|
status = _cairo_default_context_rel_line_to (cr, width, 0); |
if (unlikely (status)) |
return status; |
|
status = _cairo_default_context_rel_line_to (cr, 0, height); |
if (unlikely (status)) |
return status; |
|
status = _cairo_default_context_rel_line_to (cr, -width, 0); |
if (unlikely (status)) |
return status; |
|
return _cairo_default_context_close_path (cr); |
} |
|
static void |
_cairo_default_context_path_extents (void *abstract_cr, |
double *x1, |
double *y1, |
double *x2, |
double *y2) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_path_extents (cr->gstate, |
cr->path, |
x1, y1, x2, y2); |
} |
|
static cairo_bool_t |
_cairo_default_context_has_current_point (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return cr->path->has_current_point; |
} |
|
static cairo_bool_t |
_cairo_default_context_get_current_point (void *abstract_cr, |
double *x, |
double *y) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_fixed_t x_fixed, y_fixed; |
|
if (_cairo_path_fixed_get_current_point (cr->path, &x_fixed, &y_fixed)) |
{ |
*x = _cairo_fixed_to_double (x_fixed); |
*y = _cairo_fixed_to_double (y_fixed); |
_cairo_gstate_backend_to_user (cr->gstate, x, y); |
|
return TRUE; |
} |
else |
{ |
return FALSE; |
} |
} |
|
static cairo_path_t * |
_cairo_default_context_copy_path (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_path_create (cr->path, &cr->base); |
} |
|
static cairo_path_t * |
_cairo_default_context_copy_path_flat (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_path_create_flat (cr->path, &cr->base); |
} |
|
static cairo_status_t |
_cairo_default_context_append_path (void *abstract_cr, |
const cairo_path_t *path) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_path_append_to_context (path, &cr->base); |
} |
|
static cairo_status_t |
_cairo_default_context_paint (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_paint (cr->gstate); |
} |
|
static cairo_status_t |
_cairo_default_context_paint_with_alpha (void *abstract_cr, |
double alpha) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_solid_pattern_t pattern; |
cairo_status_t status; |
cairo_color_t color; |
|
if (CAIRO_ALPHA_IS_OPAQUE (alpha)) |
return _cairo_gstate_paint (cr->gstate); |
|
if (CAIRO_ALPHA_IS_ZERO (alpha) && |
_cairo_operator_bounded_by_mask (cr->gstate->op)) { |
return CAIRO_STATUS_SUCCESS; |
} |
|
_cairo_color_init_rgba (&color, 0., 0., 0., alpha); |
_cairo_pattern_init_solid (&pattern, &color); |
|
status = _cairo_gstate_mask (cr->gstate, &pattern.base); |
_cairo_pattern_fini (&pattern.base); |
|
return status; |
} |
|
static cairo_status_t |
_cairo_default_context_mask (void *abstract_cr, |
cairo_pattern_t *mask) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_mask (cr->gstate, mask); |
} |
|
static cairo_status_t |
_cairo_default_context_stroke_preserve (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_stroke (cr->gstate, cr->path); |
} |
|
static cairo_status_t |
_cairo_default_context_stroke (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_status_t status; |
|
status = _cairo_gstate_stroke (cr->gstate, cr->path); |
if (unlikely (status)) |
return status; |
|
return _cairo_default_context_new_path (cr); |
} |
|
static cairo_status_t |
_cairo_default_context_in_stroke (void *abstract_cr, |
double x, double y, |
cairo_bool_t *inside) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_in_stroke (cr->gstate, |
cr->path, |
x, y, |
inside); |
} |
|
static cairo_status_t |
_cairo_default_context_stroke_extents (void *abstract_cr, |
double *x1, double *y1, double *x2, double *y2) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_stroke_extents (cr->gstate, |
cr->path, |
x1, y1, x2, y2); |
} |
|
static cairo_status_t |
_cairo_default_context_fill_preserve (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_fill (cr->gstate, cr->path); |
} |
|
static cairo_status_t |
_cairo_default_context_fill (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_status_t status; |
|
status = _cairo_gstate_fill (cr->gstate, cr->path); |
if (unlikely (status)) |
return status; |
|
return _cairo_default_context_new_path (cr); |
} |
|
static cairo_status_t |
_cairo_default_context_in_fill (void *abstract_cr, |
double x, double y, |
cairo_bool_t *inside) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
*inside = _cairo_gstate_in_fill (cr->gstate, |
cr->path, |
x, y); |
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_status_t |
_cairo_default_context_fill_extents (void *abstract_cr, |
double *x1, double *y1, double *x2, double *y2) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_fill_extents (cr->gstate, |
cr->path, |
x1, y1, x2, y2); |
} |
|
static cairo_status_t |
_cairo_default_context_clip_preserve (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_clip (cr->gstate, cr->path); |
} |
|
static cairo_status_t |
_cairo_default_context_clip (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_status_t status; |
|
status = _cairo_gstate_clip (cr->gstate, cr->path); |
if (unlikely (status)) |
return status; |
|
return _cairo_default_context_new_path (cr); |
} |
|
static cairo_status_t |
_cairo_default_context_in_clip (void *abstract_cr, |
double x, double y, |
cairo_bool_t *inside) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
*inside = _cairo_gstate_in_clip (cr->gstate, x, y); |
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_status_t |
_cairo_default_context_reset_clip (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_reset_clip (cr->gstate); |
} |
|
static cairo_status_t |
_cairo_default_context_clip_extents (void *abstract_cr, |
double *x1, double *y1, double *x2, double *y2) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
if (! _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2)) { |
*x1 = -INFINITY; |
*y1 = -INFINITY; |
*x2 = +INFINITY; |
*y2 = +INFINITY; |
} |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_rectangle_list_t * |
_cairo_default_context_copy_clip_rectangle_list (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_copy_clip_rectangle_list (cr->gstate); |
} |
|
static cairo_status_t |
_cairo_default_context_copy_page (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_copy_page (cr->gstate); |
} |
|
static cairo_status_t |
_cairo_default_context_show_page (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_show_page (cr->gstate); |
} |
|
static cairo_status_t |
_cairo_default_context_set_font_face (void *abstract_cr, |
cairo_font_face_t *font_face) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_font_face (cr->gstate, font_face); |
} |
|
static cairo_font_face_t * |
_cairo_default_context_get_font_face (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_font_face_t *font_face; |
cairo_status_t status; |
|
status = _cairo_gstate_get_font_face (cr->gstate, &font_face); |
if (unlikely (status)) { |
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
return (cairo_font_face_t *) &_cairo_font_face_nil; |
} |
|
return font_face; |
} |
|
static cairo_status_t |
_cairo_default_context_font_extents (void *abstract_cr, |
cairo_font_extents_t *extents) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_get_font_extents (cr->gstate, extents); |
} |
|
static cairo_status_t |
_cairo_default_context_set_font_size (void *abstract_cr, |
double size) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_font_size (cr->gstate, size); |
} |
|
static cairo_status_t |
_cairo_default_context_set_font_matrix (void *abstract_cr, |
const cairo_matrix_t *matrix) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_set_font_matrix (cr->gstate, matrix); |
} |
|
static void |
_cairo_default_context_get_font_matrix (void *abstract_cr, |
cairo_matrix_t *matrix) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_get_font_matrix (cr->gstate, matrix); |
} |
|
static cairo_status_t |
_cairo_default_context_set_font_options (void *abstract_cr, |
const cairo_font_options_t *options) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_set_font_options (cr->gstate, options); |
return CAIRO_STATUS_SUCCESS; |
} |
|
static void |
_cairo_default_context_get_font_options (void *abstract_cr, |
cairo_font_options_t *options) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
_cairo_gstate_get_font_options (cr->gstate, options); |
} |
|
static cairo_status_t |
_cairo_default_context_set_scaled_font (void *abstract_cr, |
cairo_scaled_font_t *scaled_font) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_bool_t was_previous; |
cairo_status_t status; |
|
if (scaled_font == cr->gstate->scaled_font) |
return CAIRO_STATUS_SUCCESS; |
|
was_previous = scaled_font == cr->gstate->previous_scaled_font; |
|
status = _cairo_gstate_set_font_face (cr->gstate, scaled_font->font_face); |
if (unlikely (status)) |
return status; |
|
status = _cairo_gstate_set_font_matrix (cr->gstate, &scaled_font->font_matrix); |
if (unlikely (status)) |
return status; |
|
_cairo_gstate_set_font_options (cr->gstate, &scaled_font->options); |
|
if (was_previous) |
cr->gstate->scaled_font = cairo_scaled_font_reference (scaled_font); |
|
return CAIRO_STATUS_SUCCESS; |
} |
|
static cairo_scaled_font_t * |
_cairo_default_context_get_scaled_font (void *abstract_cr) |
{ |
cairo_default_context_t *cr = abstract_cr; |
cairo_scaled_font_t *scaled_font; |
cairo_status_t status; |
|
status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font); |
if (unlikely (status)) |
return _cairo_scaled_font_create_in_error (status); |
|
return scaled_font; |
} |
|
static cairo_status_t |
_cairo_default_context_glyphs (void *abstract_cr, |
const cairo_glyph_t *glyphs, |
int num_glyphs, |
cairo_glyph_text_info_t *info) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_show_text_glyphs (cr->gstate, glyphs, num_glyphs, info); |
} |
|
static cairo_status_t |
_cairo_default_context_glyph_path (void *abstract_cr, |
const cairo_glyph_t *glyphs, |
int num_glyphs) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_glyph_path (cr->gstate, |
glyphs, num_glyphs, |
cr->path); |
} |
|
static cairo_status_t |
_cairo_default_context_glyph_extents (void *abstract_cr, |
const cairo_glyph_t *glyphs, |
int num_glyphs, |
cairo_text_extents_t *extents) |
{ |
cairo_default_context_t *cr = abstract_cr; |
|
return _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs, extents); |
} |
|
static const cairo_backend_t _cairo_default_context_backend = { |
CAIRO_TYPE_DEFAULT, |
_cairo_default_context_destroy, |
|
_cairo_default_context_get_original_target, |
_cairo_default_context_get_current_target, |
|
_cairo_default_context_save, |
_cairo_default_context_restore, |
|
_cairo_default_context_push_group, |
_cairo_default_context_pop_group, |
|
_cairo_default_context_set_source_rgba, |
_cairo_default_context_set_source_surface, |
_cairo_default_context_set_source, |
_cairo_default_context_get_source, |
|
_cairo_default_context_set_antialias, |
_cairo_default_context_set_dash, |
_cairo_default_context_set_fill_rule, |
_cairo_default_context_set_line_cap, |
_cairo_default_context_set_line_join, |
_cairo_default_context_set_line_width, |
_cairo_default_context_set_miter_limit, |
_cairo_default_context_set_opacity, |
_cairo_default_context_set_operator, |
_cairo_default_context_set_tolerance, |
_cairo_default_context_get_antialias, |
_cairo_default_context_get_dash, |
_cairo_default_context_get_fill_rule, |
_cairo_default_context_get_line_cap, |
_cairo_default_context_get_line_join, |
_cairo_default_context_get_line_width, |
_cairo_default_context_get_miter_limit, |
_cairo_default_context_get_opacity, |
_cairo_default_context_get_operator, |
_cairo_default_context_get_tolerance, |
|
_cairo_default_context_translate, |
_cairo_default_context_scale, |
_cairo_default_context_rotate, |
_cairo_default_context_transform, |
_cairo_default_context_set_matrix, |
_cairo_default_context_set_identity_matrix, |
_cairo_default_context_get_matrix, |
|
_cairo_default_context_user_to_device, |
_cairo_default_context_user_to_device_distance, |
_cairo_default_context_device_to_user, |
_cairo_default_context_device_to_user_distance, |
|
_cairo_default_context_user_to_backend, |
_cairo_default_context_user_to_backend_distance, |
_cairo_default_context_backend_to_user, |
_cairo_default_context_backend_to_user_distance, |
|
_cairo_default_context_new_path, |
_cairo_default_context_new_sub_path, |
_cairo_default_context_move_to, |
_cairo_default_context_rel_move_to, |
_cairo_default_context_line_to, |
_cairo_default_context_rel_line_to, |
_cairo_default_context_curve_to, |
_cairo_default_context_rel_curve_to, |
NULL, /* arc-to */ |
NULL, /* rel-arc-to */ |
_cairo_default_context_close_path, |
_cairo_default_context_arc, |
_cairo_default_context_rectangle, |
_cairo_default_context_path_extents, |
_cairo_default_context_has_current_point, |
_cairo_default_context_get_current_point, |
_cairo_default_context_copy_path, |
_cairo_default_context_copy_path_flat, |
_cairo_default_context_append_path, |
|
NULL, /* stroke-to-path */ |
|
_cairo_default_context_clip, |
_cairo_default_context_clip_preserve, |
_cairo_default_context_in_clip, |
_cairo_default_context_clip_extents, |
_cairo_default_context_reset_clip, |
_cairo_default_context_copy_clip_rectangle_list, |
|
_cairo_default_context_paint, |
_cairo_default_context_paint_with_alpha, |
_cairo_default_context_mask, |
|
_cairo_default_context_stroke, |
_cairo_default_context_stroke_preserve, |
_cairo_default_context_in_stroke, |
_cairo_default_context_stroke_extents, |
|
_cairo_default_context_fill, |
_cairo_default_context_fill_preserve, |
_cairo_default_context_in_fill, |
_cairo_default_context_fill_extents, |
|
_cairo_default_context_set_font_face, |
_cairo_default_context_get_font_face, |
_cairo_default_context_set_font_size, |
_cairo_default_context_set_font_matrix, |
_cairo_default_context_get_font_matrix, |
_cairo_default_context_set_font_options, |
_cairo_default_context_get_font_options, |
_cairo_default_context_set_scaled_font, |
_cairo_default_context_get_scaled_font, |
_cairo_default_context_font_extents, |
|
_cairo_default_context_glyphs, |
_cairo_default_context_glyph_path, |
_cairo_default_context_glyph_extents, |
|
_cairo_default_context_copy_page, |
_cairo_default_context_show_page, |
}; |
|
cairo_status_t |
_cairo_default_context_init (cairo_default_context_t *cr, void *target) |
{ |
_cairo_init (&cr->base, &_cairo_default_context_backend); |
_cairo_path_fixed_init (cr->path); |
|
cr->gstate = &cr->gstate_tail[0]; |
cr->gstate_freelist = &cr->gstate_tail[1]; |
cr->gstate_tail[1].next = NULL; |
|
return _cairo_gstate_init (cr->gstate, target); |
} |
|
cairo_t * |
_cairo_default_context_create (void *target) |
{ |
cairo_default_context_t *cr; |
cairo_status_t status; |
|
cr = _freed_pool_get (&context_pool); |
if (unlikely (cr == NULL)) { |
cr = malloc (sizeof (cairo_default_context_t)); |
if (unlikely (cr == NULL)) |
return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
} |
|
status = _cairo_default_context_init (cr, target); |
if (unlikely (status)) { |
_freed_pool_put (&context_pool, cr); |
return _cairo_create_in_error (status); |
} |
|
return &cr->base; |
} |