summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog82
-rw-r--r--cairo.pc.in2
-rw-r--r--configure.in7
-rw-r--r--src/Makefile.am4
-rw-r--r--src/cairo-ft-font.c21
-rw-r--r--src/cairo-gstate.c528
-rw-r--r--src/cairo-image-surface.c23
-rw-r--r--src/cairo-ps-surface.c10
-rw-r--r--src/cairo-surface.c108
-rw-r--r--src/cairo-traps.c37
-rw-r--r--src/cairo-xcb-surface.c11
-rw-r--r--src/cairo-xlib-surface.c15
-rw-r--r--src/cairo.c33
-rw-r--r--src/cairo.h75
-rw-r--r--src/cairo_ft_font.c21
-rw-r--r--src/cairo_gstate.c528
-rw-r--r--src/cairo_image_surface.c23
-rw-r--r--src/cairo_png_surface.c10
-rw-r--r--src/cairo_ps_surface.c10
-rw-r--r--src/cairo_surface.c108
-rw-r--r--src/cairo_traps.c37
-rw-r--r--src/cairo_xcb_surface.c11
-rw-r--r--src/cairo_xlib_surface.c15
-rw-r--r--src/cairoint.h150
24 files changed, 1339 insertions, 530 deletions
diff --git a/ChangeLog b/ChangeLog
index fad879416..30660ed08 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 a7f5d40d3..316e6f337 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 85d3467f5..a2df768ad 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 4278a1bbc..518e69f21 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 3975938ab..77cf59b0d 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 f780cc945..ed8c8a1a8 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 86b4fdc2a..a11a07eed 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 82364556a..98d34e44d 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 34143f5c8..91ab8aba4 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 e786ad42a..9b44d38ea 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 e4c9307ff..ea1f72e16 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 c7efefba6..19dfde503 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 d4bdc1654..d173ca767 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 77b238445..ab3c80e82 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 3975938ab..77cf59b0d 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 f780cc945..ed8c8a1a8 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 86b4fdc2a..a11a07eed 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 f35ae017c..ed7bb039e 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 82364556a..98d34e44d 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 34143f5c8..91ab8aba4 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 e786ad42a..9b44d38ea 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 e4c9307ff..ea1f72e16 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 c7efefba6..19dfde503 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 9fcd9c7e9..5b4ccb56e 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)