mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-05 04:08:13 +02:00
Updated linear and radial patterns
This commit is contained in:
parent
c9c882d2b2
commit
f516564f98
8 changed files with 309 additions and 249 deletions
25
ChangeLog
25
ChangeLog
|
|
@ -1,3 +1,28 @@
|
|||
2004-04-30 David Reveman <c99drn@cs.umu.se>
|
||||
|
||||
* src/cairoint.h: Radial patterns only store radius per circle.
|
||||
Only inverse CTM to _cairo_pattern_transform.
|
||||
|
||||
* src/cairo_pattern.c (cairo_pattern_create_radial): Only one radius
|
||||
per circle now.
|
||||
(_cairo_pattern_transform): A matrix multiplication with inverse CTM
|
||||
is all that's needed here.
|
||||
(_cairo_pattern_calc_color_at_pixel): Fixed extend type reflect.
|
||||
(_cairo_image_data_set_linear): New linear gradient code.
|
||||
Transformation of linear gradient is now handled correctly.
|
||||
(_cairo_image_data_set_radial): New radial gradient code. Inner circle
|
||||
is now used for creating radial gradients. Transformation of radial
|
||||
gradient is now handled correctly.
|
||||
(_cairo_pattern_get_image): Fixed handling of pattern offset.
|
||||
|
||||
* src/cairo_gstate.c (_cairo_gstate_create_pattern): All pattern types
|
||||
are transformed using inverse CTM.
|
||||
|
||||
* src/cairo_gl_surface.c (_cairo_gl_surface_create_pattern): Updated
|
||||
to use glitz's new linear and radial gradients.
|
||||
|
||||
* configure.in: Require glitz 0.1.1.
|
||||
|
||||
2004-04-28 David Reveman <c99drn@cs.umu.se>
|
||||
|
||||
* src/cairo_gl_surface.c: Added CAIRO_GL_MULTITEXTURE_SUPPORT and
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ AC_ARG_ENABLE(gl,
|
|||
[use_gl=$enableval], [use_gl=yes])
|
||||
|
||||
if test "x$use_gl" = "xyes"; then
|
||||
PKG_CHECK_MODULES(GL, glitz >= 0.1.0, [
|
||||
PKG_CHECK_MODULES(GL, glitz >= 0.1.1, [
|
||||
GL_REQUIRES=glitz
|
||||
use_gl=yes], [use_gl="no (requires glitz http://freedesktop.org/software/glitz)"])
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1278,7 +1278,7 @@ _cairo_gstate_create_pattern (cairo_gstate_t *gstate,
|
|||
}
|
||||
|
||||
_cairo_pattern_set_alpha (pattern, gstate->alpha);
|
||||
_cairo_pattern_transform (pattern, &gstate->ctm, &gstate->ctm_inverse);
|
||||
_cairo_pattern_transform (pattern, &gstate->ctm_inverse);
|
||||
|
||||
_cairo_pattern_set_source_offset (pattern,
|
||||
gstate->pattern_offset.x,
|
||||
|
|
|
|||
|
|
@ -175,12 +175,10 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
|
|||
pattern->type = CAIRO_PATTERN_RADIAL;
|
||||
pattern->u.radial.center0.x = cx0;
|
||||
pattern->u.radial.center0.y = cy0;
|
||||
pattern->u.radial.radius0.dx = fabs (radius0);
|
||||
pattern->u.radial.radius0.dy = fabs (radius0);
|
||||
pattern->u.radial.radius0 = fabs (radius0);
|
||||
pattern->u.radial.center1.x = cx1;
|
||||
pattern->u.radial.center1.y = cy1;
|
||||
pattern->u.radial.radius1.dx = fabs (radius1);
|
||||
pattern->u.radial.radius1.dy = fabs (radius1);
|
||||
pattern->u.radial.radius1 = fabs (radius1);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
|
@ -353,45 +351,9 @@ _cairo_pattern_set_source_offset (cairo_pattern_t *pattern,
|
|||
|
||||
void
|
||||
_cairo_pattern_transform (cairo_pattern_t *pattern,
|
||||
cairo_matrix_t *ctm,
|
||||
cairo_matrix_t *ctm_inverse)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
switch (pattern->type) {
|
||||
case CAIRO_PATTERN_SURFACE:
|
||||
/* hmm, maybe we should instead multiply with the inverse of the
|
||||
pattern matrix here? */
|
||||
cairo_matrix_multiply (&pattern->matrix, ctm_inverse,
|
||||
&pattern->matrix);
|
||||
break;
|
||||
case CAIRO_PATTERN_LINEAR:
|
||||
cairo_matrix_multiply (&matrix, &pattern->matrix, ctm);
|
||||
cairo_matrix_transform_point (&matrix,
|
||||
&pattern->u.linear.point0.x,
|
||||
&pattern->u.linear.point0.y);
|
||||
cairo_matrix_transform_point (&matrix,
|
||||
&pattern->u.linear.point1.x,
|
||||
&pattern->u.linear.point1.y);
|
||||
break;
|
||||
case CAIRO_PATTERN_RADIAL:
|
||||
cairo_matrix_multiply (&matrix, &pattern->matrix, ctm);
|
||||
cairo_matrix_transform_point (&matrix,
|
||||
&pattern->u.radial.center0.x,
|
||||
&pattern->u.radial.center0.y);
|
||||
cairo_matrix_transform_distance (&matrix,
|
||||
&pattern->u.radial.radius0.dx,
|
||||
&pattern->u.radial.radius0.dy);
|
||||
cairo_matrix_transform_point (&matrix,
|
||||
&pattern->u.radial.center1.x,
|
||||
&pattern->u.radial.center1.y);
|
||||
cairo_matrix_transform_distance (&matrix,
|
||||
&pattern->u.radial.radius1.dx,
|
||||
&pattern->u.radial.radius1.dy);
|
||||
break;
|
||||
case CAIRO_PATTERN_SOLID:
|
||||
break;
|
||||
}
|
||||
cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -518,12 +480,7 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
|
|||
factor -= factor & 0xffff0000;
|
||||
break;
|
||||
case CAIRO_EXTEND_REFLECT:
|
||||
if (factor < 0) {
|
||||
if ((factor >> 16) % 2)
|
||||
factor -= factor & 0xffff0000;
|
||||
else
|
||||
factor = 65536 - (factor - (factor & 0xffff0000));
|
||||
} else if (factor > 65536) {
|
||||
if (factor < 0 || factor > 65536) {
|
||||
if ((factor >> 16) % 2)
|
||||
factor = 65536 - (factor - (factor & 0xffff0000));
|
||||
else
|
||||
|
|
@ -562,90 +519,156 @@ static void
|
|||
_cairo_image_data_set_linear (cairo_pattern_t *pattern,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
char *data,
|
||||
int *pixels,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int x, y;
|
||||
cairo_point_double_t point0, point1, angle;
|
||||
double a, length, start;
|
||||
cairo_point_double_t point0, point1;
|
||||
double px, py, ex, ey;
|
||||
double a, b, c, d, tx, ty;
|
||||
double length, start, angle, fx, fy, factor;
|
||||
cairo_shader_op_t op;
|
||||
double factor;
|
||||
|
||||
_cairo_pattern_shader_init (pattern, &op);
|
||||
|
||||
point0.x = pattern->u.linear.point0.x - offset_x;
|
||||
point0.y = pattern->u.linear.point0.y - offset_y;
|
||||
point1.x = pattern->u.linear.point1.x - offset_x;
|
||||
point1.y = pattern->u.linear.point1.y - offset_y;
|
||||
point0.x = pattern->u.linear.point0.x;
|
||||
point0.y = pattern->u.linear.point0.y;
|
||||
point1.x = pattern->u.linear.point1.x;
|
||||
point1.y = pattern->u.linear.point1.y;
|
||||
|
||||
cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
|
||||
|
||||
length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) +
|
||||
(point1.y - point0.y) * (point1.y - point0.y));
|
||||
length = (length) ? 1.0 / length : CAIRO_MAXSHORT;
|
||||
|
||||
a = -atan2 (point1.y - point0.y, point1.x - point0.x);
|
||||
angle.x = cos (a);
|
||||
angle.y = -sin (a);
|
||||
|
||||
start = angle.x * point0.x;
|
||||
start += angle.y * point0.y;
|
||||
angle = -atan2 (point1.y - point0.y, point1.x - point0.x);
|
||||
fx = cos (angle);
|
||||
fy = -sin (angle);
|
||||
|
||||
start = fx * point0.x;
|
||||
start += fy * point0.y;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
px = x + offset_x;
|
||||
py = y + offset_y;
|
||||
|
||||
/* transform fragment */
|
||||
ex = a * px + c * py + tx;
|
||||
ey = b * px + d * py + ty;
|
||||
|
||||
factor = ((angle.x * (double) x) +
|
||||
(angle.y * (double) y) - start) * length;
|
||||
factor = ((fx * ex + fy * ey) - start) * length;
|
||||
|
||||
_cairo_pattern_calc_color_at_pixel (&op,
|
||||
factor * 65536,
|
||||
(int *)
|
||||
&data[y * width * 4 + x * 4]);
|
||||
_cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Inner circle is currently ignored. */
|
||||
static void
|
||||
_cairo_image_data_set_radial (cairo_pattern_t *pattern,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
char *data,
|
||||
int *pixels,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int x, y;
|
||||
cairo_point_double_t center1, pos;
|
||||
cairo_distance_double_t length;
|
||||
double factor, min_length;
|
||||
int x, y, aligned_circles;
|
||||
cairo_point_double_t c0, c1;
|
||||
double px, py, ex, ey;
|
||||
double a, b, c, d, tx, ty;
|
||||
double r0, r1, c0_e_x, c0_e_y, c0_e, c1_e_x, c1_e_y, c1_e,
|
||||
c0_c1_x, c0_c1_y, c0_c1, angle_c0, c1_y, y_x, c0_y, c0_x, r1_2,
|
||||
denumerator, fraction, factor;
|
||||
cairo_shader_op_t op;
|
||||
|
||||
_cairo_pattern_shader_init (pattern, &op);
|
||||
|
||||
center1.x = pattern->u.radial.center1.x - offset_x;
|
||||
center1.y = pattern->u.radial.center1.y - offset_y;
|
||||
c0.x = pattern->u.radial.center0.x;
|
||||
c0.y = pattern->u.radial.center0.y;
|
||||
r0 = pattern->u.radial.radius0;
|
||||
c1.x = pattern->u.radial.center1.x;
|
||||
c1.y = pattern->u.radial.center1.y;
|
||||
r1 = pattern->u.radial.radius1;
|
||||
|
||||
min_length = (pattern->u.radial.radius1.dx < pattern->u.radial.radius1.dy)?
|
||||
pattern->u.radial.radius1.dx : pattern->u.radial.radius1.dy;
|
||||
|
||||
length.dx = min_length / pattern->u.radial.radius1.dx;
|
||||
length.dy = min_length / pattern->u.radial.radius1.dy;
|
||||
|
||||
min_length = (min_length)? 1.0 / min_length: CAIRO_MAXSHORT;
|
||||
if (c0.x != c1.x || c0.y != c1.y) {
|
||||
aligned_circles = 0;
|
||||
c0_c1_x = c1.x - c0.x;
|
||||
c0_c1_y = c1.y - c0.y;
|
||||
c0_c1 = sqrt (c0_c1_x * c0_c1_x + c0_c1_y * c0_c1_y);
|
||||
r1_2 = r1 * r1;
|
||||
} else {
|
||||
aligned_circles = 1;
|
||||
r1 = 1.0 / (r1 - r0);
|
||||
}
|
||||
|
||||
cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
pos.x = x - center1.x;
|
||||
pos.y = y - center1.y;
|
||||
px = x + offset_x;
|
||||
py = y + offset_y;
|
||||
|
||||
/* transform fragment */
|
||||
ex = a * px + c * py + tx;
|
||||
ey = b * px + d * py + ty;
|
||||
|
||||
pos.x *= length.dx;
|
||||
pos.y *= length.dy;
|
||||
if (aligned_circles) {
|
||||
ex = ex - c1.x;
|
||||
ey = ey - c1.y;
|
||||
|
||||
factor = sqrt (pos.x * pos.x + pos.y * pos.y) * min_length;
|
||||
factor = (sqrt (ex * ex + ey * ey) - r0) * r1;
|
||||
} else {
|
||||
/* Here we need to calulate distance c0 -> x; the distance from
|
||||
the inner circle center c0, through point (ex, ey) to
|
||||
point x where it crosses the outer circle. The gradient offset
|
||||
can then be calculated within the distance of the inner and
|
||||
outer circles.
|
||||
|
||||
y y_x (ex, ey)
|
||||
c0 -------------------+---------- x
|
||||
\ | __--
|
||||
\ | __--
|
||||
r0 \ | c1_y __--
|
||||
\ | __-- r1
|
||||
\ | __--
|
||||
c1 --
|
||||
*/
|
||||
|
||||
_cairo_pattern_calc_color_at_pixel (&op,
|
||||
factor * 65536,
|
||||
(int *)
|
||||
&data[y * width * 4 + x * 4]);
|
||||
c0_e_x = ex - c0.x;
|
||||
c0_e_y = ey - c0.y;
|
||||
c0_e = sqrt (c0_e_x * c0_e_x + c0_e_y * c0_e_y);
|
||||
|
||||
c1_e_x = ex - c1.x;
|
||||
c1_e_y = ey - c1.y;
|
||||
c1_e = sqrt (c1_e_x * c1_e_x + c1_e_y * c1_e_y);
|
||||
|
||||
denumerator = -2.0 * c0_e * c0_c1;
|
||||
|
||||
if (denumerator != 0.0) {
|
||||
fraction = (c1_e * c1_e - c0_e * c0_e - c0_c1 * c0_c1) /
|
||||
denumerator;
|
||||
|
||||
if (fraction > 1.0)
|
||||
fraction = 1.0;
|
||||
else if (fraction < -1.0)
|
||||
fraction = -1.0;
|
||||
|
||||
angle_c0 = acos (fraction);
|
||||
|
||||
c0_y = cos (angle_c0) * c0_c1;
|
||||
c1_y = sin (angle_c0) * c0_c1;
|
||||
|
||||
y_x = sqrt (r1_2 - c1_y * c1_y);
|
||||
c0_x = y_x + c0_y;
|
||||
|
||||
factor = (c0_e - r0) / (c0_x - r0);
|
||||
} else
|
||||
factor = -r0;
|
||||
}
|
||||
|
||||
_cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -670,14 +693,16 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
|
|||
|
||||
if (pattern->type == CAIRO_PATTERN_RADIAL)
|
||||
_cairo_image_data_set_radial (pattern,
|
||||
pattern->source_offset.x + x,
|
||||
pattern->source_offset.y + y,
|
||||
data, width, height);
|
||||
x - pattern->source_offset.x,
|
||||
y - pattern->source_offset.y,
|
||||
(int *) data,
|
||||
width, height);
|
||||
else
|
||||
_cairo_image_data_set_linear (pattern,
|
||||
pattern->source_offset.x + x,
|
||||
pattern->source_offset.y + y,
|
||||
data, width, height);
|
||||
x - pattern->source_offset.x,
|
||||
y - pattern->source_offset.y,
|
||||
(int *) data,
|
||||
width, height);
|
||||
|
||||
_cairo_pattern_set_source_offset (pattern, x, y);
|
||||
|
||||
|
|
@ -715,3 +740,4 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
|
|||
|
||||
return (cairo_image_surface_t *) surface;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ _cairo_gl_create_color_range (cairo_pattern_t *pattern,
|
|||
{
|
||||
unsigned int i, bytes = size * 4;
|
||||
cairo_shader_op_t op;
|
||||
|
||||
|
||||
_cairo_pattern_shader_init (pattern, &op);
|
||||
|
||||
for (i = 0; i < bytes; i += 4)
|
||||
|
|
@ -607,10 +607,6 @@ _cairo_gl_surface_create_pattern (void *abstract_surface,
|
|||
cairo_gl_surface_t *surface = abstract_surface;
|
||||
glitz_surface_t *programmatic = NULL;
|
||||
cairo_gl_surface_t *gl_surface;
|
||||
double bbox_x = box->p1.x >> 16;
|
||||
double bbox_y = box->p1.y >> 16;
|
||||
double x = bbox_x + pattern->source_offset.x;
|
||||
double y = bbox_y + pattern->source_offset.y;
|
||||
|
||||
switch (pattern->type) {
|
||||
case CAIRO_PATTERN_SOLID: {
|
||||
|
|
@ -622,8 +618,7 @@ _cairo_gl_surface_create_pattern (void *abstract_surface,
|
|||
color.alpha = pattern->color.alpha_short;
|
||||
|
||||
programmatic = glitz_surface_create_solid (&color);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case CAIRO_PATTERN_LINEAR:
|
||||
case CAIRO_PATTERN_RADIAL: {
|
||||
unsigned int color_range_size;
|
||||
|
|
@ -642,26 +637,17 @@ _cairo_gl_surface_create_pattern (void *abstract_surface,
|
|||
if (pattern->type == CAIRO_PATTERN_LINEAR) {
|
||||
double dx, dy;
|
||||
|
||||
dx = (pattern->u.linear.point1.x - x) -
|
||||
(pattern->u.linear.point0.x - x);
|
||||
dy = (pattern->u.linear.point1.y - y) -
|
||||
(pattern->u.linear.point0.y - y);
|
||||
|
||||
dx = pattern->u.linear.point1.x - pattern->u.linear.point0.x;
|
||||
dy = pattern->u.linear.point1.y - pattern->u.linear.point0.y;
|
||||
|
||||
color_range_size = sqrt (dx * dx + dy * dy);
|
||||
} else {
|
||||
/* glitz doesn't support inner circle yet. */
|
||||
if (pattern->u.radial.center0.x !=
|
||||
pattern->u.radial.center1.x
|
||||
|| pattern->u.radial.center0.y !=
|
||||
pattern->u.radial.center1.y
|
||||
|| pattern->u.radial.radius0.dx
|
||||
|| pattern->u.radial.radius0.dy)
|
||||
if (pattern->u.radial.center0.x != pattern->u.radial.center1.x ||
|
||||
pattern->u.radial.center0.y != pattern->u.radial.center1.y)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
color_range_size = sqrt (pattern->u.radial.radius1.dx *
|
||||
pattern->u.radial.radius1.dx +
|
||||
pattern->u.radial.radius1.dy *
|
||||
pattern->u.radial.radius1.dy);
|
||||
color_range_size = pattern->u.radial.radius1;
|
||||
}
|
||||
|
||||
if ((!CAIRO_GL_TEXTURE_NPOT_SUPPORT (surface)))
|
||||
|
|
@ -672,8 +658,8 @@ _cairo_gl_surface_create_pattern (void *abstract_surface,
|
|||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
_cairo_gl_create_color_range (pattern,
|
||||
glitz_color_range_get_data
|
||||
(color_range), color_range_size);
|
||||
glitz_color_range_get_data (color_range),
|
||||
color_range_size);
|
||||
|
||||
switch (pattern->extend) {
|
||||
case CAIRO_EXTEND_REPEAT:
|
||||
|
|
@ -687,60 +673,58 @@ _cairo_gl_surface_create_pattern (void *abstract_surface,
|
|||
break;
|
||||
}
|
||||
|
||||
glitz_color_range_set_filter (color_range, GLITZ_FILTER_BILINEAR);
|
||||
|
||||
if (pattern->type == CAIRO_PATTERN_LINEAR) {
|
||||
glitz_point_fixed_t start;
|
||||
glitz_point_fixed_t stop;
|
||||
|
||||
start.x =
|
||||
_cairo_fixed_from_double (pattern->u.linear.point0.x - x);
|
||||
start.y =
|
||||
_cairo_fixed_from_double (pattern->u.linear.point0.y - y);
|
||||
stop.x = _cairo_fixed_from_double (pattern->u.linear.point1.x - x);
|
||||
stop.y = _cairo_fixed_from_double (pattern->u.linear.point1.y - y);
|
||||
start.x = _cairo_fixed_from_double (pattern->u.linear.point0.x);
|
||||
start.y = _cairo_fixed_from_double (pattern->u.linear.point0.y);
|
||||
stop.x = _cairo_fixed_from_double (pattern->u.linear.point1.x);
|
||||
stop.y = _cairo_fixed_from_double (pattern->u.linear.point1.y);
|
||||
|
||||
programmatic =
|
||||
glitz_surface_create_linear (&start, &stop, color_range);
|
||||
} else {
|
||||
glitz_point_fixed_t center;
|
||||
glitz_distance_fixed_t radius;
|
||||
|
||||
center.x =
|
||||
_cairo_fixed_from_double (pattern->u.radial.center1.x - x);
|
||||
center.y =
|
||||
_cairo_fixed_from_double (pattern->u.radial.center1.y - y);
|
||||
radius.dx =
|
||||
_cairo_fixed_from_double (pattern->u.radial.radius1.dx);
|
||||
radius.dy =
|
||||
_cairo_fixed_from_double (pattern->u.radial.radius1.dy);
|
||||
|
||||
programmatic =
|
||||
glitz_surface_create_radial (¢er, &radius, color_range);
|
||||
center.x = _cairo_fixed_from_double (pattern->u.radial.center1.x);
|
||||
center.y = _cairo_fixed_from_double (pattern->u.radial.center1.y);
|
||||
|
||||
programmatic = glitz_surface_create_radial
|
||||
(¢er,
|
||||
_cairo_fixed_from_double (pattern->u.radial.radius0),
|
||||
_cairo_fixed_from_double (pattern->u.radial.radius1),
|
||||
color_range);
|
||||
}
|
||||
|
||||
glitz_color_range_destroy (color_range);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
} break;
|
||||
case CAIRO_PATTERN_SURFACE:
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (!programmatic)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
gl_surface = (cairo_gl_surface_t *)
|
||||
_cairo_gl_surface_create (programmatic, 1);
|
||||
_cairo_gl_surface_create (programmatic, 1);
|
||||
if (!gl_surface) {
|
||||
glitz_surface_destroy (programmatic);
|
||||
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (pattern->type == CAIRO_PATTERN_LINEAR ||
|
||||
pattern->type == CAIRO_PATTERN_RADIAL)
|
||||
cairo_surface_set_matrix (gl_surface, &pattern->matrix);
|
||||
|
||||
_cairo_pattern_init_copy (&gl_surface->pattern, pattern);
|
||||
gl_surface->pattern_box = *box;
|
||||
|
||||
pattern->source = &gl_surface->base;
|
||||
_cairo_pattern_set_source_offset (pattern, bbox_x, bbox_y);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1278,7 +1278,7 @@ _cairo_gstate_create_pattern (cairo_gstate_t *gstate,
|
|||
}
|
||||
|
||||
_cairo_pattern_set_alpha (pattern, gstate->alpha);
|
||||
_cairo_pattern_transform (pattern, &gstate->ctm, &gstate->ctm_inverse);
|
||||
_cairo_pattern_transform (pattern, &gstate->ctm_inverse);
|
||||
|
||||
_cairo_pattern_set_source_offset (pattern,
|
||||
gstate->pattern_offset.x,
|
||||
|
|
|
|||
|
|
@ -175,12 +175,10 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
|
|||
pattern->type = CAIRO_PATTERN_RADIAL;
|
||||
pattern->u.radial.center0.x = cx0;
|
||||
pattern->u.radial.center0.y = cy0;
|
||||
pattern->u.radial.radius0.dx = fabs (radius0);
|
||||
pattern->u.radial.radius0.dy = fabs (radius0);
|
||||
pattern->u.radial.radius0 = fabs (radius0);
|
||||
pattern->u.radial.center1.x = cx1;
|
||||
pattern->u.radial.center1.y = cy1;
|
||||
pattern->u.radial.radius1.dx = fabs (radius1);
|
||||
pattern->u.radial.radius1.dy = fabs (radius1);
|
||||
pattern->u.radial.radius1 = fabs (radius1);
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
|
@ -353,45 +351,9 @@ _cairo_pattern_set_source_offset (cairo_pattern_t *pattern,
|
|||
|
||||
void
|
||||
_cairo_pattern_transform (cairo_pattern_t *pattern,
|
||||
cairo_matrix_t *ctm,
|
||||
cairo_matrix_t *ctm_inverse)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
switch (pattern->type) {
|
||||
case CAIRO_PATTERN_SURFACE:
|
||||
/* hmm, maybe we should instead multiply with the inverse of the
|
||||
pattern matrix here? */
|
||||
cairo_matrix_multiply (&pattern->matrix, ctm_inverse,
|
||||
&pattern->matrix);
|
||||
break;
|
||||
case CAIRO_PATTERN_LINEAR:
|
||||
cairo_matrix_multiply (&matrix, &pattern->matrix, ctm);
|
||||
cairo_matrix_transform_point (&matrix,
|
||||
&pattern->u.linear.point0.x,
|
||||
&pattern->u.linear.point0.y);
|
||||
cairo_matrix_transform_point (&matrix,
|
||||
&pattern->u.linear.point1.x,
|
||||
&pattern->u.linear.point1.y);
|
||||
break;
|
||||
case CAIRO_PATTERN_RADIAL:
|
||||
cairo_matrix_multiply (&matrix, &pattern->matrix, ctm);
|
||||
cairo_matrix_transform_point (&matrix,
|
||||
&pattern->u.radial.center0.x,
|
||||
&pattern->u.radial.center0.y);
|
||||
cairo_matrix_transform_distance (&matrix,
|
||||
&pattern->u.radial.radius0.dx,
|
||||
&pattern->u.radial.radius0.dy);
|
||||
cairo_matrix_transform_point (&matrix,
|
||||
&pattern->u.radial.center1.x,
|
||||
&pattern->u.radial.center1.y);
|
||||
cairo_matrix_transform_distance (&matrix,
|
||||
&pattern->u.radial.radius1.dx,
|
||||
&pattern->u.radial.radius1.dy);
|
||||
break;
|
||||
case CAIRO_PATTERN_SOLID:
|
||||
break;
|
||||
}
|
||||
cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -518,12 +480,7 @@ _cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op,
|
|||
factor -= factor & 0xffff0000;
|
||||
break;
|
||||
case CAIRO_EXTEND_REFLECT:
|
||||
if (factor < 0) {
|
||||
if ((factor >> 16) % 2)
|
||||
factor -= factor & 0xffff0000;
|
||||
else
|
||||
factor = 65536 - (factor - (factor & 0xffff0000));
|
||||
} else if (factor > 65536) {
|
||||
if (factor < 0 || factor > 65536) {
|
||||
if ((factor >> 16) % 2)
|
||||
factor = 65536 - (factor - (factor & 0xffff0000));
|
||||
else
|
||||
|
|
@ -562,90 +519,156 @@ static void
|
|||
_cairo_image_data_set_linear (cairo_pattern_t *pattern,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
char *data,
|
||||
int *pixels,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int x, y;
|
||||
cairo_point_double_t point0, point1, angle;
|
||||
double a, length, start;
|
||||
cairo_point_double_t point0, point1;
|
||||
double px, py, ex, ey;
|
||||
double a, b, c, d, tx, ty;
|
||||
double length, start, angle, fx, fy, factor;
|
||||
cairo_shader_op_t op;
|
||||
double factor;
|
||||
|
||||
_cairo_pattern_shader_init (pattern, &op);
|
||||
|
||||
point0.x = pattern->u.linear.point0.x - offset_x;
|
||||
point0.y = pattern->u.linear.point0.y - offset_y;
|
||||
point1.x = pattern->u.linear.point1.x - offset_x;
|
||||
point1.y = pattern->u.linear.point1.y - offset_y;
|
||||
point0.x = pattern->u.linear.point0.x;
|
||||
point0.y = pattern->u.linear.point0.y;
|
||||
point1.x = pattern->u.linear.point1.x;
|
||||
point1.y = pattern->u.linear.point1.y;
|
||||
|
||||
cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
|
||||
|
||||
length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) +
|
||||
(point1.y - point0.y) * (point1.y - point0.y));
|
||||
length = (length) ? 1.0 / length : CAIRO_MAXSHORT;
|
||||
|
||||
a = -atan2 (point1.y - point0.y, point1.x - point0.x);
|
||||
angle.x = cos (a);
|
||||
angle.y = -sin (a);
|
||||
|
||||
start = angle.x * point0.x;
|
||||
start += angle.y * point0.y;
|
||||
angle = -atan2 (point1.y - point0.y, point1.x - point0.x);
|
||||
fx = cos (angle);
|
||||
fy = -sin (angle);
|
||||
|
||||
start = fx * point0.x;
|
||||
start += fy * point0.y;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
px = x + offset_x;
|
||||
py = y + offset_y;
|
||||
|
||||
/* transform fragment */
|
||||
ex = a * px + c * py + tx;
|
||||
ey = b * px + d * py + ty;
|
||||
|
||||
factor = ((angle.x * (double) x) +
|
||||
(angle.y * (double) y) - start) * length;
|
||||
factor = ((fx * ex + fy * ey) - start) * length;
|
||||
|
||||
_cairo_pattern_calc_color_at_pixel (&op,
|
||||
factor * 65536,
|
||||
(int *)
|
||||
&data[y * width * 4 + x * 4]);
|
||||
_cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Inner circle is currently ignored. */
|
||||
static void
|
||||
_cairo_image_data_set_radial (cairo_pattern_t *pattern,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
char *data,
|
||||
int *pixels,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
int x, y;
|
||||
cairo_point_double_t center1, pos;
|
||||
cairo_distance_double_t length;
|
||||
double factor, min_length;
|
||||
int x, y, aligned_circles;
|
||||
cairo_point_double_t c0, c1;
|
||||
double px, py, ex, ey;
|
||||
double a, b, c, d, tx, ty;
|
||||
double r0, r1, c0_e_x, c0_e_y, c0_e, c1_e_x, c1_e_y, c1_e,
|
||||
c0_c1_x, c0_c1_y, c0_c1, angle_c0, c1_y, y_x, c0_y, c0_x, r1_2,
|
||||
denumerator, fraction, factor;
|
||||
cairo_shader_op_t op;
|
||||
|
||||
_cairo_pattern_shader_init (pattern, &op);
|
||||
|
||||
center1.x = pattern->u.radial.center1.x - offset_x;
|
||||
center1.y = pattern->u.radial.center1.y - offset_y;
|
||||
c0.x = pattern->u.radial.center0.x;
|
||||
c0.y = pattern->u.radial.center0.y;
|
||||
r0 = pattern->u.radial.radius0;
|
||||
c1.x = pattern->u.radial.center1.x;
|
||||
c1.y = pattern->u.radial.center1.y;
|
||||
r1 = pattern->u.radial.radius1;
|
||||
|
||||
min_length = (pattern->u.radial.radius1.dx < pattern->u.radial.radius1.dy)?
|
||||
pattern->u.radial.radius1.dx : pattern->u.radial.radius1.dy;
|
||||
|
||||
length.dx = min_length / pattern->u.radial.radius1.dx;
|
||||
length.dy = min_length / pattern->u.radial.radius1.dy;
|
||||
|
||||
min_length = (min_length)? 1.0 / min_length: CAIRO_MAXSHORT;
|
||||
if (c0.x != c1.x || c0.y != c1.y) {
|
||||
aligned_circles = 0;
|
||||
c0_c1_x = c1.x - c0.x;
|
||||
c0_c1_y = c1.y - c0.y;
|
||||
c0_c1 = sqrt (c0_c1_x * c0_c1_x + c0_c1_y * c0_c1_y);
|
||||
r1_2 = r1 * r1;
|
||||
} else {
|
||||
aligned_circles = 1;
|
||||
r1 = 1.0 / (r1 - r0);
|
||||
}
|
||||
|
||||
cairo_matrix_get_affine (&pattern->matrix, &a, &b, &c, &d, &tx, &ty);
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
pos.x = x - center1.x;
|
||||
pos.y = y - center1.y;
|
||||
px = x + offset_x;
|
||||
py = y + offset_y;
|
||||
|
||||
/* transform fragment */
|
||||
ex = a * px + c * py + tx;
|
||||
ey = b * px + d * py + ty;
|
||||
|
||||
pos.x *= length.dx;
|
||||
pos.y *= length.dy;
|
||||
if (aligned_circles) {
|
||||
ex = ex - c1.x;
|
||||
ey = ey - c1.y;
|
||||
|
||||
factor = sqrt (pos.x * pos.x + pos.y * pos.y) * min_length;
|
||||
factor = (sqrt (ex * ex + ey * ey) - r0) * r1;
|
||||
} else {
|
||||
/* Here we need to calulate distance c0 -> x; the distance from
|
||||
the inner circle center c0, through point (ex, ey) to
|
||||
point x where it crosses the outer circle. The gradient offset
|
||||
can then be calculated within the distance of the inner and
|
||||
outer circles.
|
||||
|
||||
y y_x (ex, ey)
|
||||
c0 -------------------+---------- x
|
||||
\ | __--
|
||||
\ | __--
|
||||
r0 \ | c1_y __--
|
||||
\ | __-- r1
|
||||
\ | __--
|
||||
c1 --
|
||||
*/
|
||||
|
||||
_cairo_pattern_calc_color_at_pixel (&op,
|
||||
factor * 65536,
|
||||
(int *)
|
||||
&data[y * width * 4 + x * 4]);
|
||||
c0_e_x = ex - c0.x;
|
||||
c0_e_y = ey - c0.y;
|
||||
c0_e = sqrt (c0_e_x * c0_e_x + c0_e_y * c0_e_y);
|
||||
|
||||
c1_e_x = ex - c1.x;
|
||||
c1_e_y = ey - c1.y;
|
||||
c1_e = sqrt (c1_e_x * c1_e_x + c1_e_y * c1_e_y);
|
||||
|
||||
denumerator = -2.0 * c0_e * c0_c1;
|
||||
|
||||
if (denumerator != 0.0) {
|
||||
fraction = (c1_e * c1_e - c0_e * c0_e - c0_c1 * c0_c1) /
|
||||
denumerator;
|
||||
|
||||
if (fraction > 1.0)
|
||||
fraction = 1.0;
|
||||
else if (fraction < -1.0)
|
||||
fraction = -1.0;
|
||||
|
||||
angle_c0 = acos (fraction);
|
||||
|
||||
c0_y = cos (angle_c0) * c0_c1;
|
||||
c1_y = sin (angle_c0) * c0_c1;
|
||||
|
||||
y_x = sqrt (r1_2 - c1_y * c1_y);
|
||||
c0_x = y_x + c0_y;
|
||||
|
||||
factor = (c0_e - r0) / (c0_x - r0);
|
||||
} else
|
||||
factor = -r0;
|
||||
}
|
||||
|
||||
_cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -670,14 +693,16 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
|
|||
|
||||
if (pattern->type == CAIRO_PATTERN_RADIAL)
|
||||
_cairo_image_data_set_radial (pattern,
|
||||
pattern->source_offset.x + x,
|
||||
pattern->source_offset.y + y,
|
||||
data, width, height);
|
||||
x - pattern->source_offset.x,
|
||||
y - pattern->source_offset.y,
|
||||
(int *) data,
|
||||
width, height);
|
||||
else
|
||||
_cairo_image_data_set_linear (pattern,
|
||||
pattern->source_offset.x + x,
|
||||
pattern->source_offset.y + y,
|
||||
data, width, height);
|
||||
x - pattern->source_offset.x,
|
||||
y - pattern->source_offset.y,
|
||||
(int *) data,
|
||||
width, height);
|
||||
|
||||
_cairo_pattern_set_source_offset (pattern, x, y);
|
||||
|
||||
|
|
@ -715,3 +740,4 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
|
|||
|
||||
return (cairo_image_surface_t *) surface;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -508,8 +508,8 @@ struct cairo_pattern {
|
|||
struct {
|
||||
cairo_point_double_t center0;
|
||||
cairo_point_double_t center1;
|
||||
cairo_distance_double_t radius0;
|
||||
cairo_distance_double_t radius1;
|
||||
double radius0;
|
||||
double radius1;
|
||||
} radial;
|
||||
} u;
|
||||
};
|
||||
|
|
@ -1355,8 +1355,7 @@ _cairo_pattern_set_source_offset (cairo_pattern_t *pattern,
|
|||
|
||||
extern void __internal_linkage
|
||||
_cairo_pattern_transform (cairo_pattern_t *pattern,
|
||||
cairo_matrix_t *matrix,
|
||||
cairo_matrix_t *matrix_inverse);
|
||||
cairo_matrix_t *ctm_inverse);
|
||||
|
||||
extern void __internal_linkage
|
||||
_cairo_pattern_prepare_surface (cairo_pattern_t *pattern);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue