diff options
author | David Reveman <davidr@novell.com> | 2004-04-06 09:36:12 +0000 |
---|---|---|
committer | David Reveman <davidr@novell.com> | 2004-04-06 09:36:12 +0000 |
commit | e309090d2a18a896c67e731151b973b530f76980 (patch) | |
tree | 05568843c26c44738d5413269bb2358776df515b | |
parent | b17b04aa388541c0880698aed0f03796a3146d49 (diff) |
Added new pattern API
-rw-r--r-- | ChangeLog | 82 | ||||
-rw-r--r-- | cairo.pc.in | 2 | ||||
-rw-r--r-- | configure.in | 7 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/cairo-ft-font.c | 21 | ||||
-rw-r--r-- | src/cairo-gstate.c | 528 | ||||
-rw-r--r-- | src/cairo-image-surface.c | 23 | ||||
-rw-r--r-- | src/cairo-ps-surface.c | 10 | ||||
-rw-r--r-- | src/cairo-surface.c | 108 | ||||
-rw-r--r-- | src/cairo-traps.c | 37 | ||||
-rw-r--r-- | src/cairo-xcb-surface.c | 11 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 15 | ||||
-rw-r--r-- | src/cairo.c | 33 | ||||
-rw-r--r-- | src/cairo.h | 75 | ||||
-rw-r--r-- | src/cairo_ft_font.c | 21 | ||||
-rw-r--r-- | src/cairo_gstate.c | 528 | ||||
-rw-r--r-- | src/cairo_image_surface.c | 23 | ||||
-rw-r--r-- | src/cairo_png_surface.c | 10 | ||||
-rw-r--r-- | src/cairo_ps_surface.c | 10 | ||||
-rw-r--r-- | src/cairo_surface.c | 108 | ||||
-rw-r--r-- | src/cairo_traps.c | 37 | ||||
-rw-r--r-- | src/cairo_xcb_surface.c | 11 | ||||
-rw-r--r-- | src/cairo_xlib_surface.c | 15 | ||||
-rw-r--r-- | src/cairoint.h | 150 |
24 files changed, 1339 insertions, 530 deletions
@@ -1,3 +1,85 @@ +2004-04-04 David Reveman <c99drn@cs.umu.se> + + * src/cairoint.h: Added create_pattern backend function and pattern + prototypes. + + * src/cairo_xlib_surface.c: Added _cairo_xlib_surface_create_pattern. + + * src/cairo_xcb_surface.c: Added _cairo_xcb_surface_create_pattern. + + * src/cairo_traps.c: Added _cairo_trap_extents and + _cairo_traps_extents. + + * src/cairo_surface.c: Added _cairo_surface_create_pattern. + + * src/cairo_ps_surface.c: Added _cairo_ps_surface_create_pattern. + + * src/cairo_png_surface.c: Added _cairo_png_surface_create_pattern. + + * src/cairo_pattern.c (added): All functions needed for the new + pattern API. + + * src/cairo_image_surface.c: Added + _cairo_image_abstract_surface_create_pattern. + + * src/cairo_gstate.c (_cairo_gstate_init): Create solid pattern + and set alpha to 0.0. + (_cairo_gstate_init_copy): Increment pattern references. + (_cairo_gstate_fini): Destroy pattern. + (_cairo_gstate_set_pattern): Destroy current pattern, + increment references to the new pattern and update pattern + offset with the current point. + (_cairo_gstate_set_rgb_color): Destroy current pattern and + create a new solid pattern. + (_cairo_gstate_current_rgb_color): Get RGB from current pattern. + (_cairo_gstate_set_alpha): Set gstate->alpha without modifying + the current pattern. + (_cairo_gstate_stroke): + (_cairo_gstate_fill): Removed surface matrix computations as + they are now handled by _cairo_gstate_create_pattern. + (_cairo_gstate_clip_and_composite_trapezoids): Create a + possibly backend accelerated pattern source and use it for + compositing trapezoids. + (_cairo_gstate_clip): Allow backends to not support rectangular + clipping regions. Use solid pattern for creating clip surface. + (_cairo_gstate_show_surface): Use solid pattern for alpha mask. + (_cairo_gstate_show_text): + (_cairo_gstate_show_glyphs): Use current pattern when compositing + glyphs. + + Added _cairo_gstate_current_pattern and _cairo_gstate_create_pattern, + _cairo_gstate_stroke_extents, _cairo_gstate_fill_extents. + Removed restore_text_rendering_context, setup_text_rendering_context, + _cairo_gstate_ensure_source. + + * src/cairo_ft_font.c (_cairo_ft_font_show_glyphs): Advance + source offset. + + * src/cairo.h: Added cairo_current_pattern, + cairo_pattern_create_for_surface, cairo_pattern_create_linear, + cairo_pattern_create_radial, cairo_pattern_reference, + cairo_pattern_destroy, cairo_pattern_add_color_stop, + cairo_pattern_set_matrix, cairo_pattern_get_matrix, + cairo_pattern_set_extend, cairo_pattern_get_extend, + cairo_pattern_set_filter, cairo_pattern_get_filter. cairo_set_pattern + now takes a cairo_pattern_t pointer instead of a cairo_surface_t + pointer. Added CAIRO_FILTER_GAUSSIAN filter type. Added cairo_extend_t + enum. + + * src/cairo.c: _cairo_restrict_value declared not static as it's + used in cairo_pattern.c. Added rectangular extents functions + cairo_stroke_extents and cairo_fill_extents. cairo_set_pattern now + takes a cairo_pattern_t pointer instead of a cairo_surface_t + pointer. Added cairo_current_pattern function. + + * src/Makefile.am (libcairo_la_LIBADD): Removed -lz and added PS_LIBS. + + * configure.in: Bump version to 0.1.20. Includes new pattern + API. Removed an extra AC_SUBST(XRENDER_LIBS). + PS_SURFACE_LIBS -> PS_LIBS. + + * cairo.pc.in: PS_SURFACE_LIBS -> PS_LIBS. + 2004-04-02 Carl Worth <cworth@east.isi.edu> * src/cairo.h: Move weight after slant to match the order in diff --git a/cairo.pc.in b/cairo.pc.in index a7f5d40d..316e6f33 100644 --- a/cairo.pc.in +++ b/cairo.pc.in @@ -8,6 +8,6 @@ Description: Multi-platform 2D graphics library Version: @VERSION@ Requires: fontconfig libpixman @XRENDER_REQUIRES@ @PNG_REQUIRES@ -Libs: -L${libdir} -lcairo -lm @PS_SURFACE_LIBS@ @FREETYPE_LIBS@ @XRENDER_LIBS@ +Libs: -L${libdir} -lcairo -lm @XRENDER_LIBS@ @PS_LIBS@ @FREETYPE_LIBS@ Cflags: -I${includedir} @FREETYPE_CFLAGS@ diff --git a/configure.in b/configure.in index 85d3467f..a2df768a 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.19 +CAIRO_VERSION=0.1.20 # libtool shared library version @@ -59,7 +59,6 @@ AC_SUBST(XLIB_SURFACE_FEATURE) AC_SUBST(XRENDER_CFLAGS) AC_SUBST(XRENDER_LIBS) AC_SUBST(XRENDER_REQUIRES) -AC_SUBST(XRENDER_LIBS) dnl =========================================================================== @@ -91,12 +90,12 @@ if test "x$use_ps" != "xyes"; then AM_CONDITIONAL(CAIRO_HAS_PS_SURFACE, false) else PS_SURFACE_FEATURE=CAIRO_HAS_PS_SURFACE - PS_SURFACE_LIBS=-lz + PS_LIBS=-lz AM_CONDITIONAL(CAIRO_HAS_PS_SURFACE, true) fi -AC_SUBST(PS_SURFACE_LIBS) AC_SUBST(PS_SURFACE_FEATURE) +AC_SUBST(PS_LIBS) dnl =========================================================================== diff --git a/src/Makefile.am b/src/Makefile.am index 4278a1bb..518e69f2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,6 +45,7 @@ libcairo_la_SOURCES = \ cairo_spline.c \ cairo_surface.c \ cairo_traps.c \ + cairo_pattern.c \ $(libcairo_ps_sources) \ $(libcairo_png_sources) \ $(libcairo_xlib_sources)\ @@ -55,5 +56,4 @@ libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS) -libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PNG_LIBS) -lm -lz - +libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PS_LIBS) $(PNG_LIBS) -lm diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c index 3975938a..77cf59b0 100644 --- a/src/cairo-ft-font.c +++ b/src/cairo-ft-font.c @@ -477,6 +477,7 @@ _cairo_ft_font_show_glyphs (void *abstract_font, cairo_ft_font_t *ft = NULL; FT_GlyphSlot glyphslot; cairo_surface_t *mask = NULL; + cairo_point_double_t origin; double x, y; int width, height, stride; @@ -504,7 +505,12 @@ _cairo_ft_font_show_glyphs (void *abstract_font, bitmap = glyphslot->bitmap.buffer; x = glyphs[i].x; - y = glyphs[i].y; + y = glyphs[i].y; + + if (i == 0) { + origin.x = x; + origin.y = y; + } /* X gets upset with zero-sized images (such as whitespace) */ if (width * height == 0) @@ -547,11 +553,14 @@ _cairo_ft_font_show_glyphs (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; } - status = _cairo_surface_composite (operator, source, mask, surface, - 0, 0, 0, 0, - x + glyphslot->bitmap_left, - y - glyphslot->bitmap_top, - (double)width, (double)height); + status = + _cairo_surface_composite (operator, source, mask, surface, + -origin.x + x + glyphslot->bitmap_left, + -origin.y + y - glyphslot->bitmap_top, + 0, 0, + x + glyphslot->bitmap_left, + y - glyphslot->bitmap_top, + (double) width, (double) height); cairo_surface_destroy (mask); if (bitmap != glyphslot->bitmap.buffer) diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c index f780cc94..ed8c8a1a 100644 --- a/src/cairo-gstate.c +++ b/src/cairo-gstate.c @@ -31,11 +31,8 @@ #include "cairoint.h" static cairo_status_t -_cairo_gstate_ensure_source (cairo_gstate_t *gstate); - -static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_surface_t *src, + cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, cairo_traps_t *traps); @@ -76,16 +73,14 @@ _cairo_gstate_init (cairo_gstate_t *gstate) CAIRO_FONT_WEIGHT_DEFAULT); gstate->surface = NULL; - gstate->source = NULL; - gstate->source_offset.x = 0.0; - gstate->source_offset.y = 0.0; - gstate->source_is_solid = 1; gstate->clip.region = NULL; gstate->clip.surface = NULL; - + + gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0); + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; gstate->alpha = 1.0; - _cairo_color_init (&gstate->color); gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT; _cairo_gstate_default_matrix (gstate); @@ -131,8 +126,9 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) } cairo_surface_reference (gstate->surface); - cairo_surface_reference (gstate->source); cairo_surface_reference (gstate->clip.surface); + + cairo_pattern_reference (gstate->pattern); status = _cairo_path_init_copy (&gstate->path, &other->path); if (status) @@ -164,11 +160,6 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) cairo_surface_destroy (gstate->surface); gstate->surface = NULL; - if (gstate->source) - cairo_surface_destroy (gstate->source); - gstate->source = NULL; - gstate->source_is_solid = 1; - if (gstate->clip.surface) cairo_surface_destroy (gstate->clip.surface); gstate->clip.surface = NULL; @@ -177,7 +168,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) pixman_region_destroy (gstate->clip.region); gstate->clip.region = NULL; - _cairo_color_fini (&gstate->color); + cairo_pattern_destroy (gstate->pattern); _cairo_matrix_fini (&gstate->ctm); _cairo_matrix_fini (&gstate->ctm_inverse); @@ -362,22 +353,37 @@ _cairo_gstate_current_target_surface (cairo_gstate_t *gstate) } cairo_status_t -_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern) +_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern) { - cairo_surface_destroy (gstate->source); - - gstate->source = pattern; - gstate->source_is_solid = 0; + if (pattern == NULL) + return CAIRO_STATUS_NULL_POINTER; - cairo_surface_reference (gstate->source); + if (gstate->pattern) + cairo_pattern_destroy (gstate->pattern); + + gstate->pattern = pattern; + cairo_pattern_reference (pattern); _cairo_gstate_current_point (gstate, - &gstate->source_offset.x, - &gstate->source_offset.y); - + &gstate->pattern_offset.x, + &gstate->pattern_offset.y); + return CAIRO_STATUS_SUCCESS; } +cairo_pattern_t * +_cairo_gstate_current_pattern (cairo_gstate_t *gstate) +{ + if (gstate == NULL) + return NULL; + +/* XXX: Do we want this? + cairo_pattern_reference (gstate->pattern); +*/ + + return gstate->pattern; +} + cairo_status_t _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator) { @@ -395,25 +401,19 @@ _cairo_gstate_current_operator (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue) { - _cairo_color_set_rgb (&gstate->color, red, green, blue); - - if (gstate->source) - cairo_surface_destroy (gstate->source); - - gstate->source = NULL; - gstate->source_offset.x = 0; - gstate->source_offset.y = 0; - gstate->source_is_solid = 1; - + cairo_pattern_destroy (gstate->pattern); + + gstate->pattern = _cairo_pattern_create_solid (red, green, blue); + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; + return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_gstate_current_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue) { - _cairo_color_get_rgb (&gstate->color, red, green, blue); - - return CAIRO_STATUS_SUCCESS; + return _cairo_pattern_get_rgb (gstate->pattern, red, green, blue); } cairo_status_t @@ -430,20 +430,11 @@ _cairo_gstate_current_tolerance (cairo_gstate_t *gstate) return gstate->tolerance; } -/* XXX: Need to fix this so it does the right thing after set_pattern. */ cairo_status_t _cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha) { gstate->alpha = alpha; - _cairo_color_set_alpha (&gstate->color, alpha); - - cairo_surface_destroy (gstate->source); - - gstate->source = NULL; - gstate->source_offset.x = 0; - gstate->source_offset.y = 0; - return CAIRO_STATUS_SUCCESS; } @@ -1259,24 +1250,49 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate, &gpi); } +/* This function modifies the pattern and the state of the pattern surface it + may contain. The pattern surface will be restored to its orignal state + when the pattern is destroyed. The appropriate way is to pass a copy of + the original pattern to this function just before the pattern should be + used and destroy the copy when done. */ static cairo_status_t -_cairo_gstate_ensure_source (cairo_gstate_t *gstate) +_cairo_gstate_create_pattern (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + cairo_box_t *extents) { - if (gstate->source) - return CAIRO_STATUS_SUCCESS; - - if (gstate->surface == NULL) + cairo_int_status_t status; + + if (gstate->surface == NULL) { + _cairo_pattern_fini (pattern); return CAIRO_STATUS_NO_TARGET_SURFACE; + } - gstate->source = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_ARGB32, - 1, 1, - &gstate->color); - if (gstate->source == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (pattern->type == CAIRO_PATTERN_LINEAR || + pattern->type == CAIRO_PATTERN_RADIAL) { + if (pattern->n_stops < 2) { + pattern->type = CAIRO_PATTERN_SOLID; + + if (pattern->n_stops) + pattern->color = pattern->stops->color; + } + } + + _cairo_pattern_set_alpha (pattern, gstate->alpha); + _cairo_pattern_transform (pattern, &gstate->ctm, &gstate->ctm_inverse); - cairo_surface_set_repeat (gstate->source, 1); + status = _cairo_surface_create_pattern (gstate->surface, pattern, extents); + if (status) { + _cairo_pattern_fini (pattern); + return status; + } + 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; } @@ -1285,15 +1301,10 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate) { cairo_status_t status; cairo_traps_t traps; - cairo_matrix_t user_to_source, device_to_source; if (gstate->line_width <= 0.0) return CAIRO_STATUS_SUCCESS; - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; - _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); _cairo_traps_init (&traps); @@ -1304,21 +1315,11 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate) return status; } - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, &user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, &user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); - - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, &user_to_source); + gstate->pattern, + gstate->operator, + gstate->surface, + &traps); _cairo_traps_fini (&traps); @@ -1357,12 +1358,14 @@ BAIL: /* Warning: This call modifies the coordinates of traps */ static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_surface_t *src, + cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, cairo_traps_t *traps) { cairo_status_t status; + cairo_pattern_t pattern; + cairo_box_t extents; if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; @@ -1371,19 +1374,8 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, cairo_fixed_t xoff, yoff; cairo_trapezoid_t *t; int i; - - cairo_surface_t *white, *intermediate; - cairo_color_t white_color, empty_color; - - _cairo_color_init (&white_color); - white = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - 1, 1, - &white_color); - if (white == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } - cairo_surface_set_repeat (white, 1); + cairo_surface_t *intermediate; + cairo_color_t empty_color; _cairo_color_init (&empty_color); _cairo_color_set_alpha (&empty_color, 0.); @@ -1391,10 +1383,10 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, CAIRO_FORMAT_A8, gstate->clip.width, gstate->clip.height, - &empty_color); + &empty_color); if (intermediate == NULL) { status = CAIRO_STATUS_NO_MEMORY; - goto BAIL1; + goto BAIL0; } /* Ugh. The cairo_composite/(Render) interface doesn't allow @@ -1416,8 +1408,16 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, t->right.p2.y -= yoff; } + _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&pattern, 1.0); + + _cairo_traps_extents (traps, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + goto BAIL1; + status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD, - white, intermediate, + pattern.source, intermediate, 0, 0, traps->traps, traps->num_traps); @@ -1432,9 +1432,23 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, gstate->clip.width, gstate->clip.height); if (status) goto BAIL2; + + _cairo_pattern_fini (&pattern); + + _cairo_pattern_init_copy (&pattern, src); + + extents.p1.x = _cairo_fixed_from_int (gstate->clip.x); + extents.p1.y = _cairo_fixed_from_int (gstate->clip.y); + extents.p2.x = + _cairo_fixed_from_int (gstate->clip.x + gstate->clip.width); + extents.p2.y = + _cairo_fixed_from_int (gstate->clip.y + gstate->clip.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + goto BAIL2; status = _cairo_surface_composite (operator, - src, intermediate, dst, + pattern.source, intermediate, dst, 0, 0, 0, 0, gstate->clip.x, @@ -1445,12 +1459,12 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, BAIL2: cairo_surface_destroy (intermediate); BAIL1: - cairo_surface_destroy (white); + _cairo_pattern_fini (&pattern); BAIL0: if (status) return status; - + } else { int xoff, yoff; @@ -1462,16 +1476,26 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, yoff = _cairo_fixed_to_double (traps->traps[0].left.p2.y); } + _cairo_pattern_init_copy (&pattern, src); + + _cairo_traps_extents (traps, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_surface_composite_trapezoids (gstate->operator, - src, dst, - xoff - gstate->source_offset.x, - yoff - gstate->source_offset.y, + pattern.source, dst, + xoff - pattern.source_offset.x, + yoff - pattern.source_offset.y, traps->traps, traps->num_traps); + + _cairo_pattern_fini (&pattern); + if (status) return status; } - + return CAIRO_STATUS_SUCCESS; } @@ -1480,11 +1504,6 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) { cairo_status_t status; cairo_traps_t traps; - cairo_matrix_t user_to_source, device_to_source; - - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; _cairo_traps_init (&traps); @@ -1494,21 +1513,11 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) return status; } - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, &user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, &user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); - - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, &user_to_source); + gstate->pattern, + gstate->operator, + gstate->surface, + &traps); _cairo_traps_fini (&traps); @@ -1535,7 +1544,7 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, goto BAIL; *inside_ret = _cairo_traps_contain (&traps, x, y); - + BAIL: _cairo_traps_fini (&traps); @@ -1560,6 +1569,67 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate) return _cairo_surface_show_page (gstate->surface); } +cairo_status_t +_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_status_t status; + cairo_traps_t traps; + cairo_box_t extents; + + _cairo_traps_init (&traps); + + status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps); + if (status) + goto BAIL; + + _cairo_traps_extents (&traps, &extents); + + *x1 = _cairo_fixed_to_double (extents.p1.x); + *y1 = _cairo_fixed_to_double (extents.p1.y); + *x2 = _cairo_fixed_to_double (extents.p2.x); + *y2 = _cairo_fixed_to_double (extents.p2.y); + + cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); + cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + +BAIL: + _cairo_traps_fini (&traps); + + return status; +} + +cairo_status_t +_cairo_gstate_fill_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_status_t status; + cairo_traps_t traps; + cairo_box_t extents; + + _cairo_traps_init (&traps); + + status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); + if (status) + goto BAIL; + + _cairo_traps_extents (&traps, &extents); + + *x1 = _cairo_fixed_to_double (extents.p1.x); + *y1 = _cairo_fixed_to_double (extents.p1.y); + *x2 = _cairo_fixed_to_double (extents.p2.x); + *y2 = _cairo_fixed_to_double (extents.p2.y); + + cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); + cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + +BAIL: + _cairo_traps_fini (&traps); + + return status; +} cairo_status_t _cairo_gstate_init_clip (cairo_gstate_t *gstate) @@ -1625,7 +1695,7 @@ cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate) { cairo_status_t status; - cairo_surface_t *alpha_one; + cairo_pattern_t pattern; cairo_traps_t traps; cairo_color_t white_color; pixman_box16_t box; @@ -1668,12 +1738,16 @@ _cairo_gstate_clip (cairo_gstate_t *gstate) } pixman_region_destroy (rect); } - - _cairo_surface_set_clip_region (gstate->surface, - gstate->clip.region); + + if (!status) + status = _cairo_surface_set_clip_region (gstate->surface, + gstate->clip.region); + } + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + _cairo_traps_fini (&traps); + return status; } - _cairo_traps_fini (&traps); - return status; } /* Otherwise represent the clip as a mask surface. */ @@ -1682,39 +1756,35 @@ _cairo_gstate_clip (cairo_gstate_t *gstate) if (gstate->clip.surface == NULL) { double x1, y1, x2, y2; - _cairo_path_bounds (&gstate->path, - &x1, &y1, &x2, &y2); - gstate->clip.x = floor (x1); - gstate->clip.y = floor (y1); - gstate->clip.width = ceil (x2 - gstate->clip.x); - gstate->clip.height = ceil (y2 - gstate->clip.y); - gstate->clip.surface = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_A8, - gstate->clip.width, - gstate->clip.height, - &white_color); - if (gstate->clip.surface == NULL) + _cairo_path_bounds (&gstate->path, + &x1, &y1, &x2, &y2); + gstate->clip.x = floor (x1); + gstate->clip.y = floor (y1); + gstate->clip.width = ceil (x2 - gstate->clip.x); + gstate->clip.height = ceil (y2 - gstate->clip.y); + gstate->clip.surface = + _cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_A8, + gstate->clip.width, + gstate->clip.height, + &white_color); + if (gstate->clip.surface == NULL) return CAIRO_STATUS_NO_MEMORY; } - alpha_one = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - 1, 1, - &white_color); - if (alpha_one == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_repeat (alpha_one, 1); - + _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&pattern, 1.0); + _cairo_gstate_clip_and_composite_trapezoids (gstate, - alpha_one, + &pattern, CAIRO_OPERATOR_IN, gstate->clip.surface, &traps); - + + _cairo_pattern_fini (&pattern); + _cairo_traps_fini (&traps); - cairo_surface_destroy (alpha_one); - return status; } @@ -1725,27 +1795,12 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, int height) { cairo_status_t status; - cairo_surface_t *mask; cairo_matrix_t user_to_image, image_to_user; cairo_matrix_t image_to_device, device_to_image; double device_x, device_y; double device_width, device_height; - cairo_color_t alpha_color; - - if (gstate->alpha != 1.0) { - _cairo_color_init (&alpha_color); - _cairo_color_set_alpha (&alpha_color, gstate->alpha); - mask = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_A8, - 1, 1, - &alpha_color); - if (mask == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_repeat (mask, 1); - } else { - mask = NULL; - } + cairo_pattern_t pattern; + cairo_box_t extents; cairo_surface_get_matrix (surface, &user_to_image); cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image); @@ -1761,25 +1816,40 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, _cairo_matrix_transform_bounding_box (&image_to_device, &device_x, &device_y, &device_width, &device_height); + + _cairo_pattern_init (&pattern); + + if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) || + (gstate->alpha != 1.0)) { + /* I'm allowing any type of pattern for the mask right now. + Maybe this is bad. Will allow for some cool effects though. */ + _cairo_pattern_init_copy (&pattern, gstate->pattern); + extents.p1.x = _cairo_fixed_from_double (device_x); + extents.p1.y = _cairo_fixed_from_double (device_y); + extents.p2.x = _cairo_fixed_from_double (device_x + device_width); + extents.p2.y = _cairo_fixed_from_double (device_y + device_height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + } /* XXX: The rendered size is sometimes 1 or 2 pixels short from what I expect. Need to fix this. */ status = _cairo_surface_composite (gstate->operator, - surface, mask, gstate->surface, + surface, pattern.source, gstate->surface, device_x, device_y, 0, 0, device_x, device_y, device_width, device_height); - - if (mask) - cairo_surface_destroy (mask); - if (status) - return status; + _cairo_pattern_fini (&pattern); /* restore the matrix originally in the surface */ cairo_surface_set_matrix (surface, &user_to_image); + + if (status) + return status; return CAIRO_STATUS_SUCCESS; } @@ -1908,39 +1978,6 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, return status; } - -static cairo_status_t -setup_text_rendering_context(cairo_gstate_t *gstate, - cairo_matrix_t *user_to_source) -{ - cairo_status_t status; - cairo_matrix_t device_to_source; - - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; - - /* XXX: This same source matrix manipulation code shows up in - about 3 or 4 places. We should move that into a shared function - or two. */ - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - return CAIRO_STATUS_SUCCESS; -} - -static void -restore_text_rendering_context(cairo_gstate_t *gstate, - cairo_matrix_t *user_to_source) -{ - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, user_to_source); -} - - cairo_status_t _cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8) @@ -1948,8 +1985,10 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, cairo_status_t status; cairo_point_t point; double x, y; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; + cairo_pattern_t pattern; + cairo_text_extents_t text_extents; + cairo_box_t extents; status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { @@ -1960,35 +1999,47 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, x = _cairo_fixed_to_double (point.x); y = _cairo_fixed_to_double (point.y); } - - status = setup_text_rendering_context (gstate, &user_to_source); - if (status) - return status; - + cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_pattern_init_copy (&pattern, gstate->pattern); + + status = _cairo_gstate_text_extents (gstate, utf8, &text_extents); + if (status) + return status; + + extents.p1.x = _cairo_fixed_from_double (x); + extents.p1.y = _cairo_fixed_from_double (y); + extents.p2.x = _cairo_fixed_from_double (x + text_extents.width); + extents.p2.y = _cairo_fixed_from_double (y + text_extents.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_font_show_text (gstate->font, - gstate->operator, gstate->source, + gstate->operator, pattern.source, gstate->surface, x, y, utf8); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); + + _cairo_pattern_fini (&pattern); return status; } - cairo_status_t _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, int num_glyphs) { cairo_status_t status; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; int i; cairo_glyph_t *transformed_glyphs = NULL; + cairo_pattern_t pattern; + cairo_text_extents_t text_extents; + cairo_box_t extents; transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -2002,20 +2053,33 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - status = setup_text_rendering_context (gstate, &user_to_source); - if (status) - return status; - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_pattern_init_copy (&pattern, gstate->pattern); + _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs, + &text_extents); + if (status) + return status; + + extents.p1.x = _cairo_fixed_from_double (transformed_glyphs[0].x); + extents.p1.y = _cairo_fixed_from_double (transformed_glyphs[0].y); + extents.p2.x = _cairo_fixed_from_double (transformed_glyphs[0].x + + text_extents.width); + extents.p2.y = _cairo_fixed_from_double (transformed_glyphs[0].y + + text_extents.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_font_show_glyphs (gstate->font, - gstate->operator, gstate->source, + gstate->operator, pattern.source, gstate->surface, transformed_glyphs, num_glyphs); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); + + _cairo_pattern_fini (&pattern); free (transformed_glyphs); @@ -2028,15 +2092,10 @@ _cairo_gstate_text_path (cairo_gstate_t *gstate, const unsigned char *utf8) { cairo_status_t status; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; cairo_point_t point; double x, y; - status = setup_text_rendering_context (gstate, &user_to_source); - if (status) - return status; - status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { x = 0; @@ -2056,7 +2115,6 @@ _cairo_gstate_text_path (cairo_gstate_t *gstate, &gstate->path); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); return status; } @@ -2070,7 +2128,6 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_status_t status; int i; cairo_glyph_t *transformed_glyphs = NULL; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); @@ -2085,10 +2142,6 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - status = setup_text_rendering_context (gstate, &user_to_source); - if (status) - return status; - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); @@ -2097,8 +2150,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, &gstate->path); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); - + free (transformed_glyphs); return status; } diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index 86b4fdc2..a11a07ee 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -467,6 +467,26 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +static cairo_status_t +_cairo_image_abstract_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_image_surface_t *image; + + /* Fall back to general pattern creation for surface patterns. */ + if (pattern->type == CAIRO_PATTERN_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + image = _cairo_pattern_get_image (pattern, box); + if (image) { + pattern->source = &image->base; + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; +} + static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, _cairo_image_abstract_surface_destroy, @@ -481,5 +501,6 @@ static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_composite_trapezoids, _cairo_image_surface_copy_page, _cairo_image_surface_show_page, - _cairo_image_abstract_surface_set_clip_region + _cairo_image_abstract_surface_set_clip_region, + _cairo_image_abstract_surface_create_pattern }; diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c index 82364556..98d34e44 100644 --- a/src/cairo-ps-surface.c +++ b/src/cairo-ps-surface.c @@ -403,6 +403,13 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface, return _cairo_image_surface_set_clip_region (surface->image, region); } +static cairo_int_status_t +_cairo_ps_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_create_similar, @@ -418,5 +425,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_composite_trapezoids, _cairo_ps_surface_copy_page, _cairo_ps_surface_show_page, - _cairo_ps_surface_set_clip_region + _cairo_ps_surface_set_clip_region, + _cairo_ps_surface_create_pattern }; diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 34143f5c..91ab8aba 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -377,3 +377,111 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *reg { return surface->backend->set_clip_region (surface, region); } + +cairo_status_t +_cairo_surface_create_pattern (cairo_surface_t *surface, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_int_status_t status; + + status = surface->backend->create_pattern (surface, pattern, box); + + /* The backend cannot accelerate this pattern, lets create an + unaccelerated source instead. */ + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + + status = CAIRO_STATUS_SUCCESS; + switch (pattern->type) { + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_image_surface_t *image; + + image = _cairo_pattern_get_image (pattern, box); + if (image) { + pattern->source = &image->base; + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; + + } break; + case CAIRO_PATTERN_SOLID: + pattern->source = + _cairo_surface_create_similar_solid (surface, + CAIRO_FORMAT_ARGB32, + 1, 1, + &pattern->color); + if (pattern->source) { + cairo_surface_set_repeat (pattern->source, 1); + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; + break; + case CAIRO_PATTERN_SURFACE: + status = CAIRO_INT_STATUS_UNSUPPORTED; + + /* handle pattern opacity */ + if (pattern->color.alpha != 1.0) { + int width = ceil (_cairo_fixed_to_double (box->p2.x) - + _cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y) - + _cairo_fixed_to_double (box->p1.y)); + cairo_pattern_t alpha; + + pattern->source = + cairo_surface_create_similar (surface, + CAIRO_FORMAT_ARGB32, + width, height); + if (pattern->source) { + _cairo_pattern_init_solid (&alpha, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&alpha, pattern->color.alpha); + + status = _cairo_surface_create_pattern (pattern->source, + &alpha, box); + + if (status == CAIRO_STATUS_SUCCESS) { + int save_repeat = pattern->u.surface.surface->repeat; + + if (pattern->extend == CAIRO_EXTEND_REPEAT || + pattern->u.surface.surface->repeat == 1) + cairo_surface_set_repeat (pattern->u.surface.surface, 1); + else + cairo_surface_set_repeat (pattern->u.surface.surface, 0); + + status = + _cairo_surface_composite (CAIRO_OPERATOR_OVER, + pattern->u.surface.surface, + alpha.source, + pattern->source, + 0, 0, 0, 0, 0, 0, + width, height); + + cairo_surface_set_repeat (pattern->u.surface.surface, + save_repeat); + + if (status == CAIRO_STATUS_SUCCESS) { + _cairo_pattern_add_source_offset (pattern, + _cairo_fixed_to_double (box->p1.x), + _cairo_fixed_to_double (box->p1.y)); + } else + cairo_surface_destroy (pattern->source); + } + + _cairo_pattern_fini (&alpha); + } + } + + if (status != CAIRO_STATUS_SUCCESS) { + pattern->source = pattern->u.surface.surface; + cairo_surface_reference (pattern->u.surface.surface); + + return CAIRO_STATUS_SUCCESS; + } + break; + } + } + + return status; +} diff --git a/src/cairo-traps.c b/src/cairo-traps.c index e786ad42..9b44d38e 100644 --- a/src/cairo-traps.c +++ b/src/cairo-traps.c @@ -608,3 +608,40 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y) return 0; } + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +static void +_cairo_trap_extents (cairo_trapezoid_t *t, cairo_box_t *extents) +{ + cairo_fixed_t x; + + if (t->top < extents->p1.y) + extents->p1.y = t->top; + + if (t->bottom > extents->p2.y) + extents->p2.y = t->bottom; + + x = MIN (_compute_x (&t->left, t->top), + _compute_x (&t->left, t->bottom)); + if (x < extents->p1.x) + extents->p1.x = x; + + x = MAX (_compute_x (&t->right, t->top), + _compute_x (&t->right, t->bottom)); + if (x > extents->p2.x) + extents->p2.x = x; +} + +void +_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; + + for (i = 0; i < traps->num_traps; i++) + _cairo_trap_extents (&traps->traps[i], extents); +} diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index e4c9307f..ea1f72e1 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -712,6 +712,14 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_int_status_t +_cairo_xcb_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const struct cairo_surface_backend cairo_xcb_surface_backend = { _cairo_xcb_surface_create_similar, _cairo_xcb_surface_destroy, @@ -726,7 +734,8 @@ static const struct cairo_surface_backend cairo_xcb_surface_backend = { _cairo_xcb_surface_composite_trapezoids, _cairo_xcb_surface_copy_page, _cairo_xcb_surface_show_page, - _cairo_xcb_surface_set_clip_region + _cairo_xcb_surface_set_clip_region, + _cairo_xcb_surface_create_pattern }; static void diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index c7efefba..19dfde50 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -455,7 +455,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, cairo_xlib_surface_t *mask = (cairo_xlib_surface_t *) generic_mask; cairo_xlib_surface_t *src_clone = NULL; cairo_xlib_surface_t *mask_clone = NULL; - + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -619,6 +619,14 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_xlib_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, _cairo_xlib_surface_destroy, @@ -633,7 +641,8 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_composite_trapezoids, _cairo_xlib_surface_copy_page, _cairo_xlib_surface_show_page, - _cairo_xlib_surface_set_clip_region + _cairo_xlib_surface_set_clip_region, + _cairo_xlib_surface_create_pattern }; cairo_surface_t * @@ -692,7 +701,7 @@ cairo_xlib_surface_create (Display *dpy, 0, NULL); else surface->picture = 0; - + return (cairo_surface_t *) surface; } DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create); diff --git a/src/cairo.c b/src/cairo.c index d4bdc165..d173ca76 100644 --- a/src/cairo.c +++ b/src/cairo.c @@ -29,9 +29,6 @@ #define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ -static void -_cairo_restrict_value (double *value, double min, double max); - cairo_t * cairo_create (void) { @@ -220,7 +217,7 @@ cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue) } void -cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern) +cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern) { if (cr->status) return; @@ -228,6 +225,12 @@ cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern) cr->status = _cairo_gstate_set_pattern (cr->gstate, pattern); } +cairo_pattern_t * +cairo_current_pattern (cairo_t *cr) +{ + return _cairo_gstate_current_pattern (cr->gstate); +} + void cairo_set_tolerance (cairo_t *cr, double tolerance) { @@ -636,6 +639,26 @@ cairo_in_fill (cairo_t *cr, double x, double y) } void +cairo_stroke_extents (cairo_t *cr, + double *x1, double *y1, double *x2, double *y2) +{ + if (cr->status) + return; + + cr->status = _cairo_gstate_stroke_extents (cr->gstate, x1, y1, x2, y2); +} + +void +cairo_fill_extents (cairo_t *cr, + double *x1, double *y1, double *x2, double *y2) +{ + if (cr->status) + return; + + cr->status = _cairo_gstate_fill_extents (cr->gstate, x1, y1, x2, y2); +} + +void cairo_init_clip (cairo_t *cr) { if (cr->status) @@ -942,7 +965,7 @@ cairo_status_string (cairo_t *cr) } DEPRECATE (cairo_get_status_string, cairo_status_string); -static void +void _cairo_restrict_value (double *value, double min, double max) { if (*value < min) diff --git a/src/cairo.h b/src/cairo.h index 77b23844..ab3c80e8 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -36,6 +36,7 @@ typedef struct cairo cairo_t; typedef struct cairo_surface cairo_surface_t; typedef struct cairo_matrix cairo_matrix_t; +typedef struct cairo_pattern cairo_pattern_t; #ifdef __cplusplus extern "C" { @@ -181,10 +182,10 @@ void cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue); void -cairo_set_alpha (cairo_t *cr, double alpha); +cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern); void -cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern); +cairo_set_alpha (cairo_t *cr, double alpha); /* XXX: Currently, the tolerance value is specified by the user in terms of device-space units. If I'm not mistaken, this is the only @@ -353,6 +354,17 @@ cairo_in_stroke (cairo_t *cr, double x, double y); int cairo_in_fill (cairo_t *cr, double x, double y); +/* Rectangular extents */ +void +cairo_stroke_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + +void +cairo_fill_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + /* Clipping */ void cairo_init_clip (cairo_t *cr); @@ -505,6 +517,8 @@ cairo_current_operator (cairo_t *cr); void cairo_current_rgb_color (cairo_t *cr, double *red, double *green, double *blue); +cairo_pattern_t * +cairo_current_pattern (cairo_t *cr); double cairo_current_alpha (cairo_t *cr); @@ -640,14 +654,15 @@ cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix); cairo_status_t cairo_surface_get_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix); -typedef enum cairo_filter { +typedef enum { CAIRO_FILTER_FAST, CAIRO_FILTER_GOOD, CAIRO_FILTER_BEST, CAIRO_FILTER_NEAREST, - CAIRO_FILTER_BILINEAR + CAIRO_FILTER_BILINEAR, + CAIRO_FILTER_GAUSSIAN } cairo_filter_t; - + /* XXX: Rework this as a cairo function: cairo_set_pattern_filter */ cairo_status_t cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter); @@ -669,6 +684,54 @@ cairo_image_surface_create_for_data (char *data, int height, int stride); +/* Pattern creation functions */ +cairo_pattern_t * +cairo_pattern_create_for_surface (cairo_surface_t *surface); + +cairo_pattern_t * +cairo_pattern_create_linear (double x0, double y0, + double x1, double y1); + +cairo_pattern_t * +cairo_pattern_create_radial (double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1); + +void +cairo_pattern_reference (cairo_pattern_t *pattern); + +void +cairo_pattern_destroy (cairo_pattern_t *pattern); + +cairo_status_t +cairo_pattern_add_color_stop (cairo_pattern_t *pattern, + double offset, + double red, double green, double blue, + double alpha); + +cairo_status_t +cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix); + +cairo_status_t +cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix); + +typedef enum { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT +} cairo_extend_t; + +cairo_status_t +cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend); + +cairo_extend_t +cairo_pattern_get_extend (cairo_pattern_t *pattern); + +cairo_status_t +cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter); + +cairo_filter_t +cairo_pattern_get_filter (cairo_pattern_t *pattern); + #ifdef CAIRO_HAS_PS_SURFACE /* PS-surface functions */ @@ -707,7 +770,7 @@ cairo_xlib_surface_create (Display *dpy, Visual *visual, cairo_format_t format, Colormap colormap); - + /* XXX: This has been proposed cairo_status_t cairo_xlib_surface_set_size (cairo_surface_t *surface, int width, int height); diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c index 3975938a..77cf59b0 100644 --- a/src/cairo_ft_font.c +++ b/src/cairo_ft_font.c @@ -477,6 +477,7 @@ _cairo_ft_font_show_glyphs (void *abstract_font, cairo_ft_font_t *ft = NULL; FT_GlyphSlot glyphslot; cairo_surface_t *mask = NULL; + cairo_point_double_t origin; double x, y; int width, height, stride; @@ -504,7 +505,12 @@ _cairo_ft_font_show_glyphs (void *abstract_font, bitmap = glyphslot->bitmap.buffer; x = glyphs[i].x; - y = glyphs[i].y; + y = glyphs[i].y; + + if (i == 0) { + origin.x = x; + origin.y = y; + } /* X gets upset with zero-sized images (such as whitespace) */ if (width * height == 0) @@ -547,11 +553,14 @@ _cairo_ft_font_show_glyphs (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; } - status = _cairo_surface_composite (operator, source, mask, surface, - 0, 0, 0, 0, - x + glyphslot->bitmap_left, - y - glyphslot->bitmap_top, - (double)width, (double)height); + status = + _cairo_surface_composite (operator, source, mask, surface, + -origin.x + x + glyphslot->bitmap_left, + -origin.y + y - glyphslot->bitmap_top, + 0, 0, + x + glyphslot->bitmap_left, + y - glyphslot->bitmap_top, + (double) width, (double) height); cairo_surface_destroy (mask); if (bitmap != glyphslot->bitmap.buffer) diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c index f780cc94..ed8c8a1a 100644 --- a/src/cairo_gstate.c +++ b/src/cairo_gstate.c @@ -31,11 +31,8 @@ #include "cairoint.h" static cairo_status_t -_cairo_gstate_ensure_source (cairo_gstate_t *gstate); - -static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_surface_t *src, + cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, cairo_traps_t *traps); @@ -76,16 +73,14 @@ _cairo_gstate_init (cairo_gstate_t *gstate) CAIRO_FONT_WEIGHT_DEFAULT); gstate->surface = NULL; - gstate->source = NULL; - gstate->source_offset.x = 0.0; - gstate->source_offset.y = 0.0; - gstate->source_is_solid = 1; gstate->clip.region = NULL; gstate->clip.surface = NULL; - + + gstate->pattern = _cairo_pattern_create_solid (1.0, 1.0, 1.0); + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; gstate->alpha = 1.0; - _cairo_color_init (&gstate->color); gstate->pixels_per_inch = CAIRO_GSTATE_PIXELS_PER_INCH_DEFAULT; _cairo_gstate_default_matrix (gstate); @@ -131,8 +126,9 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) } cairo_surface_reference (gstate->surface); - cairo_surface_reference (gstate->source); cairo_surface_reference (gstate->clip.surface); + + cairo_pattern_reference (gstate->pattern); status = _cairo_path_init_copy (&gstate->path, &other->path); if (status) @@ -164,11 +160,6 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) cairo_surface_destroy (gstate->surface); gstate->surface = NULL; - if (gstate->source) - cairo_surface_destroy (gstate->source); - gstate->source = NULL; - gstate->source_is_solid = 1; - if (gstate->clip.surface) cairo_surface_destroy (gstate->clip.surface); gstate->clip.surface = NULL; @@ -177,7 +168,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate) pixman_region_destroy (gstate->clip.region); gstate->clip.region = NULL; - _cairo_color_fini (&gstate->color); + cairo_pattern_destroy (gstate->pattern); _cairo_matrix_fini (&gstate->ctm); _cairo_matrix_fini (&gstate->ctm_inverse); @@ -362,22 +353,37 @@ _cairo_gstate_current_target_surface (cairo_gstate_t *gstate) } cairo_status_t -_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern) +_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern) { - cairo_surface_destroy (gstate->source); - - gstate->source = pattern; - gstate->source_is_solid = 0; + if (pattern == NULL) + return CAIRO_STATUS_NULL_POINTER; - cairo_surface_reference (gstate->source); + if (gstate->pattern) + cairo_pattern_destroy (gstate->pattern); + + gstate->pattern = pattern; + cairo_pattern_reference (pattern); _cairo_gstate_current_point (gstate, - &gstate->source_offset.x, - &gstate->source_offset.y); - + &gstate->pattern_offset.x, + &gstate->pattern_offset.y); + return CAIRO_STATUS_SUCCESS; } +cairo_pattern_t * +_cairo_gstate_current_pattern (cairo_gstate_t *gstate) +{ + if (gstate == NULL) + return NULL; + +/* XXX: Do we want this? + cairo_pattern_reference (gstate->pattern); +*/ + + return gstate->pattern; +} + cairo_status_t _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator) { @@ -395,25 +401,19 @@ _cairo_gstate_current_operator (cairo_gstate_t *gstate) cairo_status_t _cairo_gstate_set_rgb_color (cairo_gstate_t *gstate, double red, double green, double blue) { - _cairo_color_set_rgb (&gstate->color, red, green, blue); - - if (gstate->source) - cairo_surface_destroy (gstate->source); - - gstate->source = NULL; - gstate->source_offset.x = 0; - gstate->source_offset.y = 0; - gstate->source_is_solid = 1; - + cairo_pattern_destroy (gstate->pattern); + + gstate->pattern = _cairo_pattern_create_solid (red, green, blue); + gstate->pattern_offset.x = 0.0; + gstate->pattern_offset.y = 0.0; + return CAIRO_STATUS_SUCCESS; } cairo_status_t _cairo_gstate_current_rgb_color (cairo_gstate_t *gstate, double *red, double *green, double *blue) { - _cairo_color_get_rgb (&gstate->color, red, green, blue); - - return CAIRO_STATUS_SUCCESS; + return _cairo_pattern_get_rgb (gstate->pattern, red, green, blue); } cairo_status_t @@ -430,20 +430,11 @@ _cairo_gstate_current_tolerance (cairo_gstate_t *gstate) return gstate->tolerance; } -/* XXX: Need to fix this so it does the right thing after set_pattern. */ cairo_status_t _cairo_gstate_set_alpha (cairo_gstate_t *gstate, double alpha) { gstate->alpha = alpha; - _cairo_color_set_alpha (&gstate->color, alpha); - - cairo_surface_destroy (gstate->source); - - gstate->source = NULL; - gstate->source_offset.x = 0; - gstate->source_offset.y = 0; - return CAIRO_STATUS_SUCCESS; } @@ -1259,24 +1250,49 @@ _cairo_gstate_interpret_path (cairo_gstate_t *gstate, &gpi); } +/* This function modifies the pattern and the state of the pattern surface it + may contain. The pattern surface will be restored to its orignal state + when the pattern is destroyed. The appropriate way is to pass a copy of + the original pattern to this function just before the pattern should be + used and destroy the copy when done. */ static cairo_status_t -_cairo_gstate_ensure_source (cairo_gstate_t *gstate) +_cairo_gstate_create_pattern (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + cairo_box_t *extents) { - if (gstate->source) - return CAIRO_STATUS_SUCCESS; - - if (gstate->surface == NULL) + cairo_int_status_t status; + + if (gstate->surface == NULL) { + _cairo_pattern_fini (pattern); return CAIRO_STATUS_NO_TARGET_SURFACE; + } - gstate->source = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_ARGB32, - 1, 1, - &gstate->color); - if (gstate->source == NULL) - return CAIRO_STATUS_NO_MEMORY; + if (pattern->type == CAIRO_PATTERN_LINEAR || + pattern->type == CAIRO_PATTERN_RADIAL) { + if (pattern->n_stops < 2) { + pattern->type = CAIRO_PATTERN_SOLID; + + if (pattern->n_stops) + pattern->color = pattern->stops->color; + } + } + + _cairo_pattern_set_alpha (pattern, gstate->alpha); + _cairo_pattern_transform (pattern, &gstate->ctm, &gstate->ctm_inverse); - cairo_surface_set_repeat (gstate->source, 1); + status = _cairo_surface_create_pattern (gstate->surface, pattern, extents); + if (status) { + _cairo_pattern_fini (pattern); + return status; + } + 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; } @@ -1285,15 +1301,10 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate) { cairo_status_t status; cairo_traps_t traps; - cairo_matrix_t user_to_source, device_to_source; if (gstate->line_width <= 0.0) return CAIRO_STATUS_SUCCESS; - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; - _cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate); _cairo_traps_init (&traps); @@ -1304,21 +1315,11 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate) return status; } - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, &user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, &user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); - - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, &user_to_source); + gstate->pattern, + gstate->operator, + gstate->surface, + &traps); _cairo_traps_fini (&traps); @@ -1357,12 +1358,14 @@ BAIL: /* Warning: This call modifies the coordinates of traps */ static cairo_status_t _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, - cairo_surface_t *src, + cairo_pattern_t *src, cairo_operator_t operator, cairo_surface_t *dst, cairo_traps_t *traps) { cairo_status_t status; + cairo_pattern_t pattern; + cairo_box_t extents; if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; @@ -1371,19 +1374,8 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, cairo_fixed_t xoff, yoff; cairo_trapezoid_t *t; int i; - - cairo_surface_t *white, *intermediate; - cairo_color_t white_color, empty_color; - - _cairo_color_init (&white_color); - white = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - 1, 1, - &white_color); - if (white == NULL) { - status = CAIRO_STATUS_NO_MEMORY; - goto BAIL0; - } - cairo_surface_set_repeat (white, 1); + cairo_surface_t *intermediate; + cairo_color_t empty_color; _cairo_color_init (&empty_color); _cairo_color_set_alpha (&empty_color, 0.); @@ -1391,10 +1383,10 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, CAIRO_FORMAT_A8, gstate->clip.width, gstate->clip.height, - &empty_color); + &empty_color); if (intermediate == NULL) { status = CAIRO_STATUS_NO_MEMORY; - goto BAIL1; + goto BAIL0; } /* Ugh. The cairo_composite/(Render) interface doesn't allow @@ -1416,8 +1408,16 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, t->right.p2.y -= yoff; } + _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&pattern, 1.0); + + _cairo_traps_extents (traps, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + goto BAIL1; + status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_ADD, - white, intermediate, + pattern.source, intermediate, 0, 0, traps->traps, traps->num_traps); @@ -1432,9 +1432,23 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, gstate->clip.width, gstate->clip.height); if (status) goto BAIL2; + + _cairo_pattern_fini (&pattern); + + _cairo_pattern_init_copy (&pattern, src); + + extents.p1.x = _cairo_fixed_from_int (gstate->clip.x); + extents.p1.y = _cairo_fixed_from_int (gstate->clip.y); + extents.p2.x = + _cairo_fixed_from_int (gstate->clip.x + gstate->clip.width); + extents.p2.y = + _cairo_fixed_from_int (gstate->clip.y + gstate->clip.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + goto BAIL2; status = _cairo_surface_composite (operator, - src, intermediate, dst, + pattern.source, intermediate, dst, 0, 0, 0, 0, gstate->clip.x, @@ -1445,12 +1459,12 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, BAIL2: cairo_surface_destroy (intermediate); BAIL1: - cairo_surface_destroy (white); + _cairo_pattern_fini (&pattern); BAIL0: if (status) return status; - + } else { int xoff, yoff; @@ -1462,16 +1476,26 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate, yoff = _cairo_fixed_to_double (traps->traps[0].left.p2.y); } + _cairo_pattern_init_copy (&pattern, src); + + _cairo_traps_extents (traps, &extents); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_surface_composite_trapezoids (gstate->operator, - src, dst, - xoff - gstate->source_offset.x, - yoff - gstate->source_offset.y, + pattern.source, dst, + xoff - pattern.source_offset.x, + yoff - pattern.source_offset.y, traps->traps, traps->num_traps); + + _cairo_pattern_fini (&pattern); + if (status) return status; } - + return CAIRO_STATUS_SUCCESS; } @@ -1480,11 +1504,6 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) { cairo_status_t status; cairo_traps_t traps; - cairo_matrix_t user_to_source, device_to_source; - - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; _cairo_traps_init (&traps); @@ -1494,21 +1513,11 @@ _cairo_gstate_fill (cairo_gstate_t *gstate) return status; } - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, &user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, &user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - _cairo_gstate_clip_and_composite_trapezoids (gstate, - gstate->source, - gstate->operator, - gstate->surface, - &traps); - - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, &user_to_source); + gstate->pattern, + gstate->operator, + gstate->surface, + &traps); _cairo_traps_fini (&traps); @@ -1535,7 +1544,7 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate, goto BAIL; *inside_ret = _cairo_traps_contain (&traps, x, y); - + BAIL: _cairo_traps_fini (&traps); @@ -1560,6 +1569,67 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate) return _cairo_surface_show_page (gstate->surface); } +cairo_status_t +_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_status_t status; + cairo_traps_t traps; + cairo_box_t extents; + + _cairo_traps_init (&traps); + + status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps); + if (status) + goto BAIL; + + _cairo_traps_extents (&traps, &extents); + + *x1 = _cairo_fixed_to_double (extents.p1.x); + *y1 = _cairo_fixed_to_double (extents.p1.y); + *x2 = _cairo_fixed_to_double (extents.p2.x); + *y2 = _cairo_fixed_to_double (extents.p2.y); + + cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); + cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + +BAIL: + _cairo_traps_fini (&traps); + + return status; +} + +cairo_status_t +_cairo_gstate_fill_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_status_t status; + cairo_traps_t traps; + cairo_box_t extents; + + _cairo_traps_init (&traps); + + status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps); + if (status) + goto BAIL; + + _cairo_traps_extents (&traps, &extents); + + *x1 = _cairo_fixed_to_double (extents.p1.x); + *y1 = _cairo_fixed_to_double (extents.p1.y); + *x2 = _cairo_fixed_to_double (extents.p2.x); + *y2 = _cairo_fixed_to_double (extents.p2.y); + + cairo_matrix_transform_point (&gstate->ctm_inverse, x1, y1); + cairo_matrix_transform_point (&gstate->ctm_inverse, x2, y2); + +BAIL: + _cairo_traps_fini (&traps); + + return status; +} cairo_status_t _cairo_gstate_init_clip (cairo_gstate_t *gstate) @@ -1625,7 +1695,7 @@ cairo_status_t _cairo_gstate_clip (cairo_gstate_t *gstate) { cairo_status_t status; - cairo_surface_t *alpha_one; + cairo_pattern_t pattern; cairo_traps_t traps; cairo_color_t white_color; pixman_box16_t box; @@ -1668,12 +1738,16 @@ _cairo_gstate_clip (cairo_gstate_t *gstate) } pixman_region_destroy (rect); } - - _cairo_surface_set_clip_region (gstate->surface, - gstate->clip.region); + + if (!status) + status = _cairo_surface_set_clip_region (gstate->surface, + gstate->clip.region); + } + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + _cairo_traps_fini (&traps); + return status; } - _cairo_traps_fini (&traps); - return status; } /* Otherwise represent the clip as a mask surface. */ @@ -1682,39 +1756,35 @@ _cairo_gstate_clip (cairo_gstate_t *gstate) if (gstate->clip.surface == NULL) { double x1, y1, x2, y2; - _cairo_path_bounds (&gstate->path, - &x1, &y1, &x2, &y2); - gstate->clip.x = floor (x1); - gstate->clip.y = floor (y1); - gstate->clip.width = ceil (x2 - gstate->clip.x); - gstate->clip.height = ceil (y2 - gstate->clip.y); - gstate->clip.surface = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_A8, - gstate->clip.width, - gstate->clip.height, - &white_color); - if (gstate->clip.surface == NULL) + _cairo_path_bounds (&gstate->path, + &x1, &y1, &x2, &y2); + gstate->clip.x = floor (x1); + gstate->clip.y = floor (y1); + gstate->clip.width = ceil (x2 - gstate->clip.x); + gstate->clip.height = ceil (y2 - gstate->clip.y); + gstate->clip.surface = + _cairo_surface_create_similar_solid (gstate->surface, + CAIRO_FORMAT_A8, + gstate->clip.width, + gstate->clip.height, + &white_color); + if (gstate->clip.surface == NULL) return CAIRO_STATUS_NO_MEMORY; } - alpha_one = _cairo_surface_create_similar_solid (gstate->surface, CAIRO_FORMAT_A8, - 1, 1, - &white_color); - if (alpha_one == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_repeat (alpha_one, 1); - + _cairo_pattern_init_solid (&pattern, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&pattern, 1.0); + _cairo_gstate_clip_and_composite_trapezoids (gstate, - alpha_one, + &pattern, CAIRO_OPERATOR_IN, gstate->clip.surface, &traps); - + + _cairo_pattern_fini (&pattern); + _cairo_traps_fini (&traps); - cairo_surface_destroy (alpha_one); - return status; } @@ -1725,27 +1795,12 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, int height) { cairo_status_t status; - cairo_surface_t *mask; cairo_matrix_t user_to_image, image_to_user; cairo_matrix_t image_to_device, device_to_image; double device_x, device_y; double device_width, device_height; - cairo_color_t alpha_color; - - if (gstate->alpha != 1.0) { - _cairo_color_init (&alpha_color); - _cairo_color_set_alpha (&alpha_color, gstate->alpha); - mask = _cairo_surface_create_similar_solid (gstate->surface, - CAIRO_FORMAT_A8, - 1, 1, - &alpha_color); - if (mask == NULL) - return CAIRO_STATUS_NO_MEMORY; - - cairo_surface_set_repeat (mask, 1); - } else { - mask = NULL; - } + cairo_pattern_t pattern; + cairo_box_t extents; cairo_surface_get_matrix (surface, &user_to_image); cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image); @@ -1761,25 +1816,40 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate, _cairo_matrix_transform_bounding_box (&image_to_device, &device_x, &device_y, &device_width, &device_height); + + _cairo_pattern_init (&pattern); + + if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) || + (gstate->alpha != 1.0)) { + /* I'm allowing any type of pattern for the mask right now. + Maybe this is bad. Will allow for some cool effects though. */ + _cairo_pattern_init_copy (&pattern, gstate->pattern); + extents.p1.x = _cairo_fixed_from_double (device_x); + extents.p1.y = _cairo_fixed_from_double (device_y); + extents.p2.x = _cairo_fixed_from_double (device_x + device_width); + extents.p2.y = _cairo_fixed_from_double (device_y + device_height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + } /* XXX: The rendered size is sometimes 1 or 2 pixels short from what I expect. Need to fix this. */ status = _cairo_surface_composite (gstate->operator, - surface, mask, gstate->surface, + surface, pattern.source, gstate->surface, device_x, device_y, 0, 0, device_x, device_y, device_width, device_height); - - if (mask) - cairo_surface_destroy (mask); - if (status) - return status; + _cairo_pattern_fini (&pattern); /* restore the matrix originally in the surface */ cairo_surface_set_matrix (surface, &user_to_image); + + if (status) + return status; return CAIRO_STATUS_SUCCESS; } @@ -1908,39 +1978,6 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate, return status; } - -static cairo_status_t -setup_text_rendering_context(cairo_gstate_t *gstate, - cairo_matrix_t *user_to_source) -{ - cairo_status_t status; - cairo_matrix_t device_to_source; - - status = _cairo_gstate_ensure_source (gstate); - if (status) - return status; - - /* XXX: This same source matrix manipulation code shows up in - about 3 or 4 places. We should move that into a shared function - or two. */ - if (! gstate->source_is_solid) { - cairo_surface_get_matrix (gstate->source, user_to_source); - cairo_matrix_multiply (&device_to_source, &gstate->ctm_inverse, user_to_source); - cairo_surface_set_matrix (gstate->source, &device_to_source); - } - return CAIRO_STATUS_SUCCESS; -} - -static void -restore_text_rendering_context(cairo_gstate_t *gstate, - cairo_matrix_t *user_to_source) -{ - /* restore the matrix originally in the source surface */ - if (! gstate->source_is_solid) - cairo_surface_set_matrix (gstate->source, user_to_source); -} - - cairo_status_t _cairo_gstate_show_text (cairo_gstate_t *gstate, const unsigned char *utf8) @@ -1948,8 +1985,10 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, cairo_status_t status; cairo_point_t point; double x, y; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; + cairo_pattern_t pattern; + cairo_text_extents_t text_extents; + cairo_box_t extents; status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { @@ -1960,35 +1999,47 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate, x = _cairo_fixed_to_double (point.x); y = _cairo_fixed_to_double (point.y); } - - status = setup_text_rendering_context (gstate, &user_to_source); - if (status) - return status; - + cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_pattern_init_copy (&pattern, gstate->pattern); + + status = _cairo_gstate_text_extents (gstate, utf8, &text_extents); + if (status) + return status; + + extents.p1.x = _cairo_fixed_from_double (x); + extents.p1.y = _cairo_fixed_from_double (y); + extents.p2.x = _cairo_fixed_from_double (x + text_extents.width); + extents.p2.y = _cairo_fixed_from_double (y + text_extents.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_font_show_text (gstate->font, - gstate->operator, gstate->source, + gstate->operator, pattern.source, gstate->surface, x, y, utf8); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); + + _cairo_pattern_fini (&pattern); return status; } - cairo_status_t _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, cairo_glyph_t *glyphs, int num_glyphs) { cairo_status_t status; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; int i; cairo_glyph_t *transformed_glyphs = NULL; + cairo_pattern_t pattern; + cairo_text_extents_t text_extents; + cairo_box_t extents; transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); if (transformed_glyphs == NULL) @@ -2002,20 +2053,33 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - status = setup_text_rendering_context (gstate, &user_to_source); - if (status) - return status; - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); + _cairo_pattern_init_copy (&pattern, gstate->pattern); + _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs, + &text_extents); + if (status) + return status; + + extents.p1.x = _cairo_fixed_from_double (transformed_glyphs[0].x); + extents.p1.y = _cairo_fixed_from_double (transformed_glyphs[0].y); + extents.p2.x = _cairo_fixed_from_double (transformed_glyphs[0].x + + text_extents.width); + extents.p2.y = _cairo_fixed_from_double (transformed_glyphs[0].y + + text_extents.height); + status = _cairo_gstate_create_pattern (gstate, &pattern, &extents); + if (status) + return status; + status = _cairo_font_show_glyphs (gstate->font, - gstate->operator, gstate->source, + gstate->operator, pattern.source, gstate->surface, transformed_glyphs, num_glyphs); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); + + _cairo_pattern_fini (&pattern); free (transformed_glyphs); @@ -2028,15 +2092,10 @@ _cairo_gstate_text_path (cairo_gstate_t *gstate, const unsigned char *utf8) { cairo_status_t status; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; cairo_point_t point; double x, y; - status = setup_text_rendering_context (gstate, &user_to_source); - if (status) - return status; - status = _cairo_path_current_point (&gstate->path, &point); if (status == CAIRO_STATUS_NO_CURRENT_POINT) { x = 0; @@ -2056,7 +2115,6 @@ _cairo_gstate_text_path (cairo_gstate_t *gstate, &gstate->path); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); return status; } @@ -2070,7 +2128,6 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, cairo_status_t status; int i; cairo_glyph_t *transformed_glyphs = NULL; - cairo_matrix_t user_to_source; cairo_matrix_t saved_font_matrix; transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t)); @@ -2085,10 +2142,6 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, &(transformed_glyphs[i].y)); } - status = setup_text_rendering_context (gstate, &user_to_source); - if (status) - return status; - cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix); cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix); @@ -2097,8 +2150,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate, &gstate->path); cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix); - restore_text_rendering_context (gstate, &user_to_source); - + free (transformed_glyphs); return status; } diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c index 86b4fdc2..a11a07ee 100644 --- a/src/cairo_image_surface.c +++ b/src/cairo_image_surface.c @@ -467,6 +467,26 @@ _cairo_image_surface_set_clip_region (cairo_image_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +static cairo_status_t +_cairo_image_abstract_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_image_surface_t *image; + + /* Fall back to general pattern creation for surface patterns. */ + if (pattern->type == CAIRO_PATTERN_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + image = _cairo_pattern_get_image (pattern, box); + if (image) { + pattern->source = &image->base; + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; +} + static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_create_similar, _cairo_image_abstract_surface_destroy, @@ -481,5 +501,6 @@ static const cairo_surface_backend_t cairo_image_surface_backend = { _cairo_image_surface_composite_trapezoids, _cairo_image_surface_copy_page, _cairo_image_surface_show_page, - _cairo_image_abstract_surface_set_clip_region + _cairo_image_abstract_surface_set_clip_region, + _cairo_image_abstract_surface_create_pattern }; diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c index f35ae017..ed7bb039 100644 --- a/src/cairo_png_surface.c +++ b/src/cairo_png_surface.c @@ -306,6 +306,13 @@ _cairo_png_surface_set_clip_region (void *abstract_surface, return _cairo_image_surface_set_clip_region (surface->image, region); } +static cairo_int_status_t +_cairo_png_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} static const cairo_surface_backend_t cairo_png_surface_backend = { _cairo_png_surface_create_similar, @@ -321,5 +328,6 @@ static const cairo_surface_backend_t cairo_png_surface_backend = { _cairo_png_surface_composite_trapezoids, _cairo_png_surface_copy_page, _cairo_png_surface_show_page, - _cairo_png_surface_set_clip_region + _cairo_png_surface_set_clip_region, + _cairo_png_surface_create_pattern }; diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c index 82364556..98d34e44 100644 --- a/src/cairo_ps_surface.c +++ b/src/cairo_ps_surface.c @@ -403,6 +403,13 @@ _cairo_ps_surface_set_clip_region (void *abstract_surface, return _cairo_image_surface_set_clip_region (surface->image, region); } +static cairo_int_status_t +_cairo_ps_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_create_similar, @@ -418,5 +425,6 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = { _cairo_ps_surface_composite_trapezoids, _cairo_ps_surface_copy_page, _cairo_ps_surface_show_page, - _cairo_ps_surface_set_clip_region + _cairo_ps_surface_set_clip_region, + _cairo_ps_surface_create_pattern }; diff --git a/src/cairo_surface.c b/src/cairo_surface.c index 34143f5c..91ab8aba 100644 --- a/src/cairo_surface.c +++ b/src/cairo_surface.c @@ -377,3 +377,111 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *reg { return surface->backend->set_clip_region (surface, region); } + +cairo_status_t +_cairo_surface_create_pattern (cairo_surface_t *surface, + cairo_pattern_t *pattern, + cairo_box_t *box) +{ + cairo_int_status_t status; + + status = surface->backend->create_pattern (surface, pattern, box); + + /* The backend cannot accelerate this pattern, lets create an + unaccelerated source instead. */ + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + + status = CAIRO_STATUS_SUCCESS; + switch (pattern->type) { + case CAIRO_PATTERN_LINEAR: + case CAIRO_PATTERN_RADIAL: { + cairo_image_surface_t *image; + + image = _cairo_pattern_get_image (pattern, box); + if (image) { + pattern->source = &image->base; + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; + + } break; + case CAIRO_PATTERN_SOLID: + pattern->source = + _cairo_surface_create_similar_solid (surface, + CAIRO_FORMAT_ARGB32, + 1, 1, + &pattern->color); + if (pattern->source) { + cairo_surface_set_repeat (pattern->source, 1); + + return CAIRO_STATUS_SUCCESS; + } else + return CAIRO_STATUS_NO_MEMORY; + break; + case CAIRO_PATTERN_SURFACE: + status = CAIRO_INT_STATUS_UNSUPPORTED; + + /* handle pattern opacity */ + if (pattern->color.alpha != 1.0) { + int width = ceil (_cairo_fixed_to_double (box->p2.x) - + _cairo_fixed_to_double (box->p1.x)); + int height = ceil (_cairo_fixed_to_double (box->p2.y) - + _cairo_fixed_to_double (box->p1.y)); + cairo_pattern_t alpha; + + pattern->source = + cairo_surface_create_similar (surface, + CAIRO_FORMAT_ARGB32, + width, height); + if (pattern->source) { + _cairo_pattern_init_solid (&alpha, 1.0, 1.0, 1.0); + _cairo_pattern_set_alpha (&alpha, pattern->color.alpha); + + status = _cairo_surface_create_pattern (pattern->source, + &alpha, box); + + if (status == CAIRO_STATUS_SUCCESS) { + int save_repeat = pattern->u.surface.surface->repeat; + + if (pattern->extend == CAIRO_EXTEND_REPEAT || + pattern->u.surface.surface->repeat == 1) + cairo_surface_set_repeat (pattern->u.surface.surface, 1); + else + cairo_surface_set_repeat (pattern->u.surface.surface, 0); + + status = + _cairo_surface_composite (CAIRO_OPERATOR_OVER, + pattern->u.surface.surface, + alpha.source, + pattern->source, + 0, 0, 0, 0, 0, 0, + width, height); + + cairo_surface_set_repeat (pattern->u.surface.surface, + save_repeat); + + if (status == CAIRO_STATUS_SUCCESS) { + _cairo_pattern_add_source_offset (pattern, + _cairo_fixed_to_double (box->p1.x), + _cairo_fixed_to_double (box->p1.y)); + } else + cairo_surface_destroy (pattern->source); + } + + _cairo_pattern_fini (&alpha); + } + } + + if (status != CAIRO_STATUS_SUCCESS) { + pattern->source = pattern->u.surface.surface; + cairo_surface_reference (pattern->u.surface.surface); + + return CAIRO_STATUS_SUCCESS; + } + break; + } + } + + return status; +} diff --git a/src/cairo_traps.c b/src/cairo_traps.c index e786ad42..9b44d38e 100644 --- a/src/cairo_traps.c +++ b/src/cairo_traps.c @@ -608,3 +608,40 @@ _cairo_traps_contain (cairo_traps_t *traps, double x, double y) return 0; } + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +static void +_cairo_trap_extents (cairo_trapezoid_t *t, cairo_box_t *extents) +{ + cairo_fixed_t x; + + if (t->top < extents->p1.y) + extents->p1.y = t->top; + + if (t->bottom > extents->p2.y) + extents->p2.y = t->bottom; + + x = MIN (_compute_x (&t->left, t->top), + _compute_x (&t->left, t->bottom)); + if (x < extents->p1.x) + extents->p1.x = x; + + x = MAX (_compute_x (&t->right, t->top), + _compute_x (&t->right, t->bottom)); + if (x > extents->p2.x) + extents->p2.x = x; +} + +void +_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; + + for (i = 0; i < traps->num_traps; i++) + _cairo_trap_extents (&traps->traps[i], extents); +} diff --git a/src/cairo_xcb_surface.c b/src/cairo_xcb_surface.c index e4c9307f..ea1f72e1 100644 --- a/src/cairo_xcb_surface.c +++ b/src/cairo_xcb_surface.c @@ -712,6 +712,14 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface, return CAIRO_INT_STATUS_UNSUPPORTED; } +static cairo_int_status_t +_cairo_xcb_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const struct cairo_surface_backend cairo_xcb_surface_backend = { _cairo_xcb_surface_create_similar, _cairo_xcb_surface_destroy, @@ -726,7 +734,8 @@ static const struct cairo_surface_backend cairo_xcb_surface_backend = { _cairo_xcb_surface_composite_trapezoids, _cairo_xcb_surface_copy_page, _cairo_xcb_surface_show_page, - _cairo_xcb_surface_set_clip_region + _cairo_xcb_surface_set_clip_region, + _cairo_xcb_surface_create_pattern }; static void diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c index c7efefba..19dfde50 100644 --- a/src/cairo_xlib_surface.c +++ b/src/cairo_xlib_surface.c @@ -455,7 +455,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator, cairo_xlib_surface_t *mask = (cairo_xlib_surface_t *) generic_mask; cairo_xlib_surface_t *src_clone = NULL; cairo_xlib_surface_t *mask_clone = NULL; - + if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst)) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -619,6 +619,14 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface, return CAIRO_STATUS_SUCCESS; } +static cairo_int_status_t +_cairo_xlib_surface_create_pattern (void *abstract_surface, + cairo_pattern_t *pattern, + cairo_box_t *extents) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} + static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_create_similar, _cairo_xlib_surface_destroy, @@ -633,7 +641,8 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = { _cairo_xlib_surface_composite_trapezoids, _cairo_xlib_surface_copy_page, _cairo_xlib_surface_show_page, - _cairo_xlib_surface_set_clip_region + _cairo_xlib_surface_set_clip_region, + _cairo_xlib_surface_create_pattern }; cairo_surface_t * @@ -692,7 +701,7 @@ cairo_xlib_surface_create (Display *dpy, 0, NULL); else surface->picture = 0; - + return (cairo_surface_t *) surface; } DEPRECATE (cairo_surface_create_for_drawable, cairo_xlib_surface_create); diff --git a/src/cairoint.h b/src/cairoint.h index 9fcd9c7e..5b4ccb56 100644 --- a/src/cairoint.h +++ b/src/cairoint.h @@ -135,10 +135,15 @@ typedef struct cairo_point_double { double y; } cairo_point_double_t; +typedef struct cairo_distance_double { + double dx; + double dy; +} cairo_distance_double_t; + typedef struct cairo_line { cairo_point_t p1; cairo_point_t p2; -} cairo_line_t; +} cairo_line_t, cairo_box_t; typedef struct cairo_trapezoid { cairo_fixed_t top, bottom; @@ -376,6 +381,10 @@ typedef struct cairo_surface_backend { cairo_int_status_t (*set_clip_region) (void *surface, pixman_region16_t *region); + cairo_int_status_t + (*create_pattern) (void *surface, + cairo_pattern_t *pattern, + cairo_box_t *extents); } cairo_surface_backend_t; struct cairo_matrix { @@ -433,6 +442,59 @@ struct cairo_color { unsigned short alpha_short; }; +#define CAIRO_EXTEND_DEFAULT CAIRO_EXTEND_NONE +#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_NEAREST + +typedef enum { + CAIRO_PATTERN_SOLID, + CAIRO_PATTERN_SURFACE, + CAIRO_PATTERN_LINEAR, + CAIRO_PATTERN_RADIAL +} cairo_pattern_type_t; + +typedef struct cairo_color_stop { + double offset; + int id; + cairo_color_t color; + unsigned char color_char[4]; +} cairo_color_stop_t; + +struct cairo_pattern { + unsigned int ref_count; + + cairo_extend_t extend; + cairo_filter_t filter; + cairo_matrix_t matrix; + + cairo_color_stop_t *stops; + int n_stops; + + cairo_color_t color; + + cairo_surface_t *source; + cairo_point_double_t source_offset; + + cairo_pattern_type_t type; + union { + struct { + cairo_surface_t *surface; + cairo_matrix_t save_matrix; + int save_repeat; + cairo_filter_t save_filter; + } surface; + struct { + cairo_point_double_t point0; + cairo_point_double_t point1; + } linear; + struct { + cairo_point_double_t center0; + cairo_point_double_t center1; + cairo_distance_double_t radius0; + cairo_distance_double_t radius1; + } radial; + } u; +}; + typedef struct cairo_traps { cairo_trapezoid_t *traps; int num_traps; @@ -492,15 +554,12 @@ typedef struct cairo_gstate { cairo_surface_t *surface; - cairo_surface_t *source; - cairo_point_double_t source_offset; - int source_is_solid; + cairo_pattern_t *pattern; + cairo_point_double_t pattern_offset; + double alpha; cairo_clip_rec_t clip; - double alpha; - cairo_color_t color; - double pixels_per_inch; cairo_matrix_t ctm; cairo_matrix_t ctm_inverse; @@ -526,6 +585,10 @@ typedef struct cairo_stroke_face { cairo_point_double_t usr_vector; } cairo_stroke_face_t; +/* cairo.c */ +extern void __internal_linkage +_cairo_restrict_value (double *value, double min, double max); + /* cairo_fixed.c */ extern cairo_fixed_t __internal_linkage _cairo_fixed_from_int (int i); @@ -574,7 +637,10 @@ extern cairo_surface_t * __internal_linkage _cairo_gstate_current_target_surface (cairo_gstate_t *gstate); extern cairo_status_t __internal_linkage -_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_surface_t *pattern); +_cairo_gstate_set_pattern (cairo_gstate_t *gstate, cairo_pattern_t *pattern); + +extern cairo_pattern_t *__internal_linkage +_cairo_gstate_current_pattern (cairo_gstate_t *gstate); extern cairo_status_t __internal_linkage _cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t operator); @@ -745,6 +811,16 @@ extern cairo_status_t __internal_linkage _cairo_gstate_show_page (cairo_gstate_t *gstate); extern cairo_status_t __internal_linkage +_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2); + +extern cairo_status_t __internal_linkage +_cairo_gstate_fill_extents (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2); + +extern cairo_status_t __internal_linkage _cairo_gstate_in_stroke (cairo_gstate_t *gstate, double x, double y, @@ -1042,9 +1118,6 @@ _cairo_surface_copy_page (cairo_surface_t *surface); extern cairo_status_t __internal_linkage _cairo_surface_show_page (cairo_surface_t *surface); -extern cairo_status_t __internal_linkage -_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region); - extern double __internal_linkage _cairo_surface_pixels_per_inch (cairo_surface_t *surface); @@ -1055,6 +1128,14 @@ extern cairo_status_t __internal_linkage _cairo_surface_set_image (cairo_surface_t *surface, cairo_image_surface_t *image); +extern cairo_status_t __internal_linkage +_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region); + +extern cairo_status_t __internal_linkage +_cairo_surface_create_pattern (cairo_surface_t *surface, + cairo_pattern_t *pattern, + cairo_box_t *extents); + /* cairo_image_surface.c */ extern cairo_image_surface_t * __internal_linkage @@ -1209,6 +1290,9 @@ _cairo_traps_tessellate_polygon (cairo_traps_t *traps, extern int __internal_linkage _cairo_traps_contain (cairo_traps_t *traps, double x, double y); +extern void __internal_linkage +_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents); + /* cairo_slope.c */ extern void __internal_linkage _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b); @@ -1222,6 +1306,50 @@ _cairo_slope_clockwise (cairo_slope_t *a, cairo_slope_t *b); extern int __internal_linkage _cairo_slope_counter_clockwise (cairo_slope_t *a, cairo_slope_t *b); +/* cairo_pattern.c */ +extern void __internal_linkage +_cairo_pattern_init (cairo_pattern_t *pattern); + +extern cairo_status_t __internal_linkage +_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other); + +extern void __internal_linkage +_cairo_pattern_fini (cairo_pattern_t *pattern); + +extern void __internal_linkage +_cairo_pattern_init_solid (cairo_pattern_t *pattern, + double red, double green, double blue); + +extern cairo_pattern_t *__internal_linkage +_cairo_pattern_create_solid (double red, double green, double blue); + +extern cairo_status_t __internal_linkage +_cairo_pattern_get_rgb (cairo_pattern_t *pattern, + double *red, double *green, double *blue); + +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, + double x, double y); + +extern void __internal_linkage +_cairo_pattern_transform (cairo_pattern_t *pattern, + cairo_matrix_t *matrix, + cairo_matrix_t *matrix_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, + int *pixel); + +extern cairo_image_surface_t *__internal_linkage +_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box); + /* Avoid unnecessary PLT entries. */ slim_hidden_proto(cairo_close_path) |