summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am32
-rw-r--r--src/cairo-features.h.in6
-rw-r--r--src/cairo-fixed.c7
-rw-r--r--src/cairo-font.c27
-rw-r--r--src/cairo-ft-font.c449
-rw-r--r--src/cairo-gstate.c1010
-rw-r--r--src/cairo-image-surface.c248
-rw-r--r--src/cairo-matrix.c19
-rw-r--r--src/cairo-path-bounds.c53
-rw-r--r--src/cairo-path-fill.c121
-rw-r--r--src/cairo-path-stroke.c309
-rw-r--r--src/cairo-path.c189
-rw-r--r--src/cairo-pattern.c716
-rw-r--r--src/cairo-pen.c2
-rw-r--r--src/cairo-polygon.c56
-rw-r--r--src/cairo-ps-surface.c48
-rw-r--r--src/cairo-surface.c121
-rw-r--r--src/cairo-traps.c41
-rw-r--r--src/cairo-xcb-surface.c799
-rw-r--r--src/cairo-xlib-surface.c90
-rw-r--r--src/cairo.c86
-rw-r--r--src/cairo.h452
-rw-r--r--src/cairo_fixed.c7
-rw-r--r--src/cairo_font.c27
-rw-r--r--src/cairo_ft_font.c449
-rw-r--r--src/cairo_gstate.c1010
-rw-r--r--src/cairo_image_surface.c248
-rw-r--r--src/cairo_matrix.c19
-rw-r--r--src/cairo_path.c189
-rw-r--r--src/cairo_path_bounds.c53
-rw-r--r--src/cairo_path_fill.c121
-rw-r--r--src/cairo_path_stroke.c309
-rw-r--r--src/cairo_pattern.c716
-rw-r--r--src/cairo_pen.c2
-rw-r--r--src/cairo_png_surface.c333
-rw-r--r--src/cairo_polygon.c56
-rw-r--r--src/cairo_ps_surface.c48
-rw-r--r--src/cairo_surface.c121
-rw-r--r--src/cairo_traps.c41
-rw-r--r--src/cairo_xcb_surface.c799
-rw-r--r--src/cairo_xlib_surface.c90
-rw-r--r--src/cairoint.h386
42 files changed, 7771 insertions, 2134 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 2ed7341b..518e69f2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,12 +1,29 @@
lib_LTLIBRARIES = libcairo.la
include_HEADERS = cairo.h cairo-features.h
+if CAIRO_HAS_PS_SURFACE
+libcairo_ps_sources = cairo_ps_surface.c
+endif
+
+if CAIRO_HAS_PNG_SURFACE
+libcairo_png_sources = cairo_png_surface.c
+endif
+
if CAIRO_HAS_XLIB_SURFACE
libcairo_xlib_sources = cairo_xlib_surface.c
-else
-libcairo_xlib_sources =
endif
+if CAIRO_HAS_XCB_SURFACE
+libcairo_xcb_sources = cairo_xcb_surface.c
+endif
+
+# These names match automake style variable definition conventions so
+# without these lines, automake will complain during the handling of
+# the libcairo_la_LIBADD below. (The INCLUDES is an autoconf only
+# term and automake does not care about it)
+FONTCONFIG_LIBS=@FONTCONFIG_LIBS@
+XRENDER_LIBS=@XRENDER_LIBS@
+
libcairo_la_SOURCES = \
cairo.c \
cairo.h \
@@ -24,16 +41,19 @@ libcairo_la_SOURCES = \
cairo_path_stroke.c \
cairo_pen.c \
cairo_polygon.c \
- cairo_ps_surface.c \
cairo_slope.c \
cairo_spline.c \
cairo_surface.c \
cairo_traps.c \
+ cairo_pattern.c \
+ $(libcairo_ps_sources) \
+ $(libcairo_png_sources) \
$(libcairo_xlib_sources)\
+ $(libcairo_xcb_sources) \
cairoint.h
-libcairo_la_LDFLAGS = -version-info @VERSION_INFO@
+libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined
-INCLUDES = $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(X_CFLAGS)
+INCLUDES = -I$(srcdir) $(CAIRO_CFLAGS) $(FONTCONFIG_CFLAGS) $(XRENDER_CFLAGS) $(XCB_CFLAGS) $(PNG_CFLAGS)
-libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(X_LIBS) -lm
+libcairo_la_LIBADD = $(CAIRO_LIBS) $(FONTCONFIG_LIBS) $(XRENDER_LIBS) $(XCB_LIBS) $(PS_LIBS) $(PNG_LIBS) -lm
diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in
index 9d83d070..e9dacad5 100644
--- a/src/cairo-features.h.in
+++ b/src/cairo-features.h.in
@@ -28,6 +28,12 @@
#ifndef _CAIRO_CONFIG_H_
#define _CAIRO_CONFIG_H_
+#define @PS_SURFACE_FEATURE@
+
+#define @PNG_SURFACE_FEATURE@
+
#define @XLIB_SURFACE_FEATURE@
+#define @XCB_SURFACE_FEATURE@
+
#endif
diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c
index 33088546..9a7e7bc4 100644
--- a/src/cairo-fixed.c
+++ b/src/cairo-fixed.c
@@ -39,8 +39,15 @@ _cairo_fixed_from_double (double d)
return (cairo_fixed_t) (d * 65536);
}
+cairo_fixed_t
+_cairo_fixed_from_26_6 (uint32_t i)
+{
+ return i << 10;
+}
+
double
_cairo_fixed_to_double (cairo_fixed_t f)
{
return ((double) f) / 65536.0;
}
+
diff --git a/src/cairo-font.c b/src/cairo-font.c
index f6bf390a..157ebedb 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -28,12 +28,18 @@
#include "cairoint.h"
cairo_font_t *
-_cairo_font_create (char *family,
+_cairo_font_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
+ /* XXX: The current freetype backend may return NULL, (for example
+ * if no fonts are installed), but I would like to guarantee that
+ * the toy API always returns at least *some* font, so I would
+ * like to build in some sort fo font here, (even a really lame,
+ * ugly one if necessary). */
+
return backend->create (family, slant, weight);
}
@@ -118,31 +124,30 @@ _cairo_font_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
- double x,
- double y,
cairo_glyph_t *glyphs,
int num_glyphs)
{
return font->backend->show_glyphs(font, operator, source,
- surface, x, y, glyphs, num_glyphs);
+ surface, glyphs, num_glyphs);
}
cairo_status_t
_cairo_font_text_path (cairo_font_t *font,
- cairo_path_t *path,
- const unsigned char *utf8)
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_path_t *path)
{
- return font->backend->text_path(font, path, utf8);
+ return font->backend->text_path(font, x, y, utf8, path);
}
cairo_status_t
_cairo_font_glyph_path (cairo_font_t *font,
- cairo_path_t *path,
cairo_glyph_t *glyphs,
- int num_glyphs)
+ int num_glyphs,
+ cairo_path_t *path)
{
- return font->backend->glyph_path(font, path,
- glyphs, num_glyphs);
+ return font->backend->glyph_path(font, glyphs, num_glyphs, path);
}
cairo_status_t
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index c3e4306d..77cf59b0 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -25,7 +25,10 @@
#include "cairoint.h"
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
-#include <freetype/freetype.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
typedef struct {
cairo_font_t base;
@@ -39,13 +42,10 @@ typedef struct {
FcPattern *pattern;
} cairo_ft_font_t;
-
-#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 63.0))
-#define DOUBLE_FROM_26_6(t) (((double)((t) >> 6)) \
- + ((double)((t) & 0x3F) / 63.0))
-#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65535.0))
-#define DOUBLE_FROM_16_16(t) (((double)((t) >> 16)) \
- + ((double)((t) & 0xFFFF) / 65535.0))
+#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0))
+#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0)
+#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
+#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
/* implement the platform-specific interface */
@@ -101,29 +101,31 @@ cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern)
}
FT_Face
-cairo_ft_font_face (cairo_font_t *font)
+cairo_ft_font_face (cairo_font_t *abstract_font)
{
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+
if (font == NULL)
return NULL;
- return ((cairo_ft_font_t *) font)->face;
+ return font->face;
}
FcPattern *
-cairo_ft_font_pattern (cairo_font_t *font)
+cairo_ft_font_pattern (cairo_font_t *abstract_font)
{
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+
if (font == NULL)
return NULL;
- return ((cairo_ft_font_t *) font)->pattern;
+ return font->pattern;
}
-
-
/* implement the backend interface */
static cairo_font_t *
-_cairo_ft_font_create (char *family,
+_cairo_ft_font_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
@@ -175,6 +177,9 @@ _cairo_ft_font_create (char *family,
}
font = cairo_ft_font_create (ft_library, pat);
+ if (font == NULL)
+ return NULL;
+
ft_font = (cairo_ft_font_t *) font;
ft_font->owns_ft_library = 1;
@@ -188,45 +193,43 @@ _cairo_ft_font_create (char *family,
return font;
}
-
static cairo_font_t *
-_cairo_ft_font_copy (cairo_font_t *font)
+_cairo_ft_font_copy (void *abstract_font)
{
- cairo_ft_font_t * ft_font_new = NULL;
- cairo_ft_font_t * ft_font = NULL;
+ cairo_ft_font_t * font_new = NULL;
+ cairo_ft_font_t * font = abstract_font;
- ft_font = (cairo_ft_font_t *)font;
+ if (font->base.backend != &cairo_ft_font_backend)
+ return NULL;
- ft_font_new = (cairo_ft_font_t *)cairo_ft_font_create_for_ft_face (ft_font->face);
- if (ft_font_new == NULL)
+ font_new = (cairo_ft_font_t *) cairo_ft_font_create_for_ft_face (font->face);
+ if (font_new == NULL)
return NULL;
- if (ft_font_new != NULL && ft_font->pattern != NULL)
- ft_font_new->pattern = FcPatternDuplicate (ft_font->pattern);
+ if (font_new != NULL && font->pattern != NULL)
+ font_new->pattern = FcPatternDuplicate (font->pattern);
- return (cairo_font_t *)ft_font_new;
+ return (cairo_font_t *) font_new;
}
static void
-_cairo_ft_font_destroy (cairo_font_t *font)
+_cairo_ft_font_destroy (void *abstract_font)
{
- cairo_ft_font_t * ft_font = NULL;
+ cairo_ft_font_t * font = abstract_font;
if (font == NULL)
return;
- ft_font = (cairo_ft_font_t *)font;
-
- if (ft_font->face != NULL && ft_font->owns_face)
- FT_Done_Face (ft_font->face);
+ if (font->face != NULL && font->owns_face)
+ FT_Done_Face (font->face);
- if (ft_font->pattern != NULL)
- FcPatternDestroy (ft_font->pattern);
+ if (font->pattern != NULL)
+ FcPatternDestroy (font->pattern);
- if (ft_font->ft_library && ft_font->owns_ft_library)
- FT_Done_FreeType (ft_font->ft_library);
+ if (font->ft_library && font->owns_ft_library)
+ FT_Done_FreeType (font->ft_library);
- free (ft_font);
+ free (font);
}
static void
@@ -260,21 +263,7 @@ _utf8_to_ucs4 (char const *utf8,
len -= step;
utf8 += step;
}
- *nchars = alloc;
-}
-
-static void
-_get_scale_factors(cairo_matrix_t *matrix, double *sx, double *sy)
-{
- double e0, e1;
- e1 = 1.; e0 = 0.;
-
- cairo_matrix_transform_distance (matrix, &e1, &e0);
- *sx = sqrt(e1*e1 + e0*e0);
-
- e1 = 1.; e0 = 0.;
- cairo_matrix_transform_distance (matrix, &e0, &e1);
- *sy = sqrt(e1*e1 + e0*e0);
+ *nchars = n;
}
static void
@@ -292,7 +281,7 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face)
* transformation.
*/
- _get_scale_factors(matrix, &scale_x, &scale_y);
+ _cairo_matrix_compute_scale_factors (matrix, &scale_x, &scale_y);
cairo_matrix_copy (&normalized, matrix);
@@ -314,23 +303,19 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face)
0, 0);
}
-
static int
-_utf8_to_glyphs (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- size_t *nglyphs)
+_utf8_to_glyphs (cairo_ft_font_t *font,
+ const unsigned char *utf8,
+ double x0,
+ double y0,
+ cairo_glyph_t **glyphs,
+ size_t *nglyphs)
{
- cairo_ft_font_t *ft;
+ FT_Face face = font->face;
double x = 0., y = 0.;
size_t i;
FT_ULong *ucs4 = NULL;
- if (font == NULL)
- return 0;
-
- ft = (cairo_ft_font_t *)font;
-
_utf8_to_ucs4 (utf8, &ucs4, nglyphs);
if (ucs4 == NULL)
@@ -343,18 +328,18 @@ _utf8_to_glyphs (cairo_font_t *font,
return 0;
}
- _install_font_matrix (&font->matrix, ft->face);
+ _install_font_matrix (&font->base.matrix, face);
for (i = 0; i < *nglyphs; i++)
{
- (*glyphs)[i].index = FT_Get_Char_Index (ft->face, ucs4[i]);
- (*glyphs)[i].x = x;
- (*glyphs)[i].y = y;
+ (*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]);
+ (*glyphs)[i].x = x0 + x;
+ (*glyphs)[i].y = y0 + y;
- FT_Load_Glyph (ft->face, (*glyphs)[i].index, FT_LOAD_DEFAULT);
+ FT_Load_Glyph (face, (*glyphs)[i].index, FT_LOAD_DEFAULT);
- x += DOUBLE_FROM_26_6 (ft->face->glyph->advance.x);
- y -= DOUBLE_FROM_26_6 (ft->face->glyph->advance.y);
+ x += DOUBLE_FROM_26_6 (face->glyph->advance.x);
+ y -= DOUBLE_FROM_26_6 (face->glyph->advance.y);
}
free (ucs4);
@@ -362,51 +347,114 @@ _utf8_to_glyphs (cairo_font_t *font,
}
static cairo_status_t
-_cairo_ft_font_font_extents (cairo_font_t *font,
- cairo_font_extents_t *extents)
+_cairo_ft_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
{
+ cairo_ft_font_t *font = abstract_font;
+ FT_Face face = font->face;
double scale_x, scale_y;
- cairo_ft_font_t *ft = (cairo_ft_font_t *)font;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- _get_scale_factors(&font->matrix, &scale_x, &scale_y);
+ double upm = face->units_per_EM;
-#define FONT_UNIT_TO_DEV(x) ((double)(x) / (double)(ft->face->units_per_EM))
+ _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y);
- extents->ascent = FONT_UNIT_TO_DEV(ft->face->ascender) * scale_y;
- extents->descent = FONT_UNIT_TO_DEV(ft->face->descender) * scale_y;
- extents->height = FONT_UNIT_TO_DEV(ft->face->height) * scale_y;
- extents->max_x_advance = FONT_UNIT_TO_DEV(ft->face->max_advance_width) * scale_x;
- extents->max_y_advance = FONT_UNIT_TO_DEV(ft->face->max_advance_height) * scale_y;
- return status;
+ extents->ascent = face->ascender / upm * scale_y;
+ extents->descent = face->descender / upm * scale_y;
+ extents->height = face->height / upm * scale_y;
+ extents->max_x_advance = face->max_advance_width / upm * scale_x;
+ extents->max_y_advance = face->max_advance_height / upm * scale_y;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_ft_font_glyph_extents (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+_cairo_ft_font_glyph_extents (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
- cairo_ft_font_t *ft;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ int i;
+ cairo_ft_font_t *font = abstract_font;
+ cairo_point_double_t origin;
+ cairo_point_double_t glyph_min, glyph_max;
+ cairo_point_double_t total_min, total_max;
+ FT_Error error;
+ FT_Face face = font->face;
+ FT_GlyphSlot glyph = face->glyph;
+ FT_Glyph_Metrics *metrics = &glyph->metrics;
- ft = (cairo_ft_font_t *)font;
+ if (num_glyphs == 0)
+ {
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
- /* FIXME: lift code from xft to do this */
+ origin.x = glyphs[0].x;
+ origin.y = glyphs[0].y;
- return status;
+ _install_font_matrix (&font->base.matrix, face);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT);
+ /* XXX: What to do in this error case? */
+ if (error)
+ continue;
+
+ /* XXX: Need to add code here to check the font's FcPattern
+ for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y
+ instead. This will require that
+ cairo_ft_font_create_for_ft_face accept an
+ FcPattern. */
+ glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX);
+ glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY);
+ glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width);
+ glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->height);
+
+ if (i==0) {
+ total_min = glyph_min;
+ total_max = glyph_max;
+ } else {
+ if (glyph_min.x < total_min.x)
+ total_min.x = glyph_min.x;
+ if (glyph_min.y < total_min.y)
+ total_min.y = glyph_min.y;
+
+ if (glyph_max.x > total_max.x)
+ total_max.x = glyph_max.x;
+ if (glyph_max.y > total_max.y)
+ total_max.y = glyph_max.y;
+ }
+ }
+
+ extents->x_bearing = total_min.x - origin.x;
+ extents->y_bearing = total_min.y - origin.y;
+ extents->width = total_max.x - total_min.x;
+ extents->height = total_max.y - total_min.y;
+ extents->x_advance = glyphs[i-1].x + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x;
+ extents->y_advance = glyphs[i-1].y + 0 - origin.y;
+
+ return CAIRO_STATUS_SUCCESS;
}
+
static cairo_status_t
-_cairo_ft_font_text_extents (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_text_extents_t *extents)
+_cairo_ft_font_text_extents (void *abstract_font,
+ const unsigned char *utf8,
+ cairo_text_extents_t *extents)
{
+ cairo_ft_font_t *font = abstract_font;
cairo_glyph_t *glyphs;
size_t nglyphs;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs))
+ if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs))
{
status = _cairo_ft_font_glyph_extents (font, glyphs, nglyphs,
extents);
@@ -414,24 +462,22 @@ _cairo_ft_font_text_extents (cairo_font_t *font,
}
return status;
}
-
-
static cairo_status_t
-_cairo_ft_font_show_glyphs (cairo_font_t *font,
+_cairo_ft_font_show_glyphs (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
- double x0,
- double y0,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
+ cairo_ft_font_t *font = abstract_font;
cairo_status_t status;
int i;
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;
@@ -444,22 +490,27 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font,
ft = (cairo_ft_font_t *)font;
glyphslot = ft->face->glyph;
- _install_font_matrix (&font->matrix, ft->face);
+ _install_font_matrix (&font->base.matrix, ft->face);
for (i = 0; i < num_glyphs; i++)
{
unsigned char *bitmap;
FT_Load_Glyph (ft->face, glyphs[i].index, FT_LOAD_DEFAULT);
- FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL);
+ FT_Render_Glyph (glyphslot, ft_render_mode_normal);
width = glyphslot->bitmap.width;
height = glyphslot->bitmap.rows;
stride = glyphslot->bitmap.pitch;
bitmap = glyphslot->bitmap.buffer;
- x = x0 + glyphs[i].x;
- y = y0 + glyphs[i].y;
+ x = glyphs[i].x;
+ 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)
@@ -502,11 +553,14 @@ _cairo_ft_font_show_glyphs (cairo_font_t *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)
@@ -519,7 +573,7 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font,
}
static cairo_status_t
-_cairo_ft_font_show_text (cairo_font_t *font,
+_cairo_ft_font_show_text (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
@@ -527,15 +581,16 @@ _cairo_ft_font_show_text (cairo_font_t *font,
double y0,
const unsigned char *utf8)
{
+ cairo_ft_font_t *font = abstract_font;
cairo_glyph_t *glyphs;
- size_t nglyphs;
+ int num_glyphs;
- if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs))
+ if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
{
cairo_status_t res;
res = _cairo_ft_font_show_glyphs (font, operator,
- source, surface, x0, y0,
- glyphs, nglyphs);
+ source, surface,
+ glyphs, num_glyphs);
free (glyphs);
return res;
}
@@ -543,35 +598,147 @@ _cairo_ft_font_show_text (cairo_font_t *font,
return CAIRO_STATUS_NO_MEMORY;
}
+static int
+_move_to (FT_Vector *to, void *closure)
+{
+ cairo_path_t *path = closure;
+ cairo_point_t point;
+
+ point.x = _cairo_fixed_from_26_6 (to->x);
+ point.y = _cairo_fixed_from_26_6 (to->y);
+
+ _cairo_path_close_path (path);
+ _cairo_path_move_to (path, &point);
+
+ return 0;
+}
+
+static int
+_line_to (FT_Vector *to, void *closure)
+{
+ cairo_path_t *path = closure;
+ cairo_point_t point;
+
+ point.x = _cairo_fixed_from_26_6 (to->x);
+ point.y = _cairo_fixed_from_26_6 (to->y);
+
+ _cairo_path_line_to (path, &point);
+
+ return 0;
+}
+
+static int
+_conic_to (FT_Vector *control, FT_Vector *to, void *closure)
+{
+ cairo_path_t *path = closure;
+
+ cairo_point_t p0, p1, p2, p3;
+ cairo_point_t conic;
+
+ _cairo_path_current_point (path, &p0);
+
+ conic.x = _cairo_fixed_from_26_6 (control->x);
+ conic.y = _cairo_fixed_from_26_6 (control->y);
+
+ p3.x = _cairo_fixed_from_26_6 (to->x);
+ p3.y = _cairo_fixed_from_26_6 (to->y);
+
+ p1.x = p0.x + 2.0/3.0 * (conic.x - p0.x);
+ p1.y = p0.y + 2.0/3.0 * (conic.y - p0.y);
+
+ p2.x = p3.x + 2.0/3.0 * (conic.x - p3.x);
+ p2.y = p3.y + 2.0/3.0 * (conic.y - p3.y);
+
+ _cairo_path_curve_to (path,
+ &p1, &p2, &p3);
+
+ return 0;
+}
+
+static int
+_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure)
+{
+ cairo_path_t *path = closure;
+ cairo_point_t p0, p1, p2;
+
+ p0.x = _cairo_fixed_from_26_6 (control1->x);
+ p0.y = _cairo_fixed_from_26_6 (control1->y);
+
+ p1.x = _cairo_fixed_from_26_6 (control2->x);
+ p1.y = _cairo_fixed_from_26_6 (control2->y);
+
+ p2.x = _cairo_fixed_from_26_6 (to->x);
+ p2.y = _cairo_fixed_from_26_6 (to->y);
+
+ _cairo_path_curve_to (path, &p0, &p1, &p2);
+
+ return 0;
+}
static cairo_status_t
-_cairo_ft_font_glyph_path (cairo_font_t *font,
- cairo_path_t *path,
- cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_ft_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_ft_font_t *ft;
-
- ft = (cairo_ft_font_t *)font;
-
- /* FIXME: lift code from xft to do this */
+ int i;
+ cairo_ft_font_t *font = abstract_font;
+ FT_GlyphSlot glyph;
+ FT_Error error;
+ FT_Outline_Funcs outline_funcs = {
+ _move_to,
+ _line_to,
+ _conic_to,
+ _cubic_to,
+ 0, /* shift */
+ 0, /* delta */
+ };
+
+ glyph = font->face->glyph;
+ _install_font_matrix (&font->base.matrix, font->face);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ FT_Matrix invert_y = {
+ DOUBLE_TO_16_16 (1.0), 0,
+ 0, DOUBLE_TO_16_16 (-1.0),
+ };
+
+ error = FT_Load_Glyph (font->face, glyphs[i].index, FT_LOAD_DEFAULT);
+ /* XXX: What to do in this error case? */
+ if (error)
+ continue;
+ /* XXX: Do we want to support bitmap fonts here? */
+ if (glyph->format == ft_glyph_format_bitmap)
+ continue;
+
+ /* Font glyphs have an inverted Y axis compared to cairo. */
+ FT_Outline_Transform (&glyph->outline, &invert_y);
+ FT_Outline_Translate (&glyph->outline,
+ DOUBLE_TO_26_6(glyphs[i].x),
+ DOUBLE_TO_26_6(glyphs[i].y));
+ FT_Outline_Decompose (&glyph->outline, &outline_funcs, path);
+ }
+ _cairo_path_close_path (path);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_ft_font_text_path (cairo_font_t *font,
- cairo_path_t *path,
- const unsigned char *utf8)
+_cairo_ft_font_text_path (void *abstract_font,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_path_t *path)
{
+ cairo_ft_font_t *font = abstract_font;
cairo_glyph_t *glyphs;
size_t nglyphs;
- if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs))
+ if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs))
{
cairo_status_t res;
- res = _cairo_ft_font_glyph_path (font, path, glyphs, nglyphs);
+ res = _cairo_ft_font_glyph_path (font, glyphs, nglyphs, path);
free (glyphs);
return res;
}
@@ -579,7 +746,6 @@ _cairo_ft_font_text_path (cairo_font_t *font,
return CAIRO_STATUS_NO_MEMORY;
}
-
cairo_font_t *
cairo_ft_font_create_for_ft_face (FT_Face face)
{
@@ -602,16 +768,15 @@ cairo_ft_font_create_for_ft_face (FT_Face face)
return (cairo_font_t *) f;
}
-
const struct cairo_font_backend cairo_ft_font_backend = {
- font_extents: (void *) _cairo_ft_font_font_extents,
- text_extents: (void *) _cairo_ft_font_text_extents,
- glyph_extents: (void *) _cairo_ft_font_glyph_extents,
- show_text: (void *) _cairo_ft_font_show_text,
- show_glyphs: (void *) _cairo_ft_font_show_glyphs,
- text_path: (void *) _cairo_ft_font_text_path,
- glyph_path: (void *) _cairo_ft_font_glyph_path,
- create: (void *) _cairo_ft_font_create,
- copy: (void *) _cairo_ft_font_copy,
- destroy: (void *) _cairo_ft_font_destroy
+ _cairo_ft_font_create,
+ _cairo_ft_font_copy,
+ _cairo_ft_font_destroy,
+ _cairo_ft_font_font_extents,
+ _cairo_ft_font_text_extents,
+ _cairo_ft_font_glyph_extents,
+ _cairo_ft_font_show_text,
+ _cairo_ft_font_show_glyphs,
+ _cairo_ft_font_text_path,
+ _cairo_ft_font_glyph_path,
};
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 8bc6e704..ed8c8a1a 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -30,15 +30,9 @@
#include "cairoint.h"
-static void
-_cairo_gstate_set_current_point (cairo_gstate_t *gstate, double x, double y);
-
-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);
@@ -79,25 +73,20 @@ _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);
_cairo_path_init (&gstate->path);
- gstate->current_point.x = 0.0;
- gstate->current_point.y = 0.0;
- gstate->has_current_point = 0;
-
_cairo_pen_init_empty (&gstate->pen_regular);
gstate->next = NULL;
@@ -130,9 +119,16 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
}
}
+ if (other->clip.region)
+ {
+ gstate->clip.region = pixman_region_create ();
+ pixman_region_copy (gstate->clip.region, other->clip.region);
+ }
+
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,16 +160,15 @@ _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;
- _cairo_color_fini (&gstate->color);
+ if (gstate->clip.region)
+ pixman_region_destroy (gstate->clip.region);
+ gstate->clip.region = NULL;
+
+ cairo_pattern_destroy (gstate->pattern);
_cairo_matrix_fini (&gstate->ctm);
_cairo_matrix_fini (&gstate->ctm_inverse);
@@ -358,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)
{
@@ -391,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
@@ -426,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;
}
@@ -680,20 +675,10 @@ _cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, do
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_gstate_set_current_point (cairo_gstate_t *gstate, double x, double y)
-{
- gstate->current_point.x = x;
- gstate->current_point.y = y;
-
- gstate->has_current_point = 1;
-}
-
cairo_status_t
_cairo_gstate_new_path (cairo_gstate_t *gstate)
{
_cairo_path_fini (&gstate->path);
- gstate->has_current_point = 0;
return CAIRO_STATUS_SUCCESS;
}
@@ -701,53 +686,51 @@ _cairo_gstate_new_path (cairo_gstate_t *gstate)
cairo_status_t
_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y)
{
- cairo_status_t status;
+ cairo_point_t point;
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
- status = _cairo_path_move_to (&gstate->path, x, y);
-
- _cairo_gstate_set_current_point (gstate, x, y);
-
- gstate->last_move_point = gstate->current_point;
+ point.x = _cairo_fixed_from_double (x);
+ point.y = _cairo_fixed_from_double (y);
- return status;
+ return _cairo_path_move_to (&gstate->path, &point);
}
cairo_status_t
_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y)
{
- cairo_status_t status;
+ cairo_point_t point;
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
- status = _cairo_path_line_to (&gstate->path, x, y);
-
- _cairo_gstate_set_current_point (gstate, x, y);
+ point.x = _cairo_fixed_from_double (x);
+ point.y = _cairo_fixed_from_double (y);
- return status;
+ return _cairo_path_line_to (&gstate->path, &point);
}
cairo_status_t
_cairo_gstate_curve_to (cairo_gstate_t *gstate,
+ double x0, double y0,
double x1, double y1,
- double x2, double y2,
- double x3, double y3)
+ double x2, double y2)
{
- cairo_status_t status;
+ cairo_point_t p0, p1, p2;
+ cairo_matrix_transform_point (&gstate->ctm, &x0, &y0);
cairo_matrix_transform_point (&gstate->ctm, &x1, &y1);
cairo_matrix_transform_point (&gstate->ctm, &x2, &y2);
- cairo_matrix_transform_point (&gstate->ctm, &x3, &y3);
- status = _cairo_path_curve_to (&gstate->path,
- x1, y1,
- x2, y2,
- x3, y3);
+ p0.x = _cairo_fixed_from_double (x0);
+ p0.y = _cairo_fixed_from_double (y0);
- _cairo_gstate_set_current_point (gstate, x3, y3);
+ p1.x = _cairo_fixed_from_double (x1);
+ p1.y = _cairo_fixed_from_double (y1);
- return status;
+ p2.x = _cairo_fixed_from_double (x2);
+ p2.y = _cairo_fixed_from_double (y2);
+
+ return _cairo_path_curve_to (&gstate->path, &p0, &p1, &p2);
}
/* Spline deviation from the circle in radius would be given by:
@@ -1025,63 +1008,54 @@ _cairo_gstate_arc_to (cairo_gstate_t *gstate,
cairo_status_t
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
{
- cairo_status_t status;
- double x, y;
+ cairo_distance_t distance;
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
- x = gstate->current_point.x + dx;
- y = gstate->current_point.y + dy;
-
- status = _cairo_path_move_to (&gstate->path, x, y);
-
- _cairo_gstate_set_current_point (gstate, x, y);
+ distance.dx = _cairo_fixed_from_double (dx);
+ distance.dy = _cairo_fixed_from_double (dy);
- gstate->last_move_point = gstate->current_point;
-
- return status;
+ return _cairo_path_rel_move_to (&gstate->path, &distance);
}
cairo_status_t
_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy)
{
- cairo_status_t status;
- double x, y;
+ cairo_distance_t distance;
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
- x = gstate->current_point.x + dx;
- y = gstate->current_point.y + dy;
-
- status = _cairo_path_line_to (&gstate->path, x, y);
-
- _cairo_gstate_set_current_point (gstate, x, y);
+ distance.dx = _cairo_fixed_from_double (dx);
+ distance.dy = _cairo_fixed_from_double (dy);
- return status;
+ return _cairo_path_rel_line_to (&gstate->path, &distance);
}
cairo_status_t
_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
+ double dx0, double dy0,
double dx1, double dy1,
- double dx2, double dy2,
- double dx3, double dy3)
+ double dx2, double dy2)
{
- cairo_status_t status;
+ cairo_distance_t distance[3];
+ cairo_matrix_transform_distance (&gstate->ctm, &dx0, &dy0);
cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
- cairo_matrix_transform_distance (&gstate->ctm, &dx3, &dy3);
- status = _cairo_path_curve_to (&gstate->path,
- gstate->current_point.x + dx1, gstate->current_point.y + dy1,
- gstate->current_point.x + dx2, gstate->current_point.y + dy2,
- gstate->current_point.x + dx3, gstate->current_point.y + dy3);
+ distance[0].dx = _cairo_fixed_from_double (dx0);
+ distance[0].dy = _cairo_fixed_from_double (dy0);
- _cairo_gstate_set_current_point (gstate,
- gstate->current_point.x + dx3,
- gstate->current_point.y + dy3);
+ distance[1].dx = _cairo_fixed_from_double (dx1);
+ distance[1].dy = _cairo_fixed_from_double (dy1);
- return status;
+ distance[2].dx = _cairo_fixed_from_double (dx2);
+ distance[2].dy = _cairo_fixed_from_double (dy2);
+
+ return _cairo_path_rel_curve_to (&gstate->path,
+ &distance[0],
+ &distance[1],
+ &distance[2]);
}
/* XXX: NYI
@@ -1098,29 +1072,24 @@ _cairo_gstate_stroke_path (cairo_gstate_t *gstate)
cairo_status_t
_cairo_gstate_close_path (cairo_gstate_t *gstate)
{
- cairo_status_t status;
-
- status = _cairo_path_close_path (&gstate->path);
-
- _cairo_gstate_set_current_point (gstate,
- gstate->last_move_point.x,
- gstate->last_move_point.y);
-
- return status;
+ return _cairo_path_close_path (&gstate->path);
}
cairo_status_t
_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_ret)
{
+ cairo_status_t status;
+ cairo_point_t point;
double x, y;
- if (gstate->has_current_point) {
- x = gstate->current_point.x;
- y = gstate->current_point.y;
- cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
- } else {
+ status = _cairo_path_current_point (&gstate->path, &point);
+ if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
x = 0.0;
y = 0.0;
+ } else {
+ x = _cairo_fixed_to_double (point.x);
+ y = _cairo_fixed_to_double (point.y);
+ cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
}
*x_ret = x;
@@ -1129,24 +1098,201 @@ _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_re
return CAIRO_STATUS_SUCCESS;
}
+typedef struct gstate_path_interpreter {
+ cairo_matrix_t ctm_inverse;
+ double tolerance;
+ cairo_point_t current_point;
+
+ cairo_move_to_func_t *move_to;
+ cairo_line_to_func_t *line_to;
+ cairo_curve_to_func_t *curve_to;
+ cairo_close_path_func_t *close_path;
+
+ void *closure;
+} gpi_t;
+
static cairo_status_t
-_cairo_gstate_ensure_source (cairo_gstate_t *gstate)
+_gpi_move_to (void *closure, cairo_point_t *point)
{
- if (gstate->source)
- return CAIRO_STATUS_SUCCESS;
+ gpi_t *gpi = closure;
+ double x, y;
- if (gstate->surface == NULL)
+ x = _cairo_fixed_to_double (point->x);
+ y = _cairo_fixed_to_double (point->y);
+
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+
+ gpi->move_to (gpi->closure, x, y);
+ gpi->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_gpi_line_to (void *closure, cairo_point_t *point)
+{
+ gpi_t *gpi = closure;
+ double x, y;
+
+ x = _cairo_fixed_to_double (point->x);
+ y = _cairo_fixed_to_double (point->y);
+
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+
+ gpi->line_to (gpi->closure, x, y);
+ gpi->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_gpi_curve_to (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ gpi_t *gpi = closure;
+ cairo_status_t status;
+ cairo_spline_t spline;
+ double x1, y1, x2, y2, x3, y3;
+
+ if (gpi->curve_to) {
+ x1 = _cairo_fixed_to_double (p1->x);
+ y1 = _cairo_fixed_to_double (p1->y);
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x1, &y1);
+
+ x2 = _cairo_fixed_to_double (p2->x);
+ y2 = _cairo_fixed_to_double (p2->y);
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x2, &y2);
+
+ x3 = _cairo_fixed_to_double (p3->x);
+ y3 = _cairo_fixed_to_double (p3->y);
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x3, &y3);
+
+ gpi->curve_to (gpi->closure, x1, y1, x2, y2, x3, y3);
+ } else {
+ cairo_point_t *p0 = &gpi->current_point;
+ int i;
+ double x, y;
+
+ status = _cairo_spline_init (&spline, p0, p1, p2, p3);
+ if (status == CAIRO_INT_STATUS_DEGENERATE)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_spline_decompose (&spline, gpi->tolerance);
+ if (status)
+ return status;
+
+ for (i=1; i < spline.num_points; i++) {
+ x = _cairo_fixed_to_double (spline.points[i].x);
+ y = _cairo_fixed_to_double (spline.points[i].y);
+
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+
+ gpi->line_to (gpi->closure, x, y);
+ }
+ }
+
+ gpi->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_gpi_close_path (void *closure)
+{
+ gpi_t *gpi = closure;
+
+ gpi->close_path (gpi->closure);
+
+ gpi->current_point.x = 0;
+ gpi->current_point.y = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* It's OK for curve_path to be NULL. In that case, all curves in the
+ path will be decomposed into one or more calls to the line_to
+ function, (according to the current tolerance). */
+cairo_status_t
+_cairo_gstate_interpret_path (cairo_gstate_t *gstate,
+ cairo_move_to_func_t *move_to,
+ cairo_line_to_func_t *line_to,
+ cairo_curve_to_func_t *curve_to,
+ cairo_close_path_func_t *close_path,
+ void *closure)
+{
+ cairo_path_t path;
+ gpi_t gpi;
+
+ /* Anything we want from gstate must be copied. We must not retain
+ pointers into gstate. */
+ _cairo_path_init_copy (&path, &gstate->path);
+
+ cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse);
+ gpi.tolerance = gstate->tolerance;
+
+ gpi.move_to = move_to;
+ gpi.line_to = line_to;
+ gpi.curve_to = curve_to;
+ gpi.close_path = close_path;
+ gpi.closure = closure;
+
+ gpi.current_point.x = 0;
+ gpi.current_point.y = 0;
+
+ return _cairo_path_interpret (&path,
+ CAIRO_DIRECTION_FORWARD,
+ _gpi_move_to,
+ _gpi_line_to,
+ _gpi_curve_to,
+ _gpi_close_path,
+ &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_create_pattern (cairo_gstate_t *gstate,
+ cairo_pattern_t *pattern,
+ cairo_box_t *extents)
+{
+ 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;
}
@@ -1155,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);
@@ -1174,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);
@@ -1227,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;
@@ -1241,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.);
@@ -1261,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
@@ -1286,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);
@@ -1302,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,
@@ -1315,11 +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;
@@ -1331,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;
}
@@ -1349,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);
@@ -1363,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);
@@ -1404,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);
@@ -1430,39 +1570,137 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate)
}
cairo_status_t
-_cairo_gstate_clip (cairo_gstate_t *gstate)
+_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+ double *x1, double *y1,
+ double *x2, double *y2)
{
cairo_status_t status;
- cairo_surface_t *alpha_one;
cairo_traps_t traps;
- cairo_color_t white_color;
+ cairo_box_t extents;
+
+ _cairo_traps_init (&traps);
+
+ status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
+ if (status)
+ goto BAIL;
- _cairo_color_init (&white_color);
+ _cairo_traps_extents (&traps, &extents);
- 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)
- return CAIRO_STATUS_NO_MEMORY;
+ *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)
+{
+ /* destroy any existing clip-region artifacts */
+ if (gstate->clip.surface)
+ cairo_surface_destroy (gstate->clip.surface);
+ gstate->clip.surface = NULL;
+
+ if (gstate->clip.region)
+ pixman_region_destroy (gstate->clip.region);
+ gstate->clip.region = NULL;
+
+ /* reset the surface's clip to the whole surface */
+ _cairo_surface_set_clip_region (gstate->surface,
+ gstate->clip.region);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static int
+extract_transformed_rectangle(cairo_matrix_t *mat,
+ cairo_traps_t *tr,
+ pixman_box16_t *box)
+{
+#define CAIRO_FIXED_IS_INTEGER(x) (((x) & 0xFFFF) == 0)
+#define CAIRO_FIXED_INTEGER_PART(x) ((x) >> 16)
+
+ double a, b, c, d, tx, ty;
+ cairo_status_t st;
+
+ st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
+ if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
+ return 0;
+
+ if (tr->num_traps == 1
+ && tr->traps[0].left.p1.x == tr->traps[0].left.p2.x
+ && tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
+ && tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
+ && tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.x)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.y)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.x)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.y)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.x)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.y)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.x)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.y)) {
+
+ box->x1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.x);
+ box->x2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].right.p1.x);
+ box->y1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.y);
+ box->y2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p2.y);
+ return 1;
}
+ return 0;
- 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;
+#undef CAIRO_FIXED_IS_INTEGER
+#undef CAIRO_FIXED_INTEGER_PART
+}
- cairo_surface_set_repeat (alpha_one, 1);
+cairo_status_t
+_cairo_gstate_clip (cairo_gstate_t *gstate)
+{
+ cairo_status_t status;
+ cairo_pattern_t pattern;
+ cairo_traps_t traps;
+ cairo_color_t white_color;
+ pixman_box16_t box;
+
+ /* Fill the clip region as traps. */
_cairo_traps_init (&traps);
status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
@@ -1471,16 +1709,82 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
return status;
}
+ /* Check to see if we can represent these traps as a PixRegion. */
+
+ if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) {
+
+ pixman_region16_t *rect = NULL;
+ pixman_region16_t *intersection = NULL;
+
+ status = CAIRO_STATUS_SUCCESS;
+ rect = pixman_region_create_simple (&box);
+
+ if (rect == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+
+ } else {
+
+ if (gstate->clip.region == NULL) {
+ gstate->clip.region = rect;
+ } else {
+ intersection = pixman_region_create();
+ if (pixman_region_intersect (intersection,
+ gstate->clip.region, rect)
+ == PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (gstate->clip.region);
+ gstate->clip.region = intersection;
+ } else {
+ status = CAIRO_STATUS_NO_MEMORY;
+ }
+ pixman_region_destroy (rect);
+ }
+
+ 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;
+ }
+ }
+
+ /* Otherwise represent the clip as a mask surface. */
+
+ _cairo_color_init (&white_color);
+
+ 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)
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ _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;
}
@@ -1491,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);
@@ -1527,32 +1816,47 @@ _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;
}
cairo_status_t
_cairo_gstate_select_font (cairo_gstate_t *gstate,
- char *family,
+ const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
@@ -1600,6 +1904,7 @@ _cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
status = _cairo_font_font_extents (gstate->font, extents);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
+
return status;
}
@@ -1622,14 +1927,24 @@ _cairo_gstate_text_extents (cairo_gstate_t *gstate,
{
cairo_matrix_t saved_font_matrix;
cairo_status_t status;
+ double scale_x, scale_y;
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
- cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
+ _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
+ cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
status = _cairo_font_text_extents (gstate->font,
utf8, extents);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
+
+ extents->x_bearing /= scale_x;
+ extents->y_bearing /= scale_y;
+ extents->width /= scale_x;
+ extents->height /= scale_y;
+ extents->x_advance /= scale_x;
+ extents->y_advance /= scale_y;
+
return status;
}
@@ -1640,120 +1955,91 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
cairo_text_extents_t *extents)
{
cairo_status_t status;
- int i;
- cairo_glyph_t *transformed_glyphs = NULL;
cairo_matrix_t saved_font_matrix;
-
- transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
- if (transformed_glyphs == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < num_glyphs; ++i)
- {
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &(transformed_glyphs[i].x),
- &(transformed_glyphs[i].y));
- }
+ double scale_x, scale_y;
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
- cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
+ _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
+ cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
status = _cairo_font_glyph_extents (gstate->font,
- transformed_glyphs, num_glyphs,
+ glyphs, num_glyphs,
extents);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
- free (transformed_glyphs);
- return status;
-}
-
+ extents->x_bearing /= scale_x;
+ extents->y_bearing /= scale_y;
+ extents->width /= scale_x;
+ extents->height /= scale_y;
+ extents->x_advance /= scale_x;
+ extents->y_advance /= scale_y;
-static cairo_status_t
-setup_text_rendering_context(cairo_gstate_t *gstate,
- double *x, double *y,
- cairo_matrix_t *user_to_source)
-{
- cairo_status_t status;
- cairo_matrix_t device_to_source;
-
- /* XXX: I believe this is correct, but it would be much more clear
- to have some explicit current_point accesor functions, (one for
- user- and one for device-space). */
-
- if (gstate->has_current_point) {
- *x = gstate->current_point.x;
- *y = gstate->current_point.y;
- } else {
- *x = 0;
- *y = 0;
- cairo_matrix_transform_point (&gstate->ctm, x, y);
- }
-
- 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);
+ return status;
}
-
cairo_status_t
_cairo_gstate_show_text (cairo_gstate_t *gstate,
const unsigned char *utf8)
{
cairo_status_t status;
+ cairo_point_t point;
double x, y;
- cairo_matrix_t user_to_source;
cairo_matrix_t saved_font_matrix;
-
- status = setup_text_rendering_context(gstate, &x, &y, &user_to_source);
- if (status)
- return status;
+ 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) {
+ x = 0;
+ y = 0;
+ cairo_matrix_transform_point (&gstate->ctm, &x, &y);
+ } else {
+ x = _cairo_fixed_to_double (point.x);
+ y = _cairo_fixed_to_double (point.y);
+ }
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;
- double x, y;
- 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)
@@ -1767,25 +2053,37 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
&(transformed_glyphs[i].y));
}
- status = setup_text_rendering_context (gstate, &x, &y, &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->surface, x, y,
+ 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);
return status;
-
}
@@ -1795,21 +2093,35 @@ _cairo_gstate_text_path (cairo_gstate_t *gstate,
{
cairo_status_t status;
cairo_matrix_t saved_font_matrix;
+ cairo_point_t point;
+ double x, y;
+
+ status = _cairo_path_current_point (&gstate->path, &point);
+ if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
+ x = 0;
+ y = 0;
+ cairo_matrix_transform_point (&gstate->ctm, &x, &y);
+ } else {
+ x = _cairo_fixed_to_double (point.x);
+ y = _cairo_fixed_to_double (point.y);
+ }
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
status = _cairo_font_text_path (gstate->font,
- &gstate->path,
- utf8);
+ x, y,
+ utf8,
+ &gstate->path);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
+
return status;
}
cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
+_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
int num_glyphs)
{
@@ -1834,11 +2146,11 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
status = _cairo_font_glyph_path (gstate->font,
- &gstate->path,
- transformed_glyphs, num_glyphs);
+ transformed_glyphs, num_glyphs,
+ &gstate->path);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
-
+
free (transformed_glyphs);
return status;
}
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index efa54d26..a11a07ee 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -45,7 +45,7 @@ _cairo_format_bpp (cairo_format_t format)
}
static cairo_image_surface_t *
-_cairo_image_surface_create_for_ic_image (IcImage *ic_image)
+_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image)
{
cairo_image_surface_t *surface;
@@ -55,15 +55,15 @@ _cairo_image_surface_create_for_ic_image (IcImage *ic_image)
_cairo_surface_init (&surface->base, &cairo_image_surface_backend);
- surface->ic_image = ic_image;
+ surface->pixman_image = pixman_image;
- surface->data = (char *) IcImageGetData (ic_image);
+ surface->data = (char *) pixman_image_get_data (pixman_image);
surface->owns_data = 0;
- surface->width = IcImageGetWidth (ic_image);
- surface->height = IcImageGetHeight (ic_image);
- surface->stride = IcImageGetStride (ic_image);
- surface->depth = IcImageGetDepth (ic_image);
+ surface->width = pixman_image_get_width (pixman_image);
+ surface->height = pixman_image_get_height (pixman_image);
+ surface->stride = pixman_image_get_stride (pixman_image);
+ surface->depth = pixman_image_get_depth (pixman_image);
return surface;
}
@@ -76,47 +76,47 @@ _cairo_image_surface_create_with_masks (char *data,
int stride)
{
cairo_image_surface_t *surface;
- IcFormat *ic_format;
- IcImage *ic_image;
+ pixman_format_t *pixman_format;
+ pixman_image_t *pixman_image;
- ic_format = IcFormatCreateMasks (format->bpp,
- format->alpha_mask,
- format->red_mask,
- format->green_mask,
- format->blue_mask);
+ pixman_format = pixman_format_create_masks (format->bpp,
+ format->alpha_mask,
+ format->red_mask,
+ format->green_mask,
+ format->blue_mask);
- if (ic_format == NULL)
+ if (pixman_format == NULL)
return NULL;
- ic_image = IcImageCreateForData ((IcBits *) data, ic_format,
- width, height, format->bpp, stride);
+ pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
+ width, height, format->bpp, stride);
- IcFormatDestroy (ic_format);
+ pixman_format_destroy (pixman_format);
- if (ic_image == NULL)
+ if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_ic_image (ic_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
return surface;
}
-static IcFormat *
-_create_ic_format (cairo_format_t format)
+static pixman_format_t *
+_create_pixman_format (cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_A1:
- return IcFormatCreate (IcFormatNameA1);
+ return pixman_format_create (PIXMAN_FORMAT_NAME_A1);
break;
case CAIRO_FORMAT_A8:
- return IcFormatCreate (IcFormatNameA8);
+ return pixman_format_create (PIXMAN_FORMAT_NAME_A8);
break;
case CAIRO_FORMAT_RGB24:
- return IcFormatCreate (IcFormatNameRGB24);
+ return pixman_format_create (PIXMAN_FORMAT_NAME_RG_B24);
break;
case CAIRO_FORMAT_ARGB32:
default:
- return IcFormatCreate (IcFormatNameARGB32);
+ return pixman_format_create (PIXMAN_FORMAT_NAME_AR_GB32);
break;
}
}
@@ -127,21 +127,21 @@ cairo_image_surface_create (cairo_format_t format,
int height)
{
cairo_image_surface_t *surface;
- IcFormat *ic_format;
- IcImage *ic_image;
+ pixman_format_t *pixman_format;
+ pixman_image_t *pixman_image;
- ic_format = _create_ic_format (format);
- if (ic_format == NULL)
+ pixman_format = _create_pixman_format (format);
+ if (pixman_format == NULL)
return NULL;
- ic_image = IcImageCreate (ic_format, width, height);
+ pixman_image = pixman_image_create (pixman_format, width, height);
- IcFormatDestroy (ic_format);
+ pixman_format_destroy (pixman_format);
- if (ic_image == NULL)
+ if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_ic_image (ic_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
return &surface->base;
}
@@ -154,24 +154,24 @@ cairo_image_surface_create_for_data (char *data,
int stride)
{
cairo_image_surface_t *surface;
- IcFormat *ic_format;
- IcImage *ic_image;
+ pixman_format_t *pixman_format;
+ pixman_image_t *pixman_image;
- ic_format = _create_ic_format (format);
- if (ic_format == NULL)
+ pixman_format = _create_pixman_format (format);
+ if (pixman_format == NULL)
return NULL;
- ic_image = IcImageCreateForData ((IcBits *) data, ic_format,
- width, height,
- _cairo_format_bpp (format),
- stride);
+ pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
+ width, height,
+ _cairo_format_bpp (format),
+ stride);
- IcFormatDestroy (ic_format);
+ pixman_format_destroy (pixman_format);
- if (ic_image == NULL)
+ if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_ic_image (ic_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
return &surface->base;
}
@@ -190,8 +190,8 @@ _cairo_image_abstract_surface_destroy (void *abstract_surface)
{
cairo_image_surface_t *surface = abstract_surface;
- if (surface->ic_image)
- IcImageDestroy (surface->ic_image);
+ if (surface->pixman_image)
+ pixman_image_destroy (surface->pixman_image);
if (surface->owns_data) {
free (surface->data);
@@ -247,21 +247,21 @@ cairo_status_t
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
cairo_matrix_t *matrix)
{
- IcTransform ic_transform;
+ pixman_transform_t pixman_transform;
- ic_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- ic_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- ic_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
+ pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
+ pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
- ic_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- ic_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- ic_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+ pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
+ pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
+ pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
- ic_transform.matrix[2][0] = 0;
- ic_transform.matrix[2][1] = 0;
- ic_transform.matrix[2][2] = _cairo_fixed_from_double (1);
+ pixman_transform.matrix[2][0] = 0;
+ pixman_transform.matrix[2][1] = 0;
+ pixman_transform.matrix[2][2] = _cairo_fixed_from_double (1);
- IcImageSetTransform (surface->ic_image, &ic_transform);
+ pixman_image_set_transform (surface->pixman_image, &pixman_transform);
return CAIRO_STATUS_SUCCESS;
}
@@ -277,29 +277,29 @@ _cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t
cairo_status_t
_cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter)
{
- IcFilter ic_filter;
+ pixman_filter_t pixman_filter;
switch (filter) {
case CAIRO_FILTER_FAST:
- ic_filter = IcFilterFast;
+ pixman_filter = PIXMAN_FILTER_FAST;
break;
case CAIRO_FILTER_GOOD:
- ic_filter = IcFilterGood;
+ pixman_filter = PIXMAN_FILTER_GOOD;
break;
case CAIRO_FILTER_BEST:
- ic_filter = IcFilterBest;
+ pixman_filter = PIXMAN_FILTER_BEST;
break;
case CAIRO_FILTER_NEAREST:
- ic_filter = IcFilterNearest;
+ pixman_filter = PIXMAN_FILTER_NEAREST;
break;
case CAIRO_FILTER_BILINEAR:
- ic_filter = IcFilterBilinear;
+ pixman_filter = PIXMAN_FILTER_BILINEAR;
break;
default:
- ic_filter = IcFilterBest;
+ pixman_filter = PIXMAN_FILTER_BEST;
}
- IcImageSetFilter (surface->ic_image, ic_filter);
+ pixman_image_set_filter (surface->pixman_image, pixman_filter);
return CAIRO_STATUS_SUCCESS;
}
@@ -314,45 +314,45 @@ _cairo_image_abstract_surface_set_repeat (void *abstract_surface, int repeat)
cairo_status_t
_cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat)
{
- IcImageSetRepeat (surface->ic_image, repeat);
+ pixman_image_set_repeat (surface->pixman_image, repeat);
return CAIRO_STATUS_SUCCESS;
}
-static IcOperator
-_ic_operator (cairo_operator_t operator)
+static pixman_operator_t
+_pixman_operator (cairo_operator_t operator)
{
switch (operator) {
case CAIRO_OPERATOR_CLEAR:
- return IcOperatorClear;
+ return PIXMAN_OPERATOR_CLEAR;
case CAIRO_OPERATOR_SRC:
- return IcOperatorSrc;
+ return PIXMAN_OPERATOR_SRC;
case CAIRO_OPERATOR_DST:
- return IcOperatorDst;
+ return PIXMAN_OPERATOR_DST;
case CAIRO_OPERATOR_OVER:
- return IcOperatorOver;
+ return PIXMAN_OPERATOR_OVER;
case CAIRO_OPERATOR_OVER_REVERSE:
- return IcOperatorOverReverse;
+ return PIXMAN_OPERATOR_OVER_REVERSE;
case CAIRO_OPERATOR_IN:
- return IcOperatorIn;
+ return PIXMAN_OPERATOR_IN;
case CAIRO_OPERATOR_IN_REVERSE:
- return IcOperatorInReverse;
+ return PIXMAN_OPERATOR_IN_REVERSE;
case CAIRO_OPERATOR_OUT:
- return IcOperatorOut;
+ return PIXMAN_OPERATOR_OUT;
case CAIRO_OPERATOR_OUT_REVERSE:
- return IcOperatorOutReverse;
+ return PIXMAN_OPERATOR_OUT_REVERSE;
case CAIRO_OPERATOR_ATOP:
- return IcOperatorAtop;
+ return PIXMAN_OPERATOR_ATOP;
case CAIRO_OPERATOR_ATOP_REVERSE:
- return IcOperatorAtopReverse;
+ return PIXMAN_OPERATOR_ATOP_REVERSE;
case CAIRO_OPERATOR_XOR:
- return IcOperatorXor;
+ return PIXMAN_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
- return IcOperatorAdd;
+ return PIXMAN_OPERATOR_ADD;
case CAIRO_OPERATOR_SATURATE:
- return IcOperatorSaturate;
+ return PIXMAN_OPERATOR_SATURATE;
default:
- return IcOperatorOver;
+ return PIXMAN_OPERATOR_OVER;
}
}
@@ -380,14 +380,14 @@ _cairo_image_surface_composite (cairo_operator_t operator,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- IcComposite (_ic_operator (operator),
- src->ic_image,
- mask ? mask->ic_image : NULL,
- dst->ic_image,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
+ pixman_composite (_pixman_operator (operator),
+ src->pixman_image,
+ mask ? mask->pixman_image : NULL,
+ dst->pixman_image,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
return CAIRO_STATUS_SUCCESS;
}
@@ -401,16 +401,16 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
{
cairo_image_surface_t *surface = abstract_surface;
- IcColor ic_color;
+ pixman_color_t pixman_color;
- ic_color.red = color->red_short;
- ic_color.green = color->green_short;
- ic_color.blue = color->blue_short;
- ic_color.alpha = color->alpha_short;
+ pixman_color.red = color->red_short;
+ pixman_color.green = color->green_short;
+ pixman_color.blue = color->blue_short;
+ pixman_color.alpha = color->alpha_short;
- /* XXX: The IcRectangle cast is evil... it needs to go away somehow. */
- IcFillRectangles (_ic_operator(operator), surface->ic_image,
- &ic_color, (IcRectangle *) rects, num_rects);
+ /* XXX: The pixman_rectangle_t cast is evil... it needs to go away somehow. */
+ pixman_fill_rectangles (_pixman_operator(operator), surface->pixman_image,
+ &pixman_color, (pixman_rectangle_t *) rects, num_rects);
return CAIRO_STATUS_SUCCESS;
}
@@ -430,9 +430,9 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
if (generic_src->backend != dst->base.backend)
return CAIRO_INT_STATUS_UNSUPPORTED;
- /* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */
- IcCompositeTrapezoids (operator, src->ic_image, dst->ic_image,
- x_src, y_src, (IcTrapezoid *) traps, num_traps);
+ /* XXX: The pixman_trapezoid_t cast is evil and needs to go away somehow. */
+ pixman_composite_trapezoids (operator, src->pixman_image, dst->pixman_image,
+ x_src, y_src, (pixman_trapezoid_t *) traps, num_traps);
return CAIRO_STATUS_SUCCESS;
}
@@ -449,6 +449,44 @@ _cairo_image_surface_show_page (void *abstract_surface)
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+static cairo_int_status_t
+_cairo_image_abstract_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
+
+ return _cairo_image_surface_set_clip_region (surface, region);
+}
+
+cairo_int_status_t
+_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
+ pixman_region16_t *region)
+{
+ pixman_image_set_clip_region (surface->pixman_image, region);
+
+ 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,
@@ -462,5 +500,7 @@ static const cairo_surface_backend_t cairo_image_surface_backend = {
_cairo_image_surface_fill_rectangles,
_cairo_image_surface_composite_trapezoids,
_cairo_image_surface_copy_page,
- _cairo_image_surface_show_page
+ _cairo_image_surface_show_page,
+ _cairo_image_abstract_surface_set_clip_region,
+ _cairo_image_abstract_surface_create_pattern
};
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index 655bcde8..de89c0fd 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -386,3 +386,22 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
return CAIRO_STATUS_SUCCESS;
}
+
+/* Compute the amount that each basis vector is scaled by. */
+cairo_status_t
+_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy)
+{
+ double x, y;
+
+ x = 1.0;
+ y = 0.0;
+ cairo_matrix_transform_distance (matrix, &x, &y);
+ *sx = sqrt(x*x + y*y);
+
+ x = 0.0;
+ y = 1.0;
+ cairo_matrix_transform_distance (matrix, &x, &y);
+ *sy = sqrt(x*x + y*y);
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-path-bounds.c b/src/cairo-path-bounds.c
index 40b64c3d..6a02b9ac 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -46,18 +46,19 @@ static cairo_status_t
_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point);
static cairo_status_t
-_cairo_path_bounder_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2);
+_cairo_path_bounder_move_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_path_bounder_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d);
+_cairo_path_bounder_line_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done_t done);
+_cairo_path_bounder_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d);
static cairo_status_t
-_cairo_path_bounder_done_path (void *closure);
+_cairo_path_bounder_close_path (void *closure);
static void
_cairo_path_bounder_init (cairo_path_bounder_t *bounder)
@@ -99,39 +100,42 @@ _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *poi
}
static cairo_status_t
-_cairo_path_bounder_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
+_cairo_path_bounder_move_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
- _cairo_path_bounder_add_point (bounder, p1);
- _cairo_path_bounder_add_point (bounder, p2);
+ _cairo_path_bounder_add_point (bounder, point);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_path_bounder_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d)
+_cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
- _cairo_path_bounder_add_point (bounder, a);
- _cairo_path_bounder_add_point (bounder, b);
- _cairo_path_bounder_add_point (bounder, c);
- _cairo_path_bounder_add_point (bounder, d);
+ _cairo_path_bounder_add_point (bounder, point);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done_t done)
+_cairo_path_bounder_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
{
+ cairo_path_bounder_t *bounder = closure;
+
+ _cairo_path_bounder_add_point (bounder, b);
+ _cairo_path_bounder_add_point (bounder, c);
+ _cairo_path_bounder_add_point (bounder, d);
+
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_path_bounder_done_path (void *closure)
+_cairo_path_bounder_close_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
}
@@ -141,18 +145,17 @@ cairo_status_t
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2)
{
cairo_status_t status;
- static cairo_path_callbacks_t const cb = {
- _cairo_path_bounder_add_edge,
- _cairo_path_bounder_add_spline,
- _cairo_path_bounder_done_sub_path,
- _cairo_path_bounder_done_path
- };
cairo_path_bounder_t bounder;
_cairo_path_bounder_init (&bounder);
- status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD, &cb, &bounder);
+ status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_curve_to,
+ _cairo_path_bounder_close_path,
+ &bounder);
if (status) {
*x1 = *y1 = *x2 = *y2 = 0.0;
_cairo_path_bounder_fini (&bounder);
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index 8f34af85..fba5bb09 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -31,6 +31,8 @@ typedef struct cairo_filler {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
+ cairo_point_t current_point;
+
cairo_polygon_t polygon;
} cairo_filler_t;
@@ -41,18 +43,19 @@ static void
_cairo_filler_fini (cairo_filler_t *filler);
static cairo_status_t
-_cairo_filler_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2);
+_cairo_filler_move_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_filler_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d);
+_cairo_filler_line_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done_t done);
+_cairo_filler_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d);
static cairo_status_t
-_cairo_filler_done_path (void *closure);
+_cairo_filler_close_path (void *closure);
static void
_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps)
@@ -60,6 +63,9 @@ _cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_
filler->gstate = gstate;
filler->traps = traps;
+ filler->current_point.x = 0;
+ filler->current_point.y = 0;
+
_cairo_polygon_init (&filler->polygon);
}
@@ -70,18 +76,46 @@ _cairo_filler_fini (cairo_filler_t *filler)
}
static cairo_status_t
-_cairo_filler_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
+_cairo_filler_move_to (void *closure, cairo_point_t *point)
{
+ cairo_status_t status;
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
- return _cairo_polygon_add_edge (polygon, p1, p2);
+ status = _cairo_polygon_close (polygon);
+ if (status)
+ return status;
+
+ status = _cairo_polygon_move_to (polygon, point);
+ if (status)
+ return status;
+
+ filler->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_filler_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d)
+_cairo_filler_line_to (void *closure, cairo_point_t *point)
+{
+ cairo_status_t status;
+ cairo_filler_t *filler = closure;
+ cairo_polygon_t *polygon = &filler->polygon;
+
+ status = _cairo_polygon_line_to (polygon, point);
+ if (status)
+ return status;
+
+ filler->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_filler_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
{
int i;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@@ -90,7 +124,8 @@ _cairo_filler_add_spline (void *closure,
cairo_gstate_t *gstate = filler->gstate;
cairo_spline_t spline;
- status = _cairo_spline_init (&spline, a, b, c, d);
+ status = _cairo_spline_init (&spline, &filler->current_point, b, c, d);
+
if (status == CAIRO_INT_STATUS_DEGENERATE)
return CAIRO_STATUS_SUCCESS;
@@ -98,65 +133,65 @@ _cairo_filler_add_spline (void *closure,
if (status)
goto CLEANUP_SPLINE;
- for (i = 0; i < spline.num_points - 1; i++) {
- status = _cairo_polygon_add_edge (polygon, &spline.points[i], &spline.points[i+1]);
+ for (i = 1; i < spline.num_points; i++) {
+ status = _cairo_polygon_line_to (polygon, &spline.points[i]);
if (status)
- goto CLEANUP_SPLINE;
+ break;
}
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
+ filler->current_point = *d;
+
return status;
}
static cairo_status_t
-_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done_t done)
+_cairo_filler_close_path (void *closure)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_status_t status;
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
- _cairo_polygon_close (polygon);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_filler_done_path (void *closure)
-{
- cairo_filler_t *filler = closure;
+ status = _cairo_polygon_close (polygon);
+ if (status)
+ return status;
- return _cairo_traps_tessellate_polygon (filler->traps,
- &filler->polygon,
- filler->gstate->fill_rule);
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
- static const cairo_path_callbacks_t filler_callbacks = {
- _cairo_filler_add_edge,
- _cairo_filler_add_spline,
- _cairo_filler_done_sub_path,
- _cairo_filler_done_path
- };
-
- cairo_status_t status;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
_cairo_filler_init (&filler, gstate, traps);
status = _cairo_path_interpret (path,
CAIRO_DIRECTION_FORWARD,
- &filler_callbacks, &filler);
- if (status) {
- _cairo_filler_fini (&filler);
- return status;
- }
+ _cairo_filler_move_to,
+ _cairo_filler_line_to,
+ _cairo_filler_curve_to,
+ _cairo_filler_close_path,
+ &filler);
+ if (status)
+ goto BAIL;
+ status = _cairo_polygon_close (&filler.polygon);
+ if (status)
+ goto BAIL;
+
+ status = _cairo_traps_tessellate_polygon (filler.traps,
+ &filler.polygon,
+ filler.gstate->fill_rule);
+ if (status)
+ goto BAIL;
+
+BAIL:
_cairo_filler_fini (&filler);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 35e7b1b7..c2412579 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -31,11 +31,17 @@ typedef struct cairo_stroker {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
- int have_prev;
- int have_first;
- int is_first;
- cairo_stroke_face_t prev;
- cairo_stroke_face_t first;
+ int has_current_point;
+ cairo_point_t current_point;
+ cairo_point_t first_point;
+
+ int has_current_face;
+ cairo_stroke_face_t current_face;
+
+ int has_first_face;
+ cairo_stroke_face_t first_face;
+
+ int dashed;
int dash_index;
int dash_on;
double dash_remain;
@@ -49,21 +55,22 @@ static void
_cairo_stroker_fini (cairo_stroker_t *stroker);
static cairo_status_t
-_cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2);
+_cairo_stroker_move_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t *p2);
+_cairo_stroker_line_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_stroker_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d);
+_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done_t done);
+_cairo_stroker_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d);
static cairo_status_t
-_cairo_stroker_done_path (void *closure);
+_cairo_stroker_close_path (void *closure);
static void
_translate_point (cairo_point_t *point, cairo_point_t *offset);
@@ -89,6 +96,7 @@ _cairo_stroker_start_dash (cairo_stroker_t *stroker)
if (++i == gstate->num_dashes)
i = 0;
}
+ stroker->dashed = 1;
stroker->dash_index = i;
stroker->dash_on = on;
stroker->dash_remain = gstate->dash[i] - offset;
@@ -113,11 +121,15 @@ _cairo_stroker_init (cairo_stroker_t *stroker, cairo_gstate_t *gstate, cairo_tra
{
stroker->gstate = gstate;
stroker->traps = traps;
- stroker->have_prev = 0;
- stroker->have_first = 0;
- stroker->is_first = 1;
+
+ stroker->has_current_point = 0;
+ stroker->has_current_face = 0;
+ stroker->has_first_face = 0;
+
if (gstate->dash)
_cairo_stroker_start_dash (stroker);
+ else
+ stroker->dashed = 0;
}
static void
@@ -286,10 +298,11 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st
outer.x = _cairo_fixed_from_double (mx);
outer.y = _cairo_fixed_from_double (my);
_cairo_polygon_init (&polygon);
- _cairo_polygon_add_edge (&polygon, &in->point, inpt);
- _cairo_polygon_add_edge (&polygon, inpt, &outer);
- _cairo_polygon_add_edge (&polygon, &outer, outpt);
- _cairo_polygon_add_edge (&polygon, outpt, &in->point);
+ _cairo_polygon_move_to (&polygon, &in->point);
+ _cairo_polygon_line_to (&polygon, inpt);
+ _cairo_polygon_line_to (&polygon, &outer);
+ _cairo_polygon_line_to (&polygon, outpt);
+ _cairo_polygon_close (&polygon);
status = _cairo_traps_tessellate_polygon (stroker->traps,
&polygon,
CAIRO_FILL_RULE_WINDING);
@@ -351,8 +364,6 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
cairo_point_t occw, ocw;
cairo_polygon_t polygon;
- _cairo_polygon_init (&polygon);
-
dx = f->usr_vector.x;
dy = f->usr_vector.y;
dx *= gstate->line_width / 2.0;
@@ -365,10 +376,12 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
ocw.x = f->cw.x + fvector.dx;
ocw.y = f->cw.y + fvector.dy;
- _cairo_polygon_add_edge (&polygon, &f->cw, &ocw);
- _cairo_polygon_add_edge (&polygon, &ocw, &occw);
- _cairo_polygon_add_edge (&polygon, &occw, &f->ccw);
- _cairo_polygon_add_edge (&polygon, &f->ccw, &f->cw);
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_move_to (&polygon, &f->cw);
+ _cairo_polygon_line_to (&polygon, &ocw);
+ _cairo_polygon_line_to (&polygon, &occw);
+ _cairo_polygon_line_to (&polygon, &f->ccw);
+ _cairo_polygon_close (&polygon);
status = _cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING);
_cairo_polygon_fini (&polygon);
@@ -454,8 +467,9 @@ static cairo_status_t
_cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_point_t *p2,
cairo_stroke_face_t *start, cairo_stroke_face_t *end)
{
+ cairo_status_t status;
cairo_gstate_t *gstate = stroker->gstate;
- cairo_point_t quad[4];
+ cairo_polygon_t polygon;
cairo_slope_t slope;
if (p1->x == p2->x && p1->y == p2->y) {
@@ -473,20 +487,58 @@ _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_
fields from start. */
_compute_face (p2, &slope, gstate, end);
- quad[0] = start->cw;
- quad[1] = start->ccw;
- quad[2] = end->ccw;
- quad[3] = end->cw;
+ /* XXX: I should really check the return value of the
+ move_to/line_to functions here to catch out of memory
+ conditions. But since that would be ugly, I'd prefer to add a
+ status flag to the polygon object that I could check only once
+ at then end of this sequence, (like we do with cairo_t
+ already). */
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_move_to (&polygon, &start->cw);
+ _cairo_polygon_line_to (&polygon, &start->ccw);
+ _cairo_polygon_line_to (&polygon, &end->ccw);
+ _cairo_polygon_line_to (&polygon, &end->cw);
+ _cairo_polygon_close (&polygon);
+
+ /* XXX: We can't use tessellate_rectangle as the matrix may have
+ skewed this into a non-rectangular shape. Perhaps it would be
+ worth checking the matrix for skew so that the common case
+ could use the faster tessellate_rectangle rather than
+ tessellate_polygon? */
+ status = _cairo_traps_tessellate_polygon (stroker->traps,
+ &polygon, CAIRO_FILL_RULE_WINDING);
+
+ _cairo_polygon_fini (&polygon);
- return _cairo_traps_tessellate_rectangle (stroker->traps, quad);
+ return status;
}
static cairo_status_t
-_cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
+_cairo_stroker_move_to (void *closure, cairo_point_t *point)
+{
+ cairo_stroker_t *stroker = closure;
+
+ stroker->first_point = *point;
+ stroker->current_point = *point;
+ stroker->has_current_point = 1;
+
+ stroker->has_first_face = 0;
+ stroker->has_current_face = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_stroker_line_to (void *closure, cairo_point_t *point)
{
cairo_status_t status;
cairo_stroker_t *stroker = closure;
cairo_stroke_face_t start, end;
+ cairo_point_t *p1 = &stroker->current_point;
+ cairo_point_t *p2 = point;
+
+ if (!stroker->has_current_point)
+ return _cairo_stroker_move_to (stroker, point);
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
@@ -500,19 +552,20 @@ _cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
if (status)
return status;
- if (stroker->have_prev) {
- status = _cairo_stroker_join (stroker, &stroker->prev, &start);
+ if (stroker->has_current_face) {
+ status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
if (status)
return status;
} else {
- stroker->have_prev = 1;
- if (stroker->is_first) {
- stroker->have_first = 1;
- stroker->first = start;
+ if (!stroker->has_first_face) {
+ stroker->first_face = start;
+ stroker->has_first_face = 1;
}
}
- stroker->prev = end;
- stroker->is_first = 0;
+ stroker->current_face = end;
+ stroker->has_current_face = 1;
+
+ stroker->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
@@ -521,7 +574,7 @@ _cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
* Dashed lines. Cap each dash end, join around turns when on
*/
static cairo_status_t
-_cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t *p2)
+_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t *stroker = closure;
@@ -532,6 +585,11 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t
cairo_point_t fd1, fd2;
int first = 1;
cairo_stroke_face_t sub_start, sub_end;
+ cairo_point_t *p1 = &stroker->current_point;
+ cairo_point_t *p2 = point;
+
+ if (!stroker->has_current_point)
+ return _cairo_stroker_move_to (stroker, point);
dx = _cairo_fixed_to_double (p2->x - p1->x);
dy = _cairo_fixed_to_double (p2->y - p1->y);
@@ -569,18 +627,18 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t
return status;
} else {
/*
- * First in this segment, join to any prev, else
+ * First in this segment, join to any current_face, else
* if at start of sub-path, mark position, else
* cap
*/
- if (stroker->have_prev) {
- status = _cairo_stroker_join (stroker, &stroker->prev, &sub_start);
+ if (stroker->has_current_face) {
+ status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start);
if (status)
return status;
} else {
- if (stroker->is_first) {
- stroker->have_first = 1;
- stroker->first = sub_start;
+ if (!stroker->has_first_face) {
+ stroker->first_face = sub_start;
+ stroker->has_first_face = 1;
} else {
status = _cairo_stroker_cap (stroker, &sub_start);
if (status)
@@ -600,8 +658,8 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t
* Mark previous line face and fix up next time
* through
*/
- stroker->prev = sub_end;
- stroker->have_prev = 1;
+ stroker->current_face = sub_end;
+ stroker->has_current_face = 1;
}
} else {
/*
@@ -609,27 +667,30 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t
* and cap if necessary
*/
if (first) {
- if (stroker->have_prev) {
- status = _cairo_stroker_cap (stroker, &stroker->prev);
+ if (stroker->has_current_face) {
+ status = _cairo_stroker_cap (stroker, &stroker->current_face);
if (status)
return status;
}
}
if (!remain)
- stroker->have_prev = 0;
+ stroker->has_current_face = 0;
}
_cairo_stroker_step_dash (stroker, tmp);
fd1 = fd2;
first = 0;
}
- stroker->is_first = 0;
+
+ stroker->current_point = *point;
+
return status;
}
static cairo_status_t
-_cairo_stroker_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d)
+_cairo_stroker_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t *stroker = closure;
@@ -638,6 +699,7 @@ _cairo_stroker_add_spline (void *closure,
cairo_pen_t pen;
cairo_stroke_face_t start, end;
cairo_point_t extra_points[4];
+ cairo_point_t *a = &stroker->current_point;
status = _cairo_spline_init (&spline, a, b, c, d);
if (status == CAIRO_INT_STATUS_DEGENERATE)
@@ -650,19 +712,18 @@ _cairo_stroker_add_spline (void *closure,
_compute_face (a, &spline.initial_slope, gstate, &start);
_compute_face (d, &spline.final_slope, gstate, &end);
- if (stroker->have_prev) {
- status = _cairo_stroker_join (stroker, &stroker->prev, &start);
+ if (stroker->has_current_face) {
+ status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
if (status)
return status;
} else {
- stroker->have_prev = 1;
- if (stroker->is_first) {
- stroker->have_first = 1;
- stroker->first = start;
+ if (!stroker->has_first_face) {
+ stroker->first_face = start;
+ stroker->has_first_face = 1;
}
}
- stroker->prev = end;
- stroker->is_first = 0;
+ stroker->current_face = end;
+ stroker->has_current_face = 1;
extra_points[0] = start.cw;
extra_points[0].x -= start.point.x;
@@ -690,91 +751,89 @@ _cairo_stroker_add_spline (void *closure,
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
+ stroker->current_point = *d;
+
return status;
}
static cairo_status_t
-_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done_t done)
+_cairo_stroker_close_path (void *closure)
{
cairo_status_t status;
cairo_stroker_t *stroker = closure;
- switch (done) {
- case CAIRO_SUB_PATH_DONE_JOIN:
- if (stroker->have_first && stroker->have_prev) {
- status = _cairo_stroker_join (stroker, &stroker->prev, &stroker->first);
- if (status)
- return status;
- break;
- }
- /* fall through... */
- case CAIRO_SUB_PATH_DONE_CAP:
- if (stroker->have_first) {
- cairo_point_t t;
- /* The initial cap needs an outward facing vector. Reverse everything */
- stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
- stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
- stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
- stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
- t = stroker->first.cw;
- stroker->first.cw = stroker->first.ccw;
- stroker->first.ccw = t;
- status = _cairo_stroker_cap (stroker, &stroker->first);
- if (status)
- return status;
- }
- if (stroker->have_prev) {
- status = _cairo_stroker_cap (stroker, &stroker->prev);
- if (status)
- return status;
- }
- break;
+ if (stroker->has_current_point) {
+ if (stroker->dashed)
+ status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
+ else
+ status = _cairo_stroker_line_to (stroker, &stroker->first_point);
+ if (status)
+ return status;
}
- stroker->have_prev = 0;
- stroker->have_first = 0;
- stroker->is_first = 1;
+ if (stroker->has_first_face && stroker->has_current_face) {
+ status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face);
+ if (status)
+ return status;
+ }
- return CAIRO_STATUS_SUCCESS;
-}
+ stroker->has_first_face = 0;
+ stroker->has_current_face = 0;
+ stroker->has_current_point = 0;
-static cairo_status_t
-_cairo_stroker_done_path (void *closure)
-{
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
- static const cairo_path_callbacks_t stroker_solid_cb = {
- _cairo_stroker_add_edge,
- _cairo_stroker_add_spline,
- _cairo_stroker_done_sub_path,
- _cairo_stroker_done_path
- };
- static const cairo_path_callbacks_t stroker_dashed_cb = {
- _cairo_stroker_add_edge_dashed,
- _cairo_stroker_add_spline,
- _cairo_stroker_done_sub_path,
- _cairo_stroker_done_path
- };
- const cairo_path_callbacks_t *callbacks = gstate->dash ? &stroker_dashed_cb : &stroker_solid_cb;
-
- cairo_status_t status;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t stroker;
_cairo_stroker_init (&stroker, gstate, traps);
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- callbacks, &stroker);
- if (status) {
- _cairo_stroker_fini (&stroker);
- return status;
+ if (gstate->dash)
+ status = _cairo_path_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_stroker_move_to,
+ _cairo_stroker_line_to_dashed,
+ _cairo_stroker_curve_to,
+ _cairo_stroker_close_path,
+ &stroker);
+ else
+ status = _cairo_path_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_stroker_move_to,
+ _cairo_stroker_line_to,
+ _cairo_stroker_curve_to,
+ _cairo_stroker_close_path,
+ &stroker);
+ if (status)
+ goto BAIL;
+
+ if (stroker.has_first_face) {
+ cairo_point_t t;
+ /* The initial cap needs an outward facing vector. Reverse everything */
+ stroker.first_face.usr_vector.x = -stroker.first_face.usr_vector.x;
+ stroker.first_face.usr_vector.y = -stroker.first_face.usr_vector.y;
+ stroker.first_face.dev_vector.dx = -stroker.first_face.dev_vector.dx;
+ stroker.first_face.dev_vector.dy = -stroker.first_face.dev_vector.dy;
+ t = stroker.first_face.cw;
+ stroker.first_face.cw = stroker.first_face.ccw;
+ stroker.first_face.ccw = t;
+ status = _cairo_stroker_cap (&stroker, &stroker.first_face);
+ if (status)
+ goto BAIL;
}
+ if (stroker.has_current_face) {
+ status = _cairo_stroker_cap (&stroker, &stroker.current_face);
+ if (status)
+ goto BAIL;
+ }
+
+BAIL:
_cairo_stroker_fini (&stroker);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
diff --git a/src/cairo-path.c b/src/cairo-path.c
index 9366394d..91142c8f 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -70,6 +70,11 @@ _cairo_path_init (cairo_path_t *path)
path->arg_head = NULL;
path->arg_tail = NULL;
+
+ path->current_point.x = 0;
+ path->current_point.y = 0;
+ path->has_current_point = 0;
+ path->last_move_point = path->current_point;
}
cairo_status_t
@@ -79,6 +84,9 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
cairo_path_arg_buf_t *arg, *other_arg;
_cairo_path_init (path);
+ path->current_point = other->current_point;
+ path->has_current_point = other->has_current_point;
+ path->last_move_point = other->last_move_point;
for (other_op = other->op_head; other_op; other_op = other_op->next) {
op = _cairo_path_op_buf_create ();
@@ -120,54 +128,131 @@ _cairo_path_fini (cairo_path_t *path)
_cairo_path_arg_buf_destroy (arg);
}
path->arg_tail = NULL;
+
+ path->has_current_point = 0;
+}
+
+cairo_status_t
+_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point)
+{
+ cairo_status_t status;
+
+ status = _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, point, 1);
+ if (status)
+ return status;
+
+ path->current_point = *point;
+ path->has_current_point = 1;
+ path->last_move_point = path->current_point;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_path_move_to (cairo_path_t *path, double x, double y)
+_cairo_path_rel_move_to (cairo_path_t *path, cairo_distance_t *distance)
{
cairo_point_t point;
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
+ point.x = path->current_point.x + distance->dx;
+ point.y = path->current_point.y + distance->dy;
+
+ return _cairo_path_move_to (path, &point);
+}
+
+cairo_status_t
+_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point)
+{
+ cairo_status_t status;
+
+ status = _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, point, 1);
+ if (status)
+ return status;
- return _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
+ path->current_point = *point;
+ path->has_current_point = 1;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_path_line_to (cairo_path_t *path, double x, double y)
+_cairo_path_rel_line_to (cairo_path_t *path, cairo_distance_t *distance)
{
cairo_point_t point;
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
+ point.x = path->current_point.x + distance->dx;
+ point.y = path->current_point.y + distance->dy;
- return _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
+ return _cairo_path_line_to (path, &point);
}
cairo_status_t
_cairo_path_curve_to (cairo_path_t *path,
- double x1, double y1,
- double x2, double y2,
- double x3, double y3)
+ cairo_point_t *p0,
+ cairo_point_t *p1,
+ cairo_point_t *p2)
{
+ cairo_status_t status;
cairo_point_t point[3];
- point[0].x = _cairo_fixed_from_double (x1);
- point[0].y = _cairo_fixed_from_double (y1);
+ point[0] = *p0;
+ point[1] = *p1;
+ point[2] = *p2;
- point[1].x = _cairo_fixed_from_double (x2);
- point[1].y = _cairo_fixed_from_double (y2);
+ status = _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
+ if (status)
+ return status;
- point[2].x = _cairo_fixed_from_double (x3);
- point[2].y = _cairo_fixed_from_double (y3);
+ path->current_point = *p2;
+ path->has_current_point = 1;
- return _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_path_rel_curve_to (cairo_path_t *path,
+ cairo_distance_t *d0,
+ cairo_distance_t *d1,
+ cairo_distance_t *d2)
+{
+ cairo_point_t p0, p1, p2;
+
+ p0.x = path->current_point.x + d0->dx;
+ p0.y = path->current_point.y + d0->dy;
+
+ p1.x = path->current_point.x + d1->dx;
+ p1.y = path->current_point.y + d1->dy;
+
+ p2.x = path->current_point.x + d2->dx;
+ p2.y = path->current_point.y + d2->dy;
+
+ return _cairo_path_curve_to (path, &p0, &p1, &p2);
}
cairo_status_t
_cairo_path_close_path (cairo_path_t *path)
{
- return _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
+ cairo_status_t status;
+
+ status = _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
+ if (status)
+ return status;
+
+ path->current_point.x = path->last_move_point.x;
+ path->current_point.y = path->last_move_point.y;
+ path->has_current_point = 1;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point)
+{
+ if (! path->has_current_point)
+ return CAIRO_STATUS_NO_CURRENT_POINT;
+
+ *point = path->current_point;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -320,7 +405,13 @@ static int const num_args[] =
};
cairo_status_t
-_cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_path_callbacks_t *cb, void *closure)
+_cairo_path_interpret (cairo_path_t *path,
+ cairo_direction_t dir,
+ cairo_path_move_to_func_t *move_to,
+ cairo_path_line_to_func_t *line_to,
+ cairo_path_curve_to_func_t *curve_to,
+ cairo_path_close_path_func_t *close_path,
+ void *closure)
{
cairo_status_t status;
int i, arg;
@@ -329,10 +420,6 @@ _cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_pa
cairo_path_arg_buf_t *arg_buf = path->arg_head;
int buf_i = 0;
cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS];
- cairo_point_t current = {0, 0};
- cairo_point_t first = {0, 0};
- int has_current = 0;
- int has_edge = 0;
int step = (dir == CAIRO_DIRECTION_FORWARD) ? 1 : -1;
for (op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? path->op_head : path->op_tail;
@@ -374,62 +461,24 @@ _cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_pa
switch (op) {
case CAIRO_PATH_OP_MOVE_TO:
- if (has_edge) {
- status = (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_CAP);
- if (status)
- return status;
- }
- first = point[0];
- current = point[0];
- has_current = 1;
- has_edge = 0;
+ status = (*move_to) (closure, &point[0]);
break;
case CAIRO_PATH_OP_LINE_TO:
- if (has_current) {
- status = (*cb->add_edge) (closure, &current, &point[0]);
- if (status)
- return status;
- current = point[0];
- has_edge = 1;
- } else {
- first = point[0];
- current = point[0];
- has_current = 1;
- has_edge = 0;
- }
+ status = (*line_to) (closure, &point[0]);
break;
case CAIRO_PATH_OP_CURVE_TO:
- if (has_current) {
- status = (*cb->add_spline) (closure, &current, &point[0], &point[1], &point[2]);
- if (status)
- return status;
- current = point[2];
- has_edge = 1;
- } else {
- first = point[2];
- current = point[2];
- has_current = 1;
- has_edge = 0;
- }
+ status = (*curve_to) (closure, &point[0], &point[1], &point[2]);
break;
case CAIRO_PATH_OP_CLOSE_PATH:
- if (has_edge) {
- (*cb->add_edge) (closure, &current, &first);
- (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_JOIN);
- }
- current.x = 0;
- current.y = 0;
- first.x = 0;
- first.y = 0;
- has_current = 0;
- has_edge = 0;
+ default:
+ status = (*close_path) (closure);
break;
}
+ if (status)
+ return status;
}
}
- if (has_edge)
- (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_CAP);
- return (*cb->done_path) (closure);
+ return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
new file mode 100644
index 00000000..dcdb1566
--- /dev/null
+++ b/src/cairo-pattern.c
@@ -0,0 +1,716 @@
+/*
+ * Copyright © 2002 University of Southern California
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * University of Southern California not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. The University of Southern
+ * California makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
+ * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <c99drn@cs.umu.se>
+ */
+
+#include "cairoint.h"
+
+void
+_cairo_pattern_init (cairo_pattern_t *pattern)
+{
+ pattern->ref_count = 1;
+
+ pattern->extend = CAIRO_EXTEND_DEFAULT;
+ pattern->filter = CAIRO_FILTER_DEFAULT;
+
+ _cairo_color_init (&pattern->color);
+
+ _cairo_matrix_init (&pattern->matrix);
+
+ pattern->stops = NULL;
+ pattern->n_stops = 0;
+
+ pattern->type = CAIRO_PATTERN_SOLID;
+
+ pattern->source = NULL;
+ pattern->source_offset.x = 0.0;
+ pattern->source_offset.y = 0.0;
+}
+
+cairo_status_t
+_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other)
+{
+ *pattern = *other;
+
+ pattern->ref_count = 1;
+
+ if (pattern->n_stops) {
+ pattern->stops =
+ malloc (sizeof (cairo_color_stop_t) * pattern->n_stops);
+ if (pattern->stops == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+ memcpy (pattern->stops, other->stops,
+ sizeof (cairo_color_stop_t) * other->n_stops);
+ }
+
+ if (pattern->source)
+ cairo_surface_reference (other->source);
+
+ if (pattern->type == CAIRO_PATTERN_SURFACE)
+ cairo_surface_reference (other->u.surface.surface);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_pattern_fini (cairo_pattern_t *pattern)
+{
+ if (pattern->n_stops)
+ free (pattern->stops);
+
+ if (pattern->type == CAIRO_PATTERN_SURFACE) {
+ /* show_surface require us to restore surface matrix, repeat
+ attribute, filter type */
+ if (pattern->source) {
+ cairo_surface_set_matrix (pattern->source,
+ &pattern->u.surface.save_matrix);
+ cairo_surface_set_repeat (pattern->source,
+ pattern->u.surface.save_repeat);
+ cairo_surface_set_filter (pattern->source,
+ pattern->u.surface.save_filter);
+ }
+ cairo_surface_destroy (pattern->u.surface.surface);
+ }
+
+ if (pattern->source)
+ cairo_surface_destroy (pattern->source);
+}
+
+void
+_cairo_pattern_init_solid (cairo_pattern_t *pattern,
+ double red, double green, double blue)
+{
+ _cairo_pattern_init (pattern);
+
+ pattern->type = CAIRO_PATTERN_SOLID;
+ _cairo_color_set_rgb (&pattern->color, red, green, blue);
+}
+
+cairo_pattern_t *
+_cairo_pattern_create_solid (double red, double green, double blue)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = malloc (sizeof (cairo_pattern_t));
+ if (pattern == NULL)
+ return NULL;
+
+ _cairo_pattern_init_solid (pattern, red, green, blue);
+
+ return pattern;
+}
+
+cairo_pattern_t *
+cairo_pattern_create_for_surface (cairo_surface_t *surface)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = malloc (sizeof (cairo_pattern_t));
+ if (pattern == NULL)
+ return NULL;
+
+ _cairo_pattern_init (pattern);
+
+ pattern->type = CAIRO_PATTERN_SURFACE;
+ pattern->u.surface.surface = surface;
+ cairo_surface_reference (surface);
+
+ return pattern;
+}
+
+cairo_pattern_t *
+cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = malloc (sizeof (cairo_pattern_t));
+ if (pattern == NULL)
+ return NULL;
+
+ _cairo_pattern_init (pattern);
+
+ pattern->type = CAIRO_PATTERN_LINEAR;
+ pattern->u.linear.point0.x = x0;
+ pattern->u.linear.point0.y = y0;
+ pattern->u.linear.point1.x = x1;
+ pattern->u.linear.point1.y = y1;
+
+ return pattern;
+}
+
+cairo_pattern_t *
+cairo_pattern_create_radial (double cx0, double cy0, double radius0,
+ double cx1, double cy1, double radius1)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = malloc (sizeof (cairo_pattern_t));
+ if (pattern == NULL)
+ return NULL;
+
+ _cairo_pattern_init (pattern);
+
+ pattern->type = CAIRO_PATTERN_RADIAL;
+ pattern->u.radial.center0.x = cx0;
+ pattern->u.radial.center0.y = cy0;
+ pattern->u.radial.radius0.dx = radius0;
+ pattern->u.radial.radius0.dy = radius0;
+ pattern->u.radial.center1.x = cx1;
+ pattern->u.radial.center1.y = cy1;
+ pattern->u.radial.radius1.dx = radius1;
+ pattern->u.radial.radius1.dy = radius1;
+
+ return pattern;
+}
+
+void
+cairo_pattern_reference (cairo_pattern_t *pattern)
+{
+ if (pattern == NULL)
+ return;
+
+ pattern->ref_count++;
+}
+
+void
+cairo_pattern_destroy (cairo_pattern_t *pattern)
+{
+ if (pattern == NULL)
+ return;
+
+ pattern->ref_count--;
+ if (pattern->ref_count)
+ return;
+
+ _cairo_pattern_fini (pattern);
+ free (pattern);
+}
+
+static int
+_cairo_pattern_stop_compare (const void *elem1, const void *elem2)
+{
+ return
+ (((cairo_color_stop_t *) elem1)->offset ==
+ ((cairo_color_stop_t *) elem2)->offset) ?
+ /* equal offsets, sort on id */
+ ((((cairo_color_stop_t *) elem1)->id <
+ ((cairo_color_stop_t *) elem2)->id) ? -1 : 1) :
+ /* sort on offset */
+ ((((cairo_color_stop_t *) elem1)->offset <
+ ((cairo_color_stop_t *) elem2)->offset) ? -1 : 1);
+}
+
+cairo_status_t
+cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
+ double offset,
+ double red, double green, double blue,
+ double alpha)
+{
+ cairo_color_stop_t *stop;
+
+ _cairo_restrict_value (&offset, 0.0, 1.0);
+ _cairo_restrict_value (&red, 0.0, 1.0);
+ _cairo_restrict_value (&green, 0.0, 1.0);
+ _cairo_restrict_value (&blue, 0.0, 1.0);
+
+ pattern->n_stops++;
+ pattern->stops = realloc (pattern->stops,
+ sizeof (cairo_color_stop_t) * pattern->n_stops);
+ if (pattern->stops == NULL) {
+ pattern->n_stops = 0;
+
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ stop = &pattern->stops[pattern->n_stops - 1];
+
+ stop->offset = offset;
+ stop->id = pattern->n_stops;
+ _cairo_color_init (&stop->color);
+ _cairo_color_set_rgb (&stop->color, red, green, blue);
+ _cairo_color_set_alpha (&stop->color, alpha);
+ stop->color_char[0] = stop->color.red_short / 256;
+ stop->color_char[1] = stop->color.green_short / 256;
+ stop->color_char[2] = stop->color.blue_short / 256;
+ stop->color_char[3] = stop->color.alpha_short / 256;
+
+ /* sort stops in ascending order */
+ qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t),
+ _cairo_pattern_stop_compare);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
+{
+ cairo_matrix_copy (&pattern->matrix, matrix);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
+{
+ cairo_matrix_copy (matrix, &pattern->matrix);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
+{
+ pattern->filter = filter;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_filter_t
+cairo_pattern_get_filter (cairo_pattern_t *pattern)
+{
+ return pattern->filter;
+}
+
+cairo_status_t
+cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
+{
+ pattern->extend = extend;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_extend_t
+cairo_pattern_get_extend (cairo_pattern_t *pattern)
+{
+ return pattern->extend;
+}
+
+cairo_status_t
+_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
+ double *red, double *green, double *blue)
+{
+ _cairo_color_get_rgb (&pattern->color, red, green, blue);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
+{
+ int i;
+
+ _cairo_color_set_alpha (&pattern->color, alpha);
+
+ for (i = 0; i < pattern->n_stops; i++) {
+ cairo_color_stop_t *stop = &pattern->stops[i];
+
+ _cairo_color_set_alpha (&stop->color, stop->color.alpha * alpha);
+
+ stop->color_char[0] = stop->color.red_short / 256;
+ stop->color_char[1] = stop->color.green_short / 256;
+ stop->color_char[2] = stop->color.blue_short / 256;
+ stop->color_char[3] = stop->color.alpha_short / 256;
+ }
+}
+
+void
+_cairo_pattern_add_source_offset (cairo_pattern_t *pattern,
+ double x, double y)
+{
+ pattern->source_offset.x += x;
+ pattern->source_offset.y += y;
+}
+
+void
+_cairo_pattern_transform (cairo_pattern_t *pattern,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse)
+{
+ cairo_matrix_t matrix;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SURFACE:
+ /* hmm, maybe we should instead multiply with the inverse of the
+ pattern matrix here? */
+ cairo_matrix_multiply (&pattern->matrix, ctm_inverse,
+ &pattern->matrix);
+ break;
+ case CAIRO_PATTERN_LINEAR:
+ cairo_matrix_multiply (&matrix, &pattern->matrix, ctm);
+ cairo_matrix_transform_point (&matrix,
+ &pattern->u.linear.point0.x,
+ &pattern->u.linear.point0.y);
+ cairo_matrix_transform_point (&matrix,
+ &pattern->u.linear.point1.x,
+ &pattern->u.linear.point1.y);
+ break;
+ case CAIRO_PATTERN_RADIAL:
+ cairo_matrix_multiply (&matrix, &pattern->matrix, ctm);
+ cairo_matrix_transform_point (&matrix,
+ &pattern->u.radial.center0.x,
+ &pattern->u.radial.center0.y);
+ cairo_matrix_transform_distance (&matrix,
+ &pattern->u.radial.radius0.dx,
+ &pattern->u.radial.radius0.dy);
+ cairo_matrix_transform_point (&matrix,
+ &pattern->u.radial.center1.x,
+ &pattern->u.radial.center1.y);
+ cairo_matrix_transform_distance (&matrix,
+ &pattern->u.radial.radius1.dx,
+ &pattern->u.radial.radius1.dy);
+ break;
+ case CAIRO_PATTERN_SOLID:
+ break;
+ }
+}
+
+void
+_cairo_pattern_prepare_surface (cairo_pattern_t *pattern)
+{
+ cairo_matrix_t device_to_source;
+ cairo_matrix_t user_to_source;
+
+ /* should the surface matrix interface be remove from the API?
+ for now we multiple the surface matrix with the pattern matrix */
+ cairo_surface_get_matrix (pattern->u.surface.surface, &user_to_source);
+ cairo_matrix_multiply (&device_to_source, &pattern->matrix,
+ &user_to_source);
+ cairo_surface_set_matrix (pattern->source, &device_to_source);
+
+ /* storing original surface matrix in pattern */
+ pattern->u.surface.save_matrix = user_to_source;
+
+ /* storing original surface repeat mode in pattern */
+ pattern->u.surface.save_repeat = pattern->source->repeat;
+
+ /* what do we do with extend types pad and reflect? */
+ if (pattern->extend == CAIRO_EXTEND_REPEAT
+ || pattern->source->repeat == 1)
+ cairo_surface_set_repeat (pattern->source, 1);
+ else
+ cairo_surface_set_repeat (pattern->source, 0);
+
+ /* storing original surface filter in pattern */
+ pattern->u.surface.save_filter =
+ cairo_surface_get_filter (pattern->source);
+
+ cairo_surface_set_filter (pattern->source, pattern->filter);
+}
+
+typedef void (*cairo_shader_function_t) (unsigned char *color0,
+ unsigned char *color1,
+ double factor,
+ unsigned char *result_color);
+
+#define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \
+ ((unsigned char) ((factor < 0.5)? c1: c2))
+
+static void
+_cairo_pattern_shader_nearest (unsigned char *color0,
+ unsigned char *color1,
+ double factor,
+ unsigned char *result_color)
+{
+ result_color[0] = INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor);
+ result_color[1] = INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor);
+ result_color[2] = INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor);
+ result_color[3] = INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor);
+}
+
+#undef INTERPOLATE_COLOR_NEAREST
+
+#define INTERPOLATE_COLOR_LINEAR(c1, c2, factor) \
+ ((unsigned char) ((c2 * factor) + (c1 * (1.0 - factor))))
+
+static void
+_cairo_pattern_shader_linear (unsigned char *color0,
+ unsigned char *color1,
+ double factor,
+ unsigned char *result_color)
+{
+ result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor);
+ result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor);
+ result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor);
+ result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor);
+}
+
+static void
+_cairo_pattern_shader_gaussian (unsigned char *color0,
+ unsigned char *color1,
+ double factor,
+ unsigned char *result_color)
+{
+ factor = (exp (factor * factor) - 1.0) / (M_E - 1.0);
+
+ result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor);
+ result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor);
+ result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor);
+ result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor);
+}
+
+#undef INTERPOLATE_COLOR_LINEAR
+
+void
+_cairo_pattern_calc_color_at_pixel (cairo_pattern_t *pattern,
+ double factor,
+ int *pixel)
+{
+ int p, colorstop;
+ double factorscale;
+ unsigned char result_color[4];
+ cairo_shader_function_t shader_function;
+
+ switch (pattern->filter) {
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ shader_function = _cairo_pattern_shader_nearest;
+ break;
+ case CAIRO_FILTER_GAUSSIAN:
+ shader_function = _cairo_pattern_shader_gaussian;
+ break;
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ shader_function = _cairo_pattern_shader_linear;
+ break;
+ }
+
+ if (factor > 1.0 || factor < 0.0) {
+ switch (pattern->extend) {
+ case CAIRO_EXTEND_REPEAT:
+ factor -= floor (factor);
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ if (factor >= 0.0) {
+ if (((int) factor) % 2)
+ factor = 1.0 - (factor - floor (factor));
+ else
+ factor -= floor (factor);
+ } else {
+ if (((int) factor) % 2)
+ factor -= floor (factor);
+ else
+ factor = 1.0 - (factor - floor (factor));
+ }
+ break;
+ case CAIRO_EXTEND_NONE:
+ break;
+ }
+ }
+
+ if (factor < pattern->stops[0].offset)
+ factor = pattern->stops[0].offset;
+
+ if (factor > pattern->stops[pattern->n_stops - 1].offset)
+ factor = pattern->stops[pattern->n_stops - 1].offset;
+
+ for (colorstop = 0; colorstop < pattern->n_stops - 1; colorstop++) {
+ if (factor <= pattern->stops[colorstop + 1].offset) {
+ factorscale = fabs (pattern->stops[colorstop].offset -
+ pattern->stops[colorstop + 1].offset);
+
+ /* abrubt change, difference between two offsets == 0.0 */
+ if (factorscale == 0)
+ break;
+
+ factor -= pattern->stops[colorstop].offset;
+
+ /* take offset as new 0 of coordinate system */
+ factor /= factorscale;
+
+ shader_function (pattern->stops[colorstop].color_char,
+ pattern->stops[colorstop + 1].color_char,
+ factor, result_color);
+
+ p = ((result_color[3] << 24) |
+ (result_color[0] << 16) |
+ (result_color[1] << 8) | (result_color[2] << 0));
+ *pixel = p;
+ break;
+ }
+ }
+}
+
+static void
+_cairo_image_data_set_linear (cairo_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ char *data,
+ int width,
+ int height)
+{
+ int x, y;
+ cairo_point_double_t point0, point1, angle;
+ double a, length, start, end;
+ double factor;
+
+ point0.x = pattern->u.linear.point0.x - offset_x;
+ point0.y = pattern->u.linear.point0.y - offset_y;
+ point1.x = pattern->u.linear.point1.x - offset_x;
+ point1.y = pattern->u.linear.point1.y - offset_y;
+
+ length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) +
+ (point1.y - point0.y) * (point1.y - point0.y));
+ length = (length) ? 1.0 / length : INT_MAX;
+
+ a = -atan2 (point1.y - point0.y, point1.x - point0.x);
+ angle.x = cos (a);
+ angle.y = -sin (a);
+
+ start = angle.x * point0.x;
+ start += angle.y * point0.y;
+
+ end = angle.x * point1.x;
+ end += angle.y * point1.y;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+
+ factor = angle.x * (double) x;
+ factor += angle.y * (double) y;
+
+ factor = factor - start;
+ factor *= length;
+
+ _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *)
+ &data[y * width * 4 + x * 4]);
+ }
+ }
+}
+
+/* TODO: Inner circle is currently ignored. */
+static void
+_cairo_image_data_set_radial (cairo_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ char *data,
+ int width,
+ int height)
+{
+ int x, y;
+ cairo_point_double_t center1, pos;
+ cairo_distance_double_t length;
+ double factor;
+ double min_length;
+
+ center1.x = pattern->u.radial.center1.x - offset_x;
+ center1.y = pattern->u.radial.center1.y - offset_y;
+
+ min_length =
+ fabs ((pattern->u.radial.radius1.dx < pattern->u.radial.radius1.dy) ?
+ pattern->u.radial.radius1.dx : pattern->u.radial.radius1.dy);
+
+ /* ugly */
+ if (min_length == 0.0)
+ min_length = 0.000001;
+
+ length.dx = min_length / pattern->u.radial.radius1.dx;
+ length.dy = min_length / pattern->u.radial.radius1.dy;
+
+ min_length = 1.0 / min_length;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ pos.x = x - center1.x;
+ pos.y = y - center1.y;
+
+ pos.x *= length.dx;
+ pos.y *= length.dy;
+
+ factor = sqrt (pos.x * pos.x + pos.y * pos.y) * min_length;
+
+ _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *)
+ &data[y * width * 4 + x * 4]);
+ }
+ }
+}
+
+cairo_image_surface_t *
+_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
+{
+ cairo_surface_t *surface;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ char *data;
+ 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));
+
+ data = malloc (width * height * 4);
+ if (!data)
+ return NULL;
+
+ _cairo_pattern_add_source_offset (pattern,
+ _cairo_fixed_to_double (box->p1.x),
+ _cairo_fixed_to_double (box->p1.y));
+
+ if (pattern->type == CAIRO_PATTERN_RADIAL)
+ _cairo_image_data_set_radial (pattern,
+ pattern->source_offset.x,
+ pattern->source_offset.y,
+ data, width, height);
+ else
+ _cairo_image_data_set_linear (pattern,
+ pattern->source_offset.x,
+ pattern->source_offset.y,
+ data, width, height);
+
+ surface = cairo_image_surface_create_for_data (data,
+ CAIRO_FORMAT_ARGB32,
+ width, height,
+ width * 4);
+
+ if (surface)
+ _cairo_image_surface_assume_ownership_of_data (
+ (cairo_image_surface_t *) surface);
+ }
+ break;
+ case CAIRO_PATTERN_SOLID:
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ if (surface) {
+ _cairo_surface_fill_rectangle (surface,
+ CAIRO_OPERATOR_SRC,
+ &pattern->color, 0, 0, 1, 1);
+ cairo_surface_set_repeat (surface, 1);
+ }
+ break;
+ case CAIRO_PATTERN_SURFACE: {
+ cairo_image_surface_t *image;
+
+ image = _cairo_surface_get_image (pattern->u.surface.surface);
+ if (image)
+ surface = &image->base;
+ else
+ surface = NULL;
+
+ }
+ break;
+ }
+
+ return (cairo_image_surface_t *) surface;
+}
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index dd054372..0bb5debd 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -288,7 +288,7 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen,
while (i != stop) {
hull_point.x = point[i].x + pen->vertices[active].point.x;
hull_point.y = point[i].y + pen->vertices[active].point.y;
- status = _cairo_polygon_add_point (polygon, &hull_point);
+ status = _cairo_polygon_line_to (polygon, &hull_point);
if (status)
return status;
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index 97f074a3..fbda7321 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -35,9 +35,6 @@
static cairo_status_t
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional);
-static void
-_cairo_polygon_set_last_point (cairo_polygon_t *polygon, cairo_point_t *point);
-
void
_cairo_polygon_init (cairo_polygon_t *polygon)
{
@@ -46,10 +43,7 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
polygon->edges_size = 0;
polygon->edges = NULL;
- polygon->first_point_defined = 0;
- polygon->last_point_defined = 0;
-
- polygon->closed = 0;
+ polygon->has_current_point = 0;
}
void
@@ -62,10 +56,7 @@ _cairo_polygon_fini (cairo_polygon_t *polygon)
polygon->num_edges = 0;
}
- polygon->first_point_defined = 0;
- polygon->last_point_defined = 0;
-
- polygon->closed = 0;
+ polygon->has_current_point = 0;
}
static cairo_status_t
@@ -92,25 +83,12 @@ _cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional)
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_polygon_set_last_point (cairo_polygon_t *polygon, cairo_point_t *point)
-{
- polygon->last_point = *point;
- polygon->last_point_defined = 1;
-}
-
cairo_status_t
_cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2)
{
cairo_status_t status;
cairo_edge_t *edge;
- if (! polygon->first_point_defined) {
- polygon->first_point = *p1;
- polygon->first_point_defined = 1;
- polygon->closed = 0;
- }
-
/* drop horizontal edges */
if (p1->y == p2->y) {
goto DONE;
@@ -137,20 +115,31 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin
polygon->num_edges++;
DONE:
- _cairo_polygon_set_last_point (polygon, p2);
+ _cairo_polygon_move_to (polygon, p2);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point)
+{
+ if (! polygon->has_current_point)
+ polygon->first_point = *point;
+ polygon->current_point = *point;
+ polygon->has_current_point = 1;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_polygon_add_point (cairo_polygon_t *polygon, cairo_point_t *point)
+_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- if (polygon->last_point_defined) {
- status = _cairo_polygon_add_edge (polygon, &polygon->last_point, point);
+ if (polygon->has_current_point) {
+ status = _cairo_polygon_add_edge (polygon, &polygon->current_point, point);
} else {
- _cairo_polygon_set_last_point (polygon, point);
+ _cairo_polygon_move_to (polygon, point);
}
return status;
@@ -161,13 +150,14 @@ _cairo_polygon_close (cairo_polygon_t *polygon)
{
cairo_status_t status;
- if (polygon->closed == 0 && polygon->last_point_defined) {
- status = _cairo_polygon_add_edge (polygon, &polygon->last_point, &polygon->first_point);
+ if (polygon->has_current_point) {
+ status = _cairo_polygon_add_edge (polygon,
+ &polygon->current_point,
+ &polygon->first_point);
if (status)
return status;
- polygon->closed = 1;
- polygon->first_point_defined = 0;
+ polygon->has_current_point = 0;
}
return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index c66b7098..98d34e44 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -286,19 +286,19 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
int i, x, y;
cairo_surface_t *white_surface;
- char *bgr, *compressed;
- long bgr_size, compressed_size;
+ char *rgb, *compressed;
+ long rgb_size, compressed_size;
cairo_color_t white;
- bgr_size = 3 * width * height;
- bgr = malloc (bgr_size);
- if (bgr == NULL) {
+ rgb_size = 3 * width * height;
+ rgb = malloc (rgb_size);
+ if (rgb == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto BAIL0;
}
- compressed_size = (int) (1.0 + 1.1 * bgr_size);
+ compressed_size = (int) (1.0 + 1.1 * rgb_size);
compressed = malloc (compressed_size);
if (compressed == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
@@ -330,16 +330,15 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
i = 0;
for (y = 0; y < height; y++) {
- char *line = surface->image->data + y * surface->image->stride;
- for (x = 0; x < width; x++) {
- unsigned char *pixel = (unsigned char *) line + x * 4;
- bgr[i++] = *(pixel+2);
- bgr[i++] = *(pixel+1);
- bgr[i++] = *(pixel);
+ pixman_bits_t *pixel = (pixman_bits_t *) (surface->image->data + y * surface->image->stride);
+ for (x = 0; x < width; x++, pixel++) {
+ rgb[i++] = (*pixel & 0x00ff0000) >> 16;
+ rgb[i++] = (*pixel & 0x0000ff00) >> 8;
+ rgb[i++] = (*pixel & 0x000000ff) >> 0;
}
}
- compress (compressed, &compressed_size, bgr, bgr_size);
+ compress (compressed, &compressed_size, rgb, rgb_size);
/* Page header */
fprintf (file, "%%%%Page: %d\n", ++surface->pages);
@@ -375,7 +374,7 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
BAIL2:
free (compressed);
BAIL1:
- free (bgr);
+ free (rgb);
BAIL0:
return status;
}
@@ -395,6 +394,23 @@ _cairo_ps_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+_cairo_ps_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_ps_surface_t *surface = 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,
_cairo_ps_surface_destroy,
@@ -408,5 +424,7 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
_cairo_ps_surface_fill_rectangles,
_cairo_ps_surface_composite_trapezoids,
_cairo_ps_surface_copy_page,
- _cairo_ps_surface_show_page
+ _cairo_ps_surface_show_page,
+ _cairo_ps_surface_set_clip_region,
+ _cairo_ps_surface_create_pattern
};
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index ff4f39c1..91ab8aba 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -38,6 +38,7 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->ref_count = 1;
_cairo_matrix_init (&surface->matrix);
+ surface->filter = CAIRO_FILTER_NEAREST;
surface->repeat = 0;
}
@@ -165,9 +166,16 @@ cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
if (surface == NULL)
return CAIRO_STATUS_NULL_POINTER;
+ surface->filter = filter;
return surface->backend->set_filter (surface, filter);
}
+cairo_filter_t
+cairo_surface_get_filter (cairo_surface_t *surface)
+{
+ return surface->filter;
+}
+
/* XXX: NYI
cairo_status_t
cairo_surface_clip_rectangle (cairo_surface_t *surface,
@@ -364,3 +372,116 @@ _cairo_surface_show_page (cairo_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
}
+cairo_status_t
+_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region)
+{
+ 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 63df3ea4..9b44d38e 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -58,7 +58,7 @@ _compute_inverse_slope (cairo_line_t *l);
static double
_compute_x_intercept (cairo_line_t *l, double inverse_slope);
-static cairo_fixed_t
+static int
_line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret);
void
@@ -490,7 +490,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_
*/
cairo_status_t
_cairo_traps_tessellate_polygon (cairo_traps_t *traps,
- cairo_polygon_t *poly,
+ cairo_polygon_t *poly,
cairo_fill_rule_t fill_rule)
{
cairo_status_t status;
@@ -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
new file mode 100644
index 00000000..ea1f72e1
--- /dev/null
+++ b/src/cairo-xcb-surface.c
@@ -0,0 +1,799 @@
+/*
+ * Copyright © 2002 University of Southern California
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * University of Southern California not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. The University of Southern
+ * California makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
+ * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@isi.edu>
+ */
+
+#include "cairoint.h"
+
+cairo_surface_t *
+cairo_xcb_surface_create (XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ cairo_format_t format);
+
+#define AllPlanes ((unsigned long)~0L)
+
+static XCBRenderPICTFORMAT
+format_from_visual(XCBConnection *c, XCBVISUALID visual)
+{
+ static const XCBRenderPICTFORMAT nil = { 0 };
+ XCBRenderQueryPictFormatsRep *r;
+ XCBRenderPICTSCREENIter si;
+ XCBRenderPICTDEPTHIter di;
+ XCBRenderPICTVISUALIter vi;
+
+ r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
+ if(!r)
+ return nil;
+
+ for(si = XCBRenderQueryPictFormatsScreens(r); si.rem; XCBRenderPICTSCREENNext(&si))
+ for(di = XCBRenderPICTSCREENDepths(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
+ for(vi = XCBRenderPICTDEPTHVisuals(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
+ if(vi.data->visual.id == visual.id)
+ {
+ XCBRenderPICTFORMAT ret = vi.data->format;
+ free(r);
+ return ret;
+ }
+
+ return nil;
+}
+
+static XCBRenderPICTFORMAT
+format_from_cairo(XCBConnection *c, cairo_format_t fmt)
+{
+ XCBRenderPICTFORMAT ret = { 0 };
+ struct tmpl_t {
+ XCBRenderDIRECTFORMAT direct;
+ CARD8 depth;
+ };
+ static const struct tmpl_t templates[] = {
+ /* CAIRO_FORMAT_ARGB32 */
+ {
+ {
+ 16, 0xff,
+ 8, 0xff,
+ 0, 0xff,
+ 24, 0xff
+ },
+ 32
+ },
+ /* CAIRO_FORMAT_RGB24 */
+ {
+ {
+ 16, 0xff,
+ 8, 0xff,
+ 0, 0xff,
+ 0, 0x00
+ },
+ 24
+ },
+ /* CAIRO_FORMAT_A8 */
+ {
+ {
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0xff
+ },
+ 8
+ },
+ /* CAIRO_FORMAT_A1 */
+ {
+ {
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0x01
+ },
+ 1
+ },
+ };
+ const struct tmpl_t *tmpl;
+ XCBRenderQueryPictFormatsRep *r;
+ XCBRenderPICTFORMINFOIter fi;
+
+ if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates)))
+ return ret;
+ tmpl = templates + fmt;
+
+ r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
+ if(!r)
+ return ret;
+
+ for(fi = XCBRenderQueryPictFormatsFormats(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
+ {
+ const XCBRenderDIRECTFORMAT *t, *f;
+ if(fi.data->type != XCBRenderPictTypeDirect)
+ continue;
+ if(fi.data->depth != tmpl->depth)
+ continue;
+ t = &tmpl->direct;
+ f = &fi.data->direct;
+ if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift))
+ continue;
+ if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift))
+ continue;
+ if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift))
+ continue;
+ if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
+ continue;
+
+ ret = fi.data->id;
+ }
+
+ free(r);
+ return ret;
+}
+
+void
+cairo_set_target_xcb (cairo_t *cr,
+ XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ cairo_format_t format)
+{
+ cairo_surface_t *surface;
+
+ if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
+ return;
+
+ surface = cairo_xcb_surface_create (dpy, drawable, visual, format);
+ if (surface == NULL) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface (cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy (surface);
+}
+
+typedef struct cairo_xcb_surface {
+ cairo_surface_t base;
+
+ XCBConnection *dpy;
+ XCBGCONTEXT gc;
+ XCBDRAWABLE drawable;
+ int owns_pixmap;
+ XCBVISUALTYPE *visual;
+ cairo_format_t format;
+
+ int render_major;
+ int render_minor;
+
+ int width;
+ int height;
+
+ XCBRenderPICTURE picture;
+} cairo_xcb_surface_t;
+
+#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
+ (((surface)->render_major > major) || \
+ (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
+
+#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+
+#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
+#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
+
+#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
+#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
+
+#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+
+#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+
+static int
+_CAIRO_FORMAT_DEPTH (cairo_format_t format)
+{
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ return 1;
+ case CAIRO_FORMAT_A8:
+ return 8;
+ case CAIRO_FORMAT_RGB24:
+ return 24;
+ case CAIRO_FORMAT_ARGB32:
+ default:
+ return 32;
+ }
+}
+
+static cairo_surface_t *
+_cairo_xcb_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int width,
+ int height)
+{
+ cairo_xcb_surface_t *src = abstract_src;
+ XCBConnection *dpy = src->dpy;
+ XCBDRAWABLE d;
+ cairo_xcb_surface_t *surface;
+
+ /* XXX: There's a pretty lame heuristic here. This assumes that
+ * all non-Render X servers do not support depth-32 pixmaps, (and
+ * that they do support depths 1, 8, and 24). Obviously, it would
+ * be much better to check the depths that are actually
+ * supported. */
+ if (!dpy
+ || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)
+ && format == CAIRO_FORMAT_ARGB32))
+ {
+ return NULL;
+ }
+
+ d.pixmap = XCBPIXMAPNew (dpy);
+ XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
+ d.pixmap, src->drawable,
+ width, height);
+
+ surface = (cairo_xcb_surface_t *)
+ cairo_xcb_surface_create (dpy, d, NULL, format);
+ surface->owns_pixmap = 1;
+
+ surface->width = width;
+ surface->height = height;
+
+ return &surface->base;
+}
+
+static void
+_cairo_xcb_surface_destroy (void *abstract_surface)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ if (surface->picture.xid)
+ XCBRenderFreePicture (surface->dpy, surface->picture);
+
+ if (surface->owns_pixmap)
+ XCBFreePixmap (surface->dpy, surface->drawable.pixmap);
+
+ if (surface->gc.xid)
+ XCBFreeGC (surface->dpy, surface->gc);
+
+ surface->dpy = 0;
+
+ free (surface);
+}
+
+static double
+_cairo_xcb_surface_pixels_per_inch (void *abstract_surface)
+{
+ /* XXX: We should really get this value from somewhere like Xft.dpy */
+ return 96.0;
+}
+
+static int
+bits_per_pixel(XCBConnection *c, int depth)
+{
+ XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c));
+ XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c));
+
+ for(; fmt != fmtend; ++fmt)
+ if(fmt->depth == depth)
+ return fmt->bits_per_pixel;
+
+ if(depth <= 4)
+ return 4;
+ if(depth <= 8)
+ return 8;
+ if(depth <= 16)
+ return 16;
+ return 32;
+}
+
+static int
+bytes_per_line(XCBConnection *c, int width, int bpp)
+{
+ int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
+ return (bpp * width + bitmap_pad - 1) & -bitmap_pad;
+}
+
+static cairo_image_surface_t *
+_cairo_xcb_surface_get_image (void *abstract_surface)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ XCBGetGeometryRep *geomrep;
+ XCBGetImageRep *imagerep;
+ int bpp;
+
+ geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
+ if(!geomrep)
+ return 0;
+
+ surface->width = geomrep->width;
+ surface->height = geomrep->height;
+ free(geomrep);
+
+ imagerep = XCBGetImageReply(surface->dpy,
+ XCBGetImage(surface->dpy, ZPixmap,
+ surface->drawable,
+ 0, 0,
+ surface->width, surface->height,
+ AllPlanes), 0);
+ if(!imagerep)
+ return 0;
+
+ bpp = bits_per_pixel(surface->dpy, imagerep->depth);
+
+ if (surface->visual) {
+ cairo_format_masks_t masks;
+
+ /* XXX: Add support here for pictures with external alpha? */
+
+ masks.bpp = bpp;
+ masks.alpha_mask = 0;
+ masks.red_mask = surface->visual->red_mask;
+ masks.green_mask = surface->visual->green_mask;
+ masks.blue_mask = surface->visual->blue_mask;
+
+ image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
+ &masks,
+ surface->width,
+ surface->height,
+ bytes_per_line(surface->dpy, surface->width, bpp));
+ } else {
+ image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
+ surface->format,
+ surface->width,
+ surface->height,
+ bytes_per_line(surface->dpy, surface->width, bpp));
+ }
+
+ /* Let the surface take ownership of the data */
+ /* XXX: Can probably come up with a cleaner API here. */
+ _cairo_image_surface_assume_ownership_of_data (image);
+ /* FIXME: imagerep can't be freed correctly, I think. must copy. :-( */
+
+ _cairo_image_surface_set_repeat (image, surface->base.repeat);
+ _cairo_image_surface_set_matrix (image, &(surface->base.matrix));
+
+ return image;
+}
+
+static void
+_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
+{
+ if (surface->gc.xid)
+ return;
+
+ surface->gc = XCBGCONTEXTNew(surface->dpy);
+ XCBCreateGC (surface->dpy, surface->gc, surface->drawable, 0, 0);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ int bpp, data_len;
+
+ _cairo_xcb_surface_ensure_gc (surface);
+ bpp = bits_per_pixel(surface->dpy, image->depth);
+ data_len = bytes_per_line(surface->dpy, surface->width, bpp) * surface->height;
+ XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
+ image->width,
+ image->height,
+ /* dst_x */ 0, /* dst_y */ 0,
+ /* left_pad */ 0, image->depth,
+ data_len, image->data);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ XCBRenderTRANSFORM xtransform;
+
+ if (!surface->picture.xid)
+ return CAIRO_STATUS_SUCCESS;
+
+ xtransform.matrix11 = _cairo_fixed_from_double (matrix->m[0][0]);
+ xtransform.matrix12 = _cairo_fixed_from_double (matrix->m[1][0]);
+ xtransform.matrix13 = _cairo_fixed_from_double (matrix->m[2][0]);
+
+ xtransform.matrix21 = _cairo_fixed_from_double (matrix->m[0][1]);
+ xtransform.matrix22 = _cairo_fixed_from_double (matrix->m[1][1]);
+ xtransform.matrix23 = _cairo_fixed_from_double (matrix->m[2][1]);
+
+ xtransform.matrix31 = 0;
+ xtransform.matrix32 = 0;
+ xtransform.matrix33 = _cairo_fixed_from_double (1);
+
+ if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
+ {
+ XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
+ } else {
+ /* XXX: Need support here if using an old RENDER without support
+ for SetPictureTransform */
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ char *render_filter;
+
+ if (!(surface->picture.xid
+ && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
+ return CAIRO_STATUS_SUCCESS;
+
+ switch (filter) {
+ case CAIRO_FILTER_FAST:
+ render_filter = "fast";
+ break;
+ case CAIRO_FILTER_GOOD:
+ render_filter = "good";
+ break;
+ case CAIRO_FILTER_BEST:
+ render_filter = "best";
+ break;
+ case CAIRO_FILTER_NEAREST:
+ render_filter = "nearest";
+ break;
+ case CAIRO_FILTER_BILINEAR:
+ render_filter = "bilinear";
+ break;
+ default:
+ render_filter = "best";
+ break;
+ }
+
+ XCBRenderSetPictureFilter(surface->dpy, surface->picture,
+ strlen(render_filter), 0, render_filter, NULL);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+
+ CARD32 mask = XCBRenderCPRepeat;
+ CARD32 pa[] = { repeat };
+
+ if (!surface->picture.xid)
+ return CAIRO_STATUS_SUCCESS;
+
+ XCBRenderChangePicture (surface->dpy, surface->picture, mask, pa);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_surface_t *
+_cairo_xcb_surface_clone_similar (cairo_surface_t *src,
+ cairo_xcb_surface_t *template,
+ cairo_format_t format,
+ int depth)
+{
+ cairo_xcb_surface_t *clone;
+ cairo_image_surface_t *src_image;
+
+ src_image = _cairo_surface_get_image (src);
+
+ clone = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_similar (template, format,
+ src_image->width,
+ src_image->height);
+ if (clone == NULL)
+ return NULL;
+
+ _cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src));
+
+ _cairo_xcb_surface_set_image (clone, src_image);
+
+ _cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix));
+
+ cairo_surface_destroy (&src_image->base);
+
+ return clone;
+}
+
+static int
+_render_operator (cairo_operator_t operator)
+{
+ switch (operator) {
+ case CAIRO_OPERATOR_CLEAR:
+ return XCBRenderPictOpClear;
+ case CAIRO_OPERATOR_SRC:
+ return XCBRenderPictOpSrc;
+ case CAIRO_OPERATOR_DST:
+ return XCBRenderPictOpDst;
+ case CAIRO_OPERATOR_OVER:
+ return XCBRenderPictOpOver;
+ case CAIRO_OPERATOR_OVER_REVERSE:
+ return XCBRenderPictOpOverReverse;
+ case CAIRO_OPERATOR_IN:
+ return XCBRenderPictOpIn;
+ case CAIRO_OPERATOR_IN_REVERSE:
+ return XCBRenderPictOpInReverse;
+ case CAIRO_OPERATOR_OUT:
+ return XCBRenderPictOpOut;
+ case CAIRO_OPERATOR_OUT_REVERSE:
+ return XCBRenderPictOpOutReverse;
+ case CAIRO_OPERATOR_ATOP:
+ return XCBRenderPictOpAtop;
+ case CAIRO_OPERATOR_ATOP_REVERSE:
+ return XCBRenderPictOpAtopReverse;
+ case CAIRO_OPERATOR_XOR:
+ return XCBRenderPictOpXor;
+ case CAIRO_OPERATOR_ADD:
+ return XCBRenderPictOpAdd;
+ case CAIRO_OPERATOR_SATURATE:
+ return XCBRenderPictOpSaturate;
+ default:
+ return XCBRenderPictOpOver;
+ }
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_composite (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ cairo_surface_t *generic_mask,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ cairo_xcb_surface_t *dst = abstract_dst;
+ cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
+ cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask;
+ cairo_xcb_surface_t *src_clone = NULL;
+ cairo_xcb_surface_t *mask_clone = NULL;
+ XCBRenderPICTURE maskpict = { 0 };
+
+
+ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
+ src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
+ CAIRO_FORMAT_ARGB32, 32);
+ if (!src_clone)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ src = src_clone;
+ }
+ if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) {
+ mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst,
+ CAIRO_FORMAT_A8, 8);
+ if (!mask_clone)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ mask = mask_clone;
+ }
+
+ if(mask)
+ maskpict = mask->picture;
+
+ XCBRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ maskpict,
+ dst->picture,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+
+ /* XXX: This is messed up. If I can xcb_surface_create, then I
+ should be able to xcb_surface_destroy. */
+ if (src_clone)
+ cairo_surface_destroy (&src_clone->base);
+ if (mask_clone)
+ cairo_surface_destroy (&mask_clone->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ XCBRenderCOLOR render_color;
+
+ if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ render_color.red = color->red_short;
+ render_color.green = color->green_short;
+ render_color.blue = color->blue_short;
+ render_color.alpha = color->alpha_short;
+
+ /* XXX: This XCBRECTANGLE cast is evil... it needs to go away somehow. */
+ XCBRenderFillRectangles (surface->dpy,
+ _render_operator (operator),
+ surface->picture,
+ render_color, num_rects, (XCBRECTANGLE *) rects);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int xSrc,
+ int ySrc,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ cairo_xcb_surface_t *dst = abstract_dst;
+ cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
+ cairo_xcb_surface_t *src_clone = NULL;
+
+ if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
+ src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
+ CAIRO_FORMAT_ARGB32, 32);
+ if (!src_clone)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ src = src_clone;
+ }
+
+ /* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */
+ /* XXX: format_from_cairo is slow. should cache something. */
+ XCBRenderTrapezoids (dst->dpy,
+ _render_operator (operator),
+ src->picture, dst->picture,
+ format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
+ xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps);
+
+ /* XXX: This is messed up. If I can xcb_surface_create, then I
+ should be able to xcb_surface_destroy. */
+ if (src_clone)
+ cairo_surface_destroy (&src_clone->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_copy_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_show_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ /* FIXME */
+ 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,
+ _cairo_xcb_surface_pixels_per_inch,
+ _cairo_xcb_surface_get_image,
+ _cairo_xcb_surface_set_image,
+ _cairo_xcb_surface_set_matrix,
+ _cairo_xcb_surface_set_filter,
+ _cairo_xcb_surface_set_repeat,
+ _cairo_xcb_surface_composite,
+ _cairo_xcb_surface_fill_rectangles,
+ _cairo_xcb_surface_composite_trapezoids,
+ _cairo_xcb_surface_copy_page,
+ _cairo_xcb_surface_show_page,
+ _cairo_xcb_surface_set_clip_region,
+ _cairo_xcb_surface_create_pattern
+};
+
+static void
+query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
+{
+ XCBRenderQueryVersionRep *r;
+
+ surface->render_major = -1;
+ surface->render_minor = -1;
+
+ if (!XCBRenderInit(c))
+ return;
+
+ r = XCBRenderQueryVersionReply(c, XCBRenderQueryVersion(c, 0, 6), 0);
+ if (!r)
+ return;
+
+ surface->render_major = r->major_version;
+ surface->render_minor = r->minor_version;
+ free(r);
+}
+
+cairo_surface_t *
+cairo_xcb_surface_create (XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ cairo_format_t format)
+{
+ cairo_xcb_surface_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_surface_t));
+ if (surface == NULL)
+ return NULL;
+
+ _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend);
+
+ surface->dpy = dpy;
+ surface->gc.xid = 0;
+ surface->drawable = drawable;
+ surface->owns_pixmap = 0;
+ surface->visual = visual;
+ surface->format = format;
+
+ query_render_version(dpy, surface);
+
+ if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
+ {
+ XCBRenderPICTFORMAT fmt;
+ if(visual)
+ fmt = format_from_visual (dpy, visual->visual_id);
+ else
+ fmt = format_from_cairo (dpy, format);
+ surface->picture = XCBRenderPICTURENew(dpy);
+ XCBRenderCreatePicture (dpy, surface->picture, drawable,
+ fmt, 0, NULL);
+ }
+ else
+ surface->picture.xid = 0;
+
+ return (cairo_surface_t *) surface;
+}
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 49abdb56..19dfde50 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -90,6 +90,7 @@ typedef struct cairo_xlib_surface {
#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
static int
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
@@ -257,7 +258,7 @@ _cairo_xlib_surface_set_image (void *abstract_surface,
ximage = XCreateImage (surface->dpy,
DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
- image->depth == 32 ? 24 : image->depth,
+ image->depth,
ZPixmap,
0,
image->data,
@@ -320,26 +321,29 @@ _cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
cairo_xlib_surface_t *surface = abstract_surface;
char *render_filter;
- if (!surface->picture)
+ if (!(surface->picture
+ && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
return CAIRO_STATUS_SUCCESS;
-
- /* XXX: The Render specification has capitalized versions of these
- strings. However, the current implementation is
- case-sensitive and expects lowercase versions.
- */
+
switch (filter) {
case CAIRO_FILTER_FAST:
- render_filter = "fast";
+ render_filter = FilterFast;
+ break;
case CAIRO_FILTER_GOOD:
- render_filter = "good";
+ render_filter = FilterGood;
+ break;
case CAIRO_FILTER_BEST:
- render_filter = "best";
+ render_filter = FilterBest;
+ break;
case CAIRO_FILTER_NEAREST:
- render_filter = "nearest";
+ render_filter = FilterNearest;
+ break;
case CAIRO_FILTER_BILINEAR:
- render_filter = "bilinear";
+ render_filter = FilterBilinear;
+ break;
default:
- render_filter = "best";
+ render_filter = FilterBest;
+ break;
}
XRenderSetPictureFilter (surface->dpy, surface->picture,
@@ -384,6 +388,8 @@ _cairo_xlib_surface_clone_similar (cairo_surface_t *src,
if (clone == NULL)
return NULL;
+ _cairo_xlib_surface_set_filter (clone, cairo_surface_get_filter(src));
+
_cairo_xlib_surface_set_image (clone, src_image);
_cairo_xlib_surface_set_matrix (clone, &(src_image->base.matrix));
@@ -567,6 +573,60 @@ _cairo_xlib_surface_show_page (void *abstract_surface)
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+static cairo_int_status_t
+_cairo_xlib_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ Region xregion;
+ XRectangle xr;
+ pixman_box16_t *box;
+ cairo_xlib_surface_t *surf;
+ int n, m;
+
+ surf = (cairo_xlib_surface_t *) abstract_surface;
+
+ if (region == NULL) {
+ /* NULL region == reset the clip */
+ xregion = XCreateRegion();
+ xr.x = 0;
+ xr.y = 0;
+ xr.width = surf->width;
+ xr.height = surf->height;
+ XUnionRectWithRegion (&xr, xregion, xregion);
+ } else {
+ n = pixman_region_num_rects (region);
+ /* XXX: Are we sure these are the semantics we want for an
+ * empty, (not null) region? */
+ if (n == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ box = pixman_region_rects (region);
+ xregion = XCreateRegion();
+
+ m = n;
+ for (; n > 0; --n, ++box) {
+ xr.x = (short) box->x1;
+ xr.y = (short) box->y1;
+ xr.width = (unsigned short) (box->x2 - box->x1);
+ xr.height = (unsigned short) (box->y2 - box->y1);
+ XUnionRectWithRegion (&xr, xregion, xregion);
+ }
+ }
+
+ XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
+ XDestroyRegion(xregion);
+
+ 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,
@@ -580,7 +640,9 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = {
_cairo_xlib_surface_fill_rectangles,
_cairo_xlib_surface_composite_trapezoids,
_cairo_xlib_surface_copy_page,
- _cairo_xlib_surface_show_page
+ _cairo_xlib_surface_show_page,
+ _cairo_xlib_surface_set_clip_region,
+ _cairo_xlib_surface_create_pattern
};
cairo_surface_t *
diff --git a/src/cairo.c b/src/cairo.c
index 1149337b..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,35 @@ 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)
+ return;
+
+ cr->status = _cairo_gstate_init_clip (cr->gstate);
+}
+
+void
cairo_clip (cairo_t *cr)
{
if (cr->status)
@@ -646,7 +678,7 @@ cairo_clip (cairo_t *cr)
void
cairo_select_font (cairo_t *cr,
- char *family,
+ const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
@@ -706,8 +738,6 @@ cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix)
cr->status = _cairo_gstate_transform_font (cr->gstate, matrix);
}
-
-/* XXX: NYI
void
cairo_text_extents (cairo_t *cr,
const unsigned char *utf8,
@@ -731,7 +761,6 @@ cairo_glyph_extents (cairo_t *cr,
cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs,
extents);
}
-*/
void
cairo_show_text (cairo_t *cr, const unsigned char *utf8)
@@ -751,7 +780,6 @@ cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs);
}
-/* XXX: NYI
void
cairo_text_path (cairo_t *cr, const unsigned char *utf8)
{
@@ -769,7 +797,6 @@ cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs);
}
-*/
void
cairo_show_surface (cairo_t *cr,
@@ -868,6 +895,43 @@ cairo_current_target_surface (cairo_t *cr)
}
DEPRECATE (cairo_get_target_surface, cairo_current_target_surface);
+void
+cairo_current_path (cairo_t *cr,
+ cairo_move_to_func_t *move_to,
+ cairo_line_to_func_t *line_to,
+ cairo_curve_to_func_t *curve_to,
+ cairo_close_path_func_t *close_path,
+ void *closure)
+{
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_interpret_path (cr->gstate,
+ move_to,
+ line_to,
+ curve_to,
+ close_path,
+ closure);
+}
+
+void
+cairo_current_path_flat (cairo_t *cr,
+ cairo_move_to_func_t *move_to,
+ cairo_line_to_func_t *line_to,
+ cairo_close_path_func_t *close_path,
+ void *closure)
+{
+ if (cr->status)
+ return;
+
+ cr->status = _cairo_gstate_interpret_path (cr->gstate,
+ move_to,
+ line_to,
+ NULL,
+ close_path,
+ closure);
+}
+
cairo_status_t
cairo_status (cairo_t *cr)
{
@@ -901,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 6df5f8cf..ab3c80e8 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -30,52 +30,48 @@
#include <cairo-features.h>
-#include <ic.h>
+#include <pixman.h>
#include <stdio.h>
-#ifdef _CAIROINT_H_
-#include <slim_export.h>
-#else
-#include <slim_import.h>
-#endif
-
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" {
#endif
/* Functions for manipulating state objects */
-extern cairo_t * __external_linkage
+cairo_t *
cairo_create (void);
-extern void __external_linkage
+void
cairo_reference (cairo_t *cr);
-extern void __external_linkage
+void
cairo_destroy (cairo_t *cr);
-extern void __external_linkage
+void
cairo_save (cairo_t *cr);
-extern void __external_linkage
+void
cairo_restore (cairo_t *cr);
-extern void __external_linkage
+/* XXX: Replace with cairo_current_gstate/cairo_set_gstate */
+void
cairo_copy (cairo_t *dest, cairo_t *src);
/* XXX: I want to rethink this API
-extern void __external_linkage
+void
cairo_push_group (cairo_t *cr);
-extern void __external_linkage
+void
cairo_pop_group (cairo_t *cr);
*/
/* Modify state */
-extern void __external_linkage
+void
cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface);
typedef enum cairo_format {
@@ -85,7 +81,7 @@ typedef enum cairo_format {
CAIRO_FORMAT_A1
} cairo_format_t;
-extern void __external_linkage
+void
cairo_set_target_image (cairo_t *cr,
char *data,
cairo_format_t format,
@@ -93,7 +89,11 @@ cairo_set_target_image (cairo_t *cr,
int height,
int stride);
-extern void __external_linkage
+#ifdef CAIRO_HAS_PS_SURFACE
+
+#include <stdio.h>
+
+void
cairo_set_target_ps (cairo_t *cr,
FILE *file,
double width_inches,
@@ -101,18 +101,46 @@ cairo_set_target_ps (cairo_t *cr,
double x_pixels_per_inch,
double y_pixels_per_inch);
+#endif /* CAIRO_HAS_PS_SURFACE */
+
+#ifdef CAIRO_HAS_PNG_SURFACE
+
+#include <stdio.h>
+
+void
+cairo_set_target_png (cairo_t *cr,
+ FILE *file,
+ cairo_format_t format,
+ int width,
+ int height);
+
+#endif /* CAIRO_HAS_PNG_SURFACE */
+
#ifdef CAIRO_HAS_XLIB_SURFACE
#include <X11/extensions/Xrender.h>
/* XXX: This shold be renamed to cairo_set_target_xlib to match the
* other backends */
-extern void __external_linkage
+void
cairo_set_target_drawable (cairo_t *cr,
Display *dpy,
Drawable drawable);
#endif /* CAIRO_HAS_XLIB_SURFACE */
+#ifdef CAIRO_HAS_XCB_SURFACE
+
+#include <X11/XCB/xcb.h>
+#include <X11/XCB/render.h>
+
+void
+cairo_set_target_xcb (cairo_t *cr,
+ XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ cairo_format_t format);
+#endif /* CAIRO_HAS_XCB_SURFACE */
+
typedef enum cairo_operator {
CAIRO_OPERATOR_CLEAR,
CAIRO_OPERATOR_SRC,
@@ -127,10 +155,10 @@ typedef enum cairo_operator {
CAIRO_OPERATOR_ATOP_REVERSE,
CAIRO_OPERATOR_XOR,
CAIRO_OPERATOR_ADD,
- CAIRO_OPERATOR_SATURATE,
+ CAIRO_OPERATOR_SATURATE
} cairo_operator_t;
-extern void __external_linkage
+void
cairo_set_operator (cairo_t *cr, cairo_operator_t op);
/* XXX: Probably want to bite the bullet and expose a cairo_color_t object */
@@ -150,16 +178,20 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op);
the behavior of cairo_show_surface.
*/
-extern void __external_linkage
+void
cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue);
-extern void __external_linkage
-cairo_set_alpha (cairo_t *cr, double alpha);
+void
+cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern);
-extern void __external_linkage
-cairo_set_pattern (cairo_t *cr, cairo_surface_t *pattern);
+void
+cairo_set_alpha (cairo_t *cr, double alpha);
-extern void __external_linkage
+/* 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
+ value in this API that is not expressed in user-space units. I
+ should think whether this value should be user-space instead. */
+void
cairo_set_tolerance (cairo_t *cr, double tolerance);
typedef enum cairo_fill_rule {
@@ -167,10 +199,10 @@ typedef enum cairo_fill_rule {
CAIRO_FILL_RULE_EVEN_ODD
} cairo_fill_rule_t;
-extern void __external_linkage
+void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule);
-extern void __external_linkage
+void
cairo_set_line_width (cairo_t *cr, double width);
typedef enum cairo_line_cap {
@@ -179,7 +211,7 @@ typedef enum cairo_line_cap {
CAIRO_LINE_CAP_SQUARE
} cairo_line_cap_t;
-extern void __external_linkage
+void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap);
typedef enum cairo_line_join {
@@ -188,101 +220,101 @@ typedef enum cairo_line_join {
CAIRO_LINE_JOIN_BEVEL
} cairo_line_join_t;
-extern void __external_linkage
+void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join);
-extern void __external_linkage
+void
cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset);
-extern void __external_linkage
+void
cairo_set_miter_limit (cairo_t *cr, double limit);
-extern void __external_linkage
+void
cairo_translate (cairo_t *cr, double tx, double ty);
-extern void __external_linkage
+void
cairo_scale (cairo_t *cr, double sx, double sy);
-extern void __external_linkage
+void
cairo_rotate (cairo_t *cr, double angle);
-extern void __external_linkage
+void
cairo_concat_matrix (cairo_t *cr,
- cairo_matrix_t *matrix);
+ cairo_matrix_t *matrix);
-extern void __external_linkage
+void
cairo_set_matrix (cairo_t *cr,
- cairo_matrix_t *matrix);
+ cairo_matrix_t *matrix);
-extern void __external_linkage
+void
cairo_default_matrix (cairo_t *cr);
/* XXX: There's been a proposal to add cairo_default_matrix_exact */
-extern void __external_linkage
+void
cairo_identity_matrix (cairo_t *cr);
-extern void __external_linkage
+void
cairo_transform_point (cairo_t *cr, double *x, double *y);
-extern void __external_linkage
+void
cairo_transform_distance (cairo_t *cr, double *dx, double *dy);
-extern void __external_linkage
+void
cairo_inverse_transform_point (cairo_t *cr, double *x, double *y);
-extern void __external_linkage
+void
cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy);
/* Path creation functions */
-extern void __external_linkage
+void
cairo_new_path (cairo_t *cr);
-extern void __external_linkage
+void
cairo_move_to (cairo_t *cr, double x, double y);
-extern void __external_linkage
+void
cairo_line_to (cairo_t *cr, double x, double y);
-extern void __external_linkage
+void
cairo_curve_to (cairo_t *cr,
- double x1, double y1,
- double x2, double y2,
- double x3, double y3);
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3);
-extern void __external_linkage
+void
cairo_arc (cairo_t *cr,
double xc, double yc,
double radius,
double angle1, double angle2);
-extern void __external_linkage
+void
cairo_arc_negative (cairo_t *cr,
double xc, double yc,
double radius,
double angle1, double angle2);
/* XXX: NYI
-extern void __external_linkage
+void
cairo_arc_to (cairo_t *cr,
double x1, double y1,
double x2, double y2,
double radius);
*/
-extern void __external_linkage
+void
cairo_rel_move_to (cairo_t *cr, double dx, double dy);
-extern void __external_linkage
+void
cairo_rel_line_to (cairo_t *cr, double dx, double dy);
-extern void __external_linkage
+void
cairo_rel_curve_to (cairo_t *cr,
double dx1, double dy1,
double dx2, double dy2,
double dx3, double dy3);
-extern void __external_linkage
+void
cairo_rectangle (cairo_t *cr,
double x, double y,
double width, double height);
@@ -295,35 +327,49 @@ cairo_rectangle (cairo_t *cr,
Maybe we could use something like "cairo_outline_path (cairo_t *)"?
*/
/* XXX: NYI
-extern void __external_linkage
+void
cairo_stroke_path (cairo_t *cr);
*/
-extern void __external_linkage
+void
cairo_close_path (cairo_t *cr);
/* Painting functions */
-extern void __external_linkage
+void
cairo_stroke (cairo_t *cr);
-extern void __external_linkage
+void
cairo_fill (cairo_t *cr);
-extern void __external_linkage
+void
cairo_copy_page (cairo_t *cr);
-extern void __external_linkage
+void
cairo_show_page (cairo_t *cr);
/* Insideness testing */
-extern int __external_linkage
+int
cairo_in_stroke (cairo_t *cr, double x, double y);
-extern int __external_linkage
+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 */
-extern void __external_linkage
+void
+cairo_init_clip (cairo_t *cr);
+
+void
cairo_clip (cairo_t *cr);
/* Font/Text functions */
@@ -337,10 +383,10 @@ typedef struct {
} cairo_glyph_t;
typedef struct {
- double left_side_bearing;
- double right_side_bearing;
- double ascent;
- double descent;
+ double x_bearing;
+ double y_bearing;
+ double width;
+ double height;
double x_advance;
double y_advance;
} cairo_text_extents_t;
@@ -353,115 +399,106 @@ typedef struct {
double max_y_advance;
} cairo_font_extents_t;
-typedef enum cairo_font_weight {
- CAIRO_FONT_WEIGHT_NORMAL,
- CAIRO_FONT_WEIGHT_BOLD
-} cairo_font_weight_t;
-
typedef enum cairo_font_slant {
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_SLANT_ITALIC,
CAIRO_FONT_SLANT_OBLIQUE
} cairo_font_slant_t;
-
+typedef enum cairo_font_weight {
+ CAIRO_FONT_WEIGHT_NORMAL,
+ CAIRO_FONT_WEIGHT_BOLD
+} cairo_font_weight_t;
+
/* This interface is for dealing with text as text, not caring about the
font object inside the the cairo_t. */
-extern void __external_linkage
+void
cairo_select_font (cairo_t *ct,
- char *family,
+ const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
-extern void __external_linkage
+void
cairo_scale_font (cairo_t *cr, double scale);
-extern void __external_linkage
+void
cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix);
-extern void __external_linkage
+void
cairo_show_text (cairo_t *ct, const unsigned char *utf8);
-extern void __external_linkage
+void
cairo_show_glyphs (cairo_t *ct, cairo_glyph_t *glyphs, int num_glyphs);
-extern cairo_font_t * __external_linkage
+cairo_font_t *
cairo_current_font (cairo_t *ct);
-extern void __external_linkage
+void
cairo_current_font_extents (cairo_t *ct,
cairo_font_extents_t *extents);
-extern void __external_linkage
+void
cairo_set_font (cairo_t *ct, cairo_font_t *font);
-
-/* XXX: NYI
-
-extern void __external_linkage
+void
cairo_text_extents (cairo_t *ct,
const unsigned char *utf8,
cairo_text_extents_t *extents);
-extern void __external_linkage
+void
cairo_glyph_extents (cairo_t *ct,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_text_extents_t *extents);
-extern void __external_linkage
+void
cairo_text_path (cairo_t *ct, const unsigned char *utf8);
-extern void __external_linkage
+void
cairo_glyph_path (cairo_t *ct, cairo_glyph_t *glyphs, int num_glyphs);
-*/
-
-
/* Portable interface to general font features. */
-extern void __external_linkage
+void
cairo_font_reference (cairo_font_t *font);
-extern void __external_linkage
+void
cairo_font_destroy (cairo_font_t *font);
-extern void __external_linkage
+void
cairo_font_set_transform (cairo_font_t *font,
cairo_matrix_t *matrix);
-extern void __external_linkage
+void
cairo_font_current_transform (cairo_font_t *font,
cairo_matrix_t *matrix);
-
/* Fontconfig/Freetype platform-specific font interface */
#include <fontconfig/fontconfig.h>
#include <ft2build.h>
#include FT_FREETYPE_H
-extern cairo_font_t * __external_linkage
+cairo_font_t *
cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern);
-extern cairo_font_t * __external_linkage
+cairo_font_t *
cairo_ft_font_create_for_ft_face (FT_Face face);
-extern void __external_linkage
+void
cairo_ft_font_destroy (cairo_font_t *ft_font);
-extern FT_Face __external_linkage
+FT_Face
cairo_ft_font_face (cairo_font_t *ft_font);
-extern FcPattern * __external_linkage
+FcPattern *
cairo_ft_font_pattern (cairo_font_t *ft_font);
-
-
/* Image functions */
-extern void __external_linkage
+/* XXX: Eliminate width/height here */
+void
cairo_show_surface (cairo_t *cr,
cairo_surface_t *surface,
int width,
@@ -475,48 +512,78 @@ cairo_show_surface (cairo_t *cr,
into one file and be done with it. For now, I've got a little more
typing than that. */
-extern cairo_operator_t __external_linkage
+cairo_operator_t
cairo_current_operator (cairo_t *cr);
-extern void __external_linkage
+void
cairo_current_rgb_color (cairo_t *cr, double *red, double *green, double *blue);
+cairo_pattern_t *
+cairo_current_pattern (cairo_t *cr);
-extern double __external_linkage
+double
cairo_current_alpha (cairo_t *cr);
/* XXX: Do we want cairo_current_pattern as well? */
-extern double __external_linkage
+double
cairo_current_tolerance (cairo_t *cr);
-extern void __external_linkage
+void
cairo_current_point (cairo_t *cr, double *x, double *y);
-extern cairo_fill_rule_t __external_linkage
+cairo_fill_rule_t
cairo_current_fill_rule (cairo_t *cr);
-extern double __external_linkage
+double
cairo_current_line_width (cairo_t *cr);
-extern cairo_line_cap_t __external_linkage
+cairo_line_cap_t
cairo_current_line_cap (cairo_t *cr);
-extern cairo_line_join_t __external_linkage
+cairo_line_join_t
cairo_current_line_join (cairo_t *cr);
-extern double __external_linkage
+double
cairo_current_miter_limit (cairo_t *cr);
/* XXX: How to do cairo_current_dash??? Do we want to switch to a cairo_dash object? */
-extern void __external_linkage
+void
cairo_current_matrix (cairo_t *cr, cairo_matrix_t *matrix);
/* XXX: Need to decide the memory mangement semantics of this
function. Should it reference the surface again? */
-extern cairo_surface_t * __external_linkage
+cairo_surface_t *
cairo_current_target_surface (cairo_t *cr);
+typedef void (cairo_move_to_func_t) (void *closure,
+ double x, double y);
+
+typedef void (cairo_line_to_func_t) (void *closure,
+ double x, double y);
+
+typedef void (cairo_curve_to_func_t) (void *closure,
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3);
+
+typedef void (cairo_close_path_func_t) (void *closure);
+
+extern void
+cairo_current_path (cairo_t *cr,
+ cairo_move_to_func_t *move_to,
+ cairo_line_to_func_t *line_to,
+ cairo_curve_to_func_t *curve_to,
+ cairo_close_path_func_t *close_path,
+ void *closure);
+
+extern void
+cairo_current_path_flat (cairo_t *cr,
+ cairo_move_to_func_t *move_to,
+ cairo_line_to_func_t *line_to,
+ cairo_close_path_func_t *close_path,
+ void *closure);
+
/* Error status queries */
typedef enum cairo_status {
@@ -530,16 +597,16 @@ typedef enum cairo_status {
CAIRO_STATUS_NULL_POINTER
} cairo_status_t;
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_status (cairo_t *cr);
-extern const char * __external_linkage
+const char *
cairo_status_string (cairo_t *cr);
/* Surface manipulation */
/* XXX: We may want to rename this function in light of the new
virtualized surface backends... */
-extern cairo_surface_t * __external_linkage
+cairo_surface_t *
cairo_surface_create_for_image (char *data,
cairo_format_t format,
int width,
@@ -548,26 +615,26 @@ cairo_surface_create_for_image (char *data,
/* XXX: I want to remove this function, (replace with
cairo_set_target_scratch or similar). */
-extern cairo_surface_t * __external_linkage
+cairo_surface_t *
cairo_surface_create_similar (cairo_surface_t *other,
cairo_format_t format,
int width,
int height);
-extern void __external_linkage
+void
cairo_surface_reference (cairo_surface_t *surface);
-extern void __external_linkage
+void
cairo_surface_destroy (cairo_surface_t *surface);
/* XXX: NYI
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_surface_clip_restore (cairo_surface_t *surface);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_surface_clip_begin (cairo_surface_t *surface);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_surface_clip_rectangle (cairo_surface_t *surface,
int x, int y,
int width, int height);
@@ -576,52 +643,120 @@ cairo_surface_clip_rectangle (cairo_surface_t *surface,
/* XXX: Note: The current Render/Ic implementations don't do the right
thing with repeat when the surface has a non-identity matrix. */
/* XXX: Rework this as a cairo function with an enum: cairo_set_pattern_extend */
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_surface_set_repeat (cairo_surface_t *surface, int repeat);
/* XXX: Rework this as a cairo function: cairo_set_pattern_transform */
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_surface_set_matrix (cairo_surface_t *surface, cairo_matrix_t *matrix);
/* XXX: Rework this as a cairo function: cairo_current_pattern_transform */
-extern cairo_status_t __external_linkage
+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_GAUSSIAN
} cairo_filter_t;
-
+
/* XXX: Rework this as a cairo function: cairo_set_pattern_filter */
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter);
+cairo_filter_t
+cairo_surface_get_filter (cairo_surface_t *surface);
+
/* Image-surface functions */
-extern cairo_surface_t * __external_linkage
+cairo_surface_t *
cairo_image_surface_create (cairo_format_t format,
int width,
int height);
-extern cairo_surface_t * __external_linkage
+cairo_surface_t *
cairo_image_surface_create_for_data (char *data,
cairo_format_t format,
int width,
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 */
-extern cairo_surface_t * __external_linkage
+cairo_surface_t *
cairo_ps_surface_create (FILE *file,
double width_inches,
double height_inches,
double x_pixels_per_inch,
double y_pixels_per_inch);
+#endif /* CAIRO_HAS_PS_SURFACE */
+
+#ifdef CAIRO_HAS_PNG_SURFACE
+
+/* PNG-surface functions */
+
+cairo_surface_t *
+cairo_png_surface_create (FILE *file,
+ cairo_format_t format,
+ int width,
+ int height);
+
+#endif /* CAIRO_HAS_PNG_SURFACE */
+
#ifdef CAIRO_HAS_XLIB_SURFACE
/* XXX: This is a mess from the user's POV. Should the Visual or the
@@ -629,12 +764,17 @@ cairo_ps_surface_create (FILE *file,
cairo_surface_create_for_window with a visual, and
cairo_surface_create_for_pixmap with a cairo_format_t. Would that work?
*/
-extern cairo_surface_t * __external_linkage
+cairo_surface_t *
cairo_xlib_surface_create (Display *dpy,
Drawable drawable,
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);
+*/
#endif /* CAIRO_HAS_XLIB_SURFACE */
@@ -642,49 +782,49 @@ cairo_xlib_surface_create (Display *dpy,
/* XXX: Rename all of these to cairo_transform_t */
-extern cairo_matrix_t * __external_linkage
+cairo_matrix_t *
cairo_matrix_create (void);
-extern void __external_linkage
+void
cairo_matrix_destroy (cairo_matrix_t *matrix);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_copy (cairo_matrix_t *matrix, const cairo_matrix_t *other);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_set_identity (cairo_matrix_t *matrix);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_set_affine (cairo_matrix_t *cr,
double a, double b,
double c, double d,
double tx, double ty);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_get_affine (cairo_matrix_t *matrix,
double *a, double *b,
double *c, double *d,
double *tx, double *ty);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_rotate (cairo_matrix_t *matrix, double radians);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_invert (cairo_matrix_t *matrix);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy);
-extern cairo_status_t __external_linkage
+cairo_status_t
cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
/* Deprecated functions. We've made some effort to allow the
@@ -712,6 +852,4 @@ cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y);
}
#endif
-#undef __external_linkage
-
#endif
diff --git a/src/cairo_fixed.c b/src/cairo_fixed.c
index 33088546..9a7e7bc4 100644
--- a/src/cairo_fixed.c
+++ b/src/cairo_fixed.c
@@ -39,8 +39,15 @@ _cairo_fixed_from_double (double d)
return (cairo_fixed_t) (d * 65536);
}
+cairo_fixed_t
+_cairo_fixed_from_26_6 (uint32_t i)
+{
+ return i << 10;
+}
+
double
_cairo_fixed_to_double (cairo_fixed_t f)
{
return ((double) f) / 65536.0;
}
+
diff --git a/src/cairo_font.c b/src/cairo_font.c
index f6bf390a..157ebedb 100644
--- a/src/cairo_font.c
+++ b/src/cairo_font.c
@@ -28,12 +28,18 @@
#include "cairoint.h"
cairo_font_t *
-_cairo_font_create (char *family,
+_cairo_font_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
const struct cairo_font_backend *backend = CAIRO_FONT_BACKEND_DEFAULT;
+ /* XXX: The current freetype backend may return NULL, (for example
+ * if no fonts are installed), but I would like to guarantee that
+ * the toy API always returns at least *some* font, so I would
+ * like to build in some sort fo font here, (even a really lame,
+ * ugly one if necessary). */
+
return backend->create (family, slant, weight);
}
@@ -118,31 +124,30 @@ _cairo_font_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
- double x,
- double y,
cairo_glyph_t *glyphs,
int num_glyphs)
{
return font->backend->show_glyphs(font, operator, source,
- surface, x, y, glyphs, num_glyphs);
+ surface, glyphs, num_glyphs);
}
cairo_status_t
_cairo_font_text_path (cairo_font_t *font,
- cairo_path_t *path,
- const unsigned char *utf8)
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_path_t *path)
{
- return font->backend->text_path(font, path, utf8);
+ return font->backend->text_path(font, x, y, utf8, path);
}
cairo_status_t
_cairo_font_glyph_path (cairo_font_t *font,
- cairo_path_t *path,
cairo_glyph_t *glyphs,
- int num_glyphs)
+ int num_glyphs,
+ cairo_path_t *path)
{
- return font->backend->glyph_path(font, path,
- glyphs, num_glyphs);
+ return font->backend->glyph_path(font, glyphs, num_glyphs, path);
}
cairo_status_t
diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c
index c3e4306d..77cf59b0 100644
--- a/src/cairo_ft_font.c
+++ b/src/cairo_ft_font.c
@@ -25,7 +25,10 @@
#include "cairoint.h"
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
-#include <freetype/freetype.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
typedef struct {
cairo_font_t base;
@@ -39,13 +42,10 @@ typedef struct {
FcPattern *pattern;
} cairo_ft_font_t;
-
-#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 63.0))
-#define DOUBLE_FROM_26_6(t) (((double)((t) >> 6)) \
- + ((double)((t) & 0x3F) / 63.0))
-#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65535.0))
-#define DOUBLE_FROM_16_16(t) (((double)((t) >> 16)) \
- + ((double)((t) & 0xFFFF) / 65535.0))
+#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0))
+#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0)
+#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))
+#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)
/* implement the platform-specific interface */
@@ -101,29 +101,31 @@ cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern)
}
FT_Face
-cairo_ft_font_face (cairo_font_t *font)
+cairo_ft_font_face (cairo_font_t *abstract_font)
{
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+
if (font == NULL)
return NULL;
- return ((cairo_ft_font_t *) font)->face;
+ return font->face;
}
FcPattern *
-cairo_ft_font_pattern (cairo_font_t *font)
+cairo_ft_font_pattern (cairo_font_t *abstract_font)
{
+ cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font;
+
if (font == NULL)
return NULL;
- return ((cairo_ft_font_t *) font)->pattern;
+ return font->pattern;
}
-
-
/* implement the backend interface */
static cairo_font_t *
-_cairo_ft_font_create (char *family,
+_cairo_ft_font_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
@@ -175,6 +177,9 @@ _cairo_ft_font_create (char *family,
}
font = cairo_ft_font_create (ft_library, pat);
+ if (font == NULL)
+ return NULL;
+
ft_font = (cairo_ft_font_t *) font;
ft_font->owns_ft_library = 1;
@@ -188,45 +193,43 @@ _cairo_ft_font_create (char *family,
return font;
}
-
static cairo_font_t *
-_cairo_ft_font_copy (cairo_font_t *font)
+_cairo_ft_font_copy (void *abstract_font)
{
- cairo_ft_font_t * ft_font_new = NULL;
- cairo_ft_font_t * ft_font = NULL;
+ cairo_ft_font_t * font_new = NULL;
+ cairo_ft_font_t * font = abstract_font;
- ft_font = (cairo_ft_font_t *)font;
+ if (font->base.backend != &cairo_ft_font_backend)
+ return NULL;
- ft_font_new = (cairo_ft_font_t *)cairo_ft_font_create_for_ft_face (ft_font->face);
- if (ft_font_new == NULL)
+ font_new = (cairo_ft_font_t *) cairo_ft_font_create_for_ft_face (font->face);
+ if (font_new == NULL)
return NULL;
- if (ft_font_new != NULL && ft_font->pattern != NULL)
- ft_font_new->pattern = FcPatternDuplicate (ft_font->pattern);
+ if (font_new != NULL && font->pattern != NULL)
+ font_new->pattern = FcPatternDuplicate (font->pattern);
- return (cairo_font_t *)ft_font_new;
+ return (cairo_font_t *) font_new;
}
static void
-_cairo_ft_font_destroy (cairo_font_t *font)
+_cairo_ft_font_destroy (void *abstract_font)
{
- cairo_ft_font_t * ft_font = NULL;
+ cairo_ft_font_t * font = abstract_font;
if (font == NULL)
return;
- ft_font = (cairo_ft_font_t *)font;
-
- if (ft_font->face != NULL && ft_font->owns_face)
- FT_Done_Face (ft_font->face);
+ if (font->face != NULL && font->owns_face)
+ FT_Done_Face (font->face);
- if (ft_font->pattern != NULL)
- FcPatternDestroy (ft_font->pattern);
+ if (font->pattern != NULL)
+ FcPatternDestroy (font->pattern);
- if (ft_font->ft_library && ft_font->owns_ft_library)
- FT_Done_FreeType (ft_font->ft_library);
+ if (font->ft_library && font->owns_ft_library)
+ FT_Done_FreeType (font->ft_library);
- free (ft_font);
+ free (font);
}
static void
@@ -260,21 +263,7 @@ _utf8_to_ucs4 (char const *utf8,
len -= step;
utf8 += step;
}
- *nchars = alloc;
-}
-
-static void
-_get_scale_factors(cairo_matrix_t *matrix, double *sx, double *sy)
-{
- double e0, e1;
- e1 = 1.; e0 = 0.;
-
- cairo_matrix_transform_distance (matrix, &e1, &e0);
- *sx = sqrt(e1*e1 + e0*e0);
-
- e1 = 1.; e0 = 0.;
- cairo_matrix_transform_distance (matrix, &e0, &e1);
- *sy = sqrt(e1*e1 + e0*e0);
+ *nchars = n;
}
static void
@@ -292,7 +281,7 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face)
* transformation.
*/
- _get_scale_factors(matrix, &scale_x, &scale_y);
+ _cairo_matrix_compute_scale_factors (matrix, &scale_x, &scale_y);
cairo_matrix_copy (&normalized, matrix);
@@ -314,23 +303,19 @@ _install_font_matrix(cairo_matrix_t *matrix, FT_Face face)
0, 0);
}
-
static int
-_utf8_to_glyphs (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_glyph_t **glyphs,
- size_t *nglyphs)
+_utf8_to_glyphs (cairo_ft_font_t *font,
+ const unsigned char *utf8,
+ double x0,
+ double y0,
+ cairo_glyph_t **glyphs,
+ size_t *nglyphs)
{
- cairo_ft_font_t *ft;
+ FT_Face face = font->face;
double x = 0., y = 0.;
size_t i;
FT_ULong *ucs4 = NULL;
- if (font == NULL)
- return 0;
-
- ft = (cairo_ft_font_t *)font;
-
_utf8_to_ucs4 (utf8, &ucs4, nglyphs);
if (ucs4 == NULL)
@@ -343,18 +328,18 @@ _utf8_to_glyphs (cairo_font_t *font,
return 0;
}
- _install_font_matrix (&font->matrix, ft->face);
+ _install_font_matrix (&font->base.matrix, face);
for (i = 0; i < *nglyphs; i++)
{
- (*glyphs)[i].index = FT_Get_Char_Index (ft->face, ucs4[i]);
- (*glyphs)[i].x = x;
- (*glyphs)[i].y = y;
+ (*glyphs)[i].index = FT_Get_Char_Index (face, ucs4[i]);
+ (*glyphs)[i].x = x0 + x;
+ (*glyphs)[i].y = y0 + y;
- FT_Load_Glyph (ft->face, (*glyphs)[i].index, FT_LOAD_DEFAULT);
+ FT_Load_Glyph (face, (*glyphs)[i].index, FT_LOAD_DEFAULT);
- x += DOUBLE_FROM_26_6 (ft->face->glyph->advance.x);
- y -= DOUBLE_FROM_26_6 (ft->face->glyph->advance.y);
+ x += DOUBLE_FROM_26_6 (face->glyph->advance.x);
+ y -= DOUBLE_FROM_26_6 (face->glyph->advance.y);
}
free (ucs4);
@@ -362,51 +347,114 @@ _utf8_to_glyphs (cairo_font_t *font,
}
static cairo_status_t
-_cairo_ft_font_font_extents (cairo_font_t *font,
- cairo_font_extents_t *extents)
+_cairo_ft_font_font_extents (void *abstract_font,
+ cairo_font_extents_t *extents)
{
+ cairo_ft_font_t *font = abstract_font;
+ FT_Face face = font->face;
double scale_x, scale_y;
- cairo_ft_font_t *ft = (cairo_ft_font_t *)font;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- _get_scale_factors(&font->matrix, &scale_x, &scale_y);
+ double upm = face->units_per_EM;
-#define FONT_UNIT_TO_DEV(x) ((double)(x) / (double)(ft->face->units_per_EM))
+ _cairo_matrix_compute_scale_factors (&font->base.matrix, &scale_x, &scale_y);
- extents->ascent = FONT_UNIT_TO_DEV(ft->face->ascender) * scale_y;
- extents->descent = FONT_UNIT_TO_DEV(ft->face->descender) * scale_y;
- extents->height = FONT_UNIT_TO_DEV(ft->face->height) * scale_y;
- extents->max_x_advance = FONT_UNIT_TO_DEV(ft->face->max_advance_width) * scale_x;
- extents->max_y_advance = FONT_UNIT_TO_DEV(ft->face->max_advance_height) * scale_y;
- return status;
+ extents->ascent = face->ascender / upm * scale_y;
+ extents->descent = face->descender / upm * scale_y;
+ extents->height = face->height / upm * scale_y;
+ extents->max_x_advance = face->max_advance_width / upm * scale_x;
+ extents->max_y_advance = face->max_advance_height / upm * scale_y;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_ft_font_glyph_extents (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents)
+_cairo_ft_font_glyph_extents (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents)
{
- cairo_ft_font_t *ft;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ int i;
+ cairo_ft_font_t *font = abstract_font;
+ cairo_point_double_t origin;
+ cairo_point_double_t glyph_min, glyph_max;
+ cairo_point_double_t total_min, total_max;
+ FT_Error error;
+ FT_Face face = font->face;
+ FT_GlyphSlot glyph = face->glyph;
+ FT_Glyph_Metrics *metrics = &glyph->metrics;
- ft = (cairo_ft_font_t *)font;
+ if (num_glyphs == 0)
+ {
+ extents->x_bearing = 0.0;
+ extents->y_bearing = 0.0;
+ extents->width = 0.0;
+ extents->height = 0.0;
+ extents->x_advance = 0.0;
+ extents->y_advance = 0.0;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
- /* FIXME: lift code from xft to do this */
+ origin.x = glyphs[0].x;
+ origin.y = glyphs[0].y;
- return status;
+ _install_font_matrix (&font->base.matrix, face);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ error = FT_Load_Glyph (face, glyphs[i].index, FT_LOAD_DEFAULT);
+ /* XXX: What to do in this error case? */
+ if (error)
+ continue;
+
+ /* XXX: Need to add code here to check the font's FcPattern
+ for FC_VERTICAL_LAYOUT and if set get vertBearingX/Y
+ instead. This will require that
+ cairo_ft_font_create_for_ft_face accept an
+ FcPattern. */
+ glyph_min.x = glyphs[i].x + DOUBLE_FROM_26_6 (metrics->horiBearingX);
+ glyph_min.y = glyphs[i].y - DOUBLE_FROM_26_6 (metrics->horiBearingY);
+ glyph_max.x = glyph_min.x + DOUBLE_FROM_26_6 (metrics->width);
+ glyph_max.y = glyph_min.y + DOUBLE_FROM_26_6 (metrics->height);
+
+ if (i==0) {
+ total_min = glyph_min;
+ total_max = glyph_max;
+ } else {
+ if (glyph_min.x < total_min.x)
+ total_min.x = glyph_min.x;
+ if (glyph_min.y < total_min.y)
+ total_min.y = glyph_min.y;
+
+ if (glyph_max.x > total_max.x)
+ total_max.x = glyph_max.x;
+ if (glyph_max.y > total_max.y)
+ total_max.y = glyph_max.y;
+ }
+ }
+
+ extents->x_bearing = total_min.x - origin.x;
+ extents->y_bearing = total_min.y - origin.y;
+ extents->width = total_max.x - total_min.x;
+ extents->height = total_max.y - total_min.y;
+ extents->x_advance = glyphs[i-1].x + DOUBLE_FROM_26_6 (metrics->horiAdvance) - origin.x;
+ extents->y_advance = glyphs[i-1].y + 0 - origin.y;
+
+ return CAIRO_STATUS_SUCCESS;
}
+
static cairo_status_t
-_cairo_ft_font_text_extents (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_text_extents_t *extents)
+_cairo_ft_font_text_extents (void *abstract_font,
+ const unsigned char *utf8,
+ cairo_text_extents_t *extents)
{
+ cairo_ft_font_t *font = abstract_font;
cairo_glyph_t *glyphs;
size_t nglyphs;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs))
+ if (_utf8_to_glyphs (font, utf8, 0, 0, &glyphs, &nglyphs))
{
status = _cairo_ft_font_glyph_extents (font, glyphs, nglyphs,
extents);
@@ -414,24 +462,22 @@ _cairo_ft_font_text_extents (cairo_font_t *font,
}
return status;
}
-
-
static cairo_status_t
-_cairo_ft_font_show_glyphs (cairo_font_t *font,
+_cairo_ft_font_show_glyphs (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
- double x0,
- double y0,
const cairo_glyph_t *glyphs,
int num_glyphs)
{
+ cairo_ft_font_t *font = abstract_font;
cairo_status_t status;
int i;
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;
@@ -444,22 +490,27 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font,
ft = (cairo_ft_font_t *)font;
glyphslot = ft->face->glyph;
- _install_font_matrix (&font->matrix, ft->face);
+ _install_font_matrix (&font->base.matrix, ft->face);
for (i = 0; i < num_glyphs; i++)
{
unsigned char *bitmap;
FT_Load_Glyph (ft->face, glyphs[i].index, FT_LOAD_DEFAULT);
- FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL);
+ FT_Render_Glyph (glyphslot, ft_render_mode_normal);
width = glyphslot->bitmap.width;
height = glyphslot->bitmap.rows;
stride = glyphslot->bitmap.pitch;
bitmap = glyphslot->bitmap.buffer;
- x = x0 + glyphs[i].x;
- y = y0 + glyphs[i].y;
+ x = glyphs[i].x;
+ 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)
@@ -502,11 +553,14 @@ _cairo_ft_font_show_glyphs (cairo_font_t *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)
@@ -519,7 +573,7 @@ _cairo_ft_font_show_glyphs (cairo_font_t *font,
}
static cairo_status_t
-_cairo_ft_font_show_text (cairo_font_t *font,
+_cairo_ft_font_show_text (void *abstract_font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
@@ -527,15 +581,16 @@ _cairo_ft_font_show_text (cairo_font_t *font,
double y0,
const unsigned char *utf8)
{
+ cairo_ft_font_t *font = abstract_font;
cairo_glyph_t *glyphs;
- size_t nglyphs;
+ int num_glyphs;
- if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs))
+ if (_utf8_to_glyphs (font, utf8, x0, y0, &glyphs, &num_glyphs))
{
cairo_status_t res;
res = _cairo_ft_font_show_glyphs (font, operator,
- source, surface, x0, y0,
- glyphs, nglyphs);
+ source, surface,
+ glyphs, num_glyphs);
free (glyphs);
return res;
}
@@ -543,35 +598,147 @@ _cairo_ft_font_show_text (cairo_font_t *font,
return CAIRO_STATUS_NO_MEMORY;
}
+static int
+_move_to (FT_Vector *to, void *closure)
+{
+ cairo_path_t *path = closure;
+ cairo_point_t point;
+
+ point.x = _cairo_fixed_from_26_6 (to->x);
+ point.y = _cairo_fixed_from_26_6 (to->y);
+
+ _cairo_path_close_path (path);
+ _cairo_path_move_to (path, &point);
+
+ return 0;
+}
+
+static int
+_line_to (FT_Vector *to, void *closure)
+{
+ cairo_path_t *path = closure;
+ cairo_point_t point;
+
+ point.x = _cairo_fixed_from_26_6 (to->x);
+ point.y = _cairo_fixed_from_26_6 (to->y);
+
+ _cairo_path_line_to (path, &point);
+
+ return 0;
+}
+
+static int
+_conic_to (FT_Vector *control, FT_Vector *to, void *closure)
+{
+ cairo_path_t *path = closure;
+
+ cairo_point_t p0, p1, p2, p3;
+ cairo_point_t conic;
+
+ _cairo_path_current_point (path, &p0);
+
+ conic.x = _cairo_fixed_from_26_6 (control->x);
+ conic.y = _cairo_fixed_from_26_6 (control->y);
+
+ p3.x = _cairo_fixed_from_26_6 (to->x);
+ p3.y = _cairo_fixed_from_26_6 (to->y);
+
+ p1.x = p0.x + 2.0/3.0 * (conic.x - p0.x);
+ p1.y = p0.y + 2.0/3.0 * (conic.y - p0.y);
+
+ p2.x = p3.x + 2.0/3.0 * (conic.x - p3.x);
+ p2.y = p3.y + 2.0/3.0 * (conic.y - p3.y);
+
+ _cairo_path_curve_to (path,
+ &p1, &p2, &p3);
+
+ return 0;
+}
+
+static int
+_cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closure)
+{
+ cairo_path_t *path = closure;
+ cairo_point_t p0, p1, p2;
+
+ p0.x = _cairo_fixed_from_26_6 (control1->x);
+ p0.y = _cairo_fixed_from_26_6 (control1->y);
+
+ p1.x = _cairo_fixed_from_26_6 (control2->x);
+ p1.y = _cairo_fixed_from_26_6 (control2->y);
+
+ p2.x = _cairo_fixed_from_26_6 (to->x);
+ p2.y = _cairo_fixed_from_26_6 (to->y);
+
+ _cairo_path_curve_to (path, &p0, &p1, &p2);
+
+ return 0;
+}
static cairo_status_t
-_cairo_ft_font_glyph_path (cairo_font_t *font,
- cairo_path_t *path,
- cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_ft_font_glyph_path (void *abstract_font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_ft_font_t *ft;
-
- ft = (cairo_ft_font_t *)font;
-
- /* FIXME: lift code from xft to do this */
+ int i;
+ cairo_ft_font_t *font = abstract_font;
+ FT_GlyphSlot glyph;
+ FT_Error error;
+ FT_Outline_Funcs outline_funcs = {
+ _move_to,
+ _line_to,
+ _conic_to,
+ _cubic_to,
+ 0, /* shift */
+ 0, /* delta */
+ };
+
+ glyph = font->face->glyph;
+ _install_font_matrix (&font->base.matrix, font->face);
+
+ for (i = 0; i < num_glyphs; i++)
+ {
+ FT_Matrix invert_y = {
+ DOUBLE_TO_16_16 (1.0), 0,
+ 0, DOUBLE_TO_16_16 (-1.0),
+ };
+
+ error = FT_Load_Glyph (font->face, glyphs[i].index, FT_LOAD_DEFAULT);
+ /* XXX: What to do in this error case? */
+ if (error)
+ continue;
+ /* XXX: Do we want to support bitmap fonts here? */
+ if (glyph->format == ft_glyph_format_bitmap)
+ continue;
+
+ /* Font glyphs have an inverted Y axis compared to cairo. */
+ FT_Outline_Transform (&glyph->outline, &invert_y);
+ FT_Outline_Translate (&glyph->outline,
+ DOUBLE_TO_26_6(glyphs[i].x),
+ DOUBLE_TO_26_6(glyphs[i].y));
+ FT_Outline_Decompose (&glyph->outline, &outline_funcs, path);
+ }
+ _cairo_path_close_path (path);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_ft_font_text_path (cairo_font_t *font,
- cairo_path_t *path,
- const unsigned char *utf8)
+_cairo_ft_font_text_path (void *abstract_font,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_path_t *path)
{
+ cairo_ft_font_t *font = abstract_font;
cairo_glyph_t *glyphs;
size_t nglyphs;
- if (_utf8_to_glyphs (font, utf8, &glyphs, &nglyphs))
+ if (_utf8_to_glyphs (font, utf8, x, y, &glyphs, &nglyphs))
{
cairo_status_t res;
- res = _cairo_ft_font_glyph_path (font, path, glyphs, nglyphs);
+ res = _cairo_ft_font_glyph_path (font, glyphs, nglyphs, path);
free (glyphs);
return res;
}
@@ -579,7 +746,6 @@ _cairo_ft_font_text_path (cairo_font_t *font,
return CAIRO_STATUS_NO_MEMORY;
}
-
cairo_font_t *
cairo_ft_font_create_for_ft_face (FT_Face face)
{
@@ -602,16 +768,15 @@ cairo_ft_font_create_for_ft_face (FT_Face face)
return (cairo_font_t *) f;
}
-
const struct cairo_font_backend cairo_ft_font_backend = {
- font_extents: (void *) _cairo_ft_font_font_extents,
- text_extents: (void *) _cairo_ft_font_text_extents,
- glyph_extents: (void *) _cairo_ft_font_glyph_extents,
- show_text: (void *) _cairo_ft_font_show_text,
- show_glyphs: (void *) _cairo_ft_font_show_glyphs,
- text_path: (void *) _cairo_ft_font_text_path,
- glyph_path: (void *) _cairo_ft_font_glyph_path,
- create: (void *) _cairo_ft_font_create,
- copy: (void *) _cairo_ft_font_copy,
- destroy: (void *) _cairo_ft_font_destroy
+ _cairo_ft_font_create,
+ _cairo_ft_font_copy,
+ _cairo_ft_font_destroy,
+ _cairo_ft_font_font_extents,
+ _cairo_ft_font_text_extents,
+ _cairo_ft_font_glyph_extents,
+ _cairo_ft_font_show_text,
+ _cairo_ft_font_show_glyphs,
+ _cairo_ft_font_text_path,
+ _cairo_ft_font_glyph_path,
};
diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c
index 8bc6e704..ed8c8a1a 100644
--- a/src/cairo_gstate.c
+++ b/src/cairo_gstate.c
@@ -30,15 +30,9 @@
#include "cairoint.h"
-static void
-_cairo_gstate_set_current_point (cairo_gstate_t *gstate, double x, double y);
-
-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);
@@ -79,25 +73,20 @@ _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);
_cairo_path_init (&gstate->path);
- gstate->current_point.x = 0.0;
- gstate->current_point.y = 0.0;
- gstate->has_current_point = 0;
-
_cairo_pen_init_empty (&gstate->pen_regular);
gstate->next = NULL;
@@ -130,9 +119,16 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
}
}
+ if (other->clip.region)
+ {
+ gstate->clip.region = pixman_region_create ();
+ pixman_region_copy (gstate->clip.region, other->clip.region);
+ }
+
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,16 +160,15 @@ _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;
- _cairo_color_fini (&gstate->color);
+ if (gstate->clip.region)
+ pixman_region_destroy (gstate->clip.region);
+ gstate->clip.region = NULL;
+
+ cairo_pattern_destroy (gstate->pattern);
_cairo_matrix_fini (&gstate->ctm);
_cairo_matrix_fini (&gstate->ctm_inverse);
@@ -358,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)
{
@@ -391,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
@@ -426,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;
}
@@ -680,20 +675,10 @@ _cairo_gstate_inverse_transform_distance (cairo_gstate_t *gstate, double *dx, do
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_gstate_set_current_point (cairo_gstate_t *gstate, double x, double y)
-{
- gstate->current_point.x = x;
- gstate->current_point.y = y;
-
- gstate->has_current_point = 1;
-}
-
cairo_status_t
_cairo_gstate_new_path (cairo_gstate_t *gstate)
{
_cairo_path_fini (&gstate->path);
- gstate->has_current_point = 0;
return CAIRO_STATUS_SUCCESS;
}
@@ -701,53 +686,51 @@ _cairo_gstate_new_path (cairo_gstate_t *gstate)
cairo_status_t
_cairo_gstate_move_to (cairo_gstate_t *gstate, double x, double y)
{
- cairo_status_t status;
+ cairo_point_t point;
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
- status = _cairo_path_move_to (&gstate->path, x, y);
-
- _cairo_gstate_set_current_point (gstate, x, y);
-
- gstate->last_move_point = gstate->current_point;
+ point.x = _cairo_fixed_from_double (x);
+ point.y = _cairo_fixed_from_double (y);
- return status;
+ return _cairo_path_move_to (&gstate->path, &point);
}
cairo_status_t
_cairo_gstate_line_to (cairo_gstate_t *gstate, double x, double y)
{
- cairo_status_t status;
+ cairo_point_t point;
cairo_matrix_transform_point (&gstate->ctm, &x, &y);
- status = _cairo_path_line_to (&gstate->path, x, y);
-
- _cairo_gstate_set_current_point (gstate, x, y);
+ point.x = _cairo_fixed_from_double (x);
+ point.y = _cairo_fixed_from_double (y);
- return status;
+ return _cairo_path_line_to (&gstate->path, &point);
}
cairo_status_t
_cairo_gstate_curve_to (cairo_gstate_t *gstate,
+ double x0, double y0,
double x1, double y1,
- double x2, double y2,
- double x3, double y3)
+ double x2, double y2)
{
- cairo_status_t status;
+ cairo_point_t p0, p1, p2;
+ cairo_matrix_transform_point (&gstate->ctm, &x0, &y0);
cairo_matrix_transform_point (&gstate->ctm, &x1, &y1);
cairo_matrix_transform_point (&gstate->ctm, &x2, &y2);
- cairo_matrix_transform_point (&gstate->ctm, &x3, &y3);
- status = _cairo_path_curve_to (&gstate->path,
- x1, y1,
- x2, y2,
- x3, y3);
+ p0.x = _cairo_fixed_from_double (x0);
+ p0.y = _cairo_fixed_from_double (y0);
- _cairo_gstate_set_current_point (gstate, x3, y3);
+ p1.x = _cairo_fixed_from_double (x1);
+ p1.y = _cairo_fixed_from_double (y1);
- return status;
+ p2.x = _cairo_fixed_from_double (x2);
+ p2.y = _cairo_fixed_from_double (y2);
+
+ return _cairo_path_curve_to (&gstate->path, &p0, &p1, &p2);
}
/* Spline deviation from the circle in radius would be given by:
@@ -1025,63 +1008,54 @@ _cairo_gstate_arc_to (cairo_gstate_t *gstate,
cairo_status_t
_cairo_gstate_rel_move_to (cairo_gstate_t *gstate, double dx, double dy)
{
- cairo_status_t status;
- double x, y;
+ cairo_distance_t distance;
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
- x = gstate->current_point.x + dx;
- y = gstate->current_point.y + dy;
-
- status = _cairo_path_move_to (&gstate->path, x, y);
-
- _cairo_gstate_set_current_point (gstate, x, y);
+ distance.dx = _cairo_fixed_from_double (dx);
+ distance.dy = _cairo_fixed_from_double (dy);
- gstate->last_move_point = gstate->current_point;
-
- return status;
+ return _cairo_path_rel_move_to (&gstate->path, &distance);
}
cairo_status_t
_cairo_gstate_rel_line_to (cairo_gstate_t *gstate, double dx, double dy)
{
- cairo_status_t status;
- double x, y;
+ cairo_distance_t distance;
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
- x = gstate->current_point.x + dx;
- y = gstate->current_point.y + dy;
-
- status = _cairo_path_line_to (&gstate->path, x, y);
-
- _cairo_gstate_set_current_point (gstate, x, y);
+ distance.dx = _cairo_fixed_from_double (dx);
+ distance.dy = _cairo_fixed_from_double (dy);
- return status;
+ return _cairo_path_rel_line_to (&gstate->path, &distance);
}
cairo_status_t
_cairo_gstate_rel_curve_to (cairo_gstate_t *gstate,
+ double dx0, double dy0,
double dx1, double dy1,
- double dx2, double dy2,
- double dx3, double dy3)
+ double dx2, double dy2)
{
- cairo_status_t status;
+ cairo_distance_t distance[3];
+ cairo_matrix_transform_distance (&gstate->ctm, &dx0, &dy0);
cairo_matrix_transform_distance (&gstate->ctm, &dx1, &dy1);
cairo_matrix_transform_distance (&gstate->ctm, &dx2, &dy2);
- cairo_matrix_transform_distance (&gstate->ctm, &dx3, &dy3);
- status = _cairo_path_curve_to (&gstate->path,
- gstate->current_point.x + dx1, gstate->current_point.y + dy1,
- gstate->current_point.x + dx2, gstate->current_point.y + dy2,
- gstate->current_point.x + dx3, gstate->current_point.y + dy3);
+ distance[0].dx = _cairo_fixed_from_double (dx0);
+ distance[0].dy = _cairo_fixed_from_double (dy0);
- _cairo_gstate_set_current_point (gstate,
- gstate->current_point.x + dx3,
- gstate->current_point.y + dy3);
+ distance[1].dx = _cairo_fixed_from_double (dx1);
+ distance[1].dy = _cairo_fixed_from_double (dy1);
- return status;
+ distance[2].dx = _cairo_fixed_from_double (dx2);
+ distance[2].dy = _cairo_fixed_from_double (dy2);
+
+ return _cairo_path_rel_curve_to (&gstate->path,
+ &distance[0],
+ &distance[1],
+ &distance[2]);
}
/* XXX: NYI
@@ -1098,29 +1072,24 @@ _cairo_gstate_stroke_path (cairo_gstate_t *gstate)
cairo_status_t
_cairo_gstate_close_path (cairo_gstate_t *gstate)
{
- cairo_status_t status;
-
- status = _cairo_path_close_path (&gstate->path);
-
- _cairo_gstate_set_current_point (gstate,
- gstate->last_move_point.x,
- gstate->last_move_point.y);
-
- return status;
+ return _cairo_path_close_path (&gstate->path);
}
cairo_status_t
_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_ret)
{
+ cairo_status_t status;
+ cairo_point_t point;
double x, y;
- if (gstate->has_current_point) {
- x = gstate->current_point.x;
- y = gstate->current_point.y;
- cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
- } else {
+ status = _cairo_path_current_point (&gstate->path, &point);
+ if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
x = 0.0;
y = 0.0;
+ } else {
+ x = _cairo_fixed_to_double (point.x);
+ y = _cairo_fixed_to_double (point.y);
+ cairo_matrix_transform_point (&gstate->ctm_inverse, &x, &y);
}
*x_ret = x;
@@ -1129,24 +1098,201 @@ _cairo_gstate_current_point (cairo_gstate_t *gstate, double *x_ret, double *y_re
return CAIRO_STATUS_SUCCESS;
}
+typedef struct gstate_path_interpreter {
+ cairo_matrix_t ctm_inverse;
+ double tolerance;
+ cairo_point_t current_point;
+
+ cairo_move_to_func_t *move_to;
+ cairo_line_to_func_t *line_to;
+ cairo_curve_to_func_t *curve_to;
+ cairo_close_path_func_t *close_path;
+
+ void *closure;
+} gpi_t;
+
static cairo_status_t
-_cairo_gstate_ensure_source (cairo_gstate_t *gstate)
+_gpi_move_to (void *closure, cairo_point_t *point)
{
- if (gstate->source)
- return CAIRO_STATUS_SUCCESS;
+ gpi_t *gpi = closure;
+ double x, y;
- if (gstate->surface == NULL)
+ x = _cairo_fixed_to_double (point->x);
+ y = _cairo_fixed_to_double (point->y);
+
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+
+ gpi->move_to (gpi->closure, x, y);
+ gpi->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_gpi_line_to (void *closure, cairo_point_t *point)
+{
+ gpi_t *gpi = closure;
+ double x, y;
+
+ x = _cairo_fixed_to_double (point->x);
+ y = _cairo_fixed_to_double (point->y);
+
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+
+ gpi->line_to (gpi->closure, x, y);
+ gpi->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_gpi_curve_to (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ gpi_t *gpi = closure;
+ cairo_status_t status;
+ cairo_spline_t spline;
+ double x1, y1, x2, y2, x3, y3;
+
+ if (gpi->curve_to) {
+ x1 = _cairo_fixed_to_double (p1->x);
+ y1 = _cairo_fixed_to_double (p1->y);
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x1, &y1);
+
+ x2 = _cairo_fixed_to_double (p2->x);
+ y2 = _cairo_fixed_to_double (p2->y);
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x2, &y2);
+
+ x3 = _cairo_fixed_to_double (p3->x);
+ y3 = _cairo_fixed_to_double (p3->y);
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x3, &y3);
+
+ gpi->curve_to (gpi->closure, x1, y1, x2, y2, x3, y3);
+ } else {
+ cairo_point_t *p0 = &gpi->current_point;
+ int i;
+ double x, y;
+
+ status = _cairo_spline_init (&spline, p0, p1, p2, p3);
+ if (status == CAIRO_INT_STATUS_DEGENERATE)
+ return CAIRO_STATUS_SUCCESS;
+
+ status = _cairo_spline_decompose (&spline, gpi->tolerance);
+ if (status)
+ return status;
+
+ for (i=1; i < spline.num_points; i++) {
+ x = _cairo_fixed_to_double (spline.points[i].x);
+ y = _cairo_fixed_to_double (spline.points[i].y);
+
+ cairo_matrix_transform_point (&gpi->ctm_inverse, &x, &y);
+
+ gpi->line_to (gpi->closure, x, y);
+ }
+ }
+
+ gpi->current_point = *p3;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_gpi_close_path (void *closure)
+{
+ gpi_t *gpi = closure;
+
+ gpi->close_path (gpi->closure);
+
+ gpi->current_point.x = 0;
+ gpi->current_point.y = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* It's OK for curve_path to be NULL. In that case, all curves in the
+ path will be decomposed into one or more calls to the line_to
+ function, (according to the current tolerance). */
+cairo_status_t
+_cairo_gstate_interpret_path (cairo_gstate_t *gstate,
+ cairo_move_to_func_t *move_to,
+ cairo_line_to_func_t *line_to,
+ cairo_curve_to_func_t *curve_to,
+ cairo_close_path_func_t *close_path,
+ void *closure)
+{
+ cairo_path_t path;
+ gpi_t gpi;
+
+ /* Anything we want from gstate must be copied. We must not retain
+ pointers into gstate. */
+ _cairo_path_init_copy (&path, &gstate->path);
+
+ cairo_matrix_copy (&gpi.ctm_inverse, &gstate->ctm_inverse);
+ gpi.tolerance = gstate->tolerance;
+
+ gpi.move_to = move_to;
+ gpi.line_to = line_to;
+ gpi.curve_to = curve_to;
+ gpi.close_path = close_path;
+ gpi.closure = closure;
+
+ gpi.current_point.x = 0;
+ gpi.current_point.y = 0;
+
+ return _cairo_path_interpret (&path,
+ CAIRO_DIRECTION_FORWARD,
+ _gpi_move_to,
+ _gpi_line_to,
+ _gpi_curve_to,
+ _gpi_close_path,
+ &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_create_pattern (cairo_gstate_t *gstate,
+ cairo_pattern_t *pattern,
+ cairo_box_t *extents)
+{
+ 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;
}
@@ -1155,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);
@@ -1174,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);
@@ -1227,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;
@@ -1241,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.);
@@ -1261,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
@@ -1286,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);
@@ -1302,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,
@@ -1315,11 +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;
@@ -1331,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;
}
@@ -1349,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);
@@ -1363,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);
@@ -1404,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);
@@ -1430,39 +1570,137 @@ _cairo_gstate_show_page (cairo_gstate_t *gstate)
}
cairo_status_t
-_cairo_gstate_clip (cairo_gstate_t *gstate)
+_cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
+ double *x1, double *y1,
+ double *x2, double *y2)
{
cairo_status_t status;
- cairo_surface_t *alpha_one;
cairo_traps_t traps;
- cairo_color_t white_color;
+ cairo_box_t extents;
+
+ _cairo_traps_init (&traps);
+
+ status = _cairo_path_stroke_to_traps (&gstate->path, gstate, &traps);
+ if (status)
+ goto BAIL;
- _cairo_color_init (&white_color);
+ _cairo_traps_extents (&traps, &extents);
- 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)
- return CAIRO_STATUS_NO_MEMORY;
+ *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)
+{
+ /* destroy any existing clip-region artifacts */
+ if (gstate->clip.surface)
+ cairo_surface_destroy (gstate->clip.surface);
+ gstate->clip.surface = NULL;
+
+ if (gstate->clip.region)
+ pixman_region_destroy (gstate->clip.region);
+ gstate->clip.region = NULL;
+
+ /* reset the surface's clip to the whole surface */
+ _cairo_surface_set_clip_region (gstate->surface,
+ gstate->clip.region);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static int
+extract_transformed_rectangle(cairo_matrix_t *mat,
+ cairo_traps_t *tr,
+ pixman_box16_t *box)
+{
+#define CAIRO_FIXED_IS_INTEGER(x) (((x) & 0xFFFF) == 0)
+#define CAIRO_FIXED_INTEGER_PART(x) ((x) >> 16)
+
+ double a, b, c, d, tx, ty;
+ cairo_status_t st;
+
+ st = cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
+ if (!(st == CAIRO_STATUS_SUCCESS && b == 0. && c == 0.))
+ return 0;
+
+ if (tr->num_traps == 1
+ && tr->traps[0].left.p1.x == tr->traps[0].left.p2.x
+ && tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
+ && tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
+ && tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.x)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.y)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.x)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.y)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.x)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.y)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.x)
+ && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.y)) {
+
+ box->x1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.x);
+ box->x2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].right.p1.x);
+ box->y1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.y);
+ box->y2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p2.y);
+ return 1;
}
+ return 0;
- 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;
+#undef CAIRO_FIXED_IS_INTEGER
+#undef CAIRO_FIXED_INTEGER_PART
+}
- cairo_surface_set_repeat (alpha_one, 1);
+cairo_status_t
+_cairo_gstate_clip (cairo_gstate_t *gstate)
+{
+ cairo_status_t status;
+ cairo_pattern_t pattern;
+ cairo_traps_t traps;
+ cairo_color_t white_color;
+ pixman_box16_t box;
+
+ /* Fill the clip region as traps. */
_cairo_traps_init (&traps);
status = _cairo_path_fill_to_traps (&gstate->path, gstate, &traps);
@@ -1471,16 +1709,82 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
return status;
}
+ /* Check to see if we can represent these traps as a PixRegion. */
+
+ if (extract_transformed_rectangle (&gstate->ctm, &traps, &box)) {
+
+ pixman_region16_t *rect = NULL;
+ pixman_region16_t *intersection = NULL;
+
+ status = CAIRO_STATUS_SUCCESS;
+ rect = pixman_region_create_simple (&box);
+
+ if (rect == NULL) {
+ status = CAIRO_STATUS_NO_MEMORY;
+
+ } else {
+
+ if (gstate->clip.region == NULL) {
+ gstate->clip.region = rect;
+ } else {
+ intersection = pixman_region_create();
+ if (pixman_region_intersect (intersection,
+ gstate->clip.region, rect)
+ == PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (gstate->clip.region);
+ gstate->clip.region = intersection;
+ } else {
+ status = CAIRO_STATUS_NO_MEMORY;
+ }
+ pixman_region_destroy (rect);
+ }
+
+ 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;
+ }
+ }
+
+ /* Otherwise represent the clip as a mask surface. */
+
+ _cairo_color_init (&white_color);
+
+ 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)
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ _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;
}
@@ -1491,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);
@@ -1527,32 +1816,47 @@ _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;
}
cairo_status_t
_cairo_gstate_select_font (cairo_gstate_t *gstate,
- char *family,
+ const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
@@ -1600,6 +1904,7 @@ _cairo_gstate_current_font_extents (cairo_gstate_t *gstate,
status = _cairo_font_font_extents (gstate->font, extents);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
+
return status;
}
@@ -1622,14 +1927,24 @@ _cairo_gstate_text_extents (cairo_gstate_t *gstate,
{
cairo_matrix_t saved_font_matrix;
cairo_status_t status;
+ double scale_x, scale_y;
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
- cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
+ _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
+ cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
status = _cairo_font_text_extents (gstate->font,
utf8, extents);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
+
+ extents->x_bearing /= scale_x;
+ extents->y_bearing /= scale_y;
+ extents->width /= scale_x;
+ extents->height /= scale_y;
+ extents->x_advance /= scale_x;
+ extents->y_advance /= scale_y;
+
return status;
}
@@ -1640,120 +1955,91 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
cairo_text_extents_t *extents)
{
cairo_status_t status;
- int i;
- cairo_glyph_t *transformed_glyphs = NULL;
cairo_matrix_t saved_font_matrix;
-
- transformed_glyphs = malloc (num_glyphs * sizeof(cairo_glyph_t));
- if (transformed_glyphs == NULL)
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < num_glyphs; ++i)
- {
- transformed_glyphs[i] = glyphs[i];
- cairo_matrix_transform_point (&gstate->ctm,
- &(transformed_glyphs[i].x),
- &(transformed_glyphs[i].y));
- }
+ double scale_x, scale_y;
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
- cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
+ _cairo_matrix_compute_scale_factors (&gstate->ctm, &scale_x, &scale_y);
+ cairo_matrix_scale (&gstate->font->matrix, scale_x, scale_y);
status = _cairo_font_glyph_extents (gstate->font,
- transformed_glyphs, num_glyphs,
+ glyphs, num_glyphs,
extents);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
- free (transformed_glyphs);
- return status;
-}
-
+ extents->x_bearing /= scale_x;
+ extents->y_bearing /= scale_y;
+ extents->width /= scale_x;
+ extents->height /= scale_y;
+ extents->x_advance /= scale_x;
+ extents->y_advance /= scale_y;
-static cairo_status_t
-setup_text_rendering_context(cairo_gstate_t *gstate,
- double *x, double *y,
- cairo_matrix_t *user_to_source)
-{
- cairo_status_t status;
- cairo_matrix_t device_to_source;
-
- /* XXX: I believe this is correct, but it would be much more clear
- to have some explicit current_point accesor functions, (one for
- user- and one for device-space). */
-
- if (gstate->has_current_point) {
- *x = gstate->current_point.x;
- *y = gstate->current_point.y;
- } else {
- *x = 0;
- *y = 0;
- cairo_matrix_transform_point (&gstate->ctm, x, y);
- }
-
- 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);
+ return status;
}
-
cairo_status_t
_cairo_gstate_show_text (cairo_gstate_t *gstate,
const unsigned char *utf8)
{
cairo_status_t status;
+ cairo_point_t point;
double x, y;
- cairo_matrix_t user_to_source;
cairo_matrix_t saved_font_matrix;
-
- status = setup_text_rendering_context(gstate, &x, &y, &user_to_source);
- if (status)
- return status;
+ 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) {
+ x = 0;
+ y = 0;
+ cairo_matrix_transform_point (&gstate->ctm, &x, &y);
+ } else {
+ x = _cairo_fixed_to_double (point.x);
+ y = _cairo_fixed_to_double (point.y);
+ }
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;
- double x, y;
- 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)
@@ -1767,25 +2053,37 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
&(transformed_glyphs[i].y));
}
- status = setup_text_rendering_context (gstate, &x, &y, &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->surface, x, y,
+ 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);
return status;
-
}
@@ -1795,21 +2093,35 @@ _cairo_gstate_text_path (cairo_gstate_t *gstate,
{
cairo_status_t status;
cairo_matrix_t saved_font_matrix;
+ cairo_point_t point;
+ double x, y;
+
+ status = _cairo_path_current_point (&gstate->path, &point);
+ if (status == CAIRO_STATUS_NO_CURRENT_POINT) {
+ x = 0;
+ y = 0;
+ cairo_matrix_transform_point (&gstate->ctm, &x, &y);
+ } else {
+ x = _cairo_fixed_to_double (point.x);
+ y = _cairo_fixed_to_double (point.y);
+ }
cairo_matrix_copy (&saved_font_matrix, &gstate->font->matrix);
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
status = _cairo_font_text_path (gstate->font,
- &gstate->path,
- utf8);
+ x, y,
+ utf8,
+ &gstate->path);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
+
return status;
}
cairo_status_t
-_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
+_cairo_gstate_glyph_path (cairo_gstate_t *gstate,
cairo_glyph_t *glyphs,
int num_glyphs)
{
@@ -1834,11 +2146,11 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
status = _cairo_font_glyph_path (gstate->font,
- &gstate->path,
- transformed_glyphs, num_glyphs);
+ transformed_glyphs, num_glyphs,
+ &gstate->path);
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
-
+
free (transformed_glyphs);
return status;
}
diff --git a/src/cairo_image_surface.c b/src/cairo_image_surface.c
index efa54d26..a11a07ee 100644
--- a/src/cairo_image_surface.c
+++ b/src/cairo_image_surface.c
@@ -45,7 +45,7 @@ _cairo_format_bpp (cairo_format_t format)
}
static cairo_image_surface_t *
-_cairo_image_surface_create_for_ic_image (IcImage *ic_image)
+_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image)
{
cairo_image_surface_t *surface;
@@ -55,15 +55,15 @@ _cairo_image_surface_create_for_ic_image (IcImage *ic_image)
_cairo_surface_init (&surface->base, &cairo_image_surface_backend);
- surface->ic_image = ic_image;
+ surface->pixman_image = pixman_image;
- surface->data = (char *) IcImageGetData (ic_image);
+ surface->data = (char *) pixman_image_get_data (pixman_image);
surface->owns_data = 0;
- surface->width = IcImageGetWidth (ic_image);
- surface->height = IcImageGetHeight (ic_image);
- surface->stride = IcImageGetStride (ic_image);
- surface->depth = IcImageGetDepth (ic_image);
+ surface->width = pixman_image_get_width (pixman_image);
+ surface->height = pixman_image_get_height (pixman_image);
+ surface->stride = pixman_image_get_stride (pixman_image);
+ surface->depth = pixman_image_get_depth (pixman_image);
return surface;
}
@@ -76,47 +76,47 @@ _cairo_image_surface_create_with_masks (char *data,
int stride)
{
cairo_image_surface_t *surface;
- IcFormat *ic_format;
- IcImage *ic_image;
+ pixman_format_t *pixman_format;
+ pixman_image_t *pixman_image;
- ic_format = IcFormatCreateMasks (format->bpp,
- format->alpha_mask,
- format->red_mask,
- format->green_mask,
- format->blue_mask);
+ pixman_format = pixman_format_create_masks (format->bpp,
+ format->alpha_mask,
+ format->red_mask,
+ format->green_mask,
+ format->blue_mask);
- if (ic_format == NULL)
+ if (pixman_format == NULL)
return NULL;
- ic_image = IcImageCreateForData ((IcBits *) data, ic_format,
- width, height, format->bpp, stride);
+ pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
+ width, height, format->bpp, stride);
- IcFormatDestroy (ic_format);
+ pixman_format_destroy (pixman_format);
- if (ic_image == NULL)
+ if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_ic_image (ic_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
return surface;
}
-static IcFormat *
-_create_ic_format (cairo_format_t format)
+static pixman_format_t *
+_create_pixman_format (cairo_format_t format)
{
switch (format) {
case CAIRO_FORMAT_A1:
- return IcFormatCreate (IcFormatNameA1);
+ return pixman_format_create (PIXMAN_FORMAT_NAME_A1);
break;
case CAIRO_FORMAT_A8:
- return IcFormatCreate (IcFormatNameA8);
+ return pixman_format_create (PIXMAN_FORMAT_NAME_A8);
break;
case CAIRO_FORMAT_RGB24:
- return IcFormatCreate (IcFormatNameRGB24);
+ return pixman_format_create (PIXMAN_FORMAT_NAME_RG_B24);
break;
case CAIRO_FORMAT_ARGB32:
default:
- return IcFormatCreate (IcFormatNameARGB32);
+ return pixman_format_create (PIXMAN_FORMAT_NAME_AR_GB32);
break;
}
}
@@ -127,21 +127,21 @@ cairo_image_surface_create (cairo_format_t format,
int height)
{
cairo_image_surface_t *surface;
- IcFormat *ic_format;
- IcImage *ic_image;
+ pixman_format_t *pixman_format;
+ pixman_image_t *pixman_image;
- ic_format = _create_ic_format (format);
- if (ic_format == NULL)
+ pixman_format = _create_pixman_format (format);
+ if (pixman_format == NULL)
return NULL;
- ic_image = IcImageCreate (ic_format, width, height);
+ pixman_image = pixman_image_create (pixman_format, width, height);
- IcFormatDestroy (ic_format);
+ pixman_format_destroy (pixman_format);
- if (ic_image == NULL)
+ if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_ic_image (ic_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
return &surface->base;
}
@@ -154,24 +154,24 @@ cairo_image_surface_create_for_data (char *data,
int stride)
{
cairo_image_surface_t *surface;
- IcFormat *ic_format;
- IcImage *ic_image;
+ pixman_format_t *pixman_format;
+ pixman_image_t *pixman_image;
- ic_format = _create_ic_format (format);
- if (ic_format == NULL)
+ pixman_format = _create_pixman_format (format);
+ if (pixman_format == NULL)
return NULL;
- ic_image = IcImageCreateForData ((IcBits *) data, ic_format,
- width, height,
- _cairo_format_bpp (format),
- stride);
+ pixman_image = pixman_image_create_for_data ((pixman_bits_t *) data, pixman_format,
+ width, height,
+ _cairo_format_bpp (format),
+ stride);
- IcFormatDestroy (ic_format);
+ pixman_format_destroy (pixman_format);
- if (ic_image == NULL)
+ if (pixman_image == NULL)
return NULL;
- surface = _cairo_image_surface_create_for_ic_image (ic_image);
+ surface = _cairo_image_surface_create_for_pixman_image (pixman_image);
return &surface->base;
}
@@ -190,8 +190,8 @@ _cairo_image_abstract_surface_destroy (void *abstract_surface)
{
cairo_image_surface_t *surface = abstract_surface;
- if (surface->ic_image)
- IcImageDestroy (surface->ic_image);
+ if (surface->pixman_image)
+ pixman_image_destroy (surface->pixman_image);
if (surface->owns_data) {
free (surface->data);
@@ -247,21 +247,21 @@ cairo_status_t
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
cairo_matrix_t *matrix)
{
- IcTransform ic_transform;
+ pixman_transform_t pixman_transform;
- ic_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
- ic_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
- ic_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
+ pixman_transform.matrix[0][0] = _cairo_fixed_from_double (matrix->m[0][0]);
+ pixman_transform.matrix[0][1] = _cairo_fixed_from_double (matrix->m[1][0]);
+ pixman_transform.matrix[0][2] = _cairo_fixed_from_double (matrix->m[2][0]);
- ic_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
- ic_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
- ic_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
+ pixman_transform.matrix[1][0] = _cairo_fixed_from_double (matrix->m[0][1]);
+ pixman_transform.matrix[1][1] = _cairo_fixed_from_double (matrix->m[1][1]);
+ pixman_transform.matrix[1][2] = _cairo_fixed_from_double (matrix->m[2][1]);
- ic_transform.matrix[2][0] = 0;
- ic_transform.matrix[2][1] = 0;
- ic_transform.matrix[2][2] = _cairo_fixed_from_double (1);
+ pixman_transform.matrix[2][0] = 0;
+ pixman_transform.matrix[2][1] = 0;
+ pixman_transform.matrix[2][2] = _cairo_fixed_from_double (1);
- IcImageSetTransform (surface->ic_image, &ic_transform);
+ pixman_image_set_transform (surface->pixman_image, &pixman_transform);
return CAIRO_STATUS_SUCCESS;
}
@@ -277,29 +277,29 @@ _cairo_image_abstract_surface_set_filter (void *abstract_surface, cairo_filter_t
cairo_status_t
_cairo_image_surface_set_filter (cairo_image_surface_t *surface, cairo_filter_t filter)
{
- IcFilter ic_filter;
+ pixman_filter_t pixman_filter;
switch (filter) {
case CAIRO_FILTER_FAST:
- ic_filter = IcFilterFast;
+ pixman_filter = PIXMAN_FILTER_FAST;
break;
case CAIRO_FILTER_GOOD:
- ic_filter = IcFilterGood;
+ pixman_filter = PIXMAN_FILTER_GOOD;
break;
case CAIRO_FILTER_BEST:
- ic_filter = IcFilterBest;
+ pixman_filter = PIXMAN_FILTER_BEST;
break;
case CAIRO_FILTER_NEAREST:
- ic_filter = IcFilterNearest;
+ pixman_filter = PIXMAN_FILTER_NEAREST;
break;
case CAIRO_FILTER_BILINEAR:
- ic_filter = IcFilterBilinear;
+ pixman_filter = PIXMAN_FILTER_BILINEAR;
break;
default:
- ic_filter = IcFilterBest;
+ pixman_filter = PIXMAN_FILTER_BEST;
}
- IcImageSetFilter (surface->ic_image, ic_filter);
+ pixman_image_set_filter (surface->pixman_image, pixman_filter);
return CAIRO_STATUS_SUCCESS;
}
@@ -314,45 +314,45 @@ _cairo_image_abstract_surface_set_repeat (void *abstract_surface, int repeat)
cairo_status_t
_cairo_image_surface_set_repeat (cairo_image_surface_t *surface, int repeat)
{
- IcImageSetRepeat (surface->ic_image, repeat);
+ pixman_image_set_repeat (surface->pixman_image, repeat);
return CAIRO_STATUS_SUCCESS;
}
-static IcOperator
-_ic_operator (cairo_operator_t operator)
+static pixman_operator_t
+_pixman_operator (cairo_operator_t operator)
{
switch (operator) {
case CAIRO_OPERATOR_CLEAR:
- return IcOperatorClear;
+ return PIXMAN_OPERATOR_CLEAR;
case CAIRO_OPERATOR_SRC:
- return IcOperatorSrc;
+ return PIXMAN_OPERATOR_SRC;
case CAIRO_OPERATOR_DST:
- return IcOperatorDst;
+ return PIXMAN_OPERATOR_DST;
case CAIRO_OPERATOR_OVER:
- return IcOperatorOver;
+ return PIXMAN_OPERATOR_OVER;
case CAIRO_OPERATOR_OVER_REVERSE:
- return IcOperatorOverReverse;
+ return PIXMAN_OPERATOR_OVER_REVERSE;
case CAIRO_OPERATOR_IN:
- return IcOperatorIn;
+ return PIXMAN_OPERATOR_IN;
case CAIRO_OPERATOR_IN_REVERSE:
- return IcOperatorInReverse;
+ return PIXMAN_OPERATOR_IN_REVERSE;
case CAIRO_OPERATOR_OUT:
- return IcOperatorOut;
+ return PIXMAN_OPERATOR_OUT;
case CAIRO_OPERATOR_OUT_REVERSE:
- return IcOperatorOutReverse;
+ return PIXMAN_OPERATOR_OUT_REVERSE;
case CAIRO_OPERATOR_ATOP:
- return IcOperatorAtop;
+ return PIXMAN_OPERATOR_ATOP;
case CAIRO_OPERATOR_ATOP_REVERSE:
- return IcOperatorAtopReverse;
+ return PIXMAN_OPERATOR_ATOP_REVERSE;
case CAIRO_OPERATOR_XOR:
- return IcOperatorXor;
+ return PIXMAN_OPERATOR_XOR;
case CAIRO_OPERATOR_ADD:
- return IcOperatorAdd;
+ return PIXMAN_OPERATOR_ADD;
case CAIRO_OPERATOR_SATURATE:
- return IcOperatorSaturate;
+ return PIXMAN_OPERATOR_SATURATE;
default:
- return IcOperatorOver;
+ return PIXMAN_OPERATOR_OVER;
}
}
@@ -380,14 +380,14 @@ _cairo_image_surface_composite (cairo_operator_t operator,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- IcComposite (_ic_operator (operator),
- src->ic_image,
- mask ? mask->ic_image : NULL,
- dst->ic_image,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
+ pixman_composite (_pixman_operator (operator),
+ src->pixman_image,
+ mask ? mask->pixman_image : NULL,
+ dst->pixman_image,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
return CAIRO_STATUS_SUCCESS;
}
@@ -401,16 +401,16 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
{
cairo_image_surface_t *surface = abstract_surface;
- IcColor ic_color;
+ pixman_color_t pixman_color;
- ic_color.red = color->red_short;
- ic_color.green = color->green_short;
- ic_color.blue = color->blue_short;
- ic_color.alpha = color->alpha_short;
+ pixman_color.red = color->red_short;
+ pixman_color.green = color->green_short;
+ pixman_color.blue = color->blue_short;
+ pixman_color.alpha = color->alpha_short;
- /* XXX: The IcRectangle cast is evil... it needs to go away somehow. */
- IcFillRectangles (_ic_operator(operator), surface->ic_image,
- &ic_color, (IcRectangle *) rects, num_rects);
+ /* XXX: The pixman_rectangle_t cast is evil... it needs to go away somehow. */
+ pixman_fill_rectangles (_pixman_operator(operator), surface->pixman_image,
+ &pixman_color, (pixman_rectangle_t *) rects, num_rects);
return CAIRO_STATUS_SUCCESS;
}
@@ -430,9 +430,9 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t operator,
if (generic_src->backend != dst->base.backend)
return CAIRO_INT_STATUS_UNSUPPORTED;
- /* XXX: The IcTrapezoid cast is evil and needs to go away somehow. */
- IcCompositeTrapezoids (operator, src->ic_image, dst->ic_image,
- x_src, y_src, (IcTrapezoid *) traps, num_traps);
+ /* XXX: The pixman_trapezoid_t cast is evil and needs to go away somehow. */
+ pixman_composite_trapezoids (operator, src->pixman_image, dst->pixman_image,
+ x_src, y_src, (pixman_trapezoid_t *) traps, num_traps);
return CAIRO_STATUS_SUCCESS;
}
@@ -449,6 +449,44 @@ _cairo_image_surface_show_page (void *abstract_surface)
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+static cairo_int_status_t
+_cairo_image_abstract_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
+
+ return _cairo_image_surface_set_clip_region (surface, region);
+}
+
+cairo_int_status_t
+_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
+ pixman_region16_t *region)
+{
+ pixman_image_set_clip_region (surface->pixman_image, region);
+
+ 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,
@@ -462,5 +500,7 @@ static const cairo_surface_backend_t cairo_image_surface_backend = {
_cairo_image_surface_fill_rectangles,
_cairo_image_surface_composite_trapezoids,
_cairo_image_surface_copy_page,
- _cairo_image_surface_show_page
+ _cairo_image_surface_show_page,
+ _cairo_image_abstract_surface_set_clip_region,
+ _cairo_image_abstract_surface_create_pattern
};
diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c
index 655bcde8..de89c0fd 100644
--- a/src/cairo_matrix.c
+++ b/src/cairo_matrix.c
@@ -386,3 +386,22 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
return CAIRO_STATUS_SUCCESS;
}
+
+/* Compute the amount that each basis vector is scaled by. */
+cairo_status_t
+_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy)
+{
+ double x, y;
+
+ x = 1.0;
+ y = 0.0;
+ cairo_matrix_transform_distance (matrix, &x, &y);
+ *sx = sqrt(x*x + y*y);
+
+ x = 0.0;
+ y = 1.0;
+ cairo_matrix_transform_distance (matrix, &x, &y);
+ *sy = sqrt(x*x + y*y);
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo_path.c b/src/cairo_path.c
index 9366394d..91142c8f 100644
--- a/src/cairo_path.c
+++ b/src/cairo_path.c
@@ -70,6 +70,11 @@ _cairo_path_init (cairo_path_t *path)
path->arg_head = NULL;
path->arg_tail = NULL;
+
+ path->current_point.x = 0;
+ path->current_point.y = 0;
+ path->has_current_point = 0;
+ path->last_move_point = path->current_point;
}
cairo_status_t
@@ -79,6 +84,9 @@ _cairo_path_init_copy (cairo_path_t *path, cairo_path_t *other)
cairo_path_arg_buf_t *arg, *other_arg;
_cairo_path_init (path);
+ path->current_point = other->current_point;
+ path->has_current_point = other->has_current_point;
+ path->last_move_point = other->last_move_point;
for (other_op = other->op_head; other_op; other_op = other_op->next) {
op = _cairo_path_op_buf_create ();
@@ -120,54 +128,131 @@ _cairo_path_fini (cairo_path_t *path)
_cairo_path_arg_buf_destroy (arg);
}
path->arg_tail = NULL;
+
+ path->has_current_point = 0;
+}
+
+cairo_status_t
+_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point)
+{
+ cairo_status_t status;
+
+ status = _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, point, 1);
+ if (status)
+ return status;
+
+ path->current_point = *point;
+ path->has_current_point = 1;
+ path->last_move_point = path->current_point;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_path_move_to (cairo_path_t *path, double x, double y)
+_cairo_path_rel_move_to (cairo_path_t *path, cairo_distance_t *distance)
{
cairo_point_t point;
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
+ point.x = path->current_point.x + distance->dx;
+ point.y = path->current_point.y + distance->dy;
+
+ return _cairo_path_move_to (path, &point);
+}
+
+cairo_status_t
+_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point)
+{
+ cairo_status_t status;
+
+ status = _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, point, 1);
+ if (status)
+ return status;
- return _cairo_path_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
+ path->current_point = *point;
+ path->has_current_point = 1;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_path_line_to (cairo_path_t *path, double x, double y)
+_cairo_path_rel_line_to (cairo_path_t *path, cairo_distance_t *distance)
{
cairo_point_t point;
- point.x = _cairo_fixed_from_double (x);
- point.y = _cairo_fixed_from_double (y);
+ point.x = path->current_point.x + distance->dx;
+ point.y = path->current_point.y + distance->dy;
- return _cairo_path_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
+ return _cairo_path_line_to (path, &point);
}
cairo_status_t
_cairo_path_curve_to (cairo_path_t *path,
- double x1, double y1,
- double x2, double y2,
- double x3, double y3)
+ cairo_point_t *p0,
+ cairo_point_t *p1,
+ cairo_point_t *p2)
{
+ cairo_status_t status;
cairo_point_t point[3];
- point[0].x = _cairo_fixed_from_double (x1);
- point[0].y = _cairo_fixed_from_double (y1);
+ point[0] = *p0;
+ point[1] = *p1;
+ point[2] = *p2;
- point[1].x = _cairo_fixed_from_double (x2);
- point[1].y = _cairo_fixed_from_double (y2);
+ status = _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
+ if (status)
+ return status;
- point[2].x = _cairo_fixed_from_double (x3);
- point[2].y = _cairo_fixed_from_double (y3);
+ path->current_point = *p2;
+ path->has_current_point = 1;
- return _cairo_path_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_path_rel_curve_to (cairo_path_t *path,
+ cairo_distance_t *d0,
+ cairo_distance_t *d1,
+ cairo_distance_t *d2)
+{
+ cairo_point_t p0, p1, p2;
+
+ p0.x = path->current_point.x + d0->dx;
+ p0.y = path->current_point.y + d0->dy;
+
+ p1.x = path->current_point.x + d1->dx;
+ p1.y = path->current_point.y + d1->dy;
+
+ p2.x = path->current_point.x + d2->dx;
+ p2.y = path->current_point.y + d2->dy;
+
+ return _cairo_path_curve_to (path, &p0, &p1, &p2);
}
cairo_status_t
_cairo_path_close_path (cairo_path_t *path)
{
- return _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
+ cairo_status_t status;
+
+ status = _cairo_path_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
+ if (status)
+ return status;
+
+ path->current_point.x = path->last_move_point.x;
+ path->current_point.y = path->last_move_point.y;
+ path->has_current_point = 1;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point)
+{
+ if (! path->has_current_point)
+ return CAIRO_STATUS_NO_CURRENT_POINT;
+
+ *point = path->current_point;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -320,7 +405,13 @@ static int const num_args[] =
};
cairo_status_t
-_cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_path_callbacks_t *cb, void *closure)
+_cairo_path_interpret (cairo_path_t *path,
+ cairo_direction_t dir,
+ cairo_path_move_to_func_t *move_to,
+ cairo_path_line_to_func_t *line_to,
+ cairo_path_curve_to_func_t *curve_to,
+ cairo_path_close_path_func_t *close_path,
+ void *closure)
{
cairo_status_t status;
int i, arg;
@@ -329,10 +420,6 @@ _cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_pa
cairo_path_arg_buf_t *arg_buf = path->arg_head;
int buf_i = 0;
cairo_point_t point[CAIRO_PATH_OP_MAX_ARGS];
- cairo_point_t current = {0, 0};
- cairo_point_t first = {0, 0};
- int has_current = 0;
- int has_edge = 0;
int step = (dir == CAIRO_DIRECTION_FORWARD) ? 1 : -1;
for (op_buf = (dir == CAIRO_DIRECTION_FORWARD) ? path->op_head : path->op_tail;
@@ -374,62 +461,24 @@ _cairo_path_interpret (cairo_path_t *path, cairo_direction_t dir, const cairo_pa
switch (op) {
case CAIRO_PATH_OP_MOVE_TO:
- if (has_edge) {
- status = (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_CAP);
- if (status)
- return status;
- }
- first = point[0];
- current = point[0];
- has_current = 1;
- has_edge = 0;
+ status = (*move_to) (closure, &point[0]);
break;
case CAIRO_PATH_OP_LINE_TO:
- if (has_current) {
- status = (*cb->add_edge) (closure, &current, &point[0]);
- if (status)
- return status;
- current = point[0];
- has_edge = 1;
- } else {
- first = point[0];
- current = point[0];
- has_current = 1;
- has_edge = 0;
- }
+ status = (*line_to) (closure, &point[0]);
break;
case CAIRO_PATH_OP_CURVE_TO:
- if (has_current) {
- status = (*cb->add_spline) (closure, &current, &point[0], &point[1], &point[2]);
- if (status)
- return status;
- current = point[2];
- has_edge = 1;
- } else {
- first = point[2];
- current = point[2];
- has_current = 1;
- has_edge = 0;
- }
+ status = (*curve_to) (closure, &point[0], &point[1], &point[2]);
break;
case CAIRO_PATH_OP_CLOSE_PATH:
- if (has_edge) {
- (*cb->add_edge) (closure, &current, &first);
- (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_JOIN);
- }
- current.x = 0;
- current.y = 0;
- first.x = 0;
- first.y = 0;
- has_current = 0;
- has_edge = 0;
+ default:
+ status = (*close_path) (closure);
break;
}
+ if (status)
+ return status;
}
}
- if (has_edge)
- (*cb->done_sub_path) (closure, CAIRO_SUB_PATH_DONE_CAP);
- return (*cb->done_path) (closure);
+ return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo_path_bounds.c b/src/cairo_path_bounds.c
index 40b64c3d..6a02b9ac 100644
--- a/src/cairo_path_bounds.c
+++ b/src/cairo_path_bounds.c
@@ -46,18 +46,19 @@ static cairo_status_t
_cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *point);
static cairo_status_t
-_cairo_path_bounder_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2);
+_cairo_path_bounder_move_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_path_bounder_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d);
+_cairo_path_bounder_line_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done_t done);
+_cairo_path_bounder_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d);
static cairo_status_t
-_cairo_path_bounder_done_path (void *closure);
+_cairo_path_bounder_close_path (void *closure);
static void
_cairo_path_bounder_init (cairo_path_bounder_t *bounder)
@@ -99,39 +100,42 @@ _cairo_path_bounder_add_point (cairo_path_bounder_t *bounder, cairo_point_t *poi
}
static cairo_status_t
-_cairo_path_bounder_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
+_cairo_path_bounder_move_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
- _cairo_path_bounder_add_point (bounder, p1);
- _cairo_path_bounder_add_point (bounder, p2);
+ _cairo_path_bounder_add_point (bounder, point);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_path_bounder_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d)
+_cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
{
cairo_path_bounder_t *bounder = closure;
- _cairo_path_bounder_add_point (bounder, a);
- _cairo_path_bounder_add_point (bounder, b);
- _cairo_path_bounder_add_point (bounder, c);
- _cairo_path_bounder_add_point (bounder, d);
+ _cairo_path_bounder_add_point (bounder, point);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_path_bounder_done_sub_path (void *closure, cairo_sub_path_done_t done)
+_cairo_path_bounder_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
{
+ cairo_path_bounder_t *bounder = closure;
+
+ _cairo_path_bounder_add_point (bounder, b);
+ _cairo_path_bounder_add_point (bounder, c);
+ _cairo_path_bounder_add_point (bounder, d);
+
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_path_bounder_done_path (void *closure)
+_cairo_path_bounder_close_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
}
@@ -141,18 +145,17 @@ cairo_status_t
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2)
{
cairo_status_t status;
- static cairo_path_callbacks_t const cb = {
- _cairo_path_bounder_add_edge,
- _cairo_path_bounder_add_spline,
- _cairo_path_bounder_done_sub_path,
- _cairo_path_bounder_done_path
- };
cairo_path_bounder_t bounder;
_cairo_path_bounder_init (&bounder);
- status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD, &cb, &bounder);
+ status = _cairo_path_interpret (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_curve_to,
+ _cairo_path_bounder_close_path,
+ &bounder);
if (status) {
*x1 = *y1 = *x2 = *y2 = 0.0;
_cairo_path_bounder_fini (&bounder);
diff --git a/src/cairo_path_fill.c b/src/cairo_path_fill.c
index 8f34af85..fba5bb09 100644
--- a/src/cairo_path_fill.c
+++ b/src/cairo_path_fill.c
@@ -31,6 +31,8 @@ typedef struct cairo_filler {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
+ cairo_point_t current_point;
+
cairo_polygon_t polygon;
} cairo_filler_t;
@@ -41,18 +43,19 @@ static void
_cairo_filler_fini (cairo_filler_t *filler);
static cairo_status_t
-_cairo_filler_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2);
+_cairo_filler_move_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_filler_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d);
+_cairo_filler_line_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done_t done);
+_cairo_filler_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d);
static cairo_status_t
-_cairo_filler_done_path (void *closure);
+_cairo_filler_close_path (void *closure);
static void
_cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_t *traps)
@@ -60,6 +63,9 @@ _cairo_filler_init (cairo_filler_t *filler, cairo_gstate_t *gstate, cairo_traps_
filler->gstate = gstate;
filler->traps = traps;
+ filler->current_point.x = 0;
+ filler->current_point.y = 0;
+
_cairo_polygon_init (&filler->polygon);
}
@@ -70,18 +76,46 @@ _cairo_filler_fini (cairo_filler_t *filler)
}
static cairo_status_t
-_cairo_filler_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
+_cairo_filler_move_to (void *closure, cairo_point_t *point)
{
+ cairo_status_t status;
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
- return _cairo_polygon_add_edge (polygon, p1, p2);
+ status = _cairo_polygon_close (polygon);
+ if (status)
+ return status;
+
+ status = _cairo_polygon_move_to (polygon, point);
+ if (status)
+ return status;
+
+ filler->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_cairo_filler_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d)
+_cairo_filler_line_to (void *closure, cairo_point_t *point)
+{
+ cairo_status_t status;
+ cairo_filler_t *filler = closure;
+ cairo_polygon_t *polygon = &filler->polygon;
+
+ status = _cairo_polygon_line_to (polygon, point);
+ if (status)
+ return status;
+
+ filler->current_point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_filler_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
{
int i;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@@ -90,7 +124,8 @@ _cairo_filler_add_spline (void *closure,
cairo_gstate_t *gstate = filler->gstate;
cairo_spline_t spline;
- status = _cairo_spline_init (&spline, a, b, c, d);
+ status = _cairo_spline_init (&spline, &filler->current_point, b, c, d);
+
if (status == CAIRO_INT_STATUS_DEGENERATE)
return CAIRO_STATUS_SUCCESS;
@@ -98,65 +133,65 @@ _cairo_filler_add_spline (void *closure,
if (status)
goto CLEANUP_SPLINE;
- for (i = 0; i < spline.num_points - 1; i++) {
- status = _cairo_polygon_add_edge (polygon, &spline.points[i], &spline.points[i+1]);
+ for (i = 1; i < spline.num_points; i++) {
+ status = _cairo_polygon_line_to (polygon, &spline.points[i]);
if (status)
- goto CLEANUP_SPLINE;
+ break;
}
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
+ filler->current_point = *d;
+
return status;
}
static cairo_status_t
-_cairo_filler_done_sub_path (void *closure, cairo_sub_path_done_t done)
+_cairo_filler_close_path (void *closure)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_status_t status;
cairo_filler_t *filler = closure;
cairo_polygon_t *polygon = &filler->polygon;
- _cairo_polygon_close (polygon);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_filler_done_path (void *closure)
-{
- cairo_filler_t *filler = closure;
+ status = _cairo_polygon_close (polygon);
+ if (status)
+ return status;
- return _cairo_traps_tessellate_polygon (filler->traps,
- &filler->polygon,
- filler->gstate->fill_rule);
+ return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_fill_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
- static const cairo_path_callbacks_t filler_callbacks = {
- _cairo_filler_add_edge,
- _cairo_filler_add_spline,
- _cairo_filler_done_sub_path,
- _cairo_filler_done_path
- };
-
- cairo_status_t status;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t filler;
_cairo_filler_init (&filler, gstate, traps);
status = _cairo_path_interpret (path,
CAIRO_DIRECTION_FORWARD,
- &filler_callbacks, &filler);
- if (status) {
- _cairo_filler_fini (&filler);
- return status;
- }
+ _cairo_filler_move_to,
+ _cairo_filler_line_to,
+ _cairo_filler_curve_to,
+ _cairo_filler_close_path,
+ &filler);
+ if (status)
+ goto BAIL;
+ status = _cairo_polygon_close (&filler.polygon);
+ if (status)
+ goto BAIL;
+
+ status = _cairo_traps_tessellate_polygon (filler.traps,
+ &filler.polygon,
+ filler.gstate->fill_rule);
+ if (status)
+ goto BAIL;
+
+BAIL:
_cairo_filler_fini (&filler);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
diff --git a/src/cairo_path_stroke.c b/src/cairo_path_stroke.c
index 35e7b1b7..c2412579 100644
--- a/src/cairo_path_stroke.c
+++ b/src/cairo_path_stroke.c
@@ -31,11 +31,17 @@ typedef struct cairo_stroker {
cairo_gstate_t *gstate;
cairo_traps_t *traps;
- int have_prev;
- int have_first;
- int is_first;
- cairo_stroke_face_t prev;
- cairo_stroke_face_t first;
+ int has_current_point;
+ cairo_point_t current_point;
+ cairo_point_t first_point;
+
+ int has_current_face;
+ cairo_stroke_face_t current_face;
+
+ int has_first_face;
+ cairo_stroke_face_t first_face;
+
+ int dashed;
int dash_index;
int dash_on;
double dash_remain;
@@ -49,21 +55,22 @@ static void
_cairo_stroker_fini (cairo_stroker_t *stroker);
static cairo_status_t
-_cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2);
+_cairo_stroker_move_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t *p2);
+_cairo_stroker_line_to (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_stroker_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d);
+_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point);
static cairo_status_t
-_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done_t done);
+_cairo_stroker_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d);
static cairo_status_t
-_cairo_stroker_done_path (void *closure);
+_cairo_stroker_close_path (void *closure);
static void
_translate_point (cairo_point_t *point, cairo_point_t *offset);
@@ -89,6 +96,7 @@ _cairo_stroker_start_dash (cairo_stroker_t *stroker)
if (++i == gstate->num_dashes)
i = 0;
}
+ stroker->dashed = 1;
stroker->dash_index = i;
stroker->dash_on = on;
stroker->dash_remain = gstate->dash[i] - offset;
@@ -113,11 +121,15 @@ _cairo_stroker_init (cairo_stroker_t *stroker, cairo_gstate_t *gstate, cairo_tra
{
stroker->gstate = gstate;
stroker->traps = traps;
- stroker->have_prev = 0;
- stroker->have_first = 0;
- stroker->is_first = 1;
+
+ stroker->has_current_point = 0;
+ stroker->has_current_face = 0;
+ stroker->has_first_face = 0;
+
if (gstate->dash)
_cairo_stroker_start_dash (stroker);
+ else
+ stroker->dashed = 0;
}
static void
@@ -286,10 +298,11 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st
outer.x = _cairo_fixed_from_double (mx);
outer.y = _cairo_fixed_from_double (my);
_cairo_polygon_init (&polygon);
- _cairo_polygon_add_edge (&polygon, &in->point, inpt);
- _cairo_polygon_add_edge (&polygon, inpt, &outer);
- _cairo_polygon_add_edge (&polygon, &outer, outpt);
- _cairo_polygon_add_edge (&polygon, outpt, &in->point);
+ _cairo_polygon_move_to (&polygon, &in->point);
+ _cairo_polygon_line_to (&polygon, inpt);
+ _cairo_polygon_line_to (&polygon, &outer);
+ _cairo_polygon_line_to (&polygon, outpt);
+ _cairo_polygon_close (&polygon);
status = _cairo_traps_tessellate_polygon (stroker->traps,
&polygon,
CAIRO_FILL_RULE_WINDING);
@@ -351,8 +364,6 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
cairo_point_t occw, ocw;
cairo_polygon_t polygon;
- _cairo_polygon_init (&polygon);
-
dx = f->usr_vector.x;
dy = f->usr_vector.y;
dx *= gstate->line_width / 2.0;
@@ -365,10 +376,12 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
ocw.x = f->cw.x + fvector.dx;
ocw.y = f->cw.y + fvector.dy;
- _cairo_polygon_add_edge (&polygon, &f->cw, &ocw);
- _cairo_polygon_add_edge (&polygon, &ocw, &occw);
- _cairo_polygon_add_edge (&polygon, &occw, &f->ccw);
- _cairo_polygon_add_edge (&polygon, &f->ccw, &f->cw);
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_move_to (&polygon, &f->cw);
+ _cairo_polygon_line_to (&polygon, &ocw);
+ _cairo_polygon_line_to (&polygon, &occw);
+ _cairo_polygon_line_to (&polygon, &f->ccw);
+ _cairo_polygon_close (&polygon);
status = _cairo_traps_tessellate_polygon (stroker->traps, &polygon, CAIRO_FILL_RULE_WINDING);
_cairo_polygon_fini (&polygon);
@@ -454,8 +467,9 @@ static cairo_status_t
_cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_point_t *p2,
cairo_stroke_face_t *start, cairo_stroke_face_t *end)
{
+ cairo_status_t status;
cairo_gstate_t *gstate = stroker->gstate;
- cairo_point_t quad[4];
+ cairo_polygon_t polygon;
cairo_slope_t slope;
if (p1->x == p2->x && p1->y == p2->y) {
@@ -473,20 +487,58 @@ _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_
fields from start. */
_compute_face (p2, &slope, gstate, end);
- quad[0] = start->cw;
- quad[1] = start->ccw;
- quad[2] = end->ccw;
- quad[3] = end->cw;
+ /* XXX: I should really check the return value of the
+ move_to/line_to functions here to catch out of memory
+ conditions. But since that would be ugly, I'd prefer to add a
+ status flag to the polygon object that I could check only once
+ at then end of this sequence, (like we do with cairo_t
+ already). */
+ _cairo_polygon_init (&polygon);
+ _cairo_polygon_move_to (&polygon, &start->cw);
+ _cairo_polygon_line_to (&polygon, &start->ccw);
+ _cairo_polygon_line_to (&polygon, &end->ccw);
+ _cairo_polygon_line_to (&polygon, &end->cw);
+ _cairo_polygon_close (&polygon);
+
+ /* XXX: We can't use tessellate_rectangle as the matrix may have
+ skewed this into a non-rectangular shape. Perhaps it would be
+ worth checking the matrix for skew so that the common case
+ could use the faster tessellate_rectangle rather than
+ tessellate_polygon? */
+ status = _cairo_traps_tessellate_polygon (stroker->traps,
+ &polygon, CAIRO_FILL_RULE_WINDING);
+
+ _cairo_polygon_fini (&polygon);
- return _cairo_traps_tessellate_rectangle (stroker->traps, quad);
+ return status;
}
static cairo_status_t
-_cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
+_cairo_stroker_move_to (void *closure, cairo_point_t *point)
+{
+ cairo_stroker_t *stroker = closure;
+
+ stroker->first_point = *point;
+ stroker->current_point = *point;
+ stroker->has_current_point = 1;
+
+ stroker->has_first_face = 0;
+ stroker->has_current_face = 0;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_stroker_line_to (void *closure, cairo_point_t *point)
{
cairo_status_t status;
cairo_stroker_t *stroker = closure;
cairo_stroke_face_t start, end;
+ cairo_point_t *p1 = &stroker->current_point;
+ cairo_point_t *p2 = point;
+
+ if (!stroker->has_current_point)
+ return _cairo_stroker_move_to (stroker, point);
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
@@ -500,19 +552,20 @@ _cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
if (status)
return status;
- if (stroker->have_prev) {
- status = _cairo_stroker_join (stroker, &stroker->prev, &start);
+ if (stroker->has_current_face) {
+ status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
if (status)
return status;
} else {
- stroker->have_prev = 1;
- if (stroker->is_first) {
- stroker->have_first = 1;
- stroker->first = start;
+ if (!stroker->has_first_face) {
+ stroker->first_face = start;
+ stroker->has_first_face = 1;
}
}
- stroker->prev = end;
- stroker->is_first = 0;
+ stroker->current_face = end;
+ stroker->has_current_face = 1;
+
+ stroker->current_point = *point;
return CAIRO_STATUS_SUCCESS;
}
@@ -521,7 +574,7 @@ _cairo_stroker_add_edge (void *closure, cairo_point_t *p1, cairo_point_t *p2)
* Dashed lines. Cap each dash end, join around turns when on
*/
static cairo_status_t
-_cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t *p2)
+_cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t *stroker = closure;
@@ -532,6 +585,11 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t
cairo_point_t fd1, fd2;
int first = 1;
cairo_stroke_face_t sub_start, sub_end;
+ cairo_point_t *p1 = &stroker->current_point;
+ cairo_point_t *p2 = point;
+
+ if (!stroker->has_current_point)
+ return _cairo_stroker_move_to (stroker, point);
dx = _cairo_fixed_to_double (p2->x - p1->x);
dy = _cairo_fixed_to_double (p2->y - p1->y);
@@ -569,18 +627,18 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t
return status;
} else {
/*
- * First in this segment, join to any prev, else
+ * First in this segment, join to any current_face, else
* if at start of sub-path, mark position, else
* cap
*/
- if (stroker->have_prev) {
- status = _cairo_stroker_join (stroker, &stroker->prev, &sub_start);
+ if (stroker->has_current_face) {
+ status = _cairo_stroker_join (stroker, &stroker->current_face, &sub_start);
if (status)
return status;
} else {
- if (stroker->is_first) {
- stroker->have_first = 1;
- stroker->first = sub_start;
+ if (!stroker->has_first_face) {
+ stroker->first_face = sub_start;
+ stroker->has_first_face = 1;
} else {
status = _cairo_stroker_cap (stroker, &sub_start);
if (status)
@@ -600,8 +658,8 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t
* Mark previous line face and fix up next time
* through
*/
- stroker->prev = sub_end;
- stroker->have_prev = 1;
+ stroker->current_face = sub_end;
+ stroker->has_current_face = 1;
}
} else {
/*
@@ -609,27 +667,30 @@ _cairo_stroker_add_edge_dashed (void *closure, cairo_point_t *p1, cairo_point_t
* and cap if necessary
*/
if (first) {
- if (stroker->have_prev) {
- status = _cairo_stroker_cap (stroker, &stroker->prev);
+ if (stroker->has_current_face) {
+ status = _cairo_stroker_cap (stroker, &stroker->current_face);
if (status)
return status;
}
}
if (!remain)
- stroker->have_prev = 0;
+ stroker->has_current_face = 0;
}
_cairo_stroker_step_dash (stroker, tmp);
fd1 = fd2;
first = 0;
}
- stroker->is_first = 0;
+
+ stroker->current_point = *point;
+
return status;
}
static cairo_status_t
-_cairo_stroker_add_spline (void *closure,
- cairo_point_t *a, cairo_point_t *b,
- cairo_point_t *c, cairo_point_t *d)
+_cairo_stroker_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t *stroker = closure;
@@ -638,6 +699,7 @@ _cairo_stroker_add_spline (void *closure,
cairo_pen_t pen;
cairo_stroke_face_t start, end;
cairo_point_t extra_points[4];
+ cairo_point_t *a = &stroker->current_point;
status = _cairo_spline_init (&spline, a, b, c, d);
if (status == CAIRO_INT_STATUS_DEGENERATE)
@@ -650,19 +712,18 @@ _cairo_stroker_add_spline (void *closure,
_compute_face (a, &spline.initial_slope, gstate, &start);
_compute_face (d, &spline.final_slope, gstate, &end);
- if (stroker->have_prev) {
- status = _cairo_stroker_join (stroker, &stroker->prev, &start);
+ if (stroker->has_current_face) {
+ status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
if (status)
return status;
} else {
- stroker->have_prev = 1;
- if (stroker->is_first) {
- stroker->have_first = 1;
- stroker->first = start;
+ if (!stroker->has_first_face) {
+ stroker->first_face = start;
+ stroker->has_first_face = 1;
}
}
- stroker->prev = end;
- stroker->is_first = 0;
+ stroker->current_face = end;
+ stroker->has_current_face = 1;
extra_points[0] = start.cw;
extra_points[0].x -= start.point.x;
@@ -690,91 +751,89 @@ _cairo_stroker_add_spline (void *closure,
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
+ stroker->current_point = *d;
+
return status;
}
static cairo_status_t
-_cairo_stroker_done_sub_path (void *closure, cairo_sub_path_done_t done)
+_cairo_stroker_close_path (void *closure)
{
cairo_status_t status;
cairo_stroker_t *stroker = closure;
- switch (done) {
- case CAIRO_SUB_PATH_DONE_JOIN:
- if (stroker->have_first && stroker->have_prev) {
- status = _cairo_stroker_join (stroker, &stroker->prev, &stroker->first);
- if (status)
- return status;
- break;
- }
- /* fall through... */
- case CAIRO_SUB_PATH_DONE_CAP:
- if (stroker->have_first) {
- cairo_point_t t;
- /* The initial cap needs an outward facing vector. Reverse everything */
- stroker->first.usr_vector.x = -stroker->first.usr_vector.x;
- stroker->first.usr_vector.y = -stroker->first.usr_vector.y;
- stroker->first.dev_vector.dx = -stroker->first.dev_vector.dx;
- stroker->first.dev_vector.dy = -stroker->first.dev_vector.dy;
- t = stroker->first.cw;
- stroker->first.cw = stroker->first.ccw;
- stroker->first.ccw = t;
- status = _cairo_stroker_cap (stroker, &stroker->first);
- if (status)
- return status;
- }
- if (stroker->have_prev) {
- status = _cairo_stroker_cap (stroker, &stroker->prev);
- if (status)
- return status;
- }
- break;
+ if (stroker->has_current_point) {
+ if (stroker->dashed)
+ status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
+ else
+ status = _cairo_stroker_line_to (stroker, &stroker->first_point);
+ if (status)
+ return status;
}
- stroker->have_prev = 0;
- stroker->have_first = 0;
- stroker->is_first = 1;
+ if (stroker->has_first_face && stroker->has_current_face) {
+ status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face);
+ if (status)
+ return status;
+ }
- return CAIRO_STATUS_SUCCESS;
-}
+ stroker->has_first_face = 0;
+ stroker->has_current_face = 0;
+ stroker->has_current_point = 0;
-static cairo_status_t
-_cairo_stroker_done_path (void *closure)
-{
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_path_stroke_to_traps (cairo_path_t *path, cairo_gstate_t *gstate, cairo_traps_t *traps)
{
- static const cairo_path_callbacks_t stroker_solid_cb = {
- _cairo_stroker_add_edge,
- _cairo_stroker_add_spline,
- _cairo_stroker_done_sub_path,
- _cairo_stroker_done_path
- };
- static const cairo_path_callbacks_t stroker_dashed_cb = {
- _cairo_stroker_add_edge_dashed,
- _cairo_stroker_add_spline,
- _cairo_stroker_done_sub_path,
- _cairo_stroker_done_path
- };
- const cairo_path_callbacks_t *callbacks = gstate->dash ? &stroker_dashed_cb : &stroker_solid_cb;
-
- cairo_status_t status;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t stroker;
_cairo_stroker_init (&stroker, gstate, traps);
- status = _cairo_path_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- callbacks, &stroker);
- if (status) {
- _cairo_stroker_fini (&stroker);
- return status;
+ if (gstate->dash)
+ status = _cairo_path_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_stroker_move_to,
+ _cairo_stroker_line_to_dashed,
+ _cairo_stroker_curve_to,
+ _cairo_stroker_close_path,
+ &stroker);
+ else
+ status = _cairo_path_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_stroker_move_to,
+ _cairo_stroker_line_to,
+ _cairo_stroker_curve_to,
+ _cairo_stroker_close_path,
+ &stroker);
+ if (status)
+ goto BAIL;
+
+ if (stroker.has_first_face) {
+ cairo_point_t t;
+ /* The initial cap needs an outward facing vector. Reverse everything */
+ stroker.first_face.usr_vector.x = -stroker.first_face.usr_vector.x;
+ stroker.first_face.usr_vector.y = -stroker.first_face.usr_vector.y;
+ stroker.first_face.dev_vector.dx = -stroker.first_face.dev_vector.dx;
+ stroker.first_face.dev_vector.dy = -stroker.first_face.dev_vector.dy;
+ t = stroker.first_face.cw;
+ stroker.first_face.cw = stroker.first_face.ccw;
+ stroker.first_face.ccw = t;
+ status = _cairo_stroker_cap (&stroker, &stroker.first_face);
+ if (status)
+ goto BAIL;
}
+ if (stroker.has_current_face) {
+ status = _cairo_stroker_cap (&stroker, &stroker.current_face);
+ if (status)
+ goto BAIL;
+ }
+
+BAIL:
_cairo_stroker_fini (&stroker);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
diff --git a/src/cairo_pattern.c b/src/cairo_pattern.c
new file mode 100644
index 00000000..dcdb1566
--- /dev/null
+++ b/src/cairo_pattern.c
@@ -0,0 +1,716 @@
+/*
+ * Copyright © 2002 University of Southern California
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * University of Southern California not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. The University of Southern
+ * California makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
+ * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <c99drn@cs.umu.se>
+ */
+
+#include "cairoint.h"
+
+void
+_cairo_pattern_init (cairo_pattern_t *pattern)
+{
+ pattern->ref_count = 1;
+
+ pattern->extend = CAIRO_EXTEND_DEFAULT;
+ pattern->filter = CAIRO_FILTER_DEFAULT;
+
+ _cairo_color_init (&pattern->color);
+
+ _cairo_matrix_init (&pattern->matrix);
+
+ pattern->stops = NULL;
+ pattern->n_stops = 0;
+
+ pattern->type = CAIRO_PATTERN_SOLID;
+
+ pattern->source = NULL;
+ pattern->source_offset.x = 0.0;
+ pattern->source_offset.y = 0.0;
+}
+
+cairo_status_t
+_cairo_pattern_init_copy (cairo_pattern_t *pattern, cairo_pattern_t *other)
+{
+ *pattern = *other;
+
+ pattern->ref_count = 1;
+
+ if (pattern->n_stops) {
+ pattern->stops =
+ malloc (sizeof (cairo_color_stop_t) * pattern->n_stops);
+ if (pattern->stops == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+ memcpy (pattern->stops, other->stops,
+ sizeof (cairo_color_stop_t) * other->n_stops);
+ }
+
+ if (pattern->source)
+ cairo_surface_reference (other->source);
+
+ if (pattern->type == CAIRO_PATTERN_SURFACE)
+ cairo_surface_reference (other->u.surface.surface);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_pattern_fini (cairo_pattern_t *pattern)
+{
+ if (pattern->n_stops)
+ free (pattern->stops);
+
+ if (pattern->type == CAIRO_PATTERN_SURFACE) {
+ /* show_surface require us to restore surface matrix, repeat
+ attribute, filter type */
+ if (pattern->source) {
+ cairo_surface_set_matrix (pattern->source,
+ &pattern->u.surface.save_matrix);
+ cairo_surface_set_repeat (pattern->source,
+ pattern->u.surface.save_repeat);
+ cairo_surface_set_filter (pattern->source,
+ pattern->u.surface.save_filter);
+ }
+ cairo_surface_destroy (pattern->u.surface.surface);
+ }
+
+ if (pattern->source)
+ cairo_surface_destroy (pattern->source);
+}
+
+void
+_cairo_pattern_init_solid (cairo_pattern_t *pattern,
+ double red, double green, double blue)
+{
+ _cairo_pattern_init (pattern);
+
+ pattern->type = CAIRO_PATTERN_SOLID;
+ _cairo_color_set_rgb (&pattern->color, red, green, blue);
+}
+
+cairo_pattern_t *
+_cairo_pattern_create_solid (double red, double green, double blue)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = malloc (sizeof (cairo_pattern_t));
+ if (pattern == NULL)
+ return NULL;
+
+ _cairo_pattern_init_solid (pattern, red, green, blue);
+
+ return pattern;
+}
+
+cairo_pattern_t *
+cairo_pattern_create_for_surface (cairo_surface_t *surface)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = malloc (sizeof (cairo_pattern_t));
+ if (pattern == NULL)
+ return NULL;
+
+ _cairo_pattern_init (pattern);
+
+ pattern->type = CAIRO_PATTERN_SURFACE;
+ pattern->u.surface.surface = surface;
+ cairo_surface_reference (surface);
+
+ return pattern;
+}
+
+cairo_pattern_t *
+cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = malloc (sizeof (cairo_pattern_t));
+ if (pattern == NULL)
+ return NULL;
+
+ _cairo_pattern_init (pattern);
+
+ pattern->type = CAIRO_PATTERN_LINEAR;
+ pattern->u.linear.point0.x = x0;
+ pattern->u.linear.point0.y = y0;
+ pattern->u.linear.point1.x = x1;
+ pattern->u.linear.point1.y = y1;
+
+ return pattern;
+}
+
+cairo_pattern_t *
+cairo_pattern_create_radial (double cx0, double cy0, double radius0,
+ double cx1, double cy1, double radius1)
+{
+ cairo_pattern_t *pattern;
+
+ pattern = malloc (sizeof (cairo_pattern_t));
+ if (pattern == NULL)
+ return NULL;
+
+ _cairo_pattern_init (pattern);
+
+ pattern->type = CAIRO_PATTERN_RADIAL;
+ pattern->u.radial.center0.x = cx0;
+ pattern->u.radial.center0.y = cy0;
+ pattern->u.radial.radius0.dx = radius0;
+ pattern->u.radial.radius0.dy = radius0;
+ pattern->u.radial.center1.x = cx1;
+ pattern->u.radial.center1.y = cy1;
+ pattern->u.radial.radius1.dx = radius1;
+ pattern->u.radial.radius1.dy = radius1;
+
+ return pattern;
+}
+
+void
+cairo_pattern_reference (cairo_pattern_t *pattern)
+{
+ if (pattern == NULL)
+ return;
+
+ pattern->ref_count++;
+}
+
+void
+cairo_pattern_destroy (cairo_pattern_t *pattern)
+{
+ if (pattern == NULL)
+ return;
+
+ pattern->ref_count--;
+ if (pattern->ref_count)
+ return;
+
+ _cairo_pattern_fini (pattern);
+ free (pattern);
+}
+
+static int
+_cairo_pattern_stop_compare (const void *elem1, const void *elem2)
+{
+ return
+ (((cairo_color_stop_t *) elem1)->offset ==
+ ((cairo_color_stop_t *) elem2)->offset) ?
+ /* equal offsets, sort on id */
+ ((((cairo_color_stop_t *) elem1)->id <
+ ((cairo_color_stop_t *) elem2)->id) ? -1 : 1) :
+ /* sort on offset */
+ ((((cairo_color_stop_t *) elem1)->offset <
+ ((cairo_color_stop_t *) elem2)->offset) ? -1 : 1);
+}
+
+cairo_status_t
+cairo_pattern_add_color_stop (cairo_pattern_t *pattern,
+ double offset,
+ double red, double green, double blue,
+ double alpha)
+{
+ cairo_color_stop_t *stop;
+
+ _cairo_restrict_value (&offset, 0.0, 1.0);
+ _cairo_restrict_value (&red, 0.0, 1.0);
+ _cairo_restrict_value (&green, 0.0, 1.0);
+ _cairo_restrict_value (&blue, 0.0, 1.0);
+
+ pattern->n_stops++;
+ pattern->stops = realloc (pattern->stops,
+ sizeof (cairo_color_stop_t) * pattern->n_stops);
+ if (pattern->stops == NULL) {
+ pattern->n_stops = 0;
+
+ return CAIRO_STATUS_NO_MEMORY;
+ }
+
+ stop = &pattern->stops[pattern->n_stops - 1];
+
+ stop->offset = offset;
+ stop->id = pattern->n_stops;
+ _cairo_color_init (&stop->color);
+ _cairo_color_set_rgb (&stop->color, red, green, blue);
+ _cairo_color_set_alpha (&stop->color, alpha);
+ stop->color_char[0] = stop->color.red_short / 256;
+ stop->color_char[1] = stop->color.green_short / 256;
+ stop->color_char[2] = stop->color.blue_short / 256;
+ stop->color_char[3] = stop->color.alpha_short / 256;
+
+ /* sort stops in ascending order */
+ qsort (pattern->stops, pattern->n_stops, sizeof (cairo_color_stop_t),
+ _cairo_pattern_stop_compare);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+cairo_pattern_set_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
+{
+ cairo_matrix_copy (&pattern->matrix, matrix);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
+{
+ cairo_matrix_copy (matrix, &pattern->matrix);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
+{
+ pattern->filter = filter;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_filter_t
+cairo_pattern_get_filter (cairo_pattern_t *pattern)
+{
+ return pattern->filter;
+}
+
+cairo_status_t
+cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
+{
+ pattern->extend = extend;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_extend_t
+cairo_pattern_get_extend (cairo_pattern_t *pattern)
+{
+ return pattern->extend;
+}
+
+cairo_status_t
+_cairo_pattern_get_rgb (cairo_pattern_t *pattern,
+ double *red, double *green, double *blue)
+{
+ _cairo_color_get_rgb (&pattern->color, red, green, blue);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_pattern_set_alpha (cairo_pattern_t *pattern, double alpha)
+{
+ int i;
+
+ _cairo_color_set_alpha (&pattern->color, alpha);
+
+ for (i = 0; i < pattern->n_stops; i++) {
+ cairo_color_stop_t *stop = &pattern->stops[i];
+
+ _cairo_color_set_alpha (&stop->color, stop->color.alpha * alpha);
+
+ stop->color_char[0] = stop->color.red_short / 256;
+ stop->color_char[1] = stop->color.green_short / 256;
+ stop->color_char[2] = stop->color.blue_short / 256;
+ stop->color_char[3] = stop->color.alpha_short / 256;
+ }
+}
+
+void
+_cairo_pattern_add_source_offset (cairo_pattern_t *pattern,
+ double x, double y)
+{
+ pattern->source_offset.x += x;
+ pattern->source_offset.y += y;
+}
+
+void
+_cairo_pattern_transform (cairo_pattern_t *pattern,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse)
+{
+ cairo_matrix_t matrix;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_SURFACE:
+ /* hmm, maybe we should instead multiply with the inverse of the
+ pattern matrix here? */
+ cairo_matrix_multiply (&pattern->matrix, ctm_inverse,
+ &pattern->matrix);
+ break;
+ case CAIRO_PATTERN_LINEAR:
+ cairo_matrix_multiply (&matrix, &pattern->matrix, ctm);
+ cairo_matrix_transform_point (&matrix,
+ &pattern->u.linear.point0.x,
+ &pattern->u.linear.point0.y);
+ cairo_matrix_transform_point (&matrix,
+ &pattern->u.linear.point1.x,
+ &pattern->u.linear.point1.y);
+ break;
+ case CAIRO_PATTERN_RADIAL:
+ cairo_matrix_multiply (&matrix, &pattern->matrix, ctm);
+ cairo_matrix_transform_point (&matrix,
+ &pattern->u.radial.center0.x,
+ &pattern->u.radial.center0.y);
+ cairo_matrix_transform_distance (&matrix,
+ &pattern->u.radial.radius0.dx,
+ &pattern->u.radial.radius0.dy);
+ cairo_matrix_transform_point (&matrix,
+ &pattern->u.radial.center1.x,
+ &pattern->u.radial.center1.y);
+ cairo_matrix_transform_distance (&matrix,
+ &pattern->u.radial.radius1.dx,
+ &pattern->u.radial.radius1.dy);
+ break;
+ case CAIRO_PATTERN_SOLID:
+ break;
+ }
+}
+
+void
+_cairo_pattern_prepare_surface (cairo_pattern_t *pattern)
+{
+ cairo_matrix_t device_to_source;
+ cairo_matrix_t user_to_source;
+
+ /* should the surface matrix interface be remove from the API?
+ for now we multiple the surface matrix with the pattern matrix */
+ cairo_surface_get_matrix (pattern->u.surface.surface, &user_to_source);
+ cairo_matrix_multiply (&device_to_source, &pattern->matrix,
+ &user_to_source);
+ cairo_surface_set_matrix (pattern->source, &device_to_source);
+
+ /* storing original surface matrix in pattern */
+ pattern->u.surface.save_matrix = user_to_source;
+
+ /* storing original surface repeat mode in pattern */
+ pattern->u.surface.save_repeat = pattern->source->repeat;
+
+ /* what do we do with extend types pad and reflect? */
+ if (pattern->extend == CAIRO_EXTEND_REPEAT
+ || pattern->source->repeat == 1)
+ cairo_surface_set_repeat (pattern->source, 1);
+ else
+ cairo_surface_set_repeat (pattern->source, 0);
+
+ /* storing original surface filter in pattern */
+ pattern->u.surface.save_filter =
+ cairo_surface_get_filter (pattern->source);
+
+ cairo_surface_set_filter (pattern->source, pattern->filter);
+}
+
+typedef void (*cairo_shader_function_t) (unsigned char *color0,
+ unsigned char *color1,
+ double factor,
+ unsigned char *result_color);
+
+#define INTERPOLATE_COLOR_NEAREST(c1, c2, factor) \
+ ((unsigned char) ((factor < 0.5)? c1: c2))
+
+static void
+_cairo_pattern_shader_nearest (unsigned char *color0,
+ unsigned char *color1,
+ double factor,
+ unsigned char *result_color)
+{
+ result_color[0] = INTERPOLATE_COLOR_NEAREST (color0[0], color1[0], factor);
+ result_color[1] = INTERPOLATE_COLOR_NEAREST (color0[1], color1[1], factor);
+ result_color[2] = INTERPOLATE_COLOR_NEAREST (color0[2], color1[2], factor);
+ result_color[3] = INTERPOLATE_COLOR_NEAREST (color0[3], color1[3], factor);
+}
+
+#undef INTERPOLATE_COLOR_NEAREST
+
+#define INTERPOLATE_COLOR_LINEAR(c1, c2, factor) \
+ ((unsigned char) ((c2 * factor) + (c1 * (1.0 - factor))))
+
+static void
+_cairo_pattern_shader_linear (unsigned char *color0,
+ unsigned char *color1,
+ double factor,
+ unsigned char *result_color)
+{
+ result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor);
+ result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor);
+ result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor);
+ result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor);
+}
+
+static void
+_cairo_pattern_shader_gaussian (unsigned char *color0,
+ unsigned char *color1,
+ double factor,
+ unsigned char *result_color)
+{
+ factor = (exp (factor * factor) - 1.0) / (M_E - 1.0);
+
+ result_color[0] = INTERPOLATE_COLOR_LINEAR (color0[0], color1[0], factor);
+ result_color[1] = INTERPOLATE_COLOR_LINEAR (color0[1], color1[1], factor);
+ result_color[2] = INTERPOLATE_COLOR_LINEAR (color0[2], color1[2], factor);
+ result_color[3] = INTERPOLATE_COLOR_LINEAR (color0[3], color1[3], factor);
+}
+
+#undef INTERPOLATE_COLOR_LINEAR
+
+void
+_cairo_pattern_calc_color_at_pixel (cairo_pattern_t *pattern,
+ double factor,
+ int *pixel)
+{
+ int p, colorstop;
+ double factorscale;
+ unsigned char result_color[4];
+ cairo_shader_function_t shader_function;
+
+ switch (pattern->filter) {
+ case CAIRO_FILTER_FAST:
+ case CAIRO_FILTER_NEAREST:
+ shader_function = _cairo_pattern_shader_nearest;
+ break;
+ case CAIRO_FILTER_GAUSSIAN:
+ shader_function = _cairo_pattern_shader_gaussian;
+ break;
+ case CAIRO_FILTER_GOOD:
+ case CAIRO_FILTER_BEST:
+ case CAIRO_FILTER_BILINEAR:
+ shader_function = _cairo_pattern_shader_linear;
+ break;
+ }
+
+ if (factor > 1.0 || factor < 0.0) {
+ switch (pattern->extend) {
+ case CAIRO_EXTEND_REPEAT:
+ factor -= floor (factor);
+ break;
+ case CAIRO_EXTEND_REFLECT:
+ if (factor >= 0.0) {
+ if (((int) factor) % 2)
+ factor = 1.0 - (factor - floor (factor));
+ else
+ factor -= floor (factor);
+ } else {
+ if (((int) factor) % 2)
+ factor -= floor (factor);
+ else
+ factor = 1.0 - (factor - floor (factor));
+ }
+ break;
+ case CAIRO_EXTEND_NONE:
+ break;
+ }
+ }
+
+ if (factor < pattern->stops[0].offset)
+ factor = pattern->stops[0].offset;
+
+ if (factor > pattern->stops[pattern->n_stops - 1].offset)
+ factor = pattern->stops[pattern->n_stops - 1].offset;
+
+ for (colorstop = 0; colorstop < pattern->n_stops - 1; colorstop++) {
+ if (factor <= pattern->stops[colorstop + 1].offset) {
+ factorscale = fabs (pattern->stops[colorstop].offset -
+ pattern->stops[colorstop + 1].offset);
+
+ /* abrubt change, difference between two offsets == 0.0 */
+ if (factorscale == 0)
+ break;
+
+ factor -= pattern->stops[colorstop].offset;
+
+ /* take offset as new 0 of coordinate system */
+ factor /= factorscale;
+
+ shader_function (pattern->stops[colorstop].color_char,
+ pattern->stops[colorstop + 1].color_char,
+ factor, result_color);
+
+ p = ((result_color[3] << 24) |
+ (result_color[0] << 16) |
+ (result_color[1] << 8) | (result_color[2] << 0));
+ *pixel = p;
+ break;
+ }
+ }
+}
+
+static void
+_cairo_image_data_set_linear (cairo_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ char *data,
+ int width,
+ int height)
+{
+ int x, y;
+ cairo_point_double_t point0, point1, angle;
+ double a, length, start, end;
+ double factor;
+
+ point0.x = pattern->u.linear.point0.x - offset_x;
+ point0.y = pattern->u.linear.point0.y - offset_y;
+ point1.x = pattern->u.linear.point1.x - offset_x;
+ point1.y = pattern->u.linear.point1.y - offset_y;
+
+ length = sqrt ((point1.x - point0.x) * (point1.x - point0.x) +
+ (point1.y - point0.y) * (point1.y - point0.y));
+ length = (length) ? 1.0 / length : INT_MAX;
+
+ a = -atan2 (point1.y - point0.y, point1.x - point0.x);
+ angle.x = cos (a);
+ angle.y = -sin (a);
+
+ start = angle.x * point0.x;
+ start += angle.y * point0.y;
+
+ end = angle.x * point1.x;
+ end += angle.y * point1.y;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+
+ factor = angle.x * (double) x;
+ factor += angle.y * (double) y;
+
+ factor = factor - start;
+ factor *= length;
+
+ _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *)
+ &data[y * width * 4 + x * 4]);
+ }
+ }
+}
+
+/* TODO: Inner circle is currently ignored. */
+static void
+_cairo_image_data_set_radial (cairo_pattern_t *pattern,
+ double offset_x,
+ double offset_y,
+ char *data,
+ int width,
+ int height)
+{
+ int x, y;
+ cairo_point_double_t center1, pos;
+ cairo_distance_double_t length;
+ double factor;
+ double min_length;
+
+ center1.x = pattern->u.radial.center1.x - offset_x;
+ center1.y = pattern->u.radial.center1.y - offset_y;
+
+ min_length =
+ fabs ((pattern->u.radial.radius1.dx < pattern->u.radial.radius1.dy) ?
+ pattern->u.radial.radius1.dx : pattern->u.radial.radius1.dy);
+
+ /* ugly */
+ if (min_length == 0.0)
+ min_length = 0.000001;
+
+ length.dx = min_length / pattern->u.radial.radius1.dx;
+ length.dy = min_length / pattern->u.radial.radius1.dy;
+
+ min_length = 1.0 / min_length;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ pos.x = x - center1.x;
+ pos.y = y - center1.y;
+
+ pos.x *= length.dx;
+ pos.y *= length.dy;
+
+ factor = sqrt (pos.x * pos.x + pos.y * pos.y) * min_length;
+
+ _cairo_pattern_calc_color_at_pixel (pattern, factor, (int *)
+ &data[y * width * 4 + x * 4]);
+ }
+ }
+}
+
+cairo_image_surface_t *
+_cairo_pattern_get_image (cairo_pattern_t *pattern, cairo_box_t *box)
+{
+ cairo_surface_t *surface;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_RADIAL: {
+ char *data;
+ 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));
+
+ data = malloc (width * height * 4);
+ if (!data)
+ return NULL;
+
+ _cairo_pattern_add_source_offset (pattern,
+ _cairo_fixed_to_double (box->p1.x),
+ _cairo_fixed_to_double (box->p1.y));
+
+ if (pattern->type == CAIRO_PATTERN_RADIAL)
+ _cairo_image_data_set_radial (pattern,
+ pattern->source_offset.x,
+ pattern->source_offset.y,
+ data, width, height);
+ else
+ _cairo_image_data_set_linear (pattern,
+ pattern->source_offset.x,
+ pattern->source_offset.y,
+ data, width, height);
+
+ surface = cairo_image_surface_create_for_data (data,
+ CAIRO_FORMAT_ARGB32,
+ width, height,
+ width * 4);
+
+ if (surface)
+ _cairo_image_surface_assume_ownership_of_data (
+ (cairo_image_surface_t *) surface);
+ }
+ break;
+ case CAIRO_PATTERN_SOLID:
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ if (surface) {
+ _cairo_surface_fill_rectangle (surface,
+ CAIRO_OPERATOR_SRC,
+ &pattern->color, 0, 0, 1, 1);
+ cairo_surface_set_repeat (surface, 1);
+ }
+ break;
+ case CAIRO_PATTERN_SURFACE: {
+ cairo_image_surface_t *image;
+
+ image = _cairo_surface_get_image (pattern->u.surface.surface);
+ if (image)
+ surface = &image->base;
+ else
+ surface = NULL;
+
+ }
+ break;
+ }
+
+ return (cairo_image_surface_t *) surface;
+}
diff --git a/src/cairo_pen.c b/src/cairo_pen.c
index dd054372..0bb5debd 100644
--- a/src/cairo_pen.c
+++ b/src/cairo_pen.c
@@ -288,7 +288,7 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen,
while (i != stop) {
hull_point.x = point[i].x + pen->vertices[active].point.x;
hull_point.y = point[i].y + pen->vertices[active].point.y;
- status = _cairo_polygon_add_point (polygon, &hull_point);
+ status = _cairo_polygon_line_to (polygon, &hull_point);
if (status)
return status;
diff --git a/src/cairo_png_surface.c b/src/cairo_png_surface.c
new file mode 100644
index 00000000..ed7bb039
--- /dev/null
+++ b/src/cairo_png_surface.c
@@ -0,0 +1,333 @@
+#include <png.h>
+
+#include "cairoint.h"
+
+static const cairo_surface_backend_t cairo_png_surface_backend;
+
+void
+cairo_set_target_png (cairo_t *cr,
+ FILE *file,
+ cairo_format_t format,
+ int width,
+ int height)
+{
+ cairo_surface_t *surface;
+
+ surface = cairo_png_surface_create (file, format,
+ width, height);
+
+ if (surface == NULL) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface (cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy (surface);
+}
+
+typedef struct cairo_png_surface {
+ cairo_surface_t base;
+
+ /* PNG-specific fields */
+ FILE *file;
+
+ png_structp png_w;
+ png_infop png_i;
+
+ cairo_image_surface_t *image;
+} cairo_png_surface_t;
+
+
+static void
+_cairo_png_surface_erase (cairo_png_surface_t *surface);
+
+cairo_surface_t *
+cairo_png_surface_create (FILE *file,
+ cairo_format_t format,
+ int width,
+ int height)
+{
+ cairo_png_surface_t *surface;
+ time_t now = time (NULL);
+ png_time png_time;
+
+ if (format == CAIRO_FORMAT_A8 ||
+ format == CAIRO_FORMAT_A1 ||
+ file == NULL)
+ return NULL;
+
+ surface = malloc (sizeof (cairo_png_surface_t));
+ if (surface == NULL)
+ goto failure;
+
+ _cairo_surface_init (&surface->base, &cairo_png_surface_backend);
+ surface->png_w = NULL;
+ surface->png_i = NULL;
+
+ surface->image = (cairo_image_surface_t *)
+ cairo_image_surface_create (format, width, height);
+ if (surface->image == NULL)
+ goto failure;
+
+ _cairo_png_surface_erase (surface);
+
+ surface->file = file;
+
+ surface->png_w = png_create_write_struct (PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL);
+ if (surface->png_w == NULL)
+ goto failure;
+ surface->png_i = png_create_info_struct (surface->png_w);
+ if (surface->png_i == NULL)
+ goto failure;
+
+ if (setjmp (png_jmpbuf (surface->png_w)))
+ goto failure;
+
+ png_init_io (surface->png_w, surface->file);
+
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ png_set_IHDR (surface->png_w, surface->png_i,
+ width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+ break;
+ case CAIRO_FORMAT_RGB24:
+ png_set_IHDR (surface->png_w, surface->png_i,
+ width, height, 8, PNG_COLOR_TYPE_RGB,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+ break;
+ }
+
+ png_convert_from_time_t (&png_time, now);
+ png_set_tIME (surface->png_w, surface->png_i, &png_time);
+
+ png_write_info (surface->png_w, surface->png_i);
+
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ png_set_bgr (surface->png_w);
+ break;
+ case CAIRO_FORMAT_RGB24:
+ png_set_filler (surface->png_w, 0, PNG_FILLER_AFTER);
+ png_set_bgr (surface->png_w);
+ break;
+ }
+
+ return &surface->base;
+
+
+ failure:
+ if (surface) {
+ if (surface->image)
+ cairo_surface_destroy (&surface->image->base);
+ if (surface->png_i)
+ png_destroy_write_struct (&surface->png_w, &surface->png_i);
+ else if (surface->png_w)
+ png_destroy_write_struct (&surface->png_w, NULL);
+ free (surface);
+ }
+ return NULL;
+}
+
+
+static cairo_surface_t *
+_cairo_png_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int width,
+ int height)
+{
+ return NULL;
+}
+
+static void
+_cairo_png_surface_destroy (void *abstract_surface)
+{
+ cairo_png_surface_t *surface = abstract_surface;
+ int i;
+ png_byte *row;
+
+ if (setjmp (png_jmpbuf (surface->png_w)))
+ goto failure;
+
+ row = surface->image->data;
+ for (i=0; i < surface->image->height; i++) {
+ png_write_row (surface->png_w, row);
+ row += surface->image->stride;
+ }
+
+ png_write_end (surface->png_w, surface->png_i);
+
+ failure:
+ png_destroy_write_struct (&surface->png_w, &surface->png_i);
+
+ cairo_surface_destroy (&surface->image->base);
+
+ free (surface);
+}
+
+static void
+_cairo_png_surface_erase (cairo_png_surface_t *surface)
+{
+ cairo_color_t transparent;
+
+ _cairo_color_init (&transparent);
+ _cairo_color_set_rgb (&transparent, 0., 0., 0.);
+ _cairo_color_set_alpha (&transparent, 0.);
+ _cairo_surface_fill_rectangle (&surface->image->base,
+ CAIRO_OPERATOR_SRC,
+ &transparent,
+ 0, 0,
+ surface->image->width,
+ surface->image->height);
+}
+
+static double
+_cairo_png_surface_pixels_per_inch (void *abstract_surface)
+{
+ return 96.0;
+}
+
+static cairo_image_surface_t *
+_cairo_png_surface_get_image (void *abstract_surface)
+{
+ cairo_png_surface_t *surface = abstract_surface;
+
+ cairo_surface_reference (&surface->image->base);
+
+ return surface->image;
+}
+
+static cairo_status_t
+_cairo_png_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ cairo_png_surface_t *surface = abstract_surface;
+
+ if (image == surface->image)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* XXX: Need to call _cairo_image_surface_set_image here, but it's
+ not implemented yet. */
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cairo_png_surface_set_matrix (void *abstract_surface,
+ cairo_matrix_t *matrix)
+{
+ cairo_png_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_matrix (surface->image, matrix);
+}
+
+static cairo_status_t
+_cairo_png_surface_set_filter (void *abstract_surface,
+ cairo_filter_t filter)
+{
+ cairo_png_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_filter (surface->image, filter);
+}
+
+static cairo_status_t
+_cairo_png_surface_set_repeat (void *abstract_surface,
+ int repeat)
+{
+ cairo_png_surface_t *surface = abstract_surface;
+
+ return _cairo_image_surface_set_repeat (surface->image, repeat);
+}
+
+static cairo_int_status_t
+_cairo_png_surface_composite (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ cairo_surface_t *generic_mask,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_png_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_png_surface_composite_trapezoids (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int x_src,
+ int y_src,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_png_surface_copy_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_png_surface_show_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_png_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_png_surface_t *surface = 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,
+ _cairo_png_surface_destroy,
+ _cairo_png_surface_pixels_per_inch,
+ _cairo_png_surface_get_image,
+ _cairo_png_surface_set_image,
+ _cairo_png_surface_set_matrix,
+ _cairo_png_surface_set_filter,
+ _cairo_png_surface_set_repeat,
+ _cairo_png_surface_composite,
+ _cairo_png_surface_fill_rectangles,
+ _cairo_png_surface_composite_trapezoids,
+ _cairo_png_surface_copy_page,
+ _cairo_png_surface_show_page,
+ _cairo_png_surface_set_clip_region,
+ _cairo_png_surface_create_pattern
+};
diff --git a/src/cairo_polygon.c b/src/cairo_polygon.c
index 97f074a3..fbda7321 100644
--- a/src/cairo_polygon.c
+++ b/src/cairo_polygon.c
@@ -35,9 +35,6 @@
static cairo_status_t
_cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional);
-static void
-_cairo_polygon_set_last_point (cairo_polygon_t *polygon, cairo_point_t *point);
-
void
_cairo_polygon_init (cairo_polygon_t *polygon)
{
@@ -46,10 +43,7 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
polygon->edges_size = 0;
polygon->edges = NULL;
- polygon->first_point_defined = 0;
- polygon->last_point_defined = 0;
-
- polygon->closed = 0;
+ polygon->has_current_point = 0;
}
void
@@ -62,10 +56,7 @@ _cairo_polygon_fini (cairo_polygon_t *polygon)
polygon->num_edges = 0;
}
- polygon->first_point_defined = 0;
- polygon->last_point_defined = 0;
-
- polygon->closed = 0;
+ polygon->has_current_point = 0;
}
static cairo_status_t
@@ -92,25 +83,12 @@ _cairo_polygon_grow_by (cairo_polygon_t *polygon, int additional)
return CAIRO_STATUS_SUCCESS;
}
-static void
-_cairo_polygon_set_last_point (cairo_polygon_t *polygon, cairo_point_t *point)
-{
- polygon->last_point = *point;
- polygon->last_point_defined = 1;
-}
-
cairo_status_t
_cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2)
{
cairo_status_t status;
cairo_edge_t *edge;
- if (! polygon->first_point_defined) {
- polygon->first_point = *p1;
- polygon->first_point_defined = 1;
- polygon->closed = 0;
- }
-
/* drop horizontal edges */
if (p1->y == p2->y) {
goto DONE;
@@ -137,20 +115,31 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_poin
polygon->num_edges++;
DONE:
- _cairo_polygon_set_last_point (polygon, p2);
+ _cairo_polygon_move_to (polygon, p2);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point)
+{
+ if (! polygon->has_current_point)
+ polygon->first_point = *point;
+ polygon->current_point = *point;
+ polygon->has_current_point = 1;
return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_polygon_add_point (cairo_polygon_t *polygon, cairo_point_t *point)
+_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- if (polygon->last_point_defined) {
- status = _cairo_polygon_add_edge (polygon, &polygon->last_point, point);
+ if (polygon->has_current_point) {
+ status = _cairo_polygon_add_edge (polygon, &polygon->current_point, point);
} else {
- _cairo_polygon_set_last_point (polygon, point);
+ _cairo_polygon_move_to (polygon, point);
}
return status;
@@ -161,13 +150,14 @@ _cairo_polygon_close (cairo_polygon_t *polygon)
{
cairo_status_t status;
- if (polygon->closed == 0 && polygon->last_point_defined) {
- status = _cairo_polygon_add_edge (polygon, &polygon->last_point, &polygon->first_point);
+ if (polygon->has_current_point) {
+ status = _cairo_polygon_add_edge (polygon,
+ &polygon->current_point,
+ &polygon->first_point);
if (status)
return status;
- polygon->closed = 1;
- polygon->first_point_defined = 0;
+ polygon->has_current_point = 0;
}
return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo_ps_surface.c b/src/cairo_ps_surface.c
index c66b7098..98d34e44 100644
--- a/src/cairo_ps_surface.c
+++ b/src/cairo_ps_surface.c
@@ -286,19 +286,19 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
int i, x, y;
cairo_surface_t *white_surface;
- char *bgr, *compressed;
- long bgr_size, compressed_size;
+ char *rgb, *compressed;
+ long rgb_size, compressed_size;
cairo_color_t white;
- bgr_size = 3 * width * height;
- bgr = malloc (bgr_size);
- if (bgr == NULL) {
+ rgb_size = 3 * width * height;
+ rgb = malloc (rgb_size);
+ if (rgb == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto BAIL0;
}
- compressed_size = (int) (1.0 + 1.1 * bgr_size);
+ compressed_size = (int) (1.0 + 1.1 * rgb_size);
compressed = malloc (compressed_size);
if (compressed == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
@@ -330,16 +330,15 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
i = 0;
for (y = 0; y < height; y++) {
- char *line = surface->image->data + y * surface->image->stride;
- for (x = 0; x < width; x++) {
- unsigned char *pixel = (unsigned char *) line + x * 4;
- bgr[i++] = *(pixel+2);
- bgr[i++] = *(pixel+1);
- bgr[i++] = *(pixel);
+ pixman_bits_t *pixel = (pixman_bits_t *) (surface->image->data + y * surface->image->stride);
+ for (x = 0; x < width; x++, pixel++) {
+ rgb[i++] = (*pixel & 0x00ff0000) >> 16;
+ rgb[i++] = (*pixel & 0x0000ff00) >> 8;
+ rgb[i++] = (*pixel & 0x000000ff) >> 0;
}
}
- compress (compressed, &compressed_size, bgr, bgr_size);
+ compress (compressed, &compressed_size, rgb, rgb_size);
/* Page header */
fprintf (file, "%%%%Page: %d\n", ++surface->pages);
@@ -375,7 +374,7 @@ _cairo_ps_surface_copy_page (void *abstract_surface)
BAIL2:
free (compressed);
BAIL1:
- free (bgr);
+ free (rgb);
BAIL0:
return status;
}
@@ -395,6 +394,23 @@ _cairo_ps_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
+static cairo_int_status_t
+_cairo_ps_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ cairo_ps_surface_t *surface = 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,
_cairo_ps_surface_destroy,
@@ -408,5 +424,7 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
_cairo_ps_surface_fill_rectangles,
_cairo_ps_surface_composite_trapezoids,
_cairo_ps_surface_copy_page,
- _cairo_ps_surface_show_page
+ _cairo_ps_surface_show_page,
+ _cairo_ps_surface_set_clip_region,
+ _cairo_ps_surface_create_pattern
};
diff --git a/src/cairo_surface.c b/src/cairo_surface.c
index ff4f39c1..91ab8aba 100644
--- a/src/cairo_surface.c
+++ b/src/cairo_surface.c
@@ -38,6 +38,7 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->ref_count = 1;
_cairo_matrix_init (&surface->matrix);
+ surface->filter = CAIRO_FILTER_NEAREST;
surface->repeat = 0;
}
@@ -165,9 +166,16 @@ cairo_surface_set_filter (cairo_surface_t *surface, cairo_filter_t filter)
if (surface == NULL)
return CAIRO_STATUS_NULL_POINTER;
+ surface->filter = filter;
return surface->backend->set_filter (surface, filter);
}
+cairo_filter_t
+cairo_surface_get_filter (cairo_surface_t *surface)
+{
+ return surface->filter;
+}
+
/* XXX: NYI
cairo_status_t
cairo_surface_clip_rectangle (cairo_surface_t *surface,
@@ -364,3 +372,116 @@ _cairo_surface_show_page (cairo_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
}
+cairo_status_t
+_cairo_surface_set_clip_region (cairo_surface_t *surface, pixman_region16_t *region)
+{
+ 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 63df3ea4..9b44d38e 100644
--- a/src/cairo_traps.c
+++ b/src/cairo_traps.c
@@ -58,7 +58,7 @@ _compute_inverse_slope (cairo_line_t *l);
static double
_compute_x_intercept (cairo_line_t *l, double inverse_slope);
-static cairo_fixed_t
+static int
_line_segs_intersect_ceil (cairo_line_t *left, cairo_line_t *right, cairo_fixed_t *y_ret);
void
@@ -490,7 +490,7 @@ _line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_
*/
cairo_status_t
_cairo_traps_tessellate_polygon (cairo_traps_t *traps,
- cairo_polygon_t *poly,
+ cairo_polygon_t *poly,
cairo_fill_rule_t fill_rule)
{
cairo_status_t status;
@@ -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
new file mode 100644
index 00000000..ea1f72e1
--- /dev/null
+++ b/src/cairo_xcb_surface.c
@@ -0,0 +1,799 @@
+/*
+ * Copyright © 2002 University of Southern California
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * University of Southern California not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. The University of Southern
+ * California makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
+ * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@isi.edu>
+ */
+
+#include "cairoint.h"
+
+cairo_surface_t *
+cairo_xcb_surface_create (XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ cairo_format_t format);
+
+#define AllPlanes ((unsigned long)~0L)
+
+static XCBRenderPICTFORMAT
+format_from_visual(XCBConnection *c, XCBVISUALID visual)
+{
+ static const XCBRenderPICTFORMAT nil = { 0 };
+ XCBRenderQueryPictFormatsRep *r;
+ XCBRenderPICTSCREENIter si;
+ XCBRenderPICTDEPTHIter di;
+ XCBRenderPICTVISUALIter vi;
+
+ r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
+ if(!r)
+ return nil;
+
+ for(si = XCBRenderQueryPictFormatsScreens(r); si.rem; XCBRenderPICTSCREENNext(&si))
+ for(di = XCBRenderPICTSCREENDepths(si.data); di.rem; XCBRenderPICTDEPTHNext(&di))
+ for(vi = XCBRenderPICTDEPTHVisuals(di.data); vi.rem; XCBRenderPICTVISUALNext(&vi))
+ if(vi.data->visual.id == visual.id)
+ {
+ XCBRenderPICTFORMAT ret = vi.data->format;
+ free(r);
+ return ret;
+ }
+
+ return nil;
+}
+
+static XCBRenderPICTFORMAT
+format_from_cairo(XCBConnection *c, cairo_format_t fmt)
+{
+ XCBRenderPICTFORMAT ret = { 0 };
+ struct tmpl_t {
+ XCBRenderDIRECTFORMAT direct;
+ CARD8 depth;
+ };
+ static const struct tmpl_t templates[] = {
+ /* CAIRO_FORMAT_ARGB32 */
+ {
+ {
+ 16, 0xff,
+ 8, 0xff,
+ 0, 0xff,
+ 24, 0xff
+ },
+ 32
+ },
+ /* CAIRO_FORMAT_RGB24 */
+ {
+ {
+ 16, 0xff,
+ 8, 0xff,
+ 0, 0xff,
+ 0, 0x00
+ },
+ 24
+ },
+ /* CAIRO_FORMAT_A8 */
+ {
+ {
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0xff
+ },
+ 8
+ },
+ /* CAIRO_FORMAT_A1 */
+ {
+ {
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0x00,
+ 0, 0x01
+ },
+ 1
+ },
+ };
+ const struct tmpl_t *tmpl;
+ XCBRenderQueryPictFormatsRep *r;
+ XCBRenderPICTFORMINFOIter fi;
+
+ if(fmt < 0 || fmt >= (sizeof(templates) / sizeof(*templates)))
+ return ret;
+ tmpl = templates + fmt;
+
+ r = XCBRenderQueryPictFormatsReply(c, XCBRenderQueryPictFormats(c), 0);
+ if(!r)
+ return ret;
+
+ for(fi = XCBRenderQueryPictFormatsFormats(r); fi.rem; XCBRenderPICTFORMINFONext(&fi))
+ {
+ const XCBRenderDIRECTFORMAT *t, *f;
+ if(fi.data->type != XCBRenderPictTypeDirect)
+ continue;
+ if(fi.data->depth != tmpl->depth)
+ continue;
+ t = &tmpl->direct;
+ f = &fi.data->direct;
+ if(t->red_mask && (t->red_mask != f->red_mask || t->red_shift != f->red_shift))
+ continue;
+ if(t->green_mask && (t->green_mask != f->green_mask || t->green_shift != f->green_shift))
+ continue;
+ if(t->blue_mask && (t->blue_mask != f->blue_mask || t->blue_shift != f->blue_shift))
+ continue;
+ if(t->alpha_mask && (t->alpha_mask != f->alpha_mask || t->alpha_shift != f->alpha_shift))
+ continue;
+
+ ret = fi.data->id;
+ }
+
+ free(r);
+ return ret;
+}
+
+void
+cairo_set_target_xcb (cairo_t *cr,
+ XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ cairo_format_t format)
+{
+ cairo_surface_t *surface;
+
+ if (cr->status && cr->status != CAIRO_STATUS_NO_TARGET_SURFACE)
+ return;
+
+ surface = cairo_xcb_surface_create (dpy, drawable, visual, format);
+ if (surface == NULL) {
+ cr->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ cairo_set_target_surface (cr, surface);
+
+ /* cairo_set_target_surface takes a reference, so we must destroy ours */
+ cairo_surface_destroy (surface);
+}
+
+typedef struct cairo_xcb_surface {
+ cairo_surface_t base;
+
+ XCBConnection *dpy;
+ XCBGCONTEXT gc;
+ XCBDRAWABLE drawable;
+ int owns_pixmap;
+ XCBVISUALTYPE *visual;
+ cairo_format_t format;
+
+ int render_major;
+ int render_minor;
+
+ int width;
+ int height;
+
+ XCBRenderPICTURE picture;
+} cairo_xcb_surface_t;
+
+#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor) \
+ (((surface)->render_major > major) || \
+ (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
+
+#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+
+#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
+#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
+
+#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
+#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
+
+#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+
+#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+
+static int
+_CAIRO_FORMAT_DEPTH (cairo_format_t format)
+{
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ return 1;
+ case CAIRO_FORMAT_A8:
+ return 8;
+ case CAIRO_FORMAT_RGB24:
+ return 24;
+ case CAIRO_FORMAT_ARGB32:
+ default:
+ return 32;
+ }
+}
+
+static cairo_surface_t *
+_cairo_xcb_surface_create_similar (void *abstract_src,
+ cairo_format_t format,
+ int width,
+ int height)
+{
+ cairo_xcb_surface_t *src = abstract_src;
+ XCBConnection *dpy = src->dpy;
+ XCBDRAWABLE d;
+ cairo_xcb_surface_t *surface;
+
+ /* XXX: There's a pretty lame heuristic here. This assumes that
+ * all non-Render X servers do not support depth-32 pixmaps, (and
+ * that they do support depths 1, 8, and 24). Obviously, it would
+ * be much better to check the depths that are actually
+ * supported. */
+ if (!dpy
+ || (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)
+ && format == CAIRO_FORMAT_ARGB32))
+ {
+ return NULL;
+ }
+
+ d.pixmap = XCBPIXMAPNew (dpy);
+ XCBCreatePixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
+ d.pixmap, src->drawable,
+ width, height);
+
+ surface = (cairo_xcb_surface_t *)
+ cairo_xcb_surface_create (dpy, d, NULL, format);
+ surface->owns_pixmap = 1;
+
+ surface->width = width;
+ surface->height = height;
+
+ return &surface->base;
+}
+
+static void
+_cairo_xcb_surface_destroy (void *abstract_surface)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ if (surface->picture.xid)
+ XCBRenderFreePicture (surface->dpy, surface->picture);
+
+ if (surface->owns_pixmap)
+ XCBFreePixmap (surface->dpy, surface->drawable.pixmap);
+
+ if (surface->gc.xid)
+ XCBFreeGC (surface->dpy, surface->gc);
+
+ surface->dpy = 0;
+
+ free (surface);
+}
+
+static double
+_cairo_xcb_surface_pixels_per_inch (void *abstract_surface)
+{
+ /* XXX: We should really get this value from somewhere like Xft.dpy */
+ return 96.0;
+}
+
+static int
+bits_per_pixel(XCBConnection *c, int depth)
+{
+ XCBFORMAT *fmt = XCBConnSetupSuccessRepPixmapFormats(XCBGetSetup(c));
+ XCBFORMAT *fmtend = fmt + XCBConnSetupSuccessRepPixmapFormatsLength(XCBGetSetup(c));
+
+ for(; fmt != fmtend; ++fmt)
+ if(fmt->depth == depth)
+ return fmt->bits_per_pixel;
+
+ if(depth <= 4)
+ return 4;
+ if(depth <= 8)
+ return 8;
+ if(depth <= 16)
+ return 16;
+ return 32;
+}
+
+static int
+bytes_per_line(XCBConnection *c, int width, int bpp)
+{
+ int bitmap_pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
+ return (bpp * width + bitmap_pad - 1) & -bitmap_pad;
+}
+
+static cairo_image_surface_t *
+_cairo_xcb_surface_get_image (void *abstract_surface)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ cairo_image_surface_t *image;
+ XCBGetGeometryRep *geomrep;
+ XCBGetImageRep *imagerep;
+ int bpp;
+
+ geomrep = XCBGetGeometryReply(surface->dpy, XCBGetGeometry(surface->dpy, surface->drawable), 0);
+ if(!geomrep)
+ return 0;
+
+ surface->width = geomrep->width;
+ surface->height = geomrep->height;
+ free(geomrep);
+
+ imagerep = XCBGetImageReply(surface->dpy,
+ XCBGetImage(surface->dpy, ZPixmap,
+ surface->drawable,
+ 0, 0,
+ surface->width, surface->height,
+ AllPlanes), 0);
+ if(!imagerep)
+ return 0;
+
+ bpp = bits_per_pixel(surface->dpy, imagerep->depth);
+
+ if (surface->visual) {
+ cairo_format_masks_t masks;
+
+ /* XXX: Add support here for pictures with external alpha? */
+
+ masks.bpp = bpp;
+ masks.alpha_mask = 0;
+ masks.red_mask = surface->visual->red_mask;
+ masks.green_mask = surface->visual->green_mask;
+ masks.blue_mask = surface->visual->blue_mask;
+
+ image = _cairo_image_surface_create_with_masks (XCBGetImageData(imagerep),
+ &masks,
+ surface->width,
+ surface->height,
+ bytes_per_line(surface->dpy, surface->width, bpp));
+ } else {
+ image = (cairo_image_surface_t *)
+ cairo_image_surface_create_for_data (XCBGetImageData(imagerep),
+ surface->format,
+ surface->width,
+ surface->height,
+ bytes_per_line(surface->dpy, surface->width, bpp));
+ }
+
+ /* Let the surface take ownership of the data */
+ /* XXX: Can probably come up with a cleaner API here. */
+ _cairo_image_surface_assume_ownership_of_data (image);
+ /* FIXME: imagerep can't be freed correctly, I think. must copy. :-( */
+
+ _cairo_image_surface_set_repeat (image, surface->base.repeat);
+ _cairo_image_surface_set_matrix (image, &(surface->base.matrix));
+
+ return image;
+}
+
+static void
+_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
+{
+ if (surface->gc.xid)
+ return;
+
+ surface->gc = XCBGCONTEXTNew(surface->dpy);
+ XCBCreateGC (surface->dpy, surface->gc, surface->drawable, 0, 0);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_image (void *abstract_surface,
+ cairo_image_surface_t *image)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ int bpp, data_len;
+
+ _cairo_xcb_surface_ensure_gc (surface);
+ bpp = bits_per_pixel(surface->dpy, image->depth);
+ data_len = bytes_per_line(surface->dpy, surface->width, bpp) * surface->height;
+ XCBPutImage(surface->dpy, ZPixmap, surface->drawable, surface->gc,
+ image->width,
+ image->height,
+ /* dst_x */ 0, /* dst_y */ 0,
+ /* left_pad */ 0, image->depth,
+ data_len, image->data);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_matrix (void *abstract_surface, cairo_matrix_t *matrix)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ XCBRenderTRANSFORM xtransform;
+
+ if (!surface->picture.xid)
+ return CAIRO_STATUS_SUCCESS;
+
+ xtransform.matrix11 = _cairo_fixed_from_double (matrix->m[0][0]);
+ xtransform.matrix12 = _cairo_fixed_from_double (matrix->m[1][0]);
+ xtransform.matrix13 = _cairo_fixed_from_double (matrix->m[2][0]);
+
+ xtransform.matrix21 = _cairo_fixed_from_double (matrix->m[0][1]);
+ xtransform.matrix22 = _cairo_fixed_from_double (matrix->m[1][1]);
+ xtransform.matrix23 = _cairo_fixed_from_double (matrix->m[2][1]);
+
+ xtransform.matrix31 = 0;
+ xtransform.matrix32 = 0;
+ xtransform.matrix33 = _cairo_fixed_from_double (1);
+
+ if (CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
+ {
+ XCBRenderSetPictureTransform (surface->dpy, surface->picture, xtransform);
+ } else {
+ /* XXX: Need support here if using an old RENDER without support
+ for SetPictureTransform */
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ char *render_filter;
+
+ if (!(surface->picture.xid
+ && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
+ return CAIRO_STATUS_SUCCESS;
+
+ switch (filter) {
+ case CAIRO_FILTER_FAST:
+ render_filter = "fast";
+ break;
+ case CAIRO_FILTER_GOOD:
+ render_filter = "good";
+ break;
+ case CAIRO_FILTER_BEST:
+ render_filter = "best";
+ break;
+ case CAIRO_FILTER_NEAREST:
+ render_filter = "nearest";
+ break;
+ case CAIRO_FILTER_BILINEAR:
+ render_filter = "bilinear";
+ break;
+ default:
+ render_filter = "best";
+ break;
+ }
+
+ XCBRenderSetPictureFilter(surface->dpy, surface->picture,
+ strlen(render_filter), 0, render_filter, NULL);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_set_repeat (void *abstract_surface, int repeat)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+
+ CARD32 mask = XCBRenderCPRepeat;
+ CARD32 pa[] = { repeat };
+
+ if (!surface->picture.xid)
+ return CAIRO_STATUS_SUCCESS;
+
+ XCBRenderChangePicture (surface->dpy, surface->picture, mask, pa);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_surface_t *
+_cairo_xcb_surface_clone_similar (cairo_surface_t *src,
+ cairo_xcb_surface_t *template,
+ cairo_format_t format,
+ int depth)
+{
+ cairo_xcb_surface_t *clone;
+ cairo_image_surface_t *src_image;
+
+ src_image = _cairo_surface_get_image (src);
+
+ clone = (cairo_xcb_surface_t *)
+ _cairo_xcb_surface_create_similar (template, format,
+ src_image->width,
+ src_image->height);
+ if (clone == NULL)
+ return NULL;
+
+ _cairo_xcb_surface_set_filter (clone, cairo_surface_get_filter(src));
+
+ _cairo_xcb_surface_set_image (clone, src_image);
+
+ _cairo_xcb_surface_set_matrix (clone, &(src_image->base.matrix));
+
+ cairo_surface_destroy (&src_image->base);
+
+ return clone;
+}
+
+static int
+_render_operator (cairo_operator_t operator)
+{
+ switch (operator) {
+ case CAIRO_OPERATOR_CLEAR:
+ return XCBRenderPictOpClear;
+ case CAIRO_OPERATOR_SRC:
+ return XCBRenderPictOpSrc;
+ case CAIRO_OPERATOR_DST:
+ return XCBRenderPictOpDst;
+ case CAIRO_OPERATOR_OVER:
+ return XCBRenderPictOpOver;
+ case CAIRO_OPERATOR_OVER_REVERSE:
+ return XCBRenderPictOpOverReverse;
+ case CAIRO_OPERATOR_IN:
+ return XCBRenderPictOpIn;
+ case CAIRO_OPERATOR_IN_REVERSE:
+ return XCBRenderPictOpInReverse;
+ case CAIRO_OPERATOR_OUT:
+ return XCBRenderPictOpOut;
+ case CAIRO_OPERATOR_OUT_REVERSE:
+ return XCBRenderPictOpOutReverse;
+ case CAIRO_OPERATOR_ATOP:
+ return XCBRenderPictOpAtop;
+ case CAIRO_OPERATOR_ATOP_REVERSE:
+ return XCBRenderPictOpAtopReverse;
+ case CAIRO_OPERATOR_XOR:
+ return XCBRenderPictOpXor;
+ case CAIRO_OPERATOR_ADD:
+ return XCBRenderPictOpAdd;
+ case CAIRO_OPERATOR_SATURATE:
+ return XCBRenderPictOpSaturate;
+ default:
+ return XCBRenderPictOpOver;
+ }
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_composite (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ cairo_surface_t *generic_mask,
+ void *abstract_dst,
+ int src_x,
+ int src_y,
+ int mask_x,
+ int mask_y,
+ int dst_x,
+ int dst_y,
+ unsigned int width,
+ unsigned int height)
+{
+ cairo_xcb_surface_t *dst = abstract_dst;
+ cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
+ cairo_xcb_surface_t *mask = (cairo_xcb_surface_t *) generic_mask;
+ cairo_xcb_surface_t *src_clone = NULL;
+ cairo_xcb_surface_t *mask_clone = NULL;
+ XCBRenderPICTURE maskpict = { 0 };
+
+
+ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
+ src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
+ CAIRO_FORMAT_ARGB32, 32);
+ if (!src_clone)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ src = src_clone;
+ }
+ if (generic_mask && (generic_mask->backend != dst->base.backend || mask->dpy != dst->dpy)) {
+ mask_clone = _cairo_xcb_surface_clone_similar (generic_mask, dst,
+ CAIRO_FORMAT_A8, 8);
+ if (!mask_clone)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ mask = mask_clone;
+ }
+
+ if(mask)
+ maskpict = mask->picture;
+
+ XCBRenderComposite (dst->dpy,
+ _render_operator (operator),
+ src->picture,
+ maskpict,
+ dst->picture,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y,
+ width, height);
+
+ /* XXX: This is messed up. If I can xcb_surface_create, then I
+ should be able to xcb_surface_destroy. */
+ if (src_clone)
+ cairo_surface_destroy (&src_clone->base);
+ if (mask_clone)
+ cairo_surface_destroy (&mask_clone->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t operator,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
+{
+ cairo_xcb_surface_t *surface = abstract_surface;
+ XCBRenderCOLOR render_color;
+
+ if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ render_color.red = color->red_short;
+ render_color.green = color->green_short;
+ render_color.blue = color->blue_short;
+ render_color.alpha = color->alpha_short;
+
+ /* XXX: This XCBRECTANGLE cast is evil... it needs to go away somehow. */
+ XCBRenderFillRectangles (surface->dpy,
+ _render_operator (operator),
+ surface->picture,
+ render_color, num_rects, (XCBRECTANGLE *) rects);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_composite_trapezoids (cairo_operator_t operator,
+ cairo_surface_t *generic_src,
+ void *abstract_dst,
+ int xSrc,
+ int ySrc,
+ cairo_trapezoid_t *traps,
+ int num_traps)
+{
+ cairo_xcb_surface_t *dst = abstract_dst;
+ cairo_xcb_surface_t *src = (cairo_xcb_surface_t *) generic_src;
+ cairo_xcb_surface_t *src_clone = NULL;
+
+ if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (generic_src->backend != dst->base.backend || src->dpy != dst->dpy) {
+ src_clone = _cairo_xcb_surface_clone_similar (generic_src, dst,
+ CAIRO_FORMAT_ARGB32, 32);
+ if (!src_clone)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ src = src_clone;
+ }
+
+ /* XXX: The XCBRenderTRAP cast is evil and needs to go away somehow. */
+ /* XXX: format_from_cairo is slow. should cache something. */
+ XCBRenderTrapezoids (dst->dpy,
+ _render_operator (operator),
+ src->picture, dst->picture,
+ format_from_cairo (dst->dpy, CAIRO_FORMAT_A8),
+ xSrc, ySrc, num_traps, (XCBRenderTRAP *) traps);
+
+ /* XXX: This is messed up. If I can xcb_surface_create, then I
+ should be able to xcb_surface_destroy. */
+ if (src_clone)
+ cairo_surface_destroy (&src_clone->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_copy_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_show_page (void *abstract_surface)
+{
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ /* FIXME */
+ 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,
+ _cairo_xcb_surface_pixels_per_inch,
+ _cairo_xcb_surface_get_image,
+ _cairo_xcb_surface_set_image,
+ _cairo_xcb_surface_set_matrix,
+ _cairo_xcb_surface_set_filter,
+ _cairo_xcb_surface_set_repeat,
+ _cairo_xcb_surface_composite,
+ _cairo_xcb_surface_fill_rectangles,
+ _cairo_xcb_surface_composite_trapezoids,
+ _cairo_xcb_surface_copy_page,
+ _cairo_xcb_surface_show_page,
+ _cairo_xcb_surface_set_clip_region,
+ _cairo_xcb_surface_create_pattern
+};
+
+static void
+query_render_version (XCBConnection *c, cairo_xcb_surface_t *surface)
+{
+ XCBRenderQueryVersionRep *r;
+
+ surface->render_major = -1;
+ surface->render_minor = -1;
+
+ if (!XCBRenderInit(c))
+ return;
+
+ r = XCBRenderQueryVersionReply(c, XCBRenderQueryVersion(c, 0, 6), 0);
+ if (!r)
+ return;
+
+ surface->render_major = r->major_version;
+ surface->render_minor = r->minor_version;
+ free(r);
+}
+
+cairo_surface_t *
+cairo_xcb_surface_create (XCBConnection *dpy,
+ XCBDRAWABLE drawable,
+ XCBVISUALTYPE *visual,
+ cairo_format_t format)
+{
+ cairo_xcb_surface_t *surface;
+
+ surface = malloc (sizeof (cairo_xcb_surface_t));
+ if (surface == NULL)
+ return NULL;
+
+ _cairo_surface_init (&surface->base, &cairo_xcb_surface_backend);
+
+ surface->dpy = dpy;
+ surface->gc.xid = 0;
+ surface->drawable = drawable;
+ surface->owns_pixmap = 0;
+ surface->visual = visual;
+ surface->format = format;
+
+ query_render_version(dpy, surface);
+
+ if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
+ {
+ XCBRenderPICTFORMAT fmt;
+ if(visual)
+ fmt = format_from_visual (dpy, visual->visual_id);
+ else
+ fmt = format_from_cairo (dpy, format);
+ surface->picture = XCBRenderPICTURENew(dpy);
+ XCBRenderCreatePicture (dpy, surface->picture, drawable,
+ fmt, 0, NULL);
+ }
+ else
+ surface->picture.xid = 0;
+
+ return (cairo_surface_t *) surface;
+}
diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c
index 49abdb56..19dfde50 100644
--- a/src/cairo_xlib_surface.c
+++ b/src/cairo_xlib_surface.c
@@ -90,6 +90,7 @@ typedef struct cairo_xlib_surface {
#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
+#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface) CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
static int
_CAIRO_FORMAT_DEPTH (cairo_format_t format)
@@ -257,7 +258,7 @@ _cairo_xlib_surface_set_image (void *abstract_surface,
ximage = XCreateImage (surface->dpy,
DefaultVisual(surface->dpy, DefaultScreen(surface->dpy)),
- image->depth == 32 ? 24 : image->depth,
+ image->depth,
ZPixmap,
0,
image->data,
@@ -320,26 +321,29 @@ _cairo_xlib_surface_set_filter (void *abstract_surface, cairo_filter_t filter)
cairo_xlib_surface_t *surface = abstract_surface;
char *render_filter;
- if (!surface->picture)
+ if (!(surface->picture
+ && CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)))
return CAIRO_STATUS_SUCCESS;
-
- /* XXX: The Render specification has capitalized versions of these
- strings. However, the current implementation is
- case-sensitive and expects lowercase versions.
- */
+
switch (filter) {
case CAIRO_FILTER_FAST:
- render_filter = "fast";
+ render_filter = FilterFast;
+ break;
case CAIRO_FILTER_GOOD:
- render_filter = "good";
+ render_filter = FilterGood;
+ break;
case CAIRO_FILTER_BEST:
- render_filter = "best";
+ render_filter = FilterBest;
+ break;
case CAIRO_FILTER_NEAREST:
- render_filter = "nearest";
+ render_filter = FilterNearest;
+ break;
case CAIRO_FILTER_BILINEAR:
- render_filter = "bilinear";
+ render_filter = FilterBilinear;
+ break;
default:
- render_filter = "best";
+ render_filter = FilterBest;
+ break;
}
XRenderSetPictureFilter (surface->dpy, surface->picture,
@@ -384,6 +388,8 @@ _cairo_xlib_surface_clone_similar (cairo_surface_t *src,
if (clone == NULL)
return NULL;
+ _cairo_xlib_surface_set_filter (clone, cairo_surface_get_filter(src));
+
_cairo_xlib_surface_set_image (clone, src_image);
_cairo_xlib_surface_set_matrix (clone, &(src_image->base.matrix));
@@ -567,6 +573,60 @@ _cairo_xlib_surface_show_page (void *abstract_surface)
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+static cairo_int_status_t
+_cairo_xlib_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ Region xregion;
+ XRectangle xr;
+ pixman_box16_t *box;
+ cairo_xlib_surface_t *surf;
+ int n, m;
+
+ surf = (cairo_xlib_surface_t *) abstract_surface;
+
+ if (region == NULL) {
+ /* NULL region == reset the clip */
+ xregion = XCreateRegion();
+ xr.x = 0;
+ xr.y = 0;
+ xr.width = surf->width;
+ xr.height = surf->height;
+ XUnionRectWithRegion (&xr, xregion, xregion);
+ } else {
+ n = pixman_region_num_rects (region);
+ /* XXX: Are we sure these are the semantics we want for an
+ * empty, (not null) region? */
+ if (n == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ box = pixman_region_rects (region);
+ xregion = XCreateRegion();
+
+ m = n;
+ for (; n > 0; --n, ++box) {
+ xr.x = (short) box->x1;
+ xr.y = (short) box->y1;
+ xr.width = (unsigned short) (box->x2 - box->x1);
+ xr.height = (unsigned short) (box->y2 - box->y1);
+ XUnionRectWithRegion (&xr, xregion, xregion);
+ }
+ }
+
+ XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
+ XDestroyRegion(xregion);
+
+ 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,
@@ -580,7 +640,9 @@ static const struct cairo_surface_backend cairo_xlib_surface_backend = {
_cairo_xlib_surface_fill_rectangles,
_cairo_xlib_surface_composite_trapezoids,
_cairo_xlib_surface_copy_page,
- _cairo_xlib_surface_show_page
+ _cairo_xlib_surface_show_page,
+ _cairo_xlib_surface_set_clip_region,
+ _cairo_xlib_surface_create_pattern
};
cairo_surface_t *
diff --git a/src/cairoint.h b/src/cairoint.h
index 036bff21..5b4ccb56 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -43,7 +43,33 @@
#include "cairo.h"
-#include <slim_internal.h>
+#if __GNUC__ >= 3 && defined(__ELF__)
+# define slim_hidden_proto(name) slim_hidden_proto1(name, INT_##name)
+# define slim_hidden_def(name) slim_hidden_def1(name, INT_##name)
+# define slim_hidden_proto1(name, internal) \
+ extern __typeof (name) name \
+ __asm__ (slim_hidden_asmname (internal)) \
+ __internal_linkage;
+# define slim_hidden_def1(name, internal) \
+ extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
+ __attribute__((__alias__(slim_hidden_asmname(internal))))
+# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__)
+# define slim_hidden_ulp1(x) slim_hidden_ulp2(x)
+# define slim_hidden_ulp2(x) #x
+# define slim_hidden_asmname(name) slim_hidden_asmname1(name)
+# define slim_hidden_asmname1(name) slim_hidden_ulp #name
+#else
+# define slim_hidden_proto(name)
+# define slim_hidden_def(name)
+#endif
+
+/* slim_internal.h */
+#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
+#define __internal_linkage __attribute__((__visibility__("hidden")))
+#else
+#define __internal_linkage
+#endif
+
/* These macros allow us to deprecate a function by providing an alias
for the old function name to the new function name. With this
@@ -102,17 +128,22 @@ typedef struct cairo_slope
{
cairo_fixed_t dx;
cairo_fixed_t dy;
-} cairo_slope_t;
+} cairo_slope_t, cairo_distance_t;
typedef struct cairo_point_double {
double x;
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;
@@ -144,18 +175,6 @@ typedef enum cairo_direction {
CAIRO_DIRECTION_REVERSE
} cairo_direction_t;
-typedef enum cairo_sub_path_done {
- CAIRO_SUB_PATH_DONE_CAP,
- CAIRO_SUB_PATH_DONE_JOIN
-} cairo_sub_path_done_t;
-
-typedef struct cairo_path_callbacks {
- cairo_status_t (*add_edge) (void *closure, cairo_point_t *p1, cairo_point_t *p2);
- cairo_status_t (*add_spline) (void *closure, cairo_point_t *a, cairo_point_t *b, cairo_point_t *c, cairo_point_t *d);
- cairo_status_t (*done_sub_path) (void *closure, cairo_sub_path_done_t done);
- cairo_status_t (*done_path) (void *closure);
-} cairo_path_callbacks_t;
-
#define CAIRO_PATH_BUF_SZ 64
typedef struct cairo_path_op_buf {
@@ -178,6 +197,10 @@ typedef struct cairo_path {
cairo_path_arg_buf_t *arg_head;
cairo_path_arg_buf_t *arg_tail;
+
+ cairo_point_t last_move_point;
+ cairo_point_t current_point;
+ int has_current_point;
} cairo_path_t;
typedef struct cairo_edge {
@@ -193,9 +216,8 @@ typedef struct cairo_polygon {
cairo_edge_t *edges;
cairo_point_t first_point;
- int first_point_defined;
- cairo_point_t last_point;
- int last_point_defined;
+ cairo_point_t current_point;
+ int has_current_point;
int closed;
} cairo_polygon_t;
@@ -229,53 +251,51 @@ typedef struct cairo_pen {
typedef struct cairo_color cairo_color_t;
typedef struct cairo_font_backend {
+ cairo_font_t *(*create) (const char *family,
+ cairo_font_slant_t slant,
+ cairo_font_weight_t weight);
+
+ cairo_font_t *(*copy) (void *font);
- cairo_status_t (*font_extents) (cairo_font_t *font,
- cairo_font_extents_t *extents);
+ void (*destroy) (void *font);
- cairo_status_t (*text_extents) (cairo_font_t *font,
- const unsigned char *utf8,
- cairo_text_extents_t *extents);
-
- cairo_status_t (*glyph_extents) (cairo_font_t *font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_text_extents_t *extents);
+ cairo_status_t (*font_extents) (void *font,
+ cairo_font_extents_t *extents);
+
+ cairo_status_t (*text_extents) (void *font,
+ const unsigned char *utf8,
+ cairo_text_extents_t *extents);
- cairo_status_t (*show_text) (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_surface_t *source,
- cairo_surface_t *surface,
- double x,
- double y,
- const unsigned char *utf8);
-
- cairo_status_t (*show_glyphs) (cairo_font_t *font,
- cairo_operator_t operator,
- cairo_surface_t *source,
- cairo_surface_t *surface,
- double x,
- double y,
- const cairo_glyph_t *glyphs,
- int num_glyphs);
+ cairo_status_t (*glyph_extents) (void *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_text_extents_t *extents);
- cairo_status_t (*text_path) (cairo_font_t *font,
- cairo_path_t *path,
- const unsigned char *utf8);
-
- cairo_status_t (*glyph_path) (cairo_font_t *font,
- cairo_path_t *path,
- cairo_glyph_t *glyphs,
- int num_glyphs);
-
- cairo_font_t *(*create) (const char *family,
- cairo_font_slant_t slant,
- cairo_font_weight_t weight);
-
- cairo_font_t *(*copy) (cairo_font_t *other);
-
- void (*destroy) (cairo_font_t *font);
+ cairo_status_t (*show_text) (void *font,
+ cairo_operator_t operator,
+ cairo_surface_t *source,
+ cairo_surface_t *surface,
+ double x,
+ double y,
+ const unsigned char *utf8);
+
+ cairo_status_t (*show_glyphs) (void *font,
+ cairo_operator_t operator,
+ cairo_surface_t *source,
+ cairo_surface_t *surface,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs);
+ cairo_status_t (*text_path) (void *font,
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_path_t *path);
+
+ cairo_status_t (*glyph_path) (void *font,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_path_t *path);
} cairo_font_backend_t;
/* concrete font backends */
@@ -357,6 +377,14 @@ typedef struct cairo_surface_backend {
cairo_int_status_t
(*show_page) (void *surface);
+
+ 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 {
@@ -377,6 +405,7 @@ struct cairo_surface {
unsigned int ref_count;
cairo_matrix_t matrix;
+ cairo_filter_t filter;
int repeat;
};
@@ -392,7 +421,7 @@ struct cairo_image_surface {
int stride;
int depth;
- IcImage *ic_image;
+ pixman_image_t *pixman_image;
};
/* XXX: Right now, the cairo_color structure puts unpremultiplied
@@ -413,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;
@@ -447,6 +529,7 @@ typedef struct cairo_clip_rec {
int y;
int width;
int height;
+ pixman_region16_t *region;
cairo_surface_t *surface;
} cairo_clip_rec_t;
@@ -471,25 +554,18 @@ 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;
cairo_path_t path;
- cairo_point_double_t last_move_point;
- cairo_point_double_t current_point;
- int has_current_point;
-
cairo_pen_t pen_regular;
struct cairo_gstate *next;
@@ -509,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);
@@ -516,6 +596,9 @@ _cairo_fixed_from_int (int i);
extern cairo_fixed_t
_cairo_fixed_from_double (double d);
+cairo_fixed_t
+_cairo_fixed_from_26_6 (uint32_t i);
+
extern double
_cairo_fixed_to_double (cairo_fixed_t f);
@@ -554,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);
@@ -705,6 +791,14 @@ extern cairo_status_t __internal_linkage
_cairo_gstate_current_point (cairo_gstate_t *gstate, double *x, double *y);
extern cairo_status_t __internal_linkage
+_cairo_gstate_interpret_path (cairo_gstate_t *gstate,
+ cairo_move_to_func_t *move_to,
+ cairo_line_to_func_t *line_to,
+ cairo_curve_to_func_t *curve_to,
+ cairo_close_path_func_t *close_path,
+ void *closure);
+
+extern cairo_status_t __internal_linkage
_cairo_gstate_stroke (cairo_gstate_t *gstate);
extern cairo_status_t __internal_linkage
@@ -717,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,
@@ -729,6 +833,9 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate,
int *inside_ret);
extern cairo_status_t __internal_linkage
+_cairo_gstate_init_clip (cairo_gstate_t *gstate);
+
+extern cairo_status_t __internal_linkage
_cairo_gstate_clip (cairo_gstate_t *gstate);
extern cairo_status_t __internal_linkage
@@ -739,7 +846,7 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
extern cairo_status_t __internal_linkage
_cairo_gstate_select_font (cairo_gstate_t *gstate,
- char *family,
+ const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
@@ -813,7 +920,7 @@ _cairo_color_set_alpha (cairo_color_t *color, double alpha);
/* cairo_font.c */
extern cairo_font_t * __internal_linkage
-_cairo_font_create (char *family,
+_cairo_font_create (const char *family,
cairo_font_slant_t slant,
cairo_font_weight_t weight);
@@ -860,23 +967,22 @@ _cairo_font_show_glyphs (cairo_font_t *font,
cairo_operator_t operator,
cairo_surface_t *source,
cairo_surface_t *surface,
- double x,
- double y,
cairo_glyph_t *glyphs,
int num_glyphs);
extern cairo_int_status_t __internal_linkage
_cairo_font_text_path (cairo_font_t *font,
- cairo_path_t *path,
- const unsigned char *utf8);
+ double x,
+ double y,
+ const unsigned char *utf8,
+ cairo_path_t *path);
extern cairo_int_status_t __internal_linkage
_cairo_font_glyph_path (cairo_font_t *font,
- cairo_path_t *path,
cairo_glyph_t *glyphs,
- int num_glyphs);
-
+ int num_glyphs,
+ cairo_path_t *path);
/* cairo_hull.c */
extern cairo_status_t
@@ -893,25 +999,56 @@ extern void __internal_linkage
_cairo_path_fini (cairo_path_t *path);
extern cairo_status_t __internal_linkage
-_cairo_path_move_to (cairo_path_t *path, double x, double y);
+_cairo_path_move_to (cairo_path_t *path, cairo_point_t *point);
+
+extern cairo_status_t __internal_linkage
+_cairo_path_rel_move_to (cairo_path_t *path, cairo_slope_t *slope);
extern cairo_status_t __internal_linkage
-_cairo_path_line_to (cairo_path_t *path, double x, double y);
+_cairo_path_line_to (cairo_path_t *path, cairo_point_t *point);
+
+extern cairo_status_t __internal_linkage
+_cairo_path_rel_line_to (cairo_path_t *path, cairo_slope_t *slope);
extern cairo_status_t __internal_linkage
_cairo_path_curve_to (cairo_path_t *path,
- double x1, double y1,
- double x2, double y2,
- double x3, double y3);
+ cairo_point_t *p0,
+ cairo_point_t *p1,
+ cairo_point_t *p2);
+
+extern cairo_status_t __internal_linkage
+_cairo_path_rel_curve_to (cairo_path_t *path,
+ cairo_slope_t *s0,
+ cairo_slope_t *s1,
+ cairo_slope_t *s2);
extern cairo_status_t __internal_linkage
_cairo_path_close_path (cairo_path_t *path);
extern cairo_status_t __internal_linkage
-_cairo_path_interpret (cairo_path_t *path,
- cairo_direction_t dir,
- const cairo_path_callbacks_t *cb,
- void *closure);
+_cairo_path_current_point (cairo_path_t *path, cairo_point_t *point);
+
+typedef cairo_status_t (cairo_path_move_to_func_t) (void *closure,
+ cairo_point_t *point);
+
+typedef cairo_status_t (cairo_path_line_to_func_t) (void *closure,
+ cairo_point_t *point);
+
+typedef cairo_status_t (cairo_path_curve_to_func_t) (void *closure,
+ cairo_point_t *p0,
+ cairo_point_t *p1,
+ cairo_point_t *p2);
+
+typedef cairo_status_t (cairo_path_close_path_func_t) (void *closure);
+
+extern cairo_status_t __internal_linkage
+_cairo_path_interpret (cairo_path_t *path,
+ cairo_direction_t dir,
+ cairo_path_move_to_func_t *move_to,
+ cairo_path_line_to_func_t *line_to,
+ cairo_path_curve_to_func_t *curve_to,
+ cairo_path_close_path_func_t *close_path,
+ void *closure);
extern cairo_status_t __internal_linkage
_cairo_path_bounds (cairo_path_t *path, double *x1, double *y1, double *x2, double *y2);
@@ -991,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
@@ -1007,7 +1152,7 @@ extern cairo_status_t __internal_linkage
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
cairo_matrix_t *matrix);
-cairo_status_t
+extern cairo_status_t __internal_linkage
_cairo_image_surface_set_filter (cairo_image_surface_t *surface,
cairo_filter_t filter);
@@ -1015,6 +1160,10 @@ extern cairo_status_t __internal_linkage
_cairo_image_surface_set_repeat (cairo_image_surface_t *surface,
int repeat);
+extern cairo_int_status_t __internal_linkage
+_cairo_image_surface_set_clip_region (cairo_image_surface_t *surface,
+ pixman_region16_t *region);
+
/* cairo_pen.c */
extern cairo_status_t __internal_linkage
_cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate);
@@ -1065,7 +1214,10 @@ extern cairo_status_t __internal_linkage
_cairo_polygon_add_edge (cairo_polygon_t *polygon, cairo_point_t *p1, cairo_point_t *p2);
extern cairo_status_t __internal_linkage
-_cairo_polygon_add_point (cairo_polygon_t *polygon, cairo_point_t *point);
+_cairo_polygon_move_to (cairo_polygon_t *polygon, cairo_point_t *point);
+
+extern cairo_status_t __internal_linkage
+_cairo_polygon_line_to (cairo_polygon_t *polygon, cairo_point_t *point);
extern cairo_status_t __internal_linkage
_cairo_polygon_close (cairo_polygon_t *polygon);
@@ -1114,6 +1266,9 @@ _cairo_matrix_compute_determinant (cairo_matrix_t *matrix, double *det);
extern cairo_status_t __internal_linkage
_cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, double *lambda2);
+extern cairo_status_t __internal_linkage
+_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy);
+
/* cairo_traps.c */
extern void __internal_linkage
_cairo_traps_init (cairo_traps_t *traps);
@@ -1135,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);
@@ -1148,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)