diff options
author | Carl Worth <cworth@cworth.org> | 2006-02-13 16:46:06 -0800 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2006-02-13 16:46:06 -0800 |
commit | 1d28eecd8b8dd5b3082bcdbb0455df1ad825bba7 (patch) | |
tree | 8be9d3a1dfe0a25ba6eb98a45e719229e51b4f2f | |
parent | 7146e2fc48df28d462ddeab81dc3c55bee4a7527 (diff) | |
parent | 2f7b4a3ad7a0760af023d350685d1acfdc528d2c (diff) |
Remove pixman from SNAPSHOT_0_1_23SNAPSHOT_0_1_23
-rw-r--r-- | BUGS | 19 | ||||
-rw-r--r-- | ChangeLog | 159 | ||||
-rw-r--r-- | NEWS | 41 | ||||
-rw-r--r-- | RELEASING | 28 | ||||
-rw-r--r-- | TODO | 7 | ||||
-rw-r--r-- | configure.in | 4 | ||||
-rw-r--r-- | src/cairo-ft-font.c | 2 | ||||
-rw-r--r-- | src/cairo-gstate.c | 16 | ||||
-rw-r--r-- | src/cairo-pattern.c | 439 | ||||
-rw-r--r-- | src/cairo-spline.c | 7 | ||||
-rw-r--r-- | src/cairo-surface.c | 16 | ||||
-rw-r--r-- | src/cairo-traps.c | 4 | ||||
-rw-r--r-- | src/cairo.h | 1 | ||||
-rw-r--r-- | src/cairo_ft_font.c | 2 | ||||
-rw-r--r-- | src/cairo_gl_surface.c | 194 | ||||
-rw-r--r-- | src/cairo_gstate.c | 16 | ||||
-rw-r--r-- | src/cairo_pattern.c | 439 | ||||
-rw-r--r-- | src/cairo_png_surface.c | 231 | ||||
-rw-r--r-- | src/cairo_spline.c | 7 | ||||
-rw-r--r-- | src/cairo_surface.c | 16 | ||||
-rw-r--r-- | src/cairo_traps.c | 4 | ||||
-rw-r--r-- | src/cairoint.h | 54 |
22 files changed, 1056 insertions, 650 deletions
@@ -1,3 +1,9 @@ +cairo_clip is returning the wrong result in several cases. And when it +doesn't get the wrong result, it is horribly slow. This really needs +to be fixed. + +-- + Splines are not dashed. -- @@ -57,5 +63,16 @@ Caps are added only to the last subpath in a complex path. -- ref_counts will go negative if destroy is called with ref_count == -0. We noticed this is cairo_surface.c but it likely happens in several +0. We noticed this in cairo_surface.c but it likely happens in several places. + +-- + +Patterns are broken in various ways. The SVG test case demonstrates +some regressions, so something has changed in cairo. Also, +transformation plus repeat doesn't work in either Xrender or +libpixman, (nor in glitz?). + +-- + +font-size="0" in an SVG file does very bad things. @@ -1,3 +1,162 @@ +2004-05-11 Carl Worth <cworth@isi.edu> + + * configure.in: Increment CAIRO_VERSION to 0.1.23. + + * NEWS: Added notes for snapshot 0.1.23. + + * RELEASING: Add reminder to mention incompatible API changes in + NEWS. Re-order steps to avoid clobbering pre-existing tar + files. + +2004-05-11 Carl Worth <cworth@isi.edu> + + * BUGS: Several people have reported that cairo_clip is not + working right now. And it's always been slow. + +2004-05-11 David Reveman <c99drn@cs.umu.se> + + * configure.in: Require glitz 0.1.2. + + * src/cairo_gl_surface.c: Added opacity attribute. Fixed broken + CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT macro. + (_cairo_gl_surface_composite_trapezoids): Use polygon opacity. + (_cairo_gl_surface_create_pattern): Added surface pattern support. + (_cairo_gl_surface_create): Initialize opacity to 0xffff. + +2004-05-07 Carl Worth <cworth@isi.edu> + + * src/cairo_ft_font.c (_utf8_to_ucs4): Bail on NULL utf8 string. + + * src/cairo_spline.c (_cairo_spline_add_point): Don't add two + consecutive, identical points when decomposing the spline, (which + was leading to an infinte loop in the stroke algorithm when it + found a slope of (0,0)). + +2004-05-04 Carl Worth <cworth@isi.edu> + + * src/cairo_png_surface.c (cairo_png_surface_create): Move all + libpng-related code into copy_page. + (unpremultiply_data): Add missing unpremultiply step. + (_cairo_png_surface_copy_page): Move PNG output to copy_page. Add + support for A8 and A1 images. Remove time from header (we may want + to add it again later, but for now it messes up my test suite). + (_cairo_png_surface_destroy): Call copy_page if it hasn't been + called already. + (_cairo_png_surface_show_page): Add implementation. + (_cairo_png_surface_copy_page): Don't close a file we didn't open. + +2004-05-04 David Reveman <c99drn@cs.umu.se> + + * src/cairo_pattern.c (_cairo_image_data_set_radial): Corrected some + confusing comments about the math used for radial gradients. + +2004-05-01 David Reveman <c99drn@cs.umu.se> + + * src/cairo_gl_surface.c (_cairo_gl_surface_create_pattern): + cairo_surface_t pointer to cairo_surface_set_matrix. + +2004-04-29 Carl Worth <cworth@isi.edu> + + * src/cairo_gstate.c (_cairo_gstate_set_pattern): Don't set + pattern_offset by the current point. Perhaps we can eliminate + pattern_offset altogether now? + +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 + CAIRO_GL_SURFACE_IS_SOLID macros. + (_cairo_gl_surface_get_image): Simpler way for calculating rowstride. + (_cairo_gl_surface_composite): Support compositing with mask surface + when mask is solid or multi-texturing is available. + +2004-04-25 David Reveman <c99drn@cs.umu.se> + + * src/cairo_gl_surface.c (_cairo_gl_surface_set_clip_region): + Fixed conversion of pixman_box16_t to glitz_rectangle_t. + + * src/cairoint.h: Added scale factor value to cairo_color_stop_t. + Added cairo_shader_function_t and cairo_shader_op_t. + + * src/cairo_surface.c (_cairo_surface_create_pattern): + Fixed point updates. + + * src/cairo_pattern.c (cairo_pattern_create_radial): Use absolute value + of radius parameters. + (cairo_pattern_add_color_stop): Precalculate scale factors and convert + offset to fixed point value. + (_cairo_image_data_set_radial): + (_cairo_image_data_set_linear): Initialize and use shading operator. + (_cairo_pattern_get_image): Fixed point updates. + (_cairo_pattern_shader_nearest): + (_cairo_pattern_shader_linear): + (_cairo_pattern_shader_gaussian): + (_cairo_pattern_calc_color_at_pixel): + Converted shading routines to use fixed point values and introduced + a shading operator structure for more efficient shading calculations. + Added _cairo_pattern_shader_init function. + + * src/cairo_gl_surface.c (_cairo_gl_surface_composite): + (_cairo_gl_surface_fill_rectangles): + (_cairo_gl_surface_composite_trapezoids): + Make sure that target surface is OK. + (_cairo_gl_create_color_range): Initialize and use shading operator. + (_cairo_gl_surface_create_pattern): + (_cairo_gl_surface_set_clip_region): Fixed point updates. + +2004-04-23 Carl Worth <cworth@isi.edu> + + * src/cairoint.h: + * src/cairo_surface.c (_cairo_surface_composite): + * src/cairo_gstate.c (_cairo_gstate_current_fill_rule): Fixed + several function prototype mismatches between internal header file + and implementation (thanks to Carlos Romero and gcc-3.4). + +2004-04-22 David Reveman <c99drn@cs.umu.se> + + * src/cairoint.h: + * src/cairo_surface.c (_cairo_surface_create_pattern): + * src/cairo_pattern.c (_cairo_pattern_set_source_offset) + (_cairo_pattern_get_image): + * src/cairo_gstate.c (_cairo_gstate_create_pattern): + * src/cairo_gl_surface.c (_cairo_gl_surface_create_pattern): Fixed + pattern source offset. + +2004-04-20 David Reveman <c99drn@cs.umu.se> + + * src/cairo_pattern.c (_cairo_image_data_set_linear): Use + CAIRO_MAXSHORT instead of INT_MAX. + + * src/cairo_traps.c (_cairo_traps_extents): Use CAIRO_MAXSHORT and + CAIRO_MINSHORT instead of SHRT_MAX and SHRT_MIN. + + * src/cairoint.h: including limits.h and defining CAIRO_MAXSHORT and + CAIRO_MINSHORT. + 2004-04-16 Carl Worth <cworth@isi.edu> * NEWS: Added notes for snapshot 0.1.22. @@ -1,3 +1,44 @@ +Snapshot 0.1.23 (2004-05-11 Carl Worth <cworth@isi.edu>) +======================================================== +Fixes for gcc 3.4 +----------------- +Fix prototype mismatches so that cairo can be built by gcc 3.4. + +Updates to track glitz +---------------------- +Various fixes to support the latest glitz snapshot (0.1.2). + +Gradient updates +---------------- +Radial gradients now support both inner and outer circles. +Transformed linear gradients are now properly handled. +Fixes for extend type reflect. + +Glitz updates +------------- +Converted shading routines to use fixed point values and introduced a +shading operator structure for more efficient shading calculations. +Support compositing with mask surface when mask is solid or +multi-texturing is available. + +PNG backend cleanups +-------------------- +Fix output to properly compensate for pre-multiplied alpha format in cairo. +Add support for A8 and A1 image formats. + +Bug fixes +--------- +Avoid crash or infinite loop on null strings and degeneratively short +splines. + +New? bugs in cairo_clip +----------------------- +There are some fairly serious bugs in cairo_clip. It is sometimes +causing an incorrect result. And even when it does work, it is +sometimes so slow as to be unusable. Some of these bugs may not be +new, (indeed cairo_clip has only ever had a braindead-slow +implementation), but I think they're worth mentioning here. + Snapshot 0.1.22 (2004-04-16 Carl Worth <cworth@isi.edu>) ======================================================== Cairo was updated to track the changes in libpixman, and now depends @@ -13,7 +13,15 @@ snapshots. version numbers in order to get access to a specific set of features. -2) Verify that the code passes "make distcheck" +2) Increment CAIRO_VERSION in configure.in + + Right now, in its pre-release form, we are incrementing + CAIRO_VERSION for each snapshot but we are not changing the + libtool shared library version information. Until now, we've + only incremented the sub-minor version. We'll invent rules for + incrementing major and minor numbers when the time is right. + +3) Verify that the code passes "make distcheck" Running "make distcheck" should result in no warnings or errors and end with a message of the form: @@ -25,19 +33,13 @@ snapshots. (But the tar file isn't actually ready yet, as we still have some more steps to follow). -3) Fill out an entry in the NEWS file +4) Fill out an entry in the NEWS file Sift through the information in ChangeLog since the last snapshot. Summarize major changes briefly in a style similar - to other entries in NEWS. - -4) Increment CAIRO_VERSION in configure.in - - Right now, in its pre-release form, we are incrementing - CAIRO_VERSION for each snapshot but we are not changing the - libtool shared library version information. Until now, we've - only incremented the sub-minor version. We'll invent rules for - incrementing major and minor numbers when the time is right. + to other entries in NEWS. Take special care to note any + incompatible changes in the API. These should be easy to find + by looking for cairo.h in the ChangeLog. 5) Commit the changes to NEWS and configure.in @@ -45,8 +47,8 @@ snapshots. other commit. It's especially important to mention the new version number in the ChangeLog. -6) Run "make distcheck" to generate the final tar file with the - correct version number. +6) Run "make distcheck" to generate the final tar file including the + changes to NEWS and ChangeLog. 7) Copy the resulting tar file to the cairo snapshots distribution directory: @@ -13,6 +13,9 @@ problems with stroking self-intersecting paths. * Implement cairo_stroke_path, (very easy to do after the above change is done). +* Re-work the backend clipping interface to use geometry rather than +images. + * Fix the intersection problem, (see reference to Hobby's paper mentioned in cairo_traps.c). @@ -57,8 +60,8 @@ functions: * Re-implement the trapezoid rasterization algorithm according to the new "specification". -* Stroking degenerate paths should still draw caps. Round caps are -easy; square should probably draw an axis aligned square. +* Stroking closed, degenerate paths should still draw caps. Round +caps are easy; square should probably draw an axis aligned square. * Verification, profiling, optimization. diff --git a/configure.in b/configure.in index 674981551..3ac8f8459 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ AC_INIT(src/cairo.h) dnl =========================================================================== # Package version number, (as distinct from shared library version) -CAIRO_VERSION=0.1.22 +CAIRO_VERSION=0.1.23 # libtool shared library version @@ -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.2, [ GL_REQUIRES=glitz use_gl=yes], [use_gl="no (requires glitz http://freedesktop.org/software/glitz)"]) fi diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 77cf59b0d..c1c8d6ea0 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -241,7 +241,7 @@ _utf8_to_ucs4 (char const *utf8, size_t n = 0, alloc = 0; FcChar32 u = 0; - if (ucs4 == NULL || nchars == NULL) + if (utf8 == NULL || ucs4 == NULL || nchars == NULL) return; len = strlen (utf8); diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index ed8c8a1a8..0ff24c15d 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -363,10 +363,6 @@ _cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern) gstate->pattern = pattern; cairo_pattern_reference (pattern); - - _cairo_gstate_current_point (gstate, - &gstate->pattern_offset.x, - &gstate->pattern_offset.y); return CAIRO_STATUS_SUCCESS; } @@ -452,7 +448,7 @@ _cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule return CAIRO_STATUS_SUCCESS; } -cairo_status_t +cairo_fill_rule_t _cairo_gstate_current_fill_rule (cairo_gstate_t *gstate) { return gstate->fill_rule; @@ -1278,7 +1274,11 @@ _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, + gstate->pattern_offset.y); status = _cairo_surface_create_pattern (gstate->surface, pattern, extents); if (status) { @@ -1288,10 +1288,6 @@ _cairo_gstate_create_pattern (cairo_gstate_t *gstate, if (pattern->type == CAIRO_PATTERN_SURFACE) _cairo_pattern_prepare_surface (pattern); - - _cairo_pattern_add_source_offset (pattern, - gstate->pattern_offset.x, - gstate->pattern_offset.y); return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c index 6464d23f9..b81b1bd01 100644 --- a/src/cairo-pattern.c +++ b/src/cairo-pattern.c @@ -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 = radius0; - pattern->u.radial.radius0.dy = radius0; + pattern->u.radial.radius0 = fabs (radius0); pattern->u.radial.center1.x = cx1; pattern->u.radial.center1.y = cy1; - pattern->u.radial.radius1.dx = radius1; - pattern->u.radial.radius1.dy = radius1; + pattern->u.radial.radius1 = fabs (radius1); return pattern; } @@ -229,6 +227,7 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern, double alpha) { cairo_color_stop_t *stop; + int i; _cairo_restrict_value (&offset, 0.0, 1.0); _cairo_restrict_value (&red, 0.0, 1.0); @@ -246,7 +245,7 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern, stop = &pattern->stops[pattern->n_stops - 1]; - stop->offset = offset; + stop->offset = _cairo_fixed_from_double (offset); stop->id = pattern->n_stops; _cairo_color_init (&stop->color); _cairo_color_set_rgb (&stop->color, red, green, blue); @@ -260,6 +259,13 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern, qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t), _cairo_pattern_stop_compare); + for (i = 0; i < pattern->n_stops - 1; i++) { + pattern->stops[i + 1].scale = + pattern->stops[i + 1].offset - pattern->stops[i].offset; + if (pattern->stops[i + 1].scale == 65536) + pattern->stops[i + 1].scale = 0; + } + return CAIRO_STATUS_SUCCESS; } @@ -336,54 +342,18 @@ _cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha) } void -_cairo_pattern_add_source_offset (cairo_pattern_t *pattern, +_cairo_pattern_set_source_offset (cairo_pattern_t *pattern, double x, double y) { - pattern->source_offset.x += x; - pattern->source_offset.y += y; + pattern->source_offset.x = x; + pattern->source_offset.y = y; } 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 @@ -419,135 +389,127 @@ _cairo_pattern_prepare_surface (cairo_pattern_t *pattern) cairo_surface_set_filter (pattern->source, pattern->filter); } -typedef void (*cairo_shader_function_t) (unsigned char *color0, - unsigned char *color1, - double factor, - unsigned char *result_color); - #define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \ - ((unsigned char) ((factor < 0.5)? c1: c2)) + ((factor < 32768)? c1: c2) static void _cairo_pattern_shader_nearest (unsigned char *color0, unsigned char *color1, - double factor, - unsigned char *result_color) + cairo_fixed_t factor, + int *pixel) { - result_color[0] = INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor); - result_color[1] = INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor); - result_color[2] = INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor); - result_color[3] = INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor); + *pixel = + ((INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor) << 24) | + (INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor) << 16) | + (INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor) << 8) | + (INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor) << 0)); } #undef INTERPOLATE_COLOR_NEAREST #define INTERPOLATE_COLOR_LINEAR(c1, c2, factor) \ - ((unsigned char) ((c2 * factor) + (c1 * (1.0 - factor)))) + (((c2 * factor) + (c1 * (65536 - factor))) / 65536) static void _cairo_pattern_shader_linear (unsigned char *color0, unsigned char *color1, - double factor, - unsigned char *result_color) + cairo_fixed_t factor, + int *pixel) { - result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor); - result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor); - result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor); - result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor); + *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) | + (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) | + (INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor) << 8) | + (INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor) << 0)); } +#define E_MINUS_ONE 1.7182818284590452354 + static void _cairo_pattern_shader_gaussian (unsigned char *color0, unsigned char *color1, - double factor, - unsigned char *result_color) + cairo_fixed_t factor, + int *pixel) { - factor = (exp (factor * factor) - 1.0) / (M_E - 1.0); + double f = ((double) factor) / 65536.0; - result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor); - result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor); - result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor); - result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor); + factor = (cairo_fixed_t) (((exp (f * f) - 1.0) / E_MINUS_ONE) * 65536); + + *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) | + (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) | + (INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor) << 8) | + (INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor) << 0)); } #undef INTERPOLATE_COLOR_LINEAR void -_cairo_pattern_calc_color_at_pixel (cairo_pattern_t *pattern, - double factor, - int *pixel) +_cairo_pattern_shader_init (cairo_pattern_t *pattern, + cairo_shader_op_t *op) { - int p, colorstop; - double factorscale; - unsigned char result_color[4]; - cairo_shader_function_t shader_function; - + op->stops = pattern->stops; + op->n_stops = pattern->n_stops - 1; + op->min_offset = pattern->stops[0].offset; + op->max_offset = pattern->stops[op->n_stops].offset; + op->extend = pattern->extend; + switch (pattern->filter) { case CAIRO_FILTER_FAST: case CAIRO_FILTER_NEAREST: - shader_function = _cairo_pattern_shader_nearest; + op->shader_function = _cairo_pattern_shader_nearest; break; case CAIRO_FILTER_GAUSSIAN: - shader_function = _cairo_pattern_shader_gaussian; + op->shader_function = _cairo_pattern_shader_gaussian; break; case CAIRO_FILTER_GOOD: case CAIRO_FILTER_BEST: case CAIRO_FILTER_BILINEAR: - shader_function = _cairo_pattern_shader_linear; + op->shader_function = _cairo_pattern_shader_linear; break; } +} + +void +_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, + cairo_fixed_t factor, + int *pixel) +{ + int i; - if (factor > 1.0 || factor < 0.0) { - switch (pattern->extend) { - case CAIRO_EXTEND_REPEAT: - factor -= floor (factor); - break; - case CAIRO_EXTEND_REFLECT: - if (factor >= 0.0) { - if (((int) factor) % 2) - factor = 1.0 - (factor - floor (factor)); - else - factor -= floor (factor); - } else { - if (((int) factor) % 2) - factor -= floor (factor); - else - factor = 1.0 - (factor - floor (factor)); - } - break; - case CAIRO_EXTEND_NONE: - break; + switch (op->extend) { + case CAIRO_EXTEND_REPEAT: + factor -= factor & 0xffff0000; + break; + case CAIRO_EXTEND_REFLECT: + if (factor < 0 || factor > 65536) { + if ((factor >> 16) % 2) + factor = 65536 - (factor - (factor & 0xffff0000)); + else + factor -= factor & 0xffff0000; } + break; + case CAIRO_EXTEND_NONE: + break; } - - if (factor < pattern->stops[0].offset) - factor = pattern->stops[0].offset; - if (factor > pattern->stops[pattern->n_stops - 1].offset) - factor = pattern->stops[pattern->n_stops - 1].offset; - - for (colorstop = 0; colorstop < pattern->n_stops - 1; colorstop++) { - if (factor <= pattern->stops[colorstop + 1].offset) { - factorscale = fabs (pattern->stops[colorstop].offset - - pattern->stops[colorstop + 1].offset); - - /* abrubt change, difference between two offsets == 0.0 */ - if (factorscale == 0) - break; - - factor -= pattern->stops[colorstop].offset; + if (factor < op->min_offset) + factor = op->min_offset; + else if (factor > op->max_offset) + factor = op->max_offset; + for (i = 0; i < op->n_stops; i++) { + if (factor <= op->stops[i + 1].offset) { + /* take offset as new 0 of coordinate system */ - factor /= factorscale; - - shader_function (pattern->stops[colorstop].color_char, - pattern->stops[colorstop + 1].color_char, - factor, result_color); - - p = ((result_color[3] << 24) | - (result_color[0] << 16) | - (result_color[1] << 8) | (result_color[2] << 0)); - *pixel = p; + factor -= op->stops[i].offset; + + /* difference between two offsets == 0, abrubt change */ + if (op->stops[i + 1].scale) + factor = ((cairo_fixed_48_16_t) factor << 16) / + op->stops[i + 1].scale; + + op->shader_function (op->stops[i].color_char, + op->stops[i + 1].color_char, + factor, pixel); break; } } @@ -557,92 +519,164 @@ 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, end; - double factor; + 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; + + _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 : INT_MAX; - - a = -atan2 (point1.y - point0.y, point1.x - point0.x); - angle.x = cos (a); - angle.y = -sin (a); + length = (length) ? 1.0 / length : CAIRO_MAXSHORT; - start = angle.x * point0.x; - start += angle.y * point0.y; - - end = angle.x * point1.x; - end += angle.y * point1.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++) { - - factor = angle.x * (double) x; - factor += angle.y * (double) y; - - factor = factor - start; - factor *= length; - - _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *) - &data[y * width * 4 + x * 4]); + px = x + offset_x; + py = y + offset_y; + + /* transform fragment */ + ex = a * px + c * py + tx; + ey = b * px + d * py + ty; + + factor = ((fx * ex + fy * ey) - start) * length; + + _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; - double min_length; - - center1.x = pattern->u.radial.center1.x - offset_x; - center1.y = pattern->u.radial.center1.y - offset_y; - - min_length = - fabs ((pattern->u.radial.radius1.dx < pattern->u.radial.radius1.dy) ? - pattern->u.radial.radius1.dx : pattern->u.radial.radius1.dy); - - /* ugly */ - if (min_length == 0.0) - min_length = 0.000001; - - length.dx = min_length / pattern->u.radial.radius1.dx; - length.dy = min_length / pattern->u.radial.radius1.dy; + 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); + + 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; + + 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); + } - min_length = 1.0 / min_length; + 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; - - pos.x *= length.dx; - pos.y *= length.dy; - - factor = sqrt (pos.x * pos.x + pos.y * pos.y) * min_length; + px = x + offset_x; + py = y + offset_y; + + /* transform fragment */ + ex = a * px + c * py + tx; + ey = b * px + d * py + ty; + + if (aligned_circles) { + ex = ex - c1.x; + ey = ey - c1.y; + + factor = (sqrt (ex * ex + ey * ey) - r0) * r1; + } else { + /* + y (ex, ey) + c0 -------------------+---------- x + \ | __-- + \ | __-- + \ | __-- + \ | __-- r1 + \ | __-- + c1 -- + + We need to calulate distance c0->x; the distance from + the inner circle center c0, through fragment position + (ex, ey) to point x where it crosses the outer circle. + + From points c0, c1 and (ex, ey) we get angle C0. With + angle C0 we calculate distance c1->y and c0->y and by + knowing c1->y and r1, we also know y->x. Adding y->x to + c0->y gives us c0->x. The gradient offset can then be + calculated as: + + offset = (c0->e - r0) / (c0->x - r0) + + */ + + 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 (pattern, factor, (int *) - &data[y * width * 4 + x * 4]); + _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++); } } } @@ -656,35 +690,35 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) case CAIRO_PATTERN_LINEAR: case CAIRO_PATTERN_RADIAL: { char *data; - int width = ceil (_cairo_fixed_to_double (box->p2.x)) - - floor (_cairo_fixed_to_double (box->p1.x)); - int height = ceil (_cairo_fixed_to_double (box->p2.y)) - - floor (_cairo_fixed_to_double (box->p1.y)); + double x = box->p1.x >> 16; + double y = box->p1.y >> 16; + int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); + int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); data = malloc (width * height * 4); if (!data) return NULL; - - _cairo_pattern_add_source_offset (pattern, - floor (_cairo_fixed_to_double (box->p1.x)), - floor (_cairo_fixed_to_double (box->p1.y))); - + if (pattern->type == CAIRO_PATTERN_RADIAL) _cairo_image_data_set_radial (pattern, - pattern->source_offset.x, - pattern->source_offset.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, - pattern->source_offset.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); surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, width, height, width * 4); - + if (surface) _cairo_image_surface_assume_ownership_of_data ( (cairo_image_surface_t *) surface); @@ -714,3 +748,4 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) return (cairo_image_surface_t *) surface; } + diff --git a/src/cairo-spline.c b/src/cairo-spline.c index f05a9da55..6192f8636 100644 --- a/src/cairo-spline.c +++ b/src/cairo-spline.c @@ -118,6 +118,13 @@ static cairo_status_t _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point) { cairo_status_t status; + cairo_point_t *prev; + + if (spline->num_points) { + prev = &spline->points[spline->num_points - 1]; + if (prev->x == point->x && prev->y == point->y) + return CAIRO_STATUS_SUCCESS; + } if (spline->num_points >= spline->points_size) { status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC); diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 60b4487d4..79eee57b2 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -203,7 +203,7 @@ cairo_surface_set_repeat (cairo_surface_t *surface, int repeat) } slim_hidden_def(cairo_surface_set_repeat); -cairo_int_status_t +cairo_status_t _cairo_surface_composite (cairo_operator_t operator, cairo_surface_t *src, cairo_surface_t *mask, @@ -424,10 +424,10 @@ _cairo_surface_create_pattern (cairo_surface_t *surface, /* handle pattern opacity */ if (pattern->color.alpha != 1.0) { - int width = ceil (_cairo_fixed_to_double (box->p2.x)) - - floor (_cairo_fixed_to_double (box->p1.x)); - int height = ceil (_cairo_fixed_to_double (box->p2.y)) - - floor (_cairo_fixed_to_double (box->p1.y)); + double x = box->p1.x >> 16; + double y = box->p1.y >> 16; + int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); + int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); cairo_pattern_t alpha; pattern->source = @@ -462,9 +462,9 @@ _cairo_surface_create_pattern (cairo_surface_t *surface, save_repeat); if (status == CAIRO_STATUS_SUCCESS) { - _cairo_pattern_add_source_offset (pattern, - floor (_cairo_fixed_to_double (box->p1.x)), - floor (_cairo_fixed_to_double (box->p1.y))); + _cairo_pattern_set_source_offset (pattern, + pattern->source_offset.x + x, + pattern->source_offset.y + y); } else cairo_surface_destroy (pattern->source); } diff --git a/src/cairo-traps.c b/src/cairo-traps.c index 9b44d38ea..d17a27281 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -639,8 +639,8 @@ _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents) { int i; - extents->p1.x = extents->p1.y = SHRT_MAX << 16; - extents->p2.x = extents->p2.y = SHRT_MIN << 16; + extents->p1.x = extents->p1.y = CAIRO_MAXSHORT << 16; + extents->p2.x = extents->p2.y = CAIRO_MINSHORT << 16; for (i = 0; i < traps->num_traps; i++) _cairo_trap_extents (&traps->traps[i], extents); diff --git a/src/cairo.h b/src/cairo.h index a5cb20cd2..ab7cca724 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -378,6 +378,7 @@ cairo_fill_extents (cairo_t *cr, void cairo_init_clip (cairo_t *cr); +/* Note: cairo_clip does not consume the current path */ void cairo_clip (cairo_t *cr); diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c index 77cf59b0d..c1c8d6ea0 100644 --- a/src/cairo_ft_font.c +++ b/src/cairo_ft_font.c @@ -241,7 +241,7 @@ _utf8_to_ucs4 (char const *utf8, size_t n = 0, alloc = 0; FcChar32 u = 0; - if (ucs4 == NULL || nchars == NULL) + if (utf8 == NULL || ucs4 == NULL || nchars == NULL) return; len = strlen (utf8); diff --git a/src/cairo_gl_surface.c b/src/cairo_gl_surface.c index cb9871f6b..3a60302bd 100644 --- a/src/cairo_gl_surface.c +++ b/src/cairo_gl_surface.c @@ -64,6 +64,7 @@ struct cairo_gl_surface { long int features; long int hints; int owns_surface; + unsigned short opacity; cairo_pattern_t pattern; cairo_box_t pattern_box; @@ -71,6 +72,9 @@ struct cairo_gl_surface { glitz_surface_t *surface; }; +#define CAIRO_GL_MULTITEXTURE_SUPPORT(surface) \ + (surface->features & GLITZ_FEATURE_ARB_MULTITEXTURE_MASK) + #define CAIRO_GL_OFFSCREEN_SUPPORT(surface) \ (surface->features & GLITZ_FEATURE_OFFSCREEN_DRAWING_MASK) @@ -87,13 +91,17 @@ struct cairo_gl_surface { (surface->features & GLITZ_FEATURE_TEXTURE_MIRRORED_REPEAT_MASK) #define CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT(surface) \ - ((surface->format->stencil_size < \ - ((surface->hints & GLITZ_HINT_CLIPPING_MASK)? 2: 1)) && \ - (!CAIRO_GL_OFFSCREEN_SUPPORT (surface))) + ((surface->format->stencil_size >= \ + ((surface->hints & GLITZ_HINT_CLIPPING_MASK)? 2: 1)) || \ + CAIRO_GL_OFFSCREEN_SUPPORT (surface)) #define CAIRO_GL_SURFACE_IS_OFFSCREEN(surface) \ (surface->hints & GLITZ_HINT_OFFSCREEN_MASK) +#define CAIRO_GL_SURFACE_IS_SOLID(surface) \ + ((surface->hints & GLITZ_HINT_PROGRAMMATIC_MASK) && \ + (surface->pattern.type == CAIRO_PATTERN_SOLID)) + static void _cairo_gl_surface_destroy (void *abstract_surface) { @@ -130,8 +138,7 @@ _cairo_gl_surface_get_image (void *abstract_surface) width = glitz_surface_get_width (surface->surface); height = glitz_surface_get_height (surface->surface); - rowstride = width * (surface->format->bpp / 8); - rowstride += (rowstride % 4) ? (4 - (rowstride % 4)) : 0; + rowstride = (width * (surface->format->bpp / 8) + 3) & -4; pixels = (char *) malloc (sizeof (char) * height * rowstride); @@ -382,16 +389,21 @@ _cairo_gl_surface_composite (cairo_operator_t operator, cairo_gl_surface_t *src_clone = NULL; cairo_gl_surface_t *mask_clone = NULL; + /* Make sure that target surface is OK. */ + if (glitz_surface_get_status (dst->surface)) + return CAIRO_STATUS_NO_TARGET_SURFACE; + /* If destination surface is offscreen, then offscreen drawing support is required. */ if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) && (!CAIRO_GL_OFFSCREEN_SUPPORT (dst))) return CAIRO_INT_STATUS_UNSUPPORTED; - /* Fragment program or offscreen drawing required for composite with - mask. */ + /* We need multi-texturing or offscreen drawing when compositing with + non-solid mask. */ if (mask && - (!CAIRO_GL_FRAGMENT_PROGRAM_SUPPORT (dst)) && + (!CAIRO_GL_SURFACE_IS_SOLID (mask)) && + (!CAIRO_GL_MULTITEXTURE_SUPPORT (dst)) && (!CAIRO_GL_OFFSCREEN_SUPPORT (dst))) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -440,6 +452,10 @@ _cairo_gl_surface_fill_rectangles (void *abstract_surface, cairo_gl_surface_t *surface = abstract_surface; glitz_color_t glitz_color; + /* Make sure that target surface is OK. */ + if (glitz_surface_get_status (surface->surface)) + return CAIRO_STATUS_NO_TARGET_SURFACE; + /* If destination surface is offscreen, then offscreen drawing support is required. */ if (CAIRO_GL_SURFACE_IS_OFFSCREEN (surface) && @@ -495,13 +511,17 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t operator, cairo_gl_surface_t *src = (cairo_gl_surface_t *) generic_src; cairo_gl_surface_t *src_clone = NULL; + /* Make sure that target surface is OK. */ + if (glitz_surface_get_status (dst->surface)) + return CAIRO_STATUS_NO_TARGET_SURFACE; + /* If destination surface is offscreen, then offscreen drawing support is required. */ if (CAIRO_GL_SURFACE_IS_OFFSCREEN (dst) && (!CAIRO_GL_OFFSCREEN_SUPPORT (dst))) return CAIRO_INT_STATUS_UNSUPPORTED; - /* Need to get current hints as clipping might have changed. */ + /* Need to get current hints as clipping may have changed. */ dst->hints = glitz_surface_get_hints (dst->surface); /* Solid source? */ @@ -527,10 +547,14 @@ _cairo_gl_surface_composite_trapezoids (cairo_operator_t operator, src = src_clone; } + glitz_surface_set_polyopacity (dst->surface, src->opacity); + glitz_composite_trapezoids (_glitz_operator (operator), src->surface, dst->surface, x_src, y_src, (glitz_trapezoid_t *) traps, num_traps); + + glitz_surface_set_polyopacity (dst->surface, 0xffff); if (src_clone) cairo_surface_destroy (&src_clone->base); @@ -570,9 +594,13 @@ _cairo_gl_create_color_range (cairo_pattern_t *pattern, unsigned int size) { unsigned int i, bytes = size * 4; + cairo_shader_op_t op; + + _cairo_pattern_shader_init (pattern, &op); for (i = 0; i < bytes; i += 4) - _cairo_pattern_calc_color_at_pixel (pattern, i / (double) bytes, + _cairo_pattern_calc_color_at_pixel (&op, + ((double) i / bytes) * 65536, (int *) &data[i]); } @@ -582,10 +610,8 @@ _cairo_gl_surface_create_pattern (void *abstract_surface, cairo_box_t *box) { cairo_gl_surface_t *surface = abstract_surface; - glitz_surface_t *programmatic = NULL; - cairo_gl_surface_t *gl_surface; - double x = floor (_cairo_fixed_to_double (box->p1.x)); - double y = floor (_cairo_fixed_to_double (box->p1.y)); + glitz_surface_t *source = NULL; + cairo_gl_surface_t *src; switch (pattern->type) { case CAIRO_PATTERN_SOLID: { @@ -596,9 +622,8 @@ _cairo_gl_surface_create_pattern (void *abstract_surface, color.blue = pattern->color.blue_short; color.alpha = pattern->color.alpha_short; - programmatic = glitz_surface_create_solid (&color); - } - break; + source = glitz_surface_create_solid (&color); + } break; case CAIRO_PATTERN_LINEAR: case CAIRO_PATTERN_RADIAL: { unsigned int color_range_size; @@ -617,26 +642,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 { - /* libglitz doesn't support inner circle. */ - 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) + /* 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) 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))) @@ -647,8 +663,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: @@ -662,62 +678,89 @@ _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); + source = 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); + + source = 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: + if (CAIRO_GL_COMPOSITE_TRAPEZOIDS_SUPPORT (surface)) { + cairo_gl_surface_t *src_clone = NULL; + cairo_surface_t *generic_src = pattern->u.surface.surface; + + src = (cairo_gl_surface_t *) generic_src; + if (generic_src->backend != surface->base.backend) { + src_clone = + _cairo_gl_surface_clone_similar (generic_src, surface, + CAIRO_FORMAT_ARGB32); + if (!src_clone) + return CAIRO_INT_STATUS_UNSUPPORTED; + } else { + src_clone = (cairo_gl_surface_t *) + _cairo_gl_surface_create (src->surface, 0); + if (!src_clone) + return CAIRO_STATUS_NO_MEMORY; + + cairo_surface_set_filter + (&src_clone->base, cairo_surface_get_filter (generic_src)); + + cairo_surface_set_matrix (&src_clone->base, + &generic_src->matrix); + } + + cairo_surface_set_repeat (&src_clone->base, generic_src->repeat); + + src_clone->opacity = (unsigned short) + (pattern->color.alpha * 0xffff); + + pattern->source = &src_clone->base; + + return CAIRO_STATUS_SUCCESS; + } return CAIRO_INT_STATUS_UNSUPPORTED; break; } - - if (!programmatic) + + if (!source) return CAIRO_STATUS_NO_MEMORY; - gl_surface = (cairo_gl_surface_t *) - _cairo_gl_surface_create (programmatic, 1); - if (!gl_surface) { - glitz_surface_destroy (programmatic); - + src = (cairo_gl_surface_t *) _cairo_gl_surface_create (source, 1); + if (!src) { + glitz_surface_destroy (source); + return CAIRO_STATUS_NO_MEMORY; } + + if (pattern->type == CAIRO_PATTERN_LINEAR || + pattern->type == CAIRO_PATTERN_RADIAL) + cairo_surface_set_matrix (&src->base, &pattern->matrix); - _cairo_pattern_init_copy (&gl_surface->pattern, pattern); - gl_surface->pattern_box = *box; - - pattern->source = &gl_surface->base; - _cairo_pattern_add_source_offset (pattern, - floor (_cairo_fixed_to_double (box->p1.x)), - floor (_cairo_fixed_to_double (box->p1.y))); + _cairo_pattern_init_copy (&src->pattern, pattern); + src->pattern_box = *box; + + pattern->source = &src->base; return CAIRO_STATUS_SUCCESS; } @@ -757,8 +800,8 @@ _cairo_gl_surface_set_clip_region (void *abstract_surface, return CAIRO_STATUS_NO_MEMORY; for (i = 0; i < n; n++, box++) { - clip_rects[i].x = (short) box->x1; - clip_rects[i].y = (short) box->y1; + clip_rects[i].x = box->x1; + clip_rects[i].y = box->y1; clip_rects[i].width = (unsigned short) (box->x2 - box->x1); clip_rects[i].height = (unsigned short) (box->y2 - box->y1); } @@ -810,6 +853,7 @@ _cairo_gl_surface_create (glitz_surface_t *surface, int owns_surface) crsurface->features = glitz_surface_get_features (surface); crsurface->hints = glitz_surface_get_hints (surface); crsurface->owns_surface = owns_surface; + crsurface->opacity = 0xffff; return (cairo_surface_t *) crsurface; } diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c index ed8c8a1a8..0ff24c15d 100644 --- a/src/cairo_gstate.c +++ b/src/cairo_gstate.c @@ -363,10 +363,6 @@ _cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern) gstate->pattern = pattern; cairo_pattern_reference (pattern); - - _cairo_gstate_current_point (gstate, - &gstate->pattern_offset.x, - &gstate->pattern_offset.y); return CAIRO_STATUS_SUCCESS; } @@ -452,7 +448,7 @@ _cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule return CAIRO_STATUS_SUCCESS; } -cairo_status_t +cairo_fill_rule_t _cairo_gstate_current_fill_rule (cairo_gstate_t *gstate) { return gstate->fill_rule; @@ -1278,7 +1274,11 @@ _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, + gstate->pattern_offset.y); status = _cairo_surface_create_pattern (gstate->surface, pattern, extents); if (status) { @@ -1288,10 +1288,6 @@ _cairo_gstate_create_pattern (cairo_gstate_t *gstate, if (pattern->type == CAIRO_PATTERN_SURFACE) _cairo_pattern_prepare_surface (pattern); - - _cairo_pattern_add_source_offset (pattern, - gstate->pattern_offset.x, - gstate->pattern_offset.y); return CAIRO_STATUS_SUCCESS; } diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c index 6464d23f9..b81b1bd01 100644 --- a/src/cairo_pattern.c +++ b/src/cairo_pattern.c @@ -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 = radius0; - pattern->u.radial.radius0.dy = radius0; + pattern->u.radial.radius0 = fabs (radius0); pattern->u.radial.center1.x = cx1; pattern->u.radial.center1.y = cy1; - pattern->u.radial.radius1.dx = radius1; - pattern->u.radial.radius1.dy = radius1; + pattern->u.radial.radius1 = fabs (radius1); return pattern; } @@ -229,6 +227,7 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern, double alpha) { cairo_color_stop_t *stop; + int i; _cairo_restrict_value (&offset, 0.0, 1.0); _cairo_restrict_value (&red, 0.0, 1.0); @@ -246,7 +245,7 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern, stop = &pattern->stops[pattern->n_stops - 1]; - stop->offset = offset; + stop->offset = _cairo_fixed_from_double (offset); stop->id = pattern->n_stops; _cairo_color_init (&stop->color); _cairo_color_set_rgb (&stop->color, red, green, blue); @@ -260,6 +259,13 @@ cairo_pattern_add_color_stop (cairo_pattern_t *pattern, qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t), _cairo_pattern_stop_compare); + for (i = 0; i < pattern->n_stops - 1; i++) { + pattern->stops[i + 1].scale = + pattern->stops[i + 1].offset - pattern->stops[i].offset; + if (pattern->stops[i + 1].scale == 65536) + pattern->stops[i + 1].scale = 0; + } + return CAIRO_STATUS_SUCCESS; } @@ -336,54 +342,18 @@ _cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha) } void -_cairo_pattern_add_source_offset (cairo_pattern_t *pattern, +_cairo_pattern_set_source_offset (cairo_pattern_t *pattern, double x, double y) { - pattern->source_offset.x += x; - pattern->source_offset.y += y; + pattern->source_offset.x = x; + pattern->source_offset.y = y; } 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 @@ -419,135 +389,127 @@ _cairo_pattern_prepare_surface (cairo_pattern_t *pattern) cairo_surface_set_filter (pattern->source, pattern->filter); } -typedef void (*cairo_shader_function_t) (unsigned char *color0, - unsigned char *color1, - double factor, - unsigned char *result_color); - #define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \ - ((unsigned char) ((factor < 0.5)? c1: c2)) + ((factor < 32768)? c1: c2) static void _cairo_pattern_shader_nearest (unsigned char *color0, unsigned char *color1, - double factor, - unsigned char *result_color) + cairo_fixed_t factor, + int *pixel) { - result_color[0] = INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor); - result_color[1] = INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor); - result_color[2] = INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor); - result_color[3] = INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor); + *pixel = + ((INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor) << 24) | + (INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor) << 16) | + (INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor) << 8) | + (INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor) << 0)); } #undef INTERPOLATE_COLOR_NEAREST #define INTERPOLATE_COLOR_LINEAR(c1, c2, factor) \ - ((unsigned char) ((c2 * factor) + (c1 * (1.0 - factor)))) + (((c2 * factor) + (c1 * (65536 - factor))) / 65536) static void _cairo_pattern_shader_linear (unsigned char *color0, unsigned char *color1, - double factor, - unsigned char *result_color) + cairo_fixed_t factor, + int *pixel) { - result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor); - result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor); - result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor); - result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor); + *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) | + (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) | + (INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor) << 8) | + (INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor) << 0)); } +#define E_MINUS_ONE 1.7182818284590452354 + static void _cairo_pattern_shader_gaussian (unsigned char *color0, unsigned char *color1, - double factor, - unsigned char *result_color) + cairo_fixed_t factor, + int *pixel) { - factor = (exp (factor * factor) - 1.0) / (M_E - 1.0); + double f = ((double) factor) / 65536.0; - result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor); - result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor); - result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor); - result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor); + factor = (cairo_fixed_t) (((exp (f * f) - 1.0) / E_MINUS_ONE) * 65536); + + *pixel = ((INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor) << 24) | + (INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor) << 16) | + (INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor) << 8) | + (INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor) << 0)); } #undef INTERPOLATE_COLOR_LINEAR void -_cairo_pattern_calc_color_at_pixel (cairo_pattern_t *pattern, - double factor, - int *pixel) +_cairo_pattern_shader_init (cairo_pattern_t *pattern, + cairo_shader_op_t *op) { - int p, colorstop; - double factorscale; - unsigned char result_color[4]; - cairo_shader_function_t shader_function; - + op->stops = pattern->stops; + op->n_stops = pattern->n_stops - 1; + op->min_offset = pattern->stops[0].offset; + op->max_offset = pattern->stops[op->n_stops].offset; + op->extend = pattern->extend; + switch (pattern->filter) { case CAIRO_FILTER_FAST: case CAIRO_FILTER_NEAREST: - shader_function = _cairo_pattern_shader_nearest; + op->shader_function = _cairo_pattern_shader_nearest; break; case CAIRO_FILTER_GAUSSIAN: - shader_function = _cairo_pattern_shader_gaussian; + op->shader_function = _cairo_pattern_shader_gaussian; break; case CAIRO_FILTER_GOOD: case CAIRO_FILTER_BEST: case CAIRO_FILTER_BILINEAR: - shader_function = _cairo_pattern_shader_linear; + op->shader_function = _cairo_pattern_shader_linear; break; } +} + +void +_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, + cairo_fixed_t factor, + int *pixel) +{ + int i; - if (factor > 1.0 || factor < 0.0) { - switch (pattern->extend) { - case CAIRO_EXTEND_REPEAT: - factor -= floor (factor); - break; - case CAIRO_EXTEND_REFLECT: - if (factor >= 0.0) { - if (((int) factor) % 2) - factor = 1.0 - (factor - floor (factor)); - else - factor -= floor (factor); - } else { - if (((int) factor) % 2) - factor -= floor (factor); - else - factor = 1.0 - (factor - floor (factor)); - } - break; - case CAIRO_EXTEND_NONE: - break; + switch (op->extend) { + case CAIRO_EXTEND_REPEAT: + factor -= factor & 0xffff0000; + break; + case CAIRO_EXTEND_REFLECT: + if (factor < 0 || factor > 65536) { + if ((factor >> 16) % 2) + factor = 65536 - (factor - (factor & 0xffff0000)); + else + factor -= factor & 0xffff0000; } + break; + case CAIRO_EXTEND_NONE: + break; } - - if (factor < pattern->stops[0].offset) - factor = pattern->stops[0].offset; - if (factor > pattern->stops[pattern->n_stops - 1].offset) - factor = pattern->stops[pattern->n_stops - 1].offset; - - for (colorstop = 0; colorstop < pattern->n_stops - 1; colorstop++) { - if (factor <= pattern->stops[colorstop + 1].offset) { - factorscale = fabs (pattern->stops[colorstop].offset - - pattern->stops[colorstop + 1].offset); - - /* abrubt change, difference between two offsets == 0.0 */ - if (factorscale == 0) - break; - - factor -= pattern->stops[colorstop].offset; + if (factor < op->min_offset) + factor = op->min_offset; + else if (factor > op->max_offset) + factor = op->max_offset; + for (i = 0; i < op->n_stops; i++) { + if (factor <= op->stops[i + 1].offset) { + /* take offset as new 0 of coordinate system */ - factor /= factorscale; - - shader_function (pattern->stops[colorstop].color_char, - pattern->stops[colorstop + 1].color_char, - factor, result_color); - - p = ((result_color[3] << 24) | - (result_color[0] << 16) | - (result_color[1] << 8) | (result_color[2] << 0)); - *pixel = p; + factor -= op->stops[i].offset; + + /* difference between two offsets == 0, abrubt change */ + if (op->stops[i + 1].scale) + factor = ((cairo_fixed_48_16_t) factor << 16) / + op->stops[i + 1].scale; + + op->shader_function (op->stops[i].color_char, + op->stops[i + 1].color_char, + factor, pixel); break; } } @@ -557,92 +519,164 @@ 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, end; - double factor; + 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; + + _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 : INT_MAX; - - a = -atan2 (point1.y - point0.y, point1.x - point0.x); - angle.x = cos (a); - angle.y = -sin (a); + length = (length) ? 1.0 / length : CAIRO_MAXSHORT; - start = angle.x * point0.x; - start += angle.y * point0.y; - - end = angle.x * point1.x; - end += angle.y * point1.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++) { - - factor = angle.x * (double) x; - factor += angle.y * (double) y; - - factor = factor - start; - factor *= length; - - _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *) - &data[y * width * 4 + x * 4]); + px = x + offset_x; + py = y + offset_y; + + /* transform fragment */ + ex = a * px + c * py + tx; + ey = b * px + d * py + ty; + + factor = ((fx * ex + fy * ey) - start) * length; + + _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; - double min_length; - - center1.x = pattern->u.radial.center1.x - offset_x; - center1.y = pattern->u.radial.center1.y - offset_y; - - min_length = - fabs ((pattern->u.radial.radius1.dx < pattern->u.radial.radius1.dy) ? - pattern->u.radial.radius1.dx : pattern->u.radial.radius1.dy); - - /* ugly */ - if (min_length == 0.0) - min_length = 0.000001; - - length.dx = min_length / pattern->u.radial.radius1.dx; - length.dy = min_length / pattern->u.radial.radius1.dy; + 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); + + 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; + + 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); + } - min_length = 1.0 / min_length; + 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; - - pos.x *= length.dx; - pos.y *= length.dy; - - factor = sqrt (pos.x * pos.x + pos.y * pos.y) * min_length; + px = x + offset_x; + py = y + offset_y; + + /* transform fragment */ + ex = a * px + c * py + tx; + ey = b * px + d * py + ty; + + if (aligned_circles) { + ex = ex - c1.x; + ey = ey - c1.y; + + factor = (sqrt (ex * ex + ey * ey) - r0) * r1; + } else { + /* + y (ex, ey) + c0 -------------------+---------- x + \ | __-- + \ | __-- + \ | __-- + \ | __-- r1 + \ | __-- + c1 -- + + We need to calulate distance c0->x; the distance from + the inner circle center c0, through fragment position + (ex, ey) to point x where it crosses the outer circle. + + From points c0, c1 and (ex, ey) we get angle C0. With + angle C0 we calculate distance c1->y and c0->y and by + knowing c1->y and r1, we also know y->x. Adding y->x to + c0->y gives us c0->x. The gradient offset can then be + calculated as: + + offset = (c0->e - r0) / (c0->x - r0) + + */ + + 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 (pattern, factor, (int *) - &data[y * width * 4 + x * 4]); + _cairo_pattern_calc_color_at_pixel (&op, factor * 65536, pixels++); } } } @@ -656,35 +690,35 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) case CAIRO_PATTERN_LINEAR: case CAIRO_PATTERN_RADIAL: { char *data; - int width = ceil (_cairo_fixed_to_double (box->p2.x)) - - floor (_cairo_fixed_to_double (box->p1.x)); - int height = ceil (_cairo_fixed_to_double (box->p2.y)) - - floor (_cairo_fixed_to_double (box->p1.y)); + double x = box->p1.x >> 16; + double y = box->p1.y >> 16; + int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); + int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); data = malloc (width * height * 4); if (!data) return NULL; - - _cairo_pattern_add_source_offset (pattern, - floor (_cairo_fixed_to_double (box->p1.x)), - floor (_cairo_fixed_to_double (box->p1.y))); - + if (pattern->type == CAIRO_PATTERN_RADIAL) _cairo_image_data_set_radial (pattern, - pattern->source_offset.x, - pattern->source_offset.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, - pattern->source_offset.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); surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, width, height, width * 4); - + if (surface) _cairo_image_surface_assume_ownership_of_data ( (cairo_image_surface_t *) surface); @@ -714,3 +748,4 @@ _cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box) return (cairo_image_surface_t *) surface; } + diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c index 851df98da..b012514b7 100644 --- a/src/cairo_png_surface.c +++ b/src/cairo_png_surface.c @@ -4,6 +4,9 @@ static const cairo_surface_backend_t cairo_png_surface_backend; +static cairo_int_status_t +_cairo_png_surface_copy_page (void *abstract_surface); + void cairo_set_target_png (cairo_t *cr, FILE *file, @@ -31,12 +34,12 @@ typedef struct cairo_png_surface { cairo_surface_t base; /* PNG-specific fields */ + cairo_image_surface_t *image; FILE *file; + int copied; - png_structp png_w; - png_infop png_i; + cairo_format_t format; - cairo_image_surface_t *image; } cairo_png_surface_t; @@ -50,98 +53,29 @@ cairo_png_surface_create (FILE *file, int height) { cairo_png_surface_t *surface; - time_t now = time (NULL); - png_time png_time; - - if (format == CAIRO_FORMAT_A8 || - format == CAIRO_FORMAT_A1 || - file == NULL) - return NULL; surface = malloc (sizeof (cairo_png_surface_t)); if (surface == NULL) - goto failure; + return NULL; _cairo_surface_init (&surface->base, &cairo_png_surface_backend); - surface->png_w = NULL; - surface->png_i = NULL; surface->image = (cairo_image_surface_t *) cairo_image_surface_create (format, width, height); - if (surface->image == NULL) - goto failure; - - _cairo_png_surface_erase (surface); - - surface->file = file; - surface->png_w = png_create_write_struct (PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL); - if (surface->png_w == NULL) - goto failure; - surface->png_i = png_create_info_struct (surface->png_w); - if (surface->png_i == NULL) - goto failure; - - if (setjmp (png_jmpbuf (surface->png_w))) - goto failure; - - png_init_io (surface->png_w, surface->file); - - switch (format) { - case CAIRO_FORMAT_ARGB32: - png_set_IHDR (surface->png_w, surface->png_i, - width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - break; - case CAIRO_FORMAT_RGB24: - png_set_IHDR (surface->png_w, surface->png_i, - width, height, 8, PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - break; - case CAIRO_FORMAT_A8: - case CAIRO_FORMAT_A1: - /* These are not currently supported. */ - break; + if (surface->image == NULL) { + free (surface); + return NULL; } - png_convert_from_time_t (&png_time, now); - png_set_tIME (surface->png_w, surface->png_i, &png_time); + _cairo_png_surface_erase (surface); - png_write_info (surface->png_w, surface->png_i); + surface->file = file; + surface->copied = 0; - switch (format) { - case CAIRO_FORMAT_ARGB32: - png_set_bgr (surface->png_w); - break; - case CAIRO_FORMAT_RGB24: - png_set_filler (surface->png_w, 0, PNG_FILLER_AFTER); - png_set_bgr (surface->png_w); - break; - case CAIRO_FORMAT_A8: - case CAIRO_FORMAT_A1: - /* These are not currently supported. */ - break; - } + surface->format = format; return &surface->base; - - - failure: - if (surface) { - if (surface->image) - cairo_surface_destroy (&surface->image->base); - if (surface->png_i) - png_destroy_write_struct (&surface->png_w, &surface->png_i); - else if (surface->png_w) - png_destroy_write_struct (&surface->png_w, NULL); - free (surface); - } - return NULL; } @@ -155,25 +89,35 @@ _cairo_png_surface_create_similar (void *abstract_src, } static void -_cairo_png_surface_destroy (void *abstract_surface) +unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) { - cairo_png_surface_t *surface = abstract_surface; int i; - png_byte *row; - - if (setjmp (png_jmpbuf (surface->png_w))) - goto failure; - row = surface->image->data; - for (i=0; i < surface->image->height; i++) { - png_write_row (surface->png_w, row); - row += surface->image->stride; + for (i = 0; i < row_info->rowbytes; i += 4) { + unsigned char *b = &data[i]; + unsigned int pixel; + unsigned char alpha; + + memcpy (&pixel, b, sizeof (unsigned int)); + alpha = (pixel & 0xff000000) >> 24; + if (alpha == 0) { + b[0] = b[1] = b[2] = b[3] = 0; + } else { + b[0] = (((pixel & 0x0000ff) >> 0) * 255) / alpha; + b[1] = (((pixel & 0x00ff00) >> 8) * 255) / alpha; + b[2] = (((pixel & 0xff0000) >> 16) * 255) / alpha; + b[3] = alpha; + } } +} - png_write_end (surface->png_w, surface->png_i); +static void +_cairo_png_surface_destroy (void *abstract_surface) +{ + cairo_png_surface_t *surface = abstract_surface; - failure: - png_destroy_write_struct (&surface->png_w, &surface->png_i); + if (! surface->copied) + _cairo_png_surface_copy_page (surface); cairo_surface_destroy (&surface->image->base); @@ -296,13 +240,110 @@ _cairo_png_surface_composite_trapezoids (cairo_operator_t operator, static cairo_int_status_t _cairo_png_surface_copy_page (void *abstract_surface) { - return CAIRO_INT_STATUS_UNSUPPORTED; + int i; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_png_surface_t *surface = abstract_surface; + png_struct *png; + png_info *info; + png_byte **rows; + png_color_16 white; + int png_color_type; + int depth; + + rows = malloc (surface->image->height * sizeof(png_byte*)); + if (rows == NULL) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < surface->image->height; i++) + rows[i] = surface->image->data + i * surface->image->stride; + + png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png == NULL) + return CAIRO_STATUS_NO_MEMORY; + + info = png_create_info_struct (png); + if (info == NULL) { + png_destroy_write_struct (&png, NULL); + return CAIRO_STATUS_NO_MEMORY; + } + + if (setjmp (png_jmpbuf (png))) { + status = CAIRO_STATUS_NO_MEMORY; + goto BAIL; + } + + png_init_io (png, surface->file); + + switch (surface->format) { + case CAIRO_FORMAT_ARGB32: + depth = 8; + png_color_type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case CAIRO_FORMAT_RGB24: + depth = 8; + png_color_type = PNG_COLOR_TYPE_RGB; + break; + case CAIRO_FORMAT_A8: + depth = 8; + png_color_type = PNG_COLOR_TYPE_GRAY; + break; + case CAIRO_FORMAT_A1: + depth = 1; + png_color_type = PNG_COLOR_TYPE_GRAY; + break; + } + + png_set_IHDR (png, info, + surface->image->width, + surface->image->height, depth, + png_color_type, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + white.red = 0xff; + white.blue = 0xff; + white.green = 0xff; + png_set_bKGD (png, info, &white); + +/* XXX: Setting the time is interfereing with the image comparison + png_convert_from_time_t (&png_time, time (NULL)); + png_set_tIME (png, info, &png_time); +*/ + + png_set_write_user_transform_fn (png, unpremultiply_data); + if (surface->format == CAIRO_FORMAT_ARGB32 || surface->format == CAIRO_FORMAT_RGB24) + png_set_bgr (png); + if (surface->format == CAIRO_FORMAT_RGB24) + png_set_filler (png, 0, PNG_FILLER_AFTER); + + png_write_info (png, info); + png_write_image (png, rows); + png_write_end (png, info); + + surface->copied = 1; + +BAIL: + png_destroy_write_struct (&png, &info); + + free (rows); + + return status; } static cairo_int_status_t _cairo_png_surface_show_page (void *abstract_surface) { - return CAIRO_INT_STATUS_UNSUPPORTED; + cairo_int_status_t status; + cairo_png_surface_t *surface = abstract_surface; + + status = _cairo_png_surface_copy_page (surface); + if (status) + return status; + + _cairo_png_surface_erase (surface); + + return CAIRO_STATUS_SUCCESS; } static cairo_int_status_t diff --git a/src/cairo_spline.c b/src/cairo_spline.c index f05a9da55..6192f8636 100644 --- a/src/cairo_spline.c +++ b/src/cairo_spline.c @@ -118,6 +118,13 @@ static cairo_status_t _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point) { cairo_status_t status; + cairo_point_t *prev; + + if (spline->num_points) { + prev = &spline->points[spline->num_points - 1]; + if (prev->x == point->x && prev->y == point->y) + return CAIRO_STATUS_SUCCESS; + } if (spline->num_points >= spline->points_size) { status = _cairo_spline_grow_by (spline, CAIRO_SPLINE_GROWTH_INC); diff --git a/src/cairo_surface.c b/src/cairo_surface.c index 60b4487d4..79eee57b2 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -203,7 +203,7 @@ cairo_surface_set_repeat (cairo_surface_t *surface, int repeat) } slim_hidden_def(cairo_surface_set_repeat); -cairo_int_status_t +cairo_status_t _cairo_surface_composite (cairo_operator_t operator, cairo_surface_t *src, cairo_surface_t *mask, @@ -424,10 +424,10 @@ _cairo_surface_create_pattern (cairo_surface_t *surface, /* handle pattern opacity */ if (pattern->color.alpha != 1.0) { - int width = ceil (_cairo_fixed_to_double (box->p2.x)) - - floor (_cairo_fixed_to_double (box->p1.x)); - int height = ceil (_cairo_fixed_to_double (box->p2.y)) - - floor (_cairo_fixed_to_double (box->p1.y)); + double x = box->p1.x >> 16; + double y = box->p1.y >> 16; + int width = ((box->p2.x + 65535) >> 16) - (box->p1.x >> 16); + int height = ((box->p2.y + 65535) >> 16) - (box->p1.y >> 16); cairo_pattern_t alpha; pattern->source = @@ -462,9 +462,9 @@ _cairo_surface_create_pattern (cairo_surface_t *surface, save_repeat); if (status == CAIRO_STATUS_SUCCESS) { - _cairo_pattern_add_source_offset (pattern, - floor (_cairo_fixed_to_double (box->p1.x)), - floor (_cairo_fixed_to_double (box->p1.y))); + _cairo_pattern_set_source_offset (pattern, + pattern->source_offset.x + x, + pattern->source_offset.y + y); } else cairo_surface_destroy (pattern->source); } diff --git a/src/cairo_traps.c b/src/cairo_traps.c index 9b44d38ea..d17a27281 100644 --- a/src/cairo_traps.c +++ b/src/cairo_traps.c @@ -639,8 +639,8 @@ _cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents) { int i; - extents->p1.x = extents->p1.y = SHRT_MAX << 16; - extents->p2.x = extents->p2.y = SHRT_MIN << 16; + extents->p1.x = extents->p1.y = CAIRO_MAXSHORT << 16; + extents->p2.x = extents->p2.y = CAIRO_MINSHORT << 16; for (i = 0; i < traps->num_traps; i++) _cairo_trap_extents (&traps->traps[i], extents); diff --git a/src/cairoint.h b/src/cairoint.h index 5b4ccb56e..97db3be5b 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -40,6 +40,7 @@ #include <stdlib.h> #include <string.h> #include <math.h> +#include <limits.h> #include "cairo.h" @@ -119,6 +120,9 @@ typedef int32_t cairo_fixed_16_16_t; /* The common 16.16 format gets a shorter name */ typedef cairo_fixed_16_16_t cairo_fixed_t; +#define CAIRO_MAXSHORT SHRT_MAX +#define CAIRO_MINSHORT SHRT_MIN + typedef struct cairo_point { cairo_fixed_t x; cairo_fixed_t y; @@ -453,12 +457,27 @@ typedef enum { } cairo_pattern_type_t; typedef struct cairo_color_stop { - double offset; + cairo_fixed_t offset; + cairo_fixed_48_16_t scale; int id; cairo_color_t color; unsigned char color_char[4]; } cairo_color_stop_t; +typedef void (*cairo_shader_function_t) (unsigned char *color0, + unsigned char *color1, + cairo_fixed_t factor, + int *pixel); + +typedef struct cairo_shader_op { + cairo_color_stop_t *stops; + int n_stops; + cairo_fixed_t min_offset; + cairo_fixed_t max_offset; + cairo_extend_t extend; + cairo_shader_function_t shader_function; +} cairo_shader_op_t; + struct cairo_pattern { unsigned int ref_count; @@ -489,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; }; @@ -924,7 +943,7 @@ _cairo_font_create (const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight); -extern cairo_int_status_t __internal_linkage +extern cairo_status_t __internal_linkage _cairo_font_init (cairo_font_t *font, const struct cairo_font_backend *backend); @@ -937,22 +956,22 @@ _cairo_font_scale (cairo_font_t *font, double scale); extern cairo_status_t __internal_linkage _cairo_font_transform (cairo_font_t *font, cairo_matrix_t *matrix); -extern cairo_int_status_t __internal_linkage +extern cairo_status_t __internal_linkage _cairo_font_font_extents (cairo_font_t *font, cairo_font_extents_t *extents); -extern cairo_int_status_t __internal_linkage +extern cairo_status_t __internal_linkage _cairo_font_text_extents (cairo_font_t *font, const unsigned char *utf8, cairo_text_extents_t *extents); -extern cairo_int_status_t __internal_linkage +extern cairo_status_t __internal_linkage _cairo_font_glyph_extents (cairo_font_t *font, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents); -extern cairo_int_status_t __internal_linkage +extern cairo_status_t __internal_linkage _cairo_font_show_text (cairo_font_t *font, cairo_operator_t operator, cairo_surface_t *source, @@ -962,7 +981,7 @@ _cairo_font_show_text (cairo_font_t *font, const unsigned char *utf8); -extern cairo_int_status_t __internal_linkage +extern cairo_status_t __internal_linkage _cairo_font_show_glyphs (cairo_font_t *font, cairo_operator_t operator, cairo_surface_t *source, @@ -971,14 +990,14 @@ _cairo_font_show_glyphs (cairo_font_t *font, int num_glyphs); -extern cairo_int_status_t __internal_linkage +extern cairo_status_t __internal_linkage _cairo_font_text_path (cairo_font_t *font, double x, double y, const unsigned char *utf8, cairo_path_t *path); -extern cairo_int_status_t __internal_linkage +extern cairo_status_t __internal_linkage _cairo_font_glyph_path (cairo_font_t *font, cairo_glyph_t *glyphs, int num_glyphs, @@ -1331,20 +1350,23 @@ extern void __internal_linkage _cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha); extern void __internal_linkage -_cairo_pattern_add_source_offset (cairo_pattern_t *pattern, +_cairo_pattern_set_source_offset (cairo_pattern_t *pattern, double x, double y); 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); extern void __internal_linkage -_cairo_pattern_calc_color_at_pixel (cairo_pattern_t *pattern, - double factor, +_cairo_pattern_shader_init (cairo_pattern_t *pattern, + cairo_shader_op_t *op); + +extern void __internal_linkage +_cairo_pattern_calc_color_at_pixel (cairo_shader_op_t *op, + cairo_fixed_t factor, int *pixel); extern cairo_image_surface_t *__internal_linkage |