summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in40
-rw-r--r--src/Makefile.sources1
-rw-r--r--src/cairo-cff-subset.c6
-rw-r--r--src/cairo-cogl-surface.c6
-rw-r--r--src/cairo-composite-rectangles.c7
-rw-r--r--src/cairo-compositor-private.h3
-rw-r--r--src/cairo-damage-private.h3
-rw-r--r--src/cairo-damage.c7
-rw-r--r--src/cairo-default-context.c23
-rw-r--r--src/cairo-egl-context.c59
-rw-r--r--src/cairo-ft-font.c98
-rw-r--r--src/cairo-gl-composite.c497
-rw-r--r--src/cairo-gl-device.c63
-rw-r--r--src/cairo-gl-dispatch-private.h10
-rw-r--r--src/cairo-gl-dispatch.c26
-rw-r--r--src/cairo-gl-glyphs.c29
-rw-r--r--src/cairo-gl-gradient.c2
-rw-r--r--src/cairo-gl-msaa-compositor.c266
-rw-r--r--src/cairo-gl-operand.c70
-rw-r--r--src/cairo-gl-private.h107
-rw-r--r--src/cairo-gl-shaders.c80
-rw-r--r--src/cairo-gl-source.c3
-rw-r--r--src/cairo-gl-spans-compositor.c130
-rw-r--r--src/cairo-gl-surface.c148
-rw-r--r--src/cairo-gl-traps-compositor.c65
-rw-r--r--src/cairo-glx-context.c73
-rw-r--r--src/cairo-gstate.c24
-rw-r--r--src/cairo-image-compositor.c278
-rw-r--r--src/cairo-image-surface-private.h7
-rw-r--r--src/cairo-image-surface.c64
-rw-r--r--src/cairo-mask-compositor.c92
-rw-r--r--src/cairo-mempool.c9
-rw-r--r--src/cairo-path-fixed-private.h17
-rw-r--r--src/cairo-path-fixed.c136
-rw-r--r--src/cairo-path-stroke-polygon.c2
-rw-r--r--src/cairo-path-stroke-traps.c1122
-rw-r--r--src/cairo-path-stroke.c29
-rw-r--r--src/cairo-pen.c62
-rw-r--r--src/cairo-polygon.c48
-rw-r--r--src/cairo-qt-surface.cpp210
-rw-r--r--src/cairo-recording-surface.c21
-rw-r--r--src/cairo-rectangle.c2
-rw-r--r--src/cairo-scaled-font.c104
-rw-r--r--src/cairo-script-surface.c4
-rw-r--r--src/cairo-spans-compositor-private.h2
-rw-r--r--src/cairo-spans-compositor.c21
-rw-r--r--src/cairo-stroke-style.c39
-rw-r--r--src/cairo-surface.c20
-rw-r--r--src/cairo-traps-compositor.c37
-rw-r--r--src/cairo-traps-private.h9
-rw-r--r--src/cairo-traps.c252
-rw-r--r--src/cairo-type1-subset.c314
-rw-r--r--src/cairo-xcb-connection-core.c72
-rw-r--r--src/cairo-xcb-shm.c14
-rw-r--r--src/cairo-xcb-surface-render.c16
-rw-r--r--src/cairo-xcb-surface.c5
-rw-r--r--src/cairo-xlib-core-compositor.c79
-rw-r--r--src/cairo-xlib-display.c36
-rw-r--r--src/cairo-xlib-private.h23
-rw-r--r--src/cairo-xlib-render-compositor.c116
-rw-r--r--src/cairo-xlib-source.c171
-rw-r--r--src/cairo-xlib-surface-shm.c386
-rw-r--r--src/cairo-xlib-surface.c97
-rw-r--r--src/cairoint.h24
-rw-r--r--src/test-base-compositor-surface.c8
-rw-r--r--src/win32/cairo-win32-device.c6
-rw-r--r--src/win32/cairo-win32-display-surface.c11
67 files changed, 4638 insertions, 1173 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index 52f3d39..9ad7dd7 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -473,12 +473,13 @@ am__libcairo_la_SOURCES_DIST = cairo.h cairo-deprecated.h cairo-xlib.h \
cairo-paginated-surface.c cairo-path-bounds.c cairo-path.c \
cairo-path-fill.c cairo-path-fixed.c cairo-path-in-fill.c \
cairo-path-stroke.c cairo-path-stroke-boxes.c \
- cairo-path-stroke-polygon.c cairo-path-stroke-tristrip.c \
- cairo-pattern.c cairo-pen.c cairo-polygon.c \
- cairo-polygon-intersect.c cairo-polygon-reduce.c \
- cairo-raster-source-pattern.c cairo-recording-surface.c \
- cairo-rectangle.c cairo-rectangular-scan-converter.c \
- cairo-region.c cairo-rtree.c cairo-scaled-font.c \
+ cairo-path-stroke-polygon.c cairo-path-stroke-traps.c \
+ cairo-path-stroke-tristrip.c cairo-pattern.c cairo-pen.c \
+ cairo-polygon.c cairo-polygon-intersect.c \
+ cairo-polygon-reduce.c cairo-raster-source-pattern.c \
+ cairo-recording-surface.c cairo-rectangle.c \
+ cairo-rectangular-scan-converter.c cairo-region.c \
+ cairo-rtree.c cairo-scaled-font.c \
cairo-shape-mask-compositor.c cairo-slope.c cairo-spans.c \
cairo-spans-compositor.c cairo-spline.c cairo-stroke-dash.c \
cairo-stroke-style.c cairo-surface.c cairo-surface-clipper.c \
@@ -618,12 +619,12 @@ am__objects_33 = cairo-analysis-surface.lo cairo-arc.lo cairo-array.lo \
cairo-path-bounds.lo cairo-path.lo cairo-path-fill.lo \
cairo-path-fixed.lo cairo-path-in-fill.lo cairo-path-stroke.lo \
cairo-path-stroke-boxes.lo cairo-path-stroke-polygon.lo \
- cairo-path-stroke-tristrip.lo cairo-pattern.lo cairo-pen.lo \
- cairo-polygon.lo cairo-polygon-intersect.lo \
- cairo-polygon-reduce.lo cairo-raster-source-pattern.lo \
- cairo-recording-surface.lo cairo-rectangle.lo \
- cairo-rectangular-scan-converter.lo cairo-region.lo \
- cairo-rtree.lo cairo-scaled-font.lo \
+ cairo-path-stroke-traps.lo cairo-path-stroke-tristrip.lo \
+ cairo-pattern.lo cairo-pen.lo cairo-polygon.lo \
+ cairo-polygon-intersect.lo cairo-polygon-reduce.lo \
+ cairo-raster-source-pattern.lo cairo-recording-surface.lo \
+ cairo-rectangle.lo cairo-rectangular-scan-converter.lo \
+ cairo-region.lo cairo-rtree.lo cairo-scaled-font.lo \
cairo-shape-mask-compositor.lo cairo-slope.lo cairo-spans.lo \
cairo-spans-compositor.lo cairo-spline.lo cairo-stroke-dash.lo \
cairo-stroke-style.lo cairo-surface.lo \
@@ -1094,6 +1095,7 @@ libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
+lzo_LIBS = @lzo_LIBS@
mandir = @mandir@
mesa_DIR = @mesa_DIR@
mkdir_p = @mkdir_p@
@@ -1213,12 +1215,13 @@ cairo_sources = cairo-analysis-surface.c cairo-arc.c cairo-array.c \
cairo-paginated-surface.c cairo-path-bounds.c cairo-path.c \
cairo-path-fill.c cairo-path-fixed.c cairo-path-in-fill.c \
cairo-path-stroke.c cairo-path-stroke-boxes.c \
- cairo-path-stroke-polygon.c cairo-path-stroke-tristrip.c \
- cairo-pattern.c cairo-pen.c cairo-polygon.c \
- cairo-polygon-intersect.c cairo-polygon-reduce.c \
- cairo-raster-source-pattern.c cairo-recording-surface.c \
- cairo-rectangle.c cairo-rectangular-scan-converter.c \
- cairo-region.c cairo-rtree.c cairo-scaled-font.c \
+ cairo-path-stroke-polygon.c cairo-path-stroke-traps.c \
+ cairo-path-stroke-tristrip.c cairo-pattern.c cairo-pen.c \
+ cairo-polygon.c cairo-polygon-intersect.c \
+ cairo-polygon-reduce.c cairo-raster-source-pattern.c \
+ cairo-recording-surface.c cairo-rectangle.c \
+ cairo-rectangular-scan-converter.c cairo-region.c \
+ cairo-rtree.c cairo-scaled-font.c \
cairo-shape-mask-compositor.c cairo-slope.c cairo-spans.c \
cairo-spans-compositor.c cairo-spline.c cairo-stroke-dash.c \
cairo-stroke-style.c cairo-surface.c cairo-surface-clipper.c \
@@ -1970,6 +1973,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-in-fill.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke-boxes.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke-polygon.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke-traps.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke-tristrip.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path-stroke.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cairo-path.Plo@am__quote@
diff --git a/src/Makefile.sources b/src/Makefile.sources
index d6793b0..4abf57d 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -195,6 +195,7 @@ cairo_sources = \
cairo-path-stroke.c \
cairo-path-stroke-boxes.c \
cairo-path-stroke-polygon.c \
+ cairo-path-stroke-traps.c \
cairo-path-stroke-tristrip.c \
cairo-pattern.c \
cairo-pen.c \
diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index e3040fc..bd8d5b5 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -2787,7 +2787,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
if (backend->is_synthetic && backend->is_synthetic (scaled_font_subset->scaled_font))
return CAIRO_INT_STATUS_UNSUPPORTED;
- font = malloc (sizeof (cairo_cff_font_t));
+ font = calloc (1, sizeof (cairo_cff_font_t));
if (unlikely (font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -2862,11 +2862,11 @@ fail4:
fail3:
free (font->subset_font_name);
fail2:
- free (font->data);
- free (font->font_name);
free (font->ps_name);
_cairo_array_fini (&font->output);
fail1:
+ free (font->data);
+ free (font->font_name);
free (font);
return status;
diff --git a/src/cairo-cogl-surface.c b/src/cairo-cogl-surface.c
index d192d75..27c3676 100644
--- a/src/cairo-cogl-surface.c
+++ b/src/cairo-cogl-surface.c
@@ -2037,8 +2037,10 @@ _cairo_cogl_stroke_to_primitive (cairo_cogl_surface_t *surface,
_cairo_traps_init (&traps);
- status = _cairo_path_fixed_stroke_to_traps (path, style, ctm, ctm_inverse, tolerance,
- &traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &traps);
if (unlikely (status))
goto BAIL;
diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c
index c792985..c26098a 100644
--- a/src/cairo-composite-rectangles.c
+++ b/src/cairo-composite-rectangles.c
@@ -444,6 +444,13 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten
if (unlikely (status))
return status;
+ if (overlap && *overlap &&
+ scaled_font->options.antialias == CAIRO_ANTIALIAS_NONE &&
+ _cairo_pattern_is_opaque_solid (&extents->source_pattern.base))
+ {
+ *overlap = FALSE;
+ }
+
return _cairo_composite_rectangles_intersect (extents, clip);
}
diff --git a/src/cairo-compositor-private.h b/src/cairo-compositor-private.h
index e5ad367..0199723 100644
--- a/src/cairo-compositor-private.h
+++ b/src/cairo-compositor-private.h
@@ -129,6 +129,9 @@ struct cairo_mask_compositor {
cairo_boxes_t *boxes);
cairo_int_status_t
+ (*check_composite) (const cairo_composite_rectangles_t *extents);
+
+ cairo_int_status_t
(*composite) (void *dst,
cairo_operator_t op,
cairo_surface_t *src,
diff --git a/src/cairo-damage-private.h b/src/cairo-damage-private.h
index 28768fd..97b177e 100644
--- a/src/cairo-damage-private.h
+++ b/src/cairo-damage-private.h
@@ -60,6 +60,9 @@ cairo_private cairo_damage_t *
_cairo_damage_create (void);
cairo_private cairo_damage_t *
+_cairo_damage_create_in_error (cairo_status_t status);
+
+cairo_private cairo_damage_t *
_cairo_damage_add_box (cairo_damage_t *damage,
const cairo_box_t *box);
diff --git a/src/cairo-damage.c b/src/cairo-damage.c
index 1e06b26..63191fe 100644
--- a/src/cairo-damage.c
+++ b/src/cairo-damage.c
@@ -40,6 +40,13 @@
static const cairo_damage_t __cairo_damage__nil = { CAIRO_STATUS_NO_MEMORY };
cairo_damage_t *
+_cairo_damage_create_in_error (cairo_status_t status)
+{
+ _cairo_error_throw (status);
+ return (cairo_damage_t *) &__cairo_damage__nil;
+}
+
+cairo_damage_t *
_cairo_damage_create (void)
{
cairo_damage_t *damage;
diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 3d828ef..fee08f0 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -149,23 +149,28 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
} else {
cairo_surface_t *parent_surface;
cairo_rectangle_int_t extents;
- cairo_bool_t is_empty;
+ cairo_bool_t bounded, is_empty;
parent_surface = _cairo_gstate_get_target (cr->gstate);
/* Get the extents that we'll use in creating our new group surface */
- is_empty = _cairo_surface_get_extents (parent_surface, &extents);
+ bounded = _cairo_surface_get_extents (parent_surface, &extents);
if (clip)
+ /* XXX: This assignment just fixes a compiler warning? */
is_empty = _cairo_rectangle_intersect (&extents,
_cairo_clip_get_extents (clip));
- /* XXX unbounded surface creation */
-
- group_surface = _cairo_surface_create_similar_solid (parent_surface,
- content,
- extents.width,
- extents.height,
- CAIRO_COLOR_TRANSPARENT);
+ if (!bounded) {
+ /* XXX: Generic solution? */
+ group_surface = cairo_recording_surface_create (content, NULL);
+ extents.x = extents.y = 0;
+ } else {
+ group_surface = _cairo_surface_create_similar_solid (parent_surface,
+ content,
+ extents.width,
+ extents.height,
+ CAIRO_COLOR_TRANSPARENT);
+ }
status = group_surface->status;
if (unlikely (status))
goto bail;
diff --git a/src/cairo-egl-context.c b/src/cairo-egl-context.c
index 0e9fd71..ba8f60f 100644
--- a/src/cairo-egl-context.c
+++ b/src/cairo-egl-context.c
@@ -49,6 +49,9 @@ typedef struct _cairo_egl_context {
EGLContext context;
EGLSurface dummy_surface;
+
+ EGLContext previous_context;
+ EGLSurface previous_surface;
} cairo_egl_context_t;
typedef struct _cairo_egl_surface {
@@ -58,20 +61,51 @@ typedef struct _cairo_egl_surface {
} cairo_egl_surface_t;
-static void
-_egl_acquire (void *abstract_ctx)
+static cairo_bool_t
+_context_acquisition_changed_egl_state (cairo_egl_context_t *ctx,
+ EGLSurface current_surface)
{
- cairo_egl_context_t *ctx = abstract_ctx;
- EGLSurface current_surface;
+ return ctx->previous_context != ctx->context ||
+ ctx->previous_surface != current_surface;
+}
+static EGLSurface
+_egl_get_current_surface (cairo_egl_context_t *ctx)
+{
if (ctx->base.current_target == NULL ||
_cairo_gl_surface_is_texture (ctx->base.current_target)) {
- current_surface = ctx->dummy_surface;
- } else {
- cairo_egl_surface_t *surface = (cairo_egl_surface_t *) ctx->base.current_target;
- current_surface = surface->egl ;
+ return ctx->dummy_surface;
}
+ return ((cairo_egl_surface_t *) ctx->base.current_target)->egl;
+}
+
+static void
+_egl_query_current_state (cairo_egl_context_t *ctx)
+{
+ ctx->previous_surface = eglGetCurrentSurface (EGL_DRAW);
+ ctx->previous_context = eglGetCurrentContext ();
+
+ /* If any of the values were none, assume they are all none. Not all
+ drivers seem well behaved when it comes to using these values across
+ multiple threads. */
+ if (ctx->previous_surface == EGL_NO_SURFACE ||
+ ctx->previous_context == EGL_NO_CONTEXT) {
+ ctx->previous_surface = EGL_NO_SURFACE;
+ ctx->previous_context = EGL_NO_CONTEXT;
+ }
+}
+
+static void
+_egl_acquire (void *abstract_ctx)
+{
+ cairo_egl_context_t *ctx = abstract_ctx;
+ EGLSurface current_surface = _egl_get_current_surface (ctx);
+
+ _egl_query_current_state (ctx);
+ if (!_context_acquisition_changed_egl_state (ctx, current_surface))
+ return;
+
eglMakeCurrent (ctx->display,
current_surface, current_surface, ctx->context);
}
@@ -80,8 +114,11 @@ static void
_egl_release (void *abstract_ctx)
{
cairo_egl_context_t *ctx = abstract_ctx;
- if (!ctx->base.thread_aware)
+ if (!ctx->base.thread_aware ||
+ !_context_acquisition_changed_egl_state (ctx,
+ _egl_get_current_surface (ctx))) {
return;
+ }
eglMakeCurrent (ctx->display,
EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
@@ -161,6 +198,10 @@ cairo_egl_device_create (EGLDisplay dpy, EGLContext egl)
ctx->base.swap_buffers = _egl_swap_buffers;
ctx->base.destroy = _egl_destroy;
+ /* We are about the change the current state of EGL, so we should
+ * query the pre-existing surface now instead of later. */
+ _egl_query_current_state (ctx);
+
if (!_egl_make_current_surfaceless (ctx)) {
/* Fall back to dummy surface, meh. */
EGLint config_attribs[] = {
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index bd616b5..8ebadb4 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -708,7 +708,8 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled)
static cairo_status_t
_compute_transform (cairo_ft_font_transform_t *sf,
- cairo_matrix_t *scale)
+ cairo_matrix_t *scale,
+ cairo_ft_unscaled_font_t *unscaled)
{
cairo_status_t status;
double x_scale, y_scale;
@@ -736,6 +737,30 @@ _compute_transform (cairo_ft_font_transform_t *sf,
if (y_scale < 1.0)
y_scale = 1.0;
+ if (unscaled && (unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) {
+ double min_distance = DBL_MAX;
+ int i;
+ int best_i = 0;
+ double best_x_size = 0;
+ double best_y_size = 0;
+
+ for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {
+ double x_size = unscaled->face->available_sizes[i].y_ppem / 64.;
+ double y_size = unscaled->face->available_sizes[i].y_ppem / 64.;
+ double distance = fabs (y_size - y_scale);
+
+ if (distance <= min_distance) {
+ min_distance = distance;
+ best_i = i;
+ best_x_size = x_size;
+ best_y_size = y_size;
+ }
+ }
+
+ x_scale = best_x_size;
+ y_scale = best_y_size;
+ }
+
sf->x_scale = x_scale;
sf->y_scale = y_scale;
@@ -773,7 +798,7 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
unscaled->have_scale = TRUE;
unscaled->current_scale = *scale;
- status = _compute_transform (&sf, scale);
+ status = _compute_transform (&sf, scale, unscaled);
if (unlikely (status))
return status;
@@ -798,44 +823,12 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
FT_Set_Transform(unscaled->face, &mat, NULL);
- if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) != 0) {
- error = FT_Set_Char_Size (unscaled->face,
- sf.x_scale * 64.0 + .5,
- sf.y_scale * 64.0 + .5,
- 0, 0);
- if (error)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- } else {
- double min_distance = DBL_MAX;
- int i;
- int best_i = 0;
-
- for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {
-#if HAVE_FT_BITMAP_SIZE_Y_PPEM
- double size = unscaled->face->available_sizes[i].y_ppem / 64.;
-#else
- double size = unscaled->face->available_sizes[i].height;
-#endif
- double distance = fabs (size - sf.y_scale);
-
- if (distance <= min_distance) {
- min_distance = distance;
- best_i = i;
- }
- }
-#if HAVE_FT_BITMAP_SIZE_Y_PPEM
- error = FT_Set_Char_Size (unscaled->face,
- unscaled->face->available_sizes[best_i].x_ppem,
- unscaled->face->available_sizes[best_i].y_ppem,
- 0, 0);
- if (error)
-#endif
- error = FT_Set_Pixel_Sizes (unscaled->face,
- unscaled->face->available_sizes[best_i].width,
- unscaled->face->available_sizes[best_i].height);
- if (error)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
+ error = FT_Set_Char_Size (unscaled->face,
+ sf.x_scale * 64.0 + .5,
+ sf.y_scale * 64.0 + .5,
+ 0, 0);
+ if (error)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
}
@@ -2521,6 +2514,22 @@ _cairo_index_to_glyph_name (void *abstract_font,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+static cairo_bool_t
+_ft_is_type1 (FT_Face face)
+{
+#if HAVE_FT_GET_X11_FONT_FORMAT
+ const char *font_format = FT_Get_X11_Font_Format (face);
+ if (font_format &&
+ (strcmp (font_format, "Type 1") == 0 ||
+ strcmp (font_format, "CFF") == 0))
+ {
+ return TRUE;
+ }
+#endif
+
+ return FALSE;
+}
+
static cairo_int_status_t
_cairo_ft_load_type1_data (void *abstract_font,
long offset,
@@ -2533,7 +2542,6 @@ _cairo_ft_load_type1_data (void *abstract_font,
cairo_status_t status = CAIRO_STATUS_SUCCESS;
unsigned long available_length;
unsigned long ret;
- const char *font_format;
assert (length != NULL);
@@ -2551,11 +2559,7 @@ _cairo_ft_load_type1_data (void *abstract_font,
}
#endif
- font_format = FT_Get_X11_Font_Format (face);
- if (!font_format ||
- !(strcmp (font_format, "Type 1") == 0 ||
- strcmp (font_format, "CFF") == 0))
- {
+ if (! _ft_is_type1 (face)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto unlock;
}
@@ -3077,7 +3081,7 @@ _cairo_ft_resolve_pattern (FcPattern *pattern,
font_matrix,
&scale);
- status = _compute_transform (&sf, &scale);
+ status = _compute_transform (&sf, &scale, NULL);
if (unlikely (status))
return (cairo_font_face_t *)&_cairo_font_face_nil;
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index 45fa042..c250e72 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -56,11 +56,12 @@ cairo_int_status_t
_cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t use_texgen)
{
_cairo_gl_operand_destroy (&setup->src);
return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
- sample, extents);
+ sample, extents, use_texgen);
}
void
@@ -83,14 +84,15 @@ cairo_int_status_t
_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t use_texgen)
{
_cairo_gl_operand_destroy (&setup->mask);
if (pattern == NULL)
return CAIRO_STATUS_SUCCESS;
return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
- sample, extents);
+ sample, extents, use_texgen);
}
void
@@ -109,6 +111,12 @@ _cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
}
void
+_cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
+{
+ setup->multisample = TRUE;
+}
+
+void
_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
cairo_region_t *clip_region)
{
@@ -242,10 +250,12 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
_cairo_gl_texture_set_filter (ctx, ctx->tex_target,
operand->texture.attributes.filter);
- dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
- GL_FLOAT, GL_FALSE, vertex_size,
- ctx->vb + vertex_offset);
- dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
+ if (! operand->texture.texgen) {
+ dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
+ GL_FLOAT, GL_FALSE, vertex_size,
+ ctx->vb + vertex_offset);
+ dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
+ }
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
@@ -256,21 +266,30 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
_cairo_gl_texture_set_extend (ctx, ctx->tex_target, operand->gradient.extend);
_cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR);
- dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
- GL_FLOAT, GL_FALSE, vertex_size,
- ctx->vb + vertex_offset);
- dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
+ if (! operand->gradient.texgen) {
+ dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
+ GL_FLOAT, GL_FALSE, vertex_size,
+ ctx->vb + vertex_offset);
+ dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
+ }
break;
}
}
static void
_cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
+ cairo_bool_t spans_enabled,
unsigned int vertex_size,
unsigned int vertex_offset)
{
cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
+ if (! spans_enabled) {
+ dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
+ ctx->spans = FALSE;
+ return;
+ }
+
dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
ctx->vb + vertex_offset);
@@ -488,8 +507,8 @@ _scissor_to_doubles (cairo_gl_surface_t *surface,
glEnable (GL_SCISSOR_TEST);
}
-static void
-_scissor_to_rectangle (cairo_gl_surface_t *surface,
+void
+_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
const cairo_rectangle_int_t *r)
{
_scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
@@ -542,19 +561,34 @@ _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
goto disable_stencil_buffer_and_return;
}
- /* If we cannot reduce the clip to a rectangular region,
- we clip using the stencil buffer. */
- glDisable (GL_SCISSOR_TEST);
-
if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto disable_stencil_buffer_and_return;
}
+ /* The clip is not rectangular, so use the stencil buffer. */
glDepthMask (GL_TRUE);
glEnable (GL_STENCIL_TEST);
+ glDisable (GL_SCISSOR_TEST);
+
+ /* Texture surfaces have private depth/stencil buffers, so we can
+ * rely on any previous clip being cached there. */
+ if (_cairo_gl_surface_is_texture (setup->dst)) {
+ cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
+ if (_cairo_clip_equal (old_clip, setup->clip))
+ goto activate_stencil_buffer_and_return;
+
+ /* Clear the stencil buffer, but only the areas that we are
+ * going to be drawing to. */
+ if (old_clip)
+ _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (old_clip));
+ setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
+ }
+
glClearStencil (0);
glClear (GL_STENCIL_BUFFER_BIT);
+ glDisable (GL_SCISSOR_TEST);
+
glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
glStencilFunc (GL_EQUAL, 1, 0xffffffff);
glColorMask (0, 0, 0, 0);
@@ -572,6 +606,7 @@ _cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
_cairo_gl_composite_flush (ctx);
_cairo_gl_composite_setup_vbo (ctx, vertex_size);
+activate_stencil_buffer_and_return:
glColorMask (1, 1, 1, 1);
glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
glStencilFunc (GL_EQUAL, 1, 0xffffffff);
@@ -587,54 +622,53 @@ _cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
cairo_gl_context_t *ctx,
int vertex_size)
{
+ cairo_bool_t clip_changing = TRUE;
+ cairo_bool_t clip_region_changing = TRUE;
+
+ if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
+ goto disable_all_clipping;
+ clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
+ clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
if (! _cairo_gl_context_is_flushed (ctx) &&
- (! cairo_region_equal (ctx->clip_region, setup->clip_region) ||
- ! _cairo_clip_equal (ctx->clip, setup->clip)))
+ (clip_region_changing || clip_changing))
_cairo_gl_composite_flush (ctx);
- cairo_region_destroy (ctx->clip_region);
- ctx->clip_region = cairo_region_reference (setup->clip_region);
- _cairo_clip_destroy (ctx->clip);
- ctx->clip = _cairo_clip_copy (setup->clip);
-
assert (!setup->clip_region || !setup->clip);
- if (ctx->clip_region) {
- _disable_stencil_buffer ();
- glEnable (GL_SCISSOR_TEST);
- return CAIRO_INT_STATUS_SUCCESS;
+ /* setup->clip is only used by the msaa compositor and setup->clip_region
+ * only by the other compositors, so it's safe to wait to clean up obsolete
+ * clips. */
+ if (clip_region_changing) {
+ cairo_region_destroy (ctx->clip_region);
+ ctx->clip_region = cairo_region_reference (setup->clip_region);
+ }
+ if (clip_changing) {
+ _cairo_clip_destroy (ctx->clip);
+ ctx->clip = _cairo_clip_copy (setup->clip);
}
- if (ctx->clip)
- return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
- vertex_size);
+ /* For clip regions, we scissor right before drawing. */
+ if (setup->clip_region)
+ goto disable_all_clipping;
+ if (setup->clip)
+ return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
+ vertex_size);
+disable_all_clipping:
_disable_stencil_buffer ();
glDisable (GL_SCISSOR_TEST);
return CAIRO_INT_STATUS_SUCCESS;
}
cairo_status_t
-_cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
- cairo_gl_context_t **ctx_out,
- cairo_bool_t multisampling)
+_cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
+ cairo_gl_context_t *ctx)
{
unsigned int dst_size, src_size, mask_size, vertex_size;
- cairo_gl_context_t *ctx;
cairo_status_t status;
- cairo_bool_t component_alpha;
cairo_gl_shader_t *shader;
-
- assert (setup->dst);
-
- status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- _cairo_gl_context_set_destination (ctx, setup->dst, multisampling);
-
- glEnable (GL_BLEND);
+ cairo_bool_t component_alpha;
component_alpha =
setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
@@ -642,62 +676,81 @@ _cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
/* Do various magic for component alpha */
if (component_alpha) {
- status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
- if (unlikely (status))
- goto FAIL;
- } else {
- if (ctx->pre_shader) {
- _cairo_gl_composite_flush (ctx);
- ctx->pre_shader = NULL;
- }
+ status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
+ if (unlikely (status))
+ return status;
+ } else {
+ if (ctx->pre_shader) {
+ _cairo_gl_composite_flush (ctx);
+ ctx->pre_shader = NULL;
+ }
}
status = _cairo_gl_get_shader_by_type (ctx,
&setup->src,
&setup->mask,
setup->spans,
- component_alpha ?
+ component_alpha ?
CAIRO_GL_SHADER_IN_CA_SOURCE :
CAIRO_GL_SHADER_IN_NORMAL,
&shader);
if (unlikely (status)) {
- ctx->pre_shader = NULL;
- goto FAIL;
+ ctx->pre_shader = NULL;
+ return status;
}
if (ctx->current_shader != shader)
_cairo_gl_composite_flush (ctx);
status = CAIRO_STATUS_SUCCESS;
- dst_size = 2 * sizeof (GLfloat);
- src_size = _cairo_gl_operand_get_vertex_size (setup->src.type);
- mask_size = _cairo_gl_operand_get_vertex_size (setup->mask.type);
+ dst_size = 2 * sizeof (GLfloat);
+ src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
+ mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
vertex_size = dst_size + src_size + mask_size;
if (setup->spans)
- vertex_size += sizeof (GLfloat);
+ vertex_size += sizeof (GLfloat);
_cairo_gl_composite_setup_vbo (ctx, vertex_size);
_cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, vertex_size, dst_size);
_cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, vertex_size, dst_size + src_size);
- if (setup->spans)
- _cairo_gl_context_setup_spans (ctx, vertex_size, dst_size + src_size + mask_size);
- else
- ctx->dispatch.DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
+
+ _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
+ dst_size + src_size + mask_size);
_cairo_gl_set_operator (ctx, setup->op, component_alpha);
if (_cairo_gl_context_is_flushed (ctx)) {
- if (ctx->pre_shader) {
- _cairo_gl_set_shader (ctx, ctx->pre_shader);
- _cairo_gl_composite_bind_to_shader (ctx, setup);
- }
- _cairo_gl_set_shader (ctx, shader);
- _cairo_gl_composite_bind_to_shader (ctx, setup);
+ if (ctx->pre_shader) {
+ _cairo_gl_set_shader (ctx, ctx->pre_shader);
+ _cairo_gl_composite_bind_to_shader (ctx, setup);
+ }
+ _cairo_gl_set_shader (ctx, shader);
+ _cairo_gl_composite_bind_to_shader (ctx, setup);
}
- status = _cairo_gl_composite_setup_clipping (setup, ctx, vertex_size);
+ return status;
+}
+
+cairo_status_t
+_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
+ cairo_gl_context_t **ctx_out)
+{
+ cairo_gl_context_t *ctx;
+ cairo_status_t status;
+
+ assert (setup->dst);
+
+ status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
+ if (unlikely (status))
+ return status;
+
+ _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
+ glEnable (GL_BLEND);
+ _cairo_gl_set_operands_and_operator (setup, ctx);
+
+ status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
if (unlikely (status))
goto FAIL;
@@ -710,13 +763,6 @@ FAIL:
return status;
}
-cairo_status_t
-_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
- cairo_gl_context_t **ctx_out)
-{
- return _cairo_gl_composite_begin_multisample (setup, ctx_out, FALSE);
-}
-
static inline void
_cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
{
@@ -774,7 +820,7 @@ _cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
cairo_region_get_rectangle (ctx->clip_region, i, &rect);
- _scissor_to_rectangle (ctx->current_target, &rect);
+ _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
_cairo_gl_composite_draw_triangles (ctx, count);
}
}
@@ -824,9 +870,7 @@ _cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
static inline void
_cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
- GLfloat x,
- GLfloat y,
- uint8_t alpha)
+ GLfloat x, GLfloat y)
{
GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
@@ -836,59 +880,177 @@ _cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
_cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
_cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
- if (ctx->spans) {
- union fi {
- float f;
- GLbyte bytes[4];
- } fi;
-
- fi.bytes[0] = 0;
- fi.bytes[1] = 0;
- fi.bytes[2] = 0;
- fi.bytes[3] = alpha;
- *vb++ = fi.f;
- }
+ ctx->vb_offset += ctx->vertex_size;
+}
+
+static inline void
+_cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
+ GLfloat x, GLfloat y, uint8_t alpha)
+{
+ GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+ union fi {
+ float f;
+ GLbyte bytes[4];
+ } fi;
+
+ *vb++ = x;
+ *vb++ = y;
+
+ _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
+ _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
+
+ fi.bytes[0] = 0;
+ fi.bytes[1] = 0;
+ fi.bytes[2] = 0;
+ fi.bytes[3] = alpha;
+ *vb++ = fi.f;
ctx->vb_offset += ctx->vertex_size;
}
static void
_cairo_gl_composite_emit_point (cairo_gl_context_t *ctx,
- const cairo_point_t *point,
- uint8_t alpha)
+ const cairo_point_t *point)
{
_cairo_gl_composite_emit_vertex (ctx,
_cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y),
- alpha);
+ _cairo_fixed_to_double (point->y));
}
-void
+static void
_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
- GLfloat x1,
- GLfloat y1,
- GLfloat x2,
- GLfloat y2,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2)
+{
+ _cairo_gl_composite_prepare_buffer (ctx, 6,
+ CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
+
+ _cairo_gl_composite_emit_vertex (ctx, x1, y1);
+ _cairo_gl_composite_emit_vertex (ctx, x2, y1);
+ _cairo_gl_composite_emit_vertex (ctx, x1, y2);
+
+ _cairo_gl_composite_emit_vertex (ctx, x2, y1);
+ _cairo_gl_composite_emit_vertex (ctx, x2, y2);
+ _cairo_gl_composite_emit_vertex (ctx, x1, y2);
+}
+
+cairo_gl_emit_rect_t
+_cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
+{
+ return _cairo_gl_composite_emit_rect;
+}
+
+void
+_cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2)
+{
+ _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
+}
+
+static void
+_cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
uint8_t alpha)
{
_cairo_gl_composite_prepare_buffer (ctx, 6,
CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
- _cairo_gl_composite_emit_vertex (ctx, x1, y1, alpha);
- _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
- _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
+
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
+ _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
+}
+
+static void
+_cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ uint8_t alpha)
+{
+ GLfloat *v;
+ union fi {
+ float f;
+ GLbyte bytes[4];
+ } fi;
+
+ _cairo_gl_composite_prepare_buffer (ctx, 6,
+ CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
+ v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+
+ v[15] = v[ 6] = v[0] = x1;
+ v[10] = v[ 4] = v[1] = y1;
+ v[12] = v[ 9] = v[3] = x2;
+ v[16] = v[13] = v[7] = y2;
+
+ fi.bytes[0] = 0;
+ fi.bytes[1] = 0;
+ fi.bytes[2] = 0;
+ fi.bytes[3] = alpha;
+ v[17] =v[14] = v[11] = v[8] = v[5] = v[2] = fi.f;
+
+ ctx->vb_offset += 6*3 * sizeof(GLfloat);
+}
+
+cairo_gl_emit_span_t
+_cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
+{
+ if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE) {
+ switch (ctx->operands[CAIRO_GL_TEX_MASK].type) {
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ case CAIRO_GL_OPERAND_CONSTANT:
+ break;
+
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ if (!ctx->operands[CAIRO_GL_TEX_MASK].gradient.texgen)
+ return _cairo_gl_composite_emit_span;
+ break;
+
+ case CAIRO_GL_OPERAND_TEXTURE:
+ if (!ctx->operands[CAIRO_GL_TEX_MASK].texture.texgen)
+ return _cairo_gl_composite_emit_span;
+ break;
+ }
+ }
+
+ switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ case CAIRO_GL_OPERAND_CONSTANT:
+ break;
+
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ if (!ctx->operands[CAIRO_GL_TEX_SOURCE].gradient.texgen)
+ return _cairo_gl_composite_emit_span;
+ break;
+
+ case CAIRO_GL_OPERAND_TEXTURE:
+ if (!ctx->operands[CAIRO_GL_TEX_SOURCE].texture.texgen)
+ return _cairo_gl_composite_emit_span;
+ }
- _cairo_gl_composite_emit_vertex (ctx, x2, y1, alpha);
- _cairo_gl_composite_emit_vertex (ctx, x2, y2, alpha);
- _cairo_gl_composite_emit_vertex (ctx, x1, y2, alpha);
+ return _cairo_gl_composite_emit_solid_span;
}
static inline void
_cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
- GLfloat x,
- GLfloat y,
- GLfloat glyph_x,
- GLfloat glyph_y)
+ GLfloat x, GLfloat y,
+ GLfloat glyph_x, GLfloat glyph_y)
{
GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
@@ -903,16 +1065,12 @@ _cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
ctx->vb_offset += ctx->vertex_size;
}
-void
+static void
_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
- GLfloat x1,
- GLfloat y1,
- GLfloat x2,
- GLfloat y2,
- GLfloat glyph_x1,
- GLfloat glyph_y1,
- GLfloat glyph_x2,
- GLfloat glyph_y2)
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ GLfloat glyph_x1, GLfloat glyph_y1,
+ GLfloat glyph_x2, GLfloat glyph_y2)
{
_cairo_gl_composite_prepare_buffer (ctx, 6,
CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
@@ -926,6 +1084,54 @@ _cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
_cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
}
+static void
+_cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ GLfloat glyph_x1, GLfloat glyph_y1,
+ GLfloat glyph_x2, GLfloat glyph_y2)
+{
+ GLfloat *v;
+
+ _cairo_gl_composite_prepare_buffer (ctx, 6,
+ CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
+
+ v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
+
+ v[20] = v[ 8] = v[0] = x1;
+ v[13] = v[ 5] = v[1] = y1;
+ v[22] = v[10] = v[2] = glyph_x1;
+ v[15] = v[ 7] = v[3] = glyph_y1;
+
+ v[16] = v[12] = v[4] = x2;
+ v[18] = v[14] = v[6] = glyph_x2;
+
+ v[21] = v[17] = v[ 9] = y2;
+ v[23] = v[19] = v[11] = glyph_y2;
+
+ ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
+}
+
+cairo_gl_emit_glyph_t
+_cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx)
+{
+ switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
+ default:
+ case CAIRO_GL_OPERAND_COUNT:
+ ASSERT_NOT_REACHED;
+ case CAIRO_GL_OPERAND_NONE:
+ case CAIRO_GL_OPERAND_CONSTANT:
+ return _cairo_gl_composite_emit_solid_glyph;
+
+ case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ case CAIRO_GL_OPERAND_TEXTURE:
+ return _cairo_gl_composite_emit_glyph;
+ }
+}
+
void
_cairo_gl_composite_fini (cairo_gl_composite_t *setup)
{
@@ -934,13 +1140,10 @@ _cairo_gl_composite_fini (cairo_gl_composite_t *setup)
}
cairo_status_t
-_cairo_gl_composite_init (cairo_gl_composite_t *setup,
- cairo_operator_t op,
- cairo_gl_surface_t *dst,
- cairo_bool_t assume_component_alpha)
+_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
+ cairo_operator_t op,
+ cairo_bool_t assume_component_alpha)
{
- memset (setup, 0, sizeof (cairo_gl_composite_t));
-
if (assume_component_alpha) {
if (op != CAIRO_OPERATOR_CLEAR &&
op != CAIRO_OPERATOR_OVER &&
@@ -951,8 +1154,26 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
return UNSUPPORTED ("unsupported operator");
}
- setup->dst = dst;
setup->op = op;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_gl_composite_init (cairo_gl_composite_t *setup,
+ cairo_operator_t op,
+ cairo_gl_surface_t *dst,
+ cairo_bool_t assume_component_alpha)
+{
+ cairo_status_t status;
+
+ memset (setup, 0, sizeof (cairo_gl_composite_t));
+
+ status = _cairo_gl_composite_set_operator (setup, op,
+ assume_component_alpha);
+ if (status)
+ return status;
+
+ setup->dst = dst;
setup->clip_region = dst->clip_region;
return CAIRO_STATUS_SUCCESS;
@@ -1005,14 +1226,14 @@ _cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t *ctx,
_cairo_gl_composite_prepare_buffer (ctx, 4,
CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
- _cairo_gl_composite_emit_point (ctx, &quad[0], 0);
- _cairo_gl_composite_emit_point (ctx, &quad[1], 0);
+ _cairo_gl_composite_emit_point (ctx, &quad[0]);
+ _cairo_gl_composite_emit_point (ctx, &quad[1]);
/* Cairo stores quad vertices in counter-clockwise order, but we need to
emit them from top to bottom in the triangle strip, so we need to reverse
the order of the last two vertices. */
- _cairo_gl_composite_emit_point (ctx, &quad[3], 0);
- _cairo_gl_composite_emit_point (ctx, &quad[2], 0);
+ _cairo_gl_composite_emit_point (ctx, &quad[3]);
+ _cairo_gl_composite_emit_point (ctx, &quad[2]);
return _cairo_gl_composite_append_vertex_indices (ctx, 4);
}
@@ -1025,8 +1246,8 @@ _cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t *ctx,
_cairo_gl_composite_prepare_buffer (ctx, 3,
CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
- _cairo_gl_composite_emit_point (ctx, &triangle[0], 0);
- _cairo_gl_composite_emit_point (ctx, &triangle[1], 0);
- _cairo_gl_composite_emit_point (ctx, &triangle[2], 0);
+ _cairo_gl_composite_emit_point (ctx, &triangle[0]);
+ _cairo_gl_composite_emit_point (ctx, &triangle[1]);
+ _cairo_gl_composite_emit_point (ctx, &triangle[2]);
return _cairo_gl_composite_append_vertex_indices (ctx, 3);
}
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
index 9cb0c21..22297b3 100644
--- a/src/cairo-gl-device.c
+++ b/src/cairo-gl-device.c
@@ -164,6 +164,22 @@ _cairo_gl_msaa_compositor_enabled (void)
return env && strcmp(env, "msaa") == 0;
}
+static cairo_bool_t
+test_can_read_bgra (cairo_gl_flavor_t gl_flavor)
+{
+ /* Desktop GL always supports BGRA formats. */
+ if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
+ return TRUE;
+
+ assert (gl_flavor == CAIRO_GL_FLAVOR_ES);
+
+ /* For OpenGL ES we have to look for the specific extension and BGRA only
+ * matches cairo's integer packed bytes on little-endian machines. */
+ if (!_cairo_is_little_endian())
+ return FALSE;
+ return _cairo_gl_has_extension ("EXT_read_format_bgra");
+}
+
cairo_status_t
_cairo_gl_context_init (cairo_gl_context_t *ctx)
{
@@ -173,6 +189,9 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor ();
int n;
+ cairo_bool_t is_desktop = gl_flavor == CAIRO_GL_FLAVOR_DESKTOP;
+ cairo_bool_t is_gles = gl_flavor == CAIRO_GL_FLAVOR_ES;
+
_cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
/* XXX The choice of compositor should be made automatically at runtime.
@@ -195,7 +214,7 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
/* Check for required extensions */
- if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
+ if (is_desktop) {
if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) {
ctx->tex_target = GL_TEXTURE_2D;
ctx->has_npot_repeat = TRUE;
@@ -206,49 +225,58 @@ _cairo_gl_context_init (cairo_gl_context_t *ctx)
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
} else {
ctx->tex_target = GL_TEXTURE_2D;
- if (_cairo_gl_has_extension ("GL_OES_texture_npot"))
+ if (_cairo_gl_has_extension ("GL_OES_texture_npot") ||
+ _cairo_gl_has_extension ("GL_IMG_texture_npot"))
ctx->has_npot_repeat = TRUE;
else
ctx->has_npot_repeat = FALSE;
}
- if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
- gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
+ if (is_desktop && gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
- if (gl_flavor == CAIRO_GL_FLAVOR_ES &&
- ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
+ if (is_gles && ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
- ctx->has_map_buffer = (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
- (gl_flavor == CAIRO_GL_FLAVOR_ES &&
- _cairo_gl_has_extension ("GL_OES_mapbuffer")));
+ ctx->has_map_buffer =
+ is_desktop || (is_gles && _cairo_gl_has_extension ("GL_OES_mapbuffer"));
+
+ ctx->can_read_bgra = test_can_read_bgra (gl_flavor);
ctx->has_mesa_pack_invert =
_cairo_gl_has_extension ("GL_MESA_pack_invert");
ctx->has_packed_depth_stencil =
- ((gl_flavor == CAIRO_GL_FLAVOR_DESKTOP &&
- _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
- (gl_flavor == CAIRO_GL_FLAVOR_ES &&
- _cairo_gl_has_extension ("GL_OES_packed_depth_stencil")));
+ (is_desktop && _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
+ (is_gles && _cairo_gl_has_extension ("GL_OES_packed_depth_stencil"));
ctx->num_samples = 1;
#if CAIRO_HAS_GL_SURFACE
- if (ctx->has_packed_depth_stencil &&
- _cairo_gl_has_extension ("GL_ARB_framebuffer_object")) {
+ if (is_desktop && ctx->has_packed_depth_stencil &&
+ (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
+ _cairo_gl_has_extension ("GL_ARB_framebuffer_object") ||
+ (_cairo_gl_has_extension ("GL_EXT_framebuffer_blit") &&
+ _cairo_gl_has_extension ("GL_EXT_framebuffer_multisample")))) {
glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
}
#endif
#if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
- if (ctx->has_packed_depth_stencil &&
+ if (is_gles && ctx->has_packed_depth_stencil &&
_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
}
#endif
+
+#if CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_IMG)
+ if (is_gles && ctx->has_packed_depth_stencil &&
+ _cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture")) {
+ glGetIntegerv(GL_MAX_SAMPLES_IMG, &ctx->num_samples);
+ }
+#endif
+
ctx->supports_msaa = ctx->num_samples > 1;
if (ctx->num_samples > MAX_MSAA_SAMPLES)
ctx->num_samples = MAX_MSAA_SAMPLES;
@@ -321,7 +349,7 @@ _get_depth_stencil_format (cairo_gl_context_t *ctx)
#if CAIRO_HAS_GLESV2_SURFACE
if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
- return GL_DEPTH24_STENCIL8;
+ return GL_DEPTH24_STENCIL8_OES;
#endif
#if CAIRO_HAS_GL_SURFACE
@@ -688,6 +716,7 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
glDisable(GL_MULTISAMPLE);
#endif
+ surface->msaa_active = multisampling;
ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
#if CAIRO_HAS_GL_SURFACE
diff --git a/src/cairo-gl-dispatch-private.h b/src/cairo-gl-dispatch-private.h
index 0c5dc39..cabf76f 100644
--- a/src/cairo-gl-dispatch-private.h
+++ b/src/cairo-gl-dispatch-private.h
@@ -53,7 +53,7 @@ typedef struct _cairo_gl_dispatch_entry {
offsetof(cairo_gl_dispatch_t, name) }
#define DISPATCH_ENTRY_ARB_OES(name) { { "gl"#name, "gl"#name"ARB", "gl"#name"OES" }, \
offsetof(cairo_gl_dispatch_t, name) }
-#define DISPATCH_ENTRY_EXT_EXT(name) { { "gl"#name, "gl"#name"EXT", "gl"#name"EXT" }, \
+#define DISPATCH_ENTRY_EXT_IMG(name) { { "gl"#name, "gl"#name"EXT", "gl"#name"IMG" }, \
offsetof(cairo_gl_dispatch_t, name) }
#define DISPATCH_ENTRY_CUSTOM(name, name2) { { "gl"#name, "gl"#name2, "gl"#name }, \
offsetof(cairo_gl_dispatch_t, name)}
@@ -117,8 +117,12 @@ cairo_private cairo_gl_dispatch_entry_t dispatch_fbo_entries[] = {
DISPATCH_ENTRY_EXT (FramebufferRenderbuffer),
DISPATCH_ENTRY_EXT (DeleteRenderbuffers),
DISPATCH_ENTRY_EXT (BlitFramebuffer),
- DISPATCH_ENTRY_EXT_EXT (RenderbufferStorageMultisample),
- DISPATCH_ENTRY_EXT_EXT (FramebufferTexture2DMultisample),
+ DISPATCH_ENTRY_LAST
+};
+
+cairo_private cairo_gl_dispatch_entry_t dispatch_multisampling_entries[] = {
+ DISPATCH_ENTRY_EXT_IMG (RenderbufferStorageMultisample),
+ DISPATCH_ENTRY_EXT_IMG (FramebufferTexture2DMultisample),
DISPATCH_ENTRY_LAST
};
diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c
index 5bffddd..76c3115 100644
--- a/src/cairo-gl-dispatch.c
+++ b/src/cairo-gl-dispatch.c
@@ -205,6 +205,27 @@ _cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_status_t
+_cairo_gl_dispatch_init_multisampling (cairo_gl_dispatch_t *dispatch,
+ cairo_gl_get_proc_addr_func_t get_proc_addr,
+ int gl_version,
+ cairo_gl_flavor_t gl_flavor)
+{
+ /* For the multisampling table, there are two GLES versions of the
+ * extension, so we put one in the EXT slot and one in the real ES slot.*/
+ cairo_gl_dispatch_name_t dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
+ if (gl_flavor == CAIRO_GL_FLAVOR_ES) {
+ if (_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture"))
+ dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
+ else if (_cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture"))
+ dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
+ }
+ _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
+ dispatch_multisampling_entries,
+ dispatch_name);
+ return CAIRO_STATUS_SUCCESS;
+}
+
cairo_status_t
_cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
cairo_gl_get_proc_addr_func_t get_proc_addr)
@@ -231,5 +252,10 @@ _cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
if (status != CAIRO_STATUS_SUCCESS)
return status;
+ status = _cairo_gl_dispatch_init_multisampling (dispatch, get_proc_addr,
+ gl_version, gl_flavor);
+ if (status != CAIRO_STATUS_SUCCESS)
+ return status;
+
return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index 431f5ee..34b5d72 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -134,7 +134,7 @@ _cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
status = _cairo_gl_surface_draw_image (cache->surface, glyph_surface,
0, 0,
glyph_surface->width, glyph_surface->height,
- node->x, node->y);
+ node->x, node->y, FALSE);
if (unlikely (status))
return status;
@@ -199,16 +199,16 @@ cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx,
}
if (unlikely (cache->surface == NULL)) {
- cairo_surface_t *surface;
+ cairo_surface_t *surface;
- surface = cairo_gl_surface_create (&ctx->base,
- content,
- GLYPH_CACHE_WIDTH,
- GLYPH_CACHE_HEIGHT);
- if (unlikely (surface->status))
- return surface->status;
+ surface = _cairo_gl_surface_create_scratch_for_caching (ctx,
+ content,
+ GLYPH_CACHE_WIDTH,
+ GLYPH_CACHE_HEIGHT);
+ if (unlikely (surface->status))
+ return surface->status;
- _cairo_surface_release_device_reference (surface);
+ _cairo_surface_release_device_reference (surface);
cache->surface = (cairo_gl_surface_t *)surface;
cache->surface->operand.texture.attributes.has_component_alpha =
@@ -231,6 +231,7 @@ render_glyphs (cairo_gl_surface_t *dst,
cairo_format_t last_format = CAIRO_FORMAT_INVALID;
cairo_gl_glyph_cache_t *cache = NULL;
cairo_gl_context_t *ctx;
+ cairo_gl_emit_glyph_t emit;
cairo_gl_composite_t setup;
cairo_int_status_t status;
int i = 0;
@@ -294,6 +295,8 @@ render_glyphs (cairo_gl_surface_t *dst,
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status))
goto FINISH;
+
+ emit = _cairo_gl_context_choose_emit_glyph (ctx);
}
if (scaled_glyph->dev_private_key != cache) {
@@ -329,10 +332,10 @@ render_glyphs (cairo_gl_surface_t *dst,
y2 = y1 + scaled_glyph->surface->height;
glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
- _cairo_gl_composite_emit_glyph (ctx,
- x1, y1, x2, y2,
- glyph->p1.x, glyph->p1.y,
- glyph->p2.x, glyph->p2.y);
+ emit (ctx,
+ x1, y1, x2, y2,
+ glyph->p1.x, glyph->p1.y,
+ glyph->p2.x, glyph->p2.y);
}
status = CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
index 1c1f972..ac32921 100644
--- a/src/cairo-gl-gradient.c
+++ b/src/cairo-gl-gradient.c
@@ -328,6 +328,8 @@ _cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient)
return;
if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) {
+ /* The gradient my still be active in the last operation, so flush */
+ _cairo_gl_composite_flush (ctx);
glDeleteTextures (1, &gradient->tex);
ignore = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
}
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index 35715d3..28001fe 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -45,6 +45,7 @@
#include "cairo-composite-rectangles-private.h"
#include "cairo-compositor-private.h"
#include "cairo-gl-private.h"
+#include "cairo-path-private.h"
#include "cairo-traps-private.h"
static cairo_bool_t
@@ -153,18 +154,23 @@ _draw_triangle_fan (cairo_gl_context_t *ctx,
return CAIRO_STATUS_SUCCESS;
}
-cairo_int_status_t
-_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_clip_t *clip)
+static cairo_int_status_t
+_clip_to_traps (cairo_clip_t *clip,
+ cairo_traps_t *traps)
{
cairo_int_status_t status;
- cairo_traps_t traps;
-
cairo_polygon_t polygon;
cairo_antialias_t antialias;
cairo_fill_rule_t fill_rule;
+ _cairo_traps_init (traps);
+
+ if (clip->num_boxes == 1 && clip->path == NULL) {
+ cairo_boxes_t boxes;
+ _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
+ return _cairo_traps_init_boxes (traps, &boxes);
+ }
+
status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
if (unlikely (status))
return status;
@@ -180,14 +186,26 @@ _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
* option.
*/
- _cairo_traps_init (&traps);
- status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
+ _cairo_traps_init (traps);
+ status = _cairo_bentley_ottmann_tessellate_polygon (traps,
&polygon,
fill_rule);
_cairo_polygon_fini (&polygon);
+
+ return status;
+}
+
+cairo_int_status_t
+_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
+ cairo_gl_composite_t *setup,
+ cairo_clip_t *clip)
+{
+ cairo_int_status_t status;
+ cairo_traps_t traps;
+
+ status = _clip_to_traps (clip, &traps);
if (unlikely (status))
return status;
-
status = _draw_traps (ctx, setup, &traps);
_cairo_traps_fini (&traps);
@@ -286,6 +304,97 @@ _cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
_cairo_gl_composite_set_clip (setup, composite->clip);
}
+/* Masking with the SOURCE operator requires two passes. In the first
+ * pass we use the mask as the source to get:
+ * result = (1 - ma) * dst
+ * In the second pass we use the add operator to achieve:
+ * result = (src * ma) + dst
+ * Combined this produces:
+ * result = (src * ma) + (1 - ma) * dst
+ */
+static cairo_int_status_t
+_cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor,
+ cairo_composite_rectangles_t *composite)
+{
+ cairo_gl_composite_t setup;
+ cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
+ cairo_gl_context_t *ctx = NULL;
+ cairo_int_status_t status;
+
+ cairo_clip_t *clip = composite->clip;
+ cairo_traps_t traps;
+
+ /* If we have a non-rectangular clip, we can avoid using the stencil buffer
+ * for clipping and just draw the clip polygon. */
+ if (clip) {
+ status = _clip_to_traps (clip, &traps);
+ if (unlikely (status)) {
+ _cairo_traps_fini (&traps);
+ return status;
+ }
+ }
+
+ status = _cairo_gl_composite_init (&setup,
+ CAIRO_OPERATOR_DEST_OUT,
+ dst,
+ FALSE /* assume_component_alpha */);
+ if (unlikely (status))
+ return status;
+ status = _cairo_gl_composite_set_source (&setup,
+ &composite->mask_pattern.base,
+ &composite->mask_sample_area,
+ &composite->bounded,
+ FALSE);
+ if (unlikely (status))
+ goto finish;
+ _cairo_gl_composite_set_multisample (&setup);
+ status = _cairo_gl_composite_begin (&setup, &ctx);
+ if (unlikely (status))
+ goto finish;
+
+ if (! clip)
+ status = _draw_int_rect (ctx, &setup, &composite->bounded);
+ else
+ status = _draw_traps (ctx, &setup, &traps);
+
+ /* Now draw the second pass. */
+ _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
+ FALSE /* assume_component_alpha */);
+ if (unlikely (status))
+ goto finish;
+ status = _cairo_gl_composite_set_source (&setup,
+ &composite->source_pattern.base,
+ &composite->source_sample_area,
+ &composite->bounded,
+ FALSE);
+ if (unlikely (status))
+ goto finish;
+ status = _cairo_gl_composite_set_mask (&setup,
+ &composite->mask_pattern.base,
+ &composite->source_sample_area,
+ &composite->bounded,
+ FALSE);
+ if (unlikely (status))
+ goto finish;
+ status = _cairo_gl_set_operands_and_operator (&setup, ctx);
+ if (unlikely (status))
+ goto finish;
+
+ if (! clip)
+ status = _draw_int_rect (ctx, &setup, &composite->bounded);
+ else
+ status = _draw_traps (ctx, &setup, &traps);
+
+finish:
+ _cairo_gl_composite_fini (&setup);
+ if (ctx)
+ status = _cairo_gl_context_release (ctx, status);
+ if (clip)
+ _cairo_traps_fini (&traps);
+
+ return status;
+}
+
static cairo_int_status_t
_cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *composite)
@@ -295,10 +404,15 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
cairo_gl_context_t *ctx = NULL;
cairo_int_status_t status;
cairo_operator_t op = composite->op;
+ cairo_clip_t *clip = composite->clip;
if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (composite->op == CAIRO_OPERATOR_CLEAR &&
+ composite->original_mask_pattern != NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
/* GL compositing operators cannot properly represent a mask operation
using the SOURCE compositing operator in one pass. This only matters if
there actually is a mask (there isn't in a paint operation) and if the
@@ -308,12 +422,13 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
&composite->mask_sample_area)) {
- /* If the source is opaque the operation reduces to OVER. */
- if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
- &composite->source_sample_area))
- op = CAIRO_OPERATOR_OVER;
- else
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
+ &composite->source_sample_area)) {
+ return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite);
+ }
+
+ /* If the source is opaque the operation reduces to OVER. */
+ op = CAIRO_OPERATOR_OVER;
}
if (_should_use_unbounded_surface (composite)) {
@@ -354,7 +469,8 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
status = _cairo_gl_composite_set_source (&setup,
&composite->source_pattern.base,
&composite->source_sample_area,
- &composite->bounded);
+ &composite->bounded,
+ FALSE);
if (unlikely (status))
goto finish;
@@ -362,20 +478,24 @@ _cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
status = _cairo_gl_composite_set_mask (&setup,
&composite->mask_pattern.base,
&composite->mask_sample_area,
- &composite->bounded);
+ &composite->bounded,
+ FALSE);
}
if (unlikely (status))
goto finish;
- _cairo_gl_msaa_compositor_set_clip (composite, &setup);
-
/* We always use multisampling here, because we do not yet have the smarts
to calculate when the clip or the source requires it. */
- status = _cairo_gl_composite_begin_multisample (&setup, &ctx, TRUE);
+ _cairo_gl_composite_set_multisample (&setup);
+
+ status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto finish;
- _draw_int_rect (ctx, &setup, &composite->bounded);
+ if (! clip)
+ status = _draw_int_rect (ctx, &setup, &composite->bounded);
+ else
+ status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
finish:
_cairo_gl_composite_fini (&setup);
@@ -424,10 +544,15 @@ _stroke_shaper_add_quad (void *closure,
}
static cairo_int_status_t
-_prevent_overlapping_drawing (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_composite_rectangles_t *composite)
+_prevent_overlapping_strokes (cairo_gl_context_t *ctx,
+ cairo_gl_composite_t *setup,
+ cairo_composite_rectangles_t *composite,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm)
{
+ cairo_rectangle_int_t stroke_extents;
+
if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -436,13 +561,33 @@ _prevent_overlapping_drawing (cairo_gl_context_t *ctx,
return CAIRO_INT_STATUS_SUCCESS;
if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
+ cairo_bool_t scissor_was_enabled;
+
+ /* In case we have pending operations we have to flush before
+ adding the stencil buffer. */
+ _cairo_gl_composite_flush (ctx);
+
/* Enable the stencil buffer, even if we are not using it for clipping,
so we can use it below to prevent overlapping shapes. We initialize
it all to one here which represents infinite clip. */
glDepthMask (GL_TRUE);
glEnable (GL_STENCIL_TEST);
+
+ /* We scissor here so that we don't have to clear the entire stencil
+ * buffer. If the scissor test is already enabled, it was enabled
+ * for clipping. In that case, instead of calculating an intersection,
+ * we just reuse it, and risk clearing too much. */
+ scissor_was_enabled = glIsEnabled (GL_SCISSOR_TEST);
+ if (! scissor_was_enabled) {
+ _cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
+ &stroke_extents);
+ _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
+ }
glClearStencil (1);
glClear (GL_STENCIL_BUFFER_BIT);
+ if (! scissor_was_enabled)
+ glDisable (GL_SCISSOR_TEST);
+
glStencilFunc (GL_EQUAL, 1, 1);
}
@@ -450,6 +595,10 @@ _prevent_overlapping_drawing (cairo_gl_context_t *ctx,
be drawn there until the stencil buffer is reset or the stencil test
is disabled. */
glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
+
+ _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
+ setup->dst->clip_on_stencil_buffer = NULL;
+
return CAIRO_INT_STATUS_SUCCESS;
}
@@ -534,18 +683,21 @@ _cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor,
status = _cairo_gl_composite_set_source (&info.setup,
&composite->source_pattern.base,
&composite->source_sample_area,
- &composite->bounded);
+ &composite->bounded,
+ FALSE);
if (unlikely (status))
goto finish;
_cairo_gl_msaa_compositor_set_clip (composite, &info.setup);
+ if (antialias != CAIRO_ANTIALIAS_NONE)
+ _cairo_gl_composite_set_multisample (&info.setup);
- status = _cairo_gl_composite_begin_multisample (&info.setup, &info.ctx,
- antialias != CAIRO_ANTIALIAS_NONE);
+ status = _cairo_gl_composite_begin (&info.setup, &info.ctx);
if (unlikely (status))
goto finish;
- status = _prevent_overlapping_drawing (info.ctx, &info.setup, composite);
+ status = _prevent_overlapping_strokes (info.ctx, &info.setup,
+ composite, path, style, ctm);
if (unlikely (status))
goto finish;
@@ -571,6 +723,29 @@ finish:
}
static cairo_int_status_t
+_draw_simple_quad_path (cairo_gl_context_t *ctx,
+ cairo_gl_composite_t *setup,
+ const cairo_path_fixed_t *path)
+{
+ cairo_point_t triangle[3];
+ cairo_int_status_t status;
+ const cairo_point_t *points;
+
+ points = cairo_path_head (path)->points;
+ triangle[0] = points[0];
+ triangle[1] = points[1];
+ triangle[2] = points[2];
+ status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
+ if (status)
+ return status;
+
+ triangle[0] = points[2];
+ triangle[1] = points[3];
+ triangle[2] = points[0];
+ return _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
+}
+
+static cairo_int_status_t
_cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
cairo_composite_rectangles_t *composite,
const cairo_path_fixed_t *path,
@@ -583,6 +758,7 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
cairo_gl_context_t *ctx = NULL;
cairo_int_status_t status;
cairo_traps_t traps;
+ cairo_bool_t draw_path_with_traps;
if (! can_use_msaa_compositor (dst, antialias))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -608,10 +784,14 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
return _paint_back_unbounded_surface (compositor, composite, surface);
}
- _cairo_traps_init (&traps);
- status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
- if (unlikely (status))
- goto cleanup_traps;
+ draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);
+
+ if (draw_path_with_traps) {
+ _cairo_traps_init (&traps);
+ status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
+ if (unlikely (status))
+ goto cleanup_traps;
+ }
status = _cairo_gl_composite_init (&setup,
composite->op,
@@ -623,18 +803,23 @@ _cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
status = _cairo_gl_composite_set_source (&setup,
&composite->source_pattern.base,
&composite->source_sample_area,
- &composite->bounded);
+ &composite->bounded,
+ FALSE);
if (unlikely (status))
goto cleanup_setup;
_cairo_gl_msaa_compositor_set_clip (composite, &setup);
+ if (antialias != CAIRO_ANTIALIAS_NONE)
+ _cairo_gl_composite_set_multisample (&setup);
- status = _cairo_gl_composite_begin_multisample (&setup, &ctx,
- antialias != CAIRO_ANTIALIAS_NONE);
+ status = _cairo_gl_composite_begin (&setup, &ctx);
if (unlikely (status))
goto cleanup_setup;
- status = _draw_traps (ctx, &setup, &traps);
+ if (! draw_path_with_traps)
+ status = _draw_simple_quad_path (ctx, &setup, path);
+ else
+ status = _draw_traps (ctx, &setup, &traps);
if (unlikely (status))
goto cleanup_setup;
@@ -645,7 +830,8 @@ cleanup_setup:
status = _cairo_gl_context_release (ctx, status);
cleanup_traps:
- _cairo_traps_fini (&traps);
+ if (draw_path_with_traps)
+ _cairo_traps_fini (&traps);
return status;
}
@@ -669,6 +855,9 @@ _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor,
if (! dst->supports_stencil)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (composite->op == CAIRO_OPERATOR_CLEAR)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (composite->is_bounded == FALSE) {
cairo_surface_t* surface = _prepare_unbounded_surface (dst);
@@ -709,7 +898,8 @@ _cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor,
info.font = scaled_font;
info.glyphs = glyphs;
info.num_glyphs = num_glyphs;
- info.use_mask = overlap || ! composite->is_bounded;
+ info.use_mask = overlap || ! composite->is_bounded ||
+ composite->op == CAIRO_OPERATOR_SOURCE;
info.extents = composite->bounded;
_cairo_scaled_font_freeze_cache (scaled_font);
diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
index ee6c08e..f99400c 100644
--- a/src/cairo-gl-operand.c
+++ b/src/cairo-gl-operand.c
@@ -107,7 +107,8 @@ _cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *_src,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t use_texgen)
{
const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
cairo_surface_pattern_t local_pattern;
@@ -185,6 +186,8 @@ _cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
attributes->extend = src->base.extend;
attributes->filter = src->base.filter;
attributes->has_component_alpha = src->base.has_component_alpha;
+
+ operand->texture.texgen = use_texgen;
return CAIRO_STATUS_SUCCESS;
}
@@ -193,7 +196,8 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *_src,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t use_texgen)
{
const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
cairo_surface_subsurface_t *sub;
@@ -208,7 +212,8 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
sample->y + sample->height > sub->extents.height)
{
return _cairo_gl_subsurface_clone_operand_init (operand, _src,
- dst, sample, extents);
+ dst, sample, extents,
+ use_texgen);
}
surface = (cairo_gl_surface_t *) sub->target;
@@ -239,6 +244,8 @@ _cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
attributes->extend = src->base.extend;
attributes->filter = src->base.filter;
attributes->has_component_alpha = src->base.has_component_alpha;
+
+ operand->texture.texgen = use_texgen;
return CAIRO_STATUS_SUCCESS;
}
@@ -247,7 +254,8 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *_src,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t use_texgen)
{
const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
cairo_gl_surface_t *surface;
@@ -261,7 +269,8 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
if (surface->base.backend->type != CAIRO_SURFACE_TYPE_GL) {
if (_cairo_surface_is_subsurface (&surface->base))
return _cairo_gl_subsurface_operand_init (operand, _src, dst,
- sample, extents);
+ sample, extents,
+ use_texgen);
return CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -269,6 +278,9 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
if (surface->base.device && surface->base.device != dst->base.device)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (surface->base.device && ! _cairo_gl_surface_is_texture (surface))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
status = _resolve_multisampling (surface);
if (unlikely (status))
return status;
@@ -283,6 +295,8 @@ _cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
attributes->extend = src->base.extend;
attributes->filter = src->base.filter;
attributes->has_component_alpha = src->base.has_component_alpha;
+
+ operand->texture.texgen = use_texgen;
return CAIRO_STATUS_SUCCESS;
}
@@ -389,7 +403,8 @@ _cairo_gl_operand_translate (cairo_gl_operand_t *operand,
static cairo_status_t
_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *pattern,
- cairo_gl_surface_t *dst)
+ cairo_gl_surface_t *dst,
+ cairo_bool_t use_texgen)
{
const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
cairo_status_t status;
@@ -472,6 +487,7 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
}
operand->gradient.extend = pattern->extend;
+ operand->gradient.texgen = use_texgen;
return CAIRO_STATUS_SUCCESS;
}
@@ -531,7 +547,8 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents)
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t use_texgen)
{
cairo_int_status_t status;
@@ -543,7 +560,7 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
return CAIRO_STATUS_SUCCESS;
case CAIRO_PATTERN_TYPE_SURFACE:
status = _cairo_gl_surface_operand_init (operand, pattern, dst,
- sample, extents);
+ sample, extents, use_texgen);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
break;
@@ -551,7 +568,8 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
case CAIRO_PATTERN_TYPE_LINEAR:
case CAIRO_PATTERN_TYPE_RADIAL:
- status = _cairo_gl_gradient_operand_init (operand, pattern, dst);
+ status = _cairo_gl_gradient_operand_init (operand, pattern, dst,
+ use_texgen);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
break;
@@ -631,6 +649,7 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
char uniform_name[50];
char *custom_part;
static const char *names[] = { "source", "mask" };
+ const cairo_matrix_t *texgen = NULL;
strcpy (uniform_name, names[tex_unit]);
custom_part = uniform_name + strlen (names[tex_unit]);
@@ -640,7 +659,8 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
- break;
+ return;
+
case CAIRO_GL_OPERAND_CONSTANT:
strcpy (custom_part, "_constant");
_cairo_gl_shader_bind_vec4 (ctx,
@@ -649,7 +669,8 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
operand->constant.color[1],
operand->constant.color[2],
operand->constant.color[3]);
- break;
+ return;
+
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
strcpy (custom_part, "_a");
@@ -692,7 +713,21 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
strcpy (custom_part, "_texdims");
_cairo_gl_shader_bind_vec2 (ctx, uniform_name, width, height);
}
- break;
+ break;
+ }
+
+ if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
+ if (operand->texture.texgen)
+ texgen = &operand->texture.attributes.matrix;
+ } else {
+ if (operand->gradient.texgen)
+ texgen = &operand->gradient.m;
+ }
+ if (texgen) {
+ char name[20];
+
+ sprintf (name, "%s_texgen", names[tex_unit]);
+ _cairo_gl_shader_bind_matrix(ctx, name, texgen);
}
}
@@ -735,9 +770,9 @@ _cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
}
unsigned int
-_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
+_cairo_gl_operand_get_vertex_size (const cairo_gl_operand_t *operand)
{
- switch (type) {
+ switch (operand->type) {
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
@@ -745,11 +780,12 @@ _cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
case CAIRO_GL_OPERAND_CONSTANT:
return 0;
case CAIRO_GL_OPERAND_TEXTURE:
+ return operand->texture.texgen ? 0 : 2 * sizeof (GLfloat);
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- return 2 * sizeof (GLfloat);
+ return operand->gradient.texgen ? 0 : 2 * sizeof (GLfloat);
}
}
@@ -770,7 +806,7 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- {
+ if (! operand->gradient.texgen) {
double s = x;
double t = y;
@@ -781,7 +817,7 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
}
break;
case CAIRO_GL_OPERAND_TEXTURE:
- {
+ if (! operand->texture.texgen) {
cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
double s = x;
double t = y;
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index d6b0554..5c9193d 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -91,8 +91,10 @@
* Random number that is hopefully big enough to not cause many cache evictions. */
#define CAIRO_GL_MAX_SHADERS_PER_CONTEXT 64
-/* VBO size that we allocate, smaller size means we gotta flush more often */
-#define CAIRO_GL_VBO_SIZE (256*1024)
+/* VBO size that we allocate, smaller size means we gotta flush more often,
+ * but larger means hogging more memory and can cause trouble for drivers
+ * (especially on embedded devices). */
+#define CAIRO_GL_VBO_SIZE (16*1024)
typedef struct _cairo_gl_surface cairo_gl_surface_t;
@@ -134,6 +136,7 @@ typedef struct cairo_gl_operand {
cairo_gl_surface_t *surface;
cairo_gl_surface_t *owns_surface;
cairo_surface_attributes_t attributes;
+ int texgen;
} texture;
struct {
GLfloat color[4];
@@ -144,6 +147,7 @@ typedef struct cairo_gl_operand {
cairo_circle_double_t circle_d;
double radius_0, a;
cairo_extend_t extend;
+ int texgen;
} gradient;
};
unsigned int vertex_offset;
@@ -175,6 +179,7 @@ struct _cairo_gl_surface {
cairo_bool_t supports_msaa;
cairo_bool_t msaa_active; /* Whether the multisampling
framebuffer is active or not. */
+ cairo_clip_t *clip_on_stencil_buffer;
int owns_tex;
cairo_bool_t needs_update;
@@ -209,6 +214,7 @@ typedef enum cairo_gl_shader_in {
typedef enum cairo_gl_var_type {
CAIRO_GL_VAR_NONE,
CAIRO_GL_VAR_TEXCOORDS,
+ CAIRO_GL_VAR_TEXGEN,
} cairo_gl_var_type_t;
typedef enum cairo_gl_primitive_type {
@@ -216,8 +222,23 @@ typedef enum cairo_gl_primitive_type {
CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS
} cairo_gl_primitive_type_t;
-#define cairo_gl_var_type_hash(src,mask,spans,dest) ((spans) << 3) | ((mask) << 2 | (src << 1) | (dest))
-#define CAIRO_GL_VAR_TYPE_MAX ((CAIRO_GL_VAR_TEXCOORDS << 3) | (CAIRO_GL_VAR_TEXCOORDS << 2) | (CAIRO_GL_VAR_TEXCOORDS << 1) | CAIRO_GL_VAR_TEXCOORDS)
+typedef void (*cairo_gl_emit_rect_t) (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2);
+
+typedef void (*cairo_gl_emit_span_t) (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ uint8_t alpha);
+
+typedef void (*cairo_gl_emit_glyph_t) (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ GLfloat glyph_x1, GLfloat glyph_y1,
+ GLfloat glyph_x2, GLfloat glyph_y2);
+
+#define cairo_gl_var_type_hash(src,mask,spans,dest) ((spans) << 5) | ((mask) << 3 | (src << 1) | (dest))
+#define CAIRO_GL_VAR_TYPE_MAX (1 << 6)
typedef void (*cairo_gl_generic_func_t)(void);
typedef cairo_gl_generic_func_t (*cairo_gl_get_proc_addr_func_t)(const char *procname);
@@ -316,7 +337,7 @@ struct _cairo_gl_context {
cairo_bool_t has_shader_support;
- GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX + 1];
+ GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX];
cairo_gl_shader_t fill_rectangles_shader;
cairo_cache_t shaders;
@@ -348,6 +369,7 @@ struct _cairo_gl_context {
cairo_bool_t has_map_buffer;
cairo_bool_t has_packed_depth_stencil;
cairo_bool_t has_npot_repeat;
+ cairo_bool_t can_read_bgra;
cairo_bool_t thread_aware;
@@ -369,6 +391,7 @@ typedef struct _cairo_gl_composite {
cairo_bool_t spans;
cairo_clip_t *clip;
+ cairo_bool_t multisample;
} cairo_gl_composite_t;
typedef struct _cairo_gl_font {
@@ -414,7 +437,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cairo_image_surface_t *src,
int src_x, int src_y,
int width, int height,
- int dst_x, int dst_y);
+ int dst_x, int dst_y,
+ cairo_bool_t force_flush);
static cairo_always_inline cairo_bool_t
_cairo_gl_device_has_glsl (cairo_device_t *device)
@@ -473,6 +497,20 @@ _cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
cairo_gl_surface_t *surface,
cairo_bool_t multisampling);
+cairo_private cairo_gl_emit_rect_t
+_cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx);
+
+cairo_private void
+_cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
+ GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2);
+
+cairo_private cairo_gl_emit_span_t
+_cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx);
+
+cairo_private cairo_gl_emit_glyph_t
+_cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx);
+
cairo_private void
_cairo_gl_context_activate (cairo_gl_context_t *ctx,
cairo_gl_tex_t tex_unit);
@@ -493,6 +531,11 @@ _cairo_gl_composite_init (cairo_gl_composite_t *setup,
cairo_private void
_cairo_gl_composite_fini (cairo_gl_composite_t *setup);
+cairo_private cairo_status_t
+_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
+ cairo_operator_t op,
+ cairo_bool_t assume_component_alpha);
+
cairo_private void
_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
cairo_region_t *clip_region);
@@ -503,9 +546,10 @@ _cairo_gl_composite_set_clip(cairo_gl_composite_t *setup,
cairo_private cairo_int_status_t
_cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
- const cairo_pattern_t *pattern,
+ const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents);
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t use_texgen);
cairo_private void
_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
@@ -519,7 +563,8 @@ cairo_private cairo_int_status_t
_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
const cairo_pattern_t *pattern,
const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents);
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t use_texgen);
cairo_private void
_cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
@@ -528,33 +573,16 @@ _cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
cairo_private void
_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup);
+cairo_private void
+_cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup);
+
cairo_private cairo_status_t
_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
cairo_gl_context_t **ctx);
cairo_private cairo_status_t
-_cairo_gl_composite_begin_multisample (cairo_gl_composite_t *setup,
- cairo_gl_context_t **ctx_out,
- cairo_bool_t multisampling);
-
-cairo_private void
-_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
- GLfloat x1,
- GLfloat y1,
- GLfloat x2,
- GLfloat y2,
- uint8_t alpha);
-
-cairo_private void
-_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
- GLfloat x1,
- GLfloat y1,
- GLfloat x2,
- GLfloat y2,
- GLfloat glyph_x1,
- GLfloat glyph_y1,
- GLfloat glyph_x2,
- GLfloat glyph_y2);
+_cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
+ cairo_gl_context_t *ctx);
cairo_private void
_cairo_gl_composite_flush (cairo_gl_context_t *ctx);
@@ -643,7 +671,7 @@ _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
cairo_private void
_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
const char *name,
- cairo_matrix_t* m);
+ const cairo_matrix_t* m);
cairo_private void
_cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
@@ -675,7 +703,8 @@ _cairo_gl_operand_init (cairo_gl_operand_t *operand,
const cairo_pattern_t *pattern,
cairo_gl_surface_t *dst,
const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents);
+ const cairo_rectangle_int_t *extents,
+ cairo_bool_t use_texgen);
cairo_private void
_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
@@ -691,7 +720,7 @@ cairo_private cairo_extend_t
_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand);
cairo_private unsigned int
-_cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type);
+_cairo_gl_operand_get_vertex_size (const cairo_gl_operand_t *operand);
cairo_private cairo_bool_t
_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
@@ -763,6 +792,12 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
int height);
cairo_private cairo_surface_t *
+_cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height);
+
+cairo_private cairo_surface_t *
_cairo_gl_pattern_to_source (cairo_surface_t *dst,
const cairo_pattern_t *pattern,
cairo_bool_t is_mask,
@@ -778,6 +813,10 @@ _cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
cairo_private cairo_surface_t *
_cairo_gl_white_source (void);
+cairo_private void
+_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
+ const cairo_rectangle_int_t *r);
+
static inline cairo_gl_operand_t *
source_to_operand (cairo_surface_t *surface)
{
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index 41672d6..0bc4e5e 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -55,10 +55,13 @@ _cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
typedef struct _cairo_shader_cache_entry {
cairo_cache_entry_t base;
+ unsigned vertex;
+
cairo_gl_operand_type_t src;
cairo_gl_operand_type_t mask;
cairo_gl_operand_type_t dest;
cairo_bool_t use_coverage;
+
cairo_gl_shader_in_t in;
GLint src_gl_filter;
cairo_bool_t src_border_fade;
@@ -79,13 +82,14 @@ _cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b)
cairo_bool_t both_have_npot_repeat =
a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
- return a->src == b->src &&
- a->mask == b->mask &&
- a->dest == b->dest &&
- a->use_coverage == b->use_coverage &&
- a->in == b->in &&
- (both_have_npot_repeat || a->src_extend == b->src_extend) &&
- (both_have_npot_repeat || a->mask_extend == b->mask_extend);
+ return (a->vertex == b->vertex &&
+ a->src == b->src &&
+ a->mask == b->mask &&
+ a->dest == b->dest &&
+ a->use_coverage == b->use_coverage &&
+ a->in == b->in &&
+ (both_have_npot_repeat || a->src_extend == b->src_extend) &&
+ (both_have_npot_repeat || a->mask_extend == b->mask_extend));
}
/*
@@ -101,23 +105,24 @@ _cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
cairo_bool_t both_have_npot_repeat =
a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
- return a->src == b->src &&
- a->mask == b->mask &&
- a->dest == b->dest &&
- a->use_coverage == b->use_coverage &&
- a->in == b->in &&
- a->src_gl_filter == b->src_gl_filter &&
- a->src_border_fade == b->src_border_fade &&
- (both_have_npot_repeat || a->src_extend == b->src_extend) &&
- a->mask_gl_filter == b->mask_gl_filter &&
- a->mask_border_fade == b->mask_border_fade &&
- (both_have_npot_repeat || a->mask_extend == b->mask_extend);
+ return (a->vertex && b->vertex &&
+ a->src == b->src &&
+ a->mask == b->mask &&
+ a->dest == b->dest &&
+ a->use_coverage == b->use_coverage &&
+ a->in == b->in &&
+ a->src_gl_filter == b->src_gl_filter &&
+ a->src_border_fade == b->src_border_fade &&
+ (both_have_npot_repeat || a->src_extend == b->src_extend) &&
+ a->mask_gl_filter == b->mask_gl_filter &&
+ a->mask_border_fade == b->mask_border_fade &&
+ (both_have_npot_repeat || a->mask_extend == b->mask_extend));
}
static unsigned long
_cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry)
{
- return (entry->src << 24) | (entry->mask << 16) | (entry->dest << 8) | (entry->in << 1) | entry->use_coverage;
+ return ((entry->src << 24) | (entry->mask << 16) | (entry->dest << 8) | (entry->in << 1) | entry->use_coverage) ^ entry->vertex;
}
static void
@@ -215,9 +220,9 @@ _cairo_gl_shader_fini (cairo_gl_context_t *ctx,
static const char *operand_names[] = { "source", "mask", "dest" };
static cairo_gl_var_type_t
-cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
+cairo_gl_operand_get_var_type (cairo_gl_operand_t *operand)
{
- switch (type) {
+ switch (operand->type) {
default:
case CAIRO_GL_OPERAND_COUNT:
ASSERT_NOT_REACHED;
@@ -228,8 +233,9 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
+ return operand->gradient.texgen ? CAIRO_GL_VAR_TEXGEN : CAIRO_GL_VAR_TEXCOORDS;
case CAIRO_GL_OPERAND_TEXTURE:
- return CAIRO_GL_VAR_TEXCOORDS;
+ return operand->texture.texgen ? CAIRO_GL_VAR_TEXGEN : CAIRO_GL_VAR_TEXCOORDS;
}
}
@@ -245,7 +251,16 @@ cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
break;
case CAIRO_GL_VAR_TEXCOORDS:
_cairo_output_stream_printf (stream,
+ "attribute vec4 MultiTexCoord%d;\n"
+ "varying vec2 %s_texcoords;\n",
+ name,
+ operand_names[name]);
+ break;
+ case CAIRO_GL_VAR_TEXGEN:
+ _cairo_output_stream_printf (stream,
+ "uniform mat3 %s_texgen;\n"
"varying vec2 %s_texcoords;\n",
+ operand_names[name],
operand_names[name]);
break;
}
@@ -266,6 +281,12 @@ cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
" %s_texcoords = MultiTexCoord%d.xy;\n",
operand_names[name], name);
break;
+
+ case CAIRO_GL_VAR_TEXGEN:
+ _cairo_output_stream_printf (stream,
+ " %s_texcoords = (%s_texgen * Vertex.xyw).xy;\n",
+ operand_names[name], operand_names[name]);
+ break;
}
}
@@ -301,8 +322,6 @@ cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
_cairo_output_stream_printf (stream,
"attribute vec4 Vertex;\n"
"attribute vec4 Color;\n"
- "attribute vec4 MultiTexCoord0;\n"
- "attribute vec4 MultiTexCoord1;\n"
"uniform mat4 ModelViewProjectionMatrix;\n"
"void main()\n"
"{\n"
@@ -920,7 +939,8 @@ _cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
void
_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
- const char *name, cairo_matrix_t* m)
+ const char *name,
+ const cairo_matrix_t* m)
{
cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
GLint location = dispatch->GetUniformLocation (ctx->current_shader->program,
@@ -973,6 +993,12 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
cairo_status_t status;
lookup.ctx = ctx;
+
+ lookup.vertex = cairo_gl_var_type_hash (cairo_gl_operand_get_var_type (source),
+ cairo_gl_operand_get_var_type (mask),
+ use_coverage,
+ CAIRO_GL_VAR_NONE);
+
lookup.src = source->type;
lookup.mask = mask->type;
lookup.dest = CAIRO_GL_OPERAND_NONE;
@@ -1016,8 +1042,8 @@ _cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
_cairo_gl_shader_init (&entry->shader);
status = _cairo_gl_shader_compile_and_link (ctx,
&entry->shader,
- cairo_gl_operand_get_var_type (source->type),
- cairo_gl_operand_get_var_type (mask->type),
+ cairo_gl_operand_get_var_type (source),
+ cairo_gl_operand_get_var_type (mask),
use_coverage,
fs_source);
free (fs_source);
diff --git a/src/cairo-gl-source.c b/src/cairo-gl-source.c
index 294f6f9..1223529 100644
--- a/src/cairo-gl-source.c
+++ b/src/cairo-gl-source.c
@@ -81,7 +81,8 @@ _cairo_gl_pattern_to_source (cairo_surface_t *dst,
*src_x = *src_y = 0;
status = _cairo_gl_operand_init (&source->operand, pattern,
(cairo_gl_surface_t *)dst,
- sample, extents);
+ sample, extents,
+ FALSE);
if (unlikely (status)) {
cairo_surface_destroy (&source->base);
return _cairo_surface_create_in_error (status);
diff --git a/src/cairo-gl-spans-compositor.c b/src/cairo-gl-spans-compositor.c
index 62da1eb..4317ccd 100644
--- a/src/cairo-gl-spans-compositor.c
+++ b/src/cairo-gl-spans-compositor.c
@@ -57,6 +57,8 @@ typedef struct _cairo_gl_span_renderer {
cairo_gl_composite_t setup;
double opacity;
+ cairo_gl_emit_span_t emit;
+
int xmin, xmax;
int ymin, ymax;
@@ -70,16 +72,17 @@ _cairo_gl_bounded_opaque_spans (void *abstract_renderer,
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
do {
if (spans[0].coverage) {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- spans[0].coverage);
+ emit (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ spans[0].coverage);
}
spans++;
@@ -95,16 +98,17 @@ _cairo_gl_bounded_spans (void *abstract_renderer,
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (num_spans == 0)
return CAIRO_STATUS_SUCCESS;
do {
if (spans[0].coverage) {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- r->opacity * spans[0].coverage);
+ emit (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ r->opacity * spans[0].coverage);
}
spans++;
@@ -120,40 +124,41 @@ _cairo_gl_unbounded_spans (void *abstract_renderer,
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (y > r->ymin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, r->ymin,
- r->xmax, y,
- 0);
+ emit (r->ctx,
+ r->xmin, r->ymin,
+ r->xmax, y,
+ 0);
}
if (num_spans == 0) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, y,
- r->xmax, y + height,
- 0);
+ emit (r->ctx,
+ r->xmin, y,
+ r->xmax, y + height,
+ 0);
} else {
if (spans[0].x != r->xmin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, y,
- spans[0].x, y + height,
- 0);
+ emit (r->ctx,
+ r->xmin, y,
+ spans[0].x, y + height,
+ 0);
}
do {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- r->opacity * spans[0].coverage);
+ emit (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ r->opacity * spans[0].coverage);
spans++;
} while (--num_spans > 1);
if (spans[0].x != r->xmax) {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- r->xmax, y + height,
- 0);
+ emit (r->ctx,
+ spans[0].x, y,
+ r->xmax, y + height,
+ 0);
}
}
@@ -169,40 +174,41 @@ _cairo_gl_clipped_spans (void *abstract_renderer,
unsigned num_spans)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (y > r->ymin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, r->ymin,
- r->xmax, y,
- 0);
+ emit (r->ctx,
+ r->xmin, r->ymin,
+ r->xmax, y,
+ 0);
}
if (num_spans == 0) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, y,
- r->xmax, y + height,
- 0);
+ emit (r->ctx,
+ r->xmin, y,
+ r->xmax, y + height,
+ 0);
} else {
if (spans[0].x != r->xmin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, y,
- spans[0].x, y + height,
- 0);
+ emit (r->ctx,
+ r->xmin, y,
+ spans[0].x, y + height,
+ 0);
}
do {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- r->opacity * spans[0].coverage);
+ emit (r->ctx,
+ spans[0].x, y,
+ spans[1].x, y + height,
+ r->opacity * spans[0].coverage);
spans++;
} while (--num_spans > 1);
if (spans[0].x != r->xmax) {
- _cairo_gl_composite_emit_rect (r->ctx,
- spans[0].x, y,
- r->xmax, y + height,
- 0);
+ emit (r->ctx,
+ spans[0].x, y,
+ r->xmax, y + height,
+ 0);
}
}
@@ -214,12 +220,13 @@ static cairo_status_t
_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
{
cairo_gl_span_renderer_t *r = abstract_renderer;
+ cairo_gl_emit_span_t emit = r->emit;
if (r->ymax > r->ymin) {
- _cairo_gl_composite_emit_rect (r->ctx,
- r->xmin, r->ymin,
- r->xmax, r->ymax,
- 0);
+ emit (r->ctx,
+ r->xmin, r->ymin,
+ r->xmax, r->ymax,
+ 0);
}
return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
@@ -238,6 +245,7 @@ emit_aligned_boxes (cairo_gl_context_t *ctx,
const cairo_boxes_t *boxes)
{
const struct _cairo_boxes_chunk *chunk;
+ cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
int i;
TRACE ((stderr, "%s: num_boxes=%d\n", __FUNCTION__, boxes->num_boxes));
@@ -247,7 +255,7 @@ emit_aligned_boxes (cairo_gl_context_t *ctx,
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
- _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 255);
+ emit (ctx, x1, y1, x2, y2);
}
}
}
@@ -303,7 +311,7 @@ draw_image_boxes (void *_dst,
status = _cairo_gl_surface_draw_image (dst, image,
x + dx, y + dy,
w, h,
- x, y);
+ x, y, TRUE);
if (unlikely (status))
return status;
}
@@ -423,6 +431,13 @@ _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t *_r,
cairo_operator_t op = composite->op;
cairo_int_status_t status;
+ if (op == CAIRO_OPERATOR_SOURCE) {
+ if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
+ &composite->source_sample_area))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ op = CAIRO_OPERATOR_OVER;
+ }
+
/* XXX earlier! */
if (op == CAIRO_OPERATOR_CLEAR) {
source = &_cairo_pattern_white.base;
@@ -446,7 +461,8 @@ _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t *_r,
status = _cairo_gl_composite_set_source (&r->setup, source,
&composite->source_sample_area,
- &composite->unbounded);
+ &composite->unbounded,
+ TRUE);
if (unlikely (status))
goto FAIL;
@@ -457,7 +473,8 @@ _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t *_r,
status = _cairo_gl_composite_set_mask (&r->setup,
&composite->mask_pattern.base,
&composite->mask_sample_area,
- &composite->unbounded);
+ &composite->unbounded,
+ TRUE);
if (unlikely (status))
goto FAIL;
}
@@ -468,6 +485,7 @@ _cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t *_r,
if (unlikely (status))
goto FAIL;
+ r->emit = _cairo_gl_context_choose_emit_span (r->ctx);
if (composite->is_bounded) {
if (r->opacity == 1.)
r->base.render_rows = _cairo_gl_bounded_opaque_spans;
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index c0ee79f..1d7515a 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -424,11 +424,12 @@ _cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx,
return &surface->base;
}
-cairo_surface_t *
-_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
- cairo_content_t content,
- int width,
- int height)
+static cairo_surface_t *
+_create_scratch_internal (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height,
+ cairo_bool_t for_caching)
{
cairo_gl_surface_t *surface;
GLenum format;
@@ -456,8 +457,13 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
format = GL_RGBA;
break;
case CAIRO_CONTENT_ALPHA:
- /* We want to be trying GL_ALPHA framebuffer objects here. */
- format = GL_RGBA;
+ /* When using GL_ALPHA, compositing doesn't work properly, but for
+ * caching surfaces, we are just uploading pixel data, so it isn't
+ * an issue. */
+ if (for_caching)
+ format = GL_ALPHA;
+ else
+ format = GL_RGBA;
break;
case CAIRO_CONTENT_COLOR:
/* GL_RGB is almost what we want here -- sampling 1 alpha when
@@ -478,6 +484,24 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
return &surface->base;
}
+cairo_surface_t *
+_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ return _create_scratch_internal (ctx, content, width, height, FALSE);
+}
+
+cairo_surface_t *
+_cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ return _create_scratch_internal (ctx, content, width, height, TRUE);
+}
+
static cairo_status_t
_cairo_gl_surface_clear (cairo_gl_surface_t *surface,
const cairo_color_t *color)
@@ -508,9 +532,36 @@ _cairo_gl_surface_clear (cairo_gl_surface_t *surface,
glClearColor (r, g, b, a);
glClear (GL_COLOR_BUFFER_BIT);
+ if (a == 0)
+ surface->base.is_clear = TRUE;
+
return _cairo_gl_context_release (ctx, status);
}
+static cairo_surface_t *
+_cairo_gl_surface_create_and_clear_scratch (cairo_gl_context_t *ctx,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_gl_surface_t *surface;
+ cairo_int_status_t status;
+
+ surface = (cairo_gl_surface_t *)
+ _cairo_gl_surface_create_scratch (ctx, content, width, height);
+ if (unlikely (surface->base.status))
+ return &surface->base;
+
+ /* Cairo surfaces start out initialized to transparent (black) */
+ status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ return &surface->base;
+}
+
cairo_surface_t *
cairo_gl_surface_create (cairo_device_t *abstract_device,
cairo_content_t content,
@@ -538,16 +589,13 @@ cairo_gl_surface_create (cairo_device_t *abstract_device,
return _cairo_surface_create_in_error (status);
surface = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_scratch (ctx, content, width, height);
+ _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
if (unlikely (surface->base.status)) {
status = _cairo_gl_context_release (ctx, surface->base.status);
cairo_surface_destroy (&surface->base);
return _cairo_surface_create_in_error (status);
}
- /* Cairo surfaces start out initialized to transparent (black) */
- status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
-
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status)) {
cairo_surface_destroy (&surface->base);
@@ -740,7 +788,7 @@ _cairo_gl_surface_create_similar (void *abstract_surface,
if (unlikely (status))
return _cairo_surface_create_in_error (status);
- surface = _cairo_gl_surface_create_scratch (ctx, content, width, height);
+ surface = _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
status = _cairo_gl_context_release (ctx, status);
if (unlikely (status)) {
@@ -774,7 +822,7 @@ _cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t *dst,
if (unlikely (status))
goto CLEANUP;
- _cairo_gl_composite_emit_rect (ctx, x, y, x + width, y + height, 0);
+ _cairo_gl_context_emit_rect (ctx, x, y, x + width, y + height);
status = _cairo_gl_context_release (ctx, status);
@@ -792,7 +840,8 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cairo_image_surface_t *src,
int src_x, int src_y,
int width, int height,
- int dst_x, int dst_y)
+ int dst_x, int dst_y,
+ cairo_bool_t force_flush)
{
GLenum internal_format, format, type;
cairo_bool_t has_alpha, needs_swap;
@@ -834,9 +883,11 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
- status = _cairo_gl_surface_flush (&dst->base, 0);
- if (unlikely (status))
- goto FAIL;
+ if (force_flush) {
+ status = _cairo_gl_surface_flush (&dst->base, 0);
+ if (unlikely (status))
+ goto FAIL;
+ }
if (_cairo_gl_surface_is_texture (dst)) {
void *data_start = src->data + src_y * src->stride + src_x * cpp;
@@ -903,7 +954,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
src,
src_x, src_y,
width, height,
- 0, 0);
+ 0, 0, force_flush);
if (status == CAIRO_INT_STATUS_SUCCESS) {
cairo_surface_pattern_t tmp_pattern;
cairo_rectangle_int_t r;
@@ -999,6 +1050,11 @@ _cairo_gl_surface_map_to_image (void *abstract_surface,
cairo_status_t status;
int y;
+ status = _cairo_gl_context_acquire (surface->base.device, &ctx);
+ if (unlikely (status)) {
+ return _cairo_image_surface_create_in_error (status);
+ }
+
/* Want to use a switch statement here but the compiler gets whiny. */
if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
format = GL_BGRA;
@@ -1020,25 +1076,26 @@ _cairo_gl_surface_map_to_image (void *abstract_surface,
return NULL;
}
- /*
- * GLES2 supports only RGBA, UNSIGNED_BYTE so use that.
- * We are also using this format for ALPHA as GLES2 does not
- * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
- * pixman image that is created has row_stride = row_width * bpp.
- */
if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES) {
- format = GL_RGBA;
- if (! _cairo_is_little_endian ()) {
- if (surface->base.content == CAIRO_CONTENT_COLOR)
- pixman_format = PIXMAN_r8g8b8x8;
- else
- pixman_format = PIXMAN_r8g8b8a8;
- } else {
- if (surface->base.content == CAIRO_CONTENT_COLOR)
- pixman_format = PIXMAN_x8b8g8r8;
- else
- pixman_format = PIXMAN_a8b8g8r8;
+ /* If only RGBA is supported, we must download data in a compatible
+ * format. This means that pixman will convert the data on the CPU when
+ * interacting with other image surfaces. For ALPHA, GLES2 does not
+ * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
+ * pixman image that is created has row_stride = row_width * bpp. */
+ if (surface->base.content == CAIRO_CONTENT_ALPHA || !ctx->can_read_bgra) {
+ cairo_bool_t little_endian = _cairo_is_little_endian ();
+ format = GL_RGBA;
+
+ if (surface->base.content == CAIRO_CONTENT_COLOR) {
+ pixman_format = little_endian ?
+ PIXMAN_x8b8g8r8 : PIXMAN_r8g8b8x8;
+ } else {
+ pixman_format = little_endian ?
+ PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
+ }
}
+
+ /* GLES2 only supports GL_UNSIGNED_BYTE. */
type = GL_UNSIGNED_BYTE;
cpp = 4;
}
@@ -1049,20 +1106,20 @@ _cairo_gl_surface_map_to_image (void *abstract_surface,
extents->width,
extents->height,
-1);
- if (unlikely (image->base.status))
- return image;
-
- if (surface->base.serial == 0)
+ if (unlikely (image->base.status)) {
+ status = _cairo_gl_context_release (ctx, status);
return image;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status)) {
- cairo_surface_destroy (&image->base);
- return _cairo_image_surface_create_in_error (status);
}
cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y);
+ /* If the original surface has not been modified or
+ * is clear, we can avoid downloading data. */
+ if (surface->base.is_clear || surface->base.serial == 0) {
+ status = _cairo_gl_context_release (ctx, status);
+ return image;
+ }
+
/* This is inefficient, as we'd rather just read the thing without making
* it the destination. But then, this is the fallback path, so let's not
* fall back instead.
@@ -1177,7 +1234,8 @@ _cairo_gl_surface_unmap_image (void *abstract_surface,
0, 0,
image->width, image->height,
image->base.device_transform_inverse.x0,
- image->base.device_transform_inverse.y0);
+ image->base.device_transform_inverse.y0,
+ TRUE);
cairo_surface_finish (&image->base);
cairo_surface_destroy (&image->base);
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
index a87fd16..548162b 100644
--- a/src/cairo-gl-traps-compositor.c
+++ b/src/cairo-gl-traps-compositor.c
@@ -50,6 +50,7 @@
#include "cairo-image-surface-private.h"
#include "cairo-spans-compositor-private.h"
#include "cairo-surface-backend-private.h"
+#include "cairo-surface-offset-private.h"
static cairo_int_status_t
acquire (void *abstract_dst)
@@ -95,7 +96,8 @@ draw_image_boxes (void *_dst,
status = _cairo_gl_surface_draw_image (dst, image,
x + dx, y + dy,
w, h,
- x, y);
+ x, y,
+ TRUE);
if (unlikely (status))
return status;
}
@@ -109,6 +111,7 @@ emit_aligned_boxes (cairo_gl_context_t *ctx,
const cairo_boxes_t *boxes)
{
const struct _cairo_boxes_chunk *chunk;
+ cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
int i;
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
@@ -117,7 +120,7 @@ emit_aligned_boxes (cairo_gl_context_t *ctx,
int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
- _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2, 0);
+ emit (ctx, x1, y1, x2, y2);
}
}
}
@@ -227,7 +230,7 @@ composite (void *_dst,
goto FAIL;
/* XXX clip */
- _cairo_gl_composite_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height, 0);
+ _cairo_gl_context_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
@@ -300,6 +303,36 @@ traps_to_operand (void *_dst,
return image->status;
}
+ /* GLES2 only supports RGB/RGBA when uploading */
+ if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) {
+ cairo_surface_pattern_t pattern;
+ cairo_surface_t *rgba_image;
+
+ /* XXX perform this fixup inside _cairo_gl_draw_image() */
+
+ rgba_image =
+ _cairo_image_surface_create_with_pixman_format (NULL,
+ _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8,
+ extents->width,
+ extents->height,
+ 0);
+ if (unlikely (rgba_image->status))
+ return rgba_image->status;
+
+ _cairo_pattern_init_for_surface (&pattern, image);
+ status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE,
+ &pattern.base, NULL);
+ _cairo_pattern_fini (&pattern.base);
+
+ cairo_surface_destroy (image);
+ image = rgba_image;
+
+ if (unlikely (status)) {
+ cairo_surface_destroy (image);
+ return status;
+ }
+ }
+
mask = _cairo_surface_create_similar_scratch (_dst,
CAIRO_CONTENT_COLOR_ALPHA,
extents->width,
@@ -313,8 +346,10 @@ traps_to_operand (void *_dst,
(cairo_image_surface_t *)image,
0, 0,
extents->width, extents->height,
- 0, 0);
+ 0, 0,
+ TRUE);
cairo_surface_destroy (image);
+
if (unlikely (status))
goto error;
@@ -325,7 +360,8 @@ traps_to_operand (void *_dst,
pattern.base.extend = CAIRO_EXTEND_NONE;
status = _cairo_gl_operand_init (operand, &pattern.base, _dst,
&_cairo_unbounded_rectangle,
- &_cairo_unbounded_rectangle);
+ &_cairo_unbounded_rectangle,
+ FALSE);
_cairo_pattern_fini (&pattern.base);
if (unlikely (status))
@@ -371,10 +407,10 @@ composite_traps (void *_dst,
goto FAIL;
/* XXX clip */
- _cairo_gl_composite_emit_rect (ctx,
- extents->x-dst_x, extents->y-dst_y,
- extents->x-dst_x+extents->width,
- extents->y-dst_y+extents->height, 0);
+ _cairo_gl_context_emit_rect (ctx,
+ extents->x-dst_x, extents->y-dst_y,
+ extents->x-dst_x+extents->width,
+ extents->y-dst_y+extents->height);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
@@ -422,7 +458,8 @@ tristrip_to_surface (void *_dst,
(cairo_image_surface_t *)image,
0, 0,
extents->width, extents->height,
- 0, 0);
+ 0, 0,
+ TRUE);
cairo_surface_destroy (image);
if (unlikely (status)) {
cairo_surface_destroy (mask);
@@ -467,10 +504,10 @@ composite_tristrip (void *_dst,
goto FAIL;
/* XXX clip */
- _cairo_gl_composite_emit_rect (ctx,
- dst_x, dst_y,
- dst_x+extents->width,
- dst_y+extents->height, 0);
+ _cairo_gl_context_emit_rect (ctx,
+ dst_x, dst_y,
+ dst_x+extents->width,
+ dst_y+extents->height);
status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
FAIL:
diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c
index 47634f1..3761b90 100644
--- a/src/cairo-glx-context.c
+++ b/src/cairo-glx-context.c
@@ -53,6 +53,9 @@ typedef struct _cairo_glx_context {
Window dummy_window;
GLXContext context;
+ GLXDrawable previous_drawable;
+ GLXContext previous_context;
+
cairo_bool_t has_multithread_makecurrent;
} cairo_glx_context_t;
@@ -62,19 +65,50 @@ typedef struct _cairo_glx_surface {
Window win;
} cairo_glx_surface_t;
+static cairo_bool_t
+_context_acquisition_changed_glx_state (cairo_glx_context_t *ctx,
+ GLXDrawable current_drawable)
+{
+ return ctx->previous_drawable != current_drawable ||
+ ctx->previous_context != ctx->context;
+}
+
+static GLXDrawable
+_glx_get_current_drawable (cairo_glx_context_t *ctx)
+{
+ if (ctx->base.current_target == NULL ||
+ _cairo_gl_surface_is_texture (ctx->base.current_target)) {
+ return ctx->dummy_window;
+ }
+
+ return ((cairo_glx_surface_t *) ctx->base.current_target)->win;
+}
+
+static void
+_glx_query_current_state (cairo_glx_context_t * ctx)
+{
+ ctx->previous_drawable = glXGetCurrentDrawable ();
+ ctx->previous_context = glXGetCurrentContext ();
+
+ /* If any of the values were none, assume they are all none. Not all
+ drivers seem well behaved when it comes to using these values across
+ multiple threads. */
+ if (ctx->previous_drawable == None ||
+ ctx->previous_context == None) {
+ ctx->previous_drawable = None;
+ ctx->previous_context = None;
+ }
+}
+
static void
_glx_acquire (void *abstract_ctx)
{
cairo_glx_context_t *ctx = abstract_ctx;
- GLXDrawable current_drawable;
+ GLXDrawable current_drawable = _glx_get_current_drawable (ctx);
- if (ctx->base.current_target == NULL ||
- _cairo_gl_surface_is_texture (ctx->base.current_target)) {
- current_drawable = ctx->dummy_window;
- } else {
- cairo_glx_surface_t *surface = (cairo_glx_surface_t *) ctx->base.current_target;
- current_drawable = surface->win;
- }
+ _glx_query_current_state (ctx);
+ if (!_context_acquisition_changed_glx_state (ctx, current_drawable))
+ return;
glXMakeCurrent (ctx->display, current_drawable, ctx->context);
}
@@ -94,8 +128,11 @@ _glx_release (void *abstract_ctx)
{
cairo_glx_context_t *ctx = abstract_ctx;
- if (ctx->has_multithread_makecurrent || !ctx->base.thread_aware)
+ if (ctx->has_multithread_makecurrent || !ctx->base.thread_aware ||
+ !_context_acquisition_changed_glx_state (ctx,
+ _glx_get_current_drawable (ctx))) {
return;
+ }
glXMakeCurrent (ctx->display, None, None);
}
@@ -118,11 +155,11 @@ _glx_destroy (void *abstract_ctx)
if (ctx->dummy_window != None)
XDestroyWindow (ctx->display, ctx->dummy_window);
- glXMakeCurrent (ctx->display, 0, 0);
+ glXMakeCurrent (ctx->display, None, None);
}
static cairo_status_t
-_glx_dummy_ctx (Display *dpy, GLXContext gl_ctx, Window *dummy)
+_glx_dummy_window (Display *dpy, GLXContext gl_ctx, Window *dummy)
{
int attr[3] = { GLX_FBCONFIG_ID, 0, None };
GLXFBConfig *config;
@@ -181,14 +218,20 @@ cairo_glx_device_create (Display *dpy, GLXContext gl_ctx)
Window dummy = None;
const char *glx_extensions;
- status = _glx_dummy_ctx (dpy, gl_ctx, &dummy);
- if (unlikely (status))
- return _cairo_gl_context_create_in_error (status);
-
ctx = calloc (1, sizeof (cairo_glx_context_t));
if (unlikely (ctx == NULL))
return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ /* glx_dummy_window will call glXMakeCurrent, so we need to
+ * query the current state of the context now. */
+ _glx_query_current_state (ctx);
+
+ status = _glx_dummy_window (dpy, gl_ctx, &dummy);
+ if (unlikely (status)) {
+ free (ctx);
+ return _cairo_gl_context_create_in_error (status);
+ }
+
ctx->display = dpy;
ctx->dummy_window = dummy;
ctx->context = gl_ctx;
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index c90f2f6..6319471 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1235,12 +1235,12 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
_cairo_traps_init (&traps);
_cairo_traps_limit (&traps, &limit, 1);
- status = _cairo_path_fixed_stroke_to_traps (path,
- &gstate->stroke_style,
- &gstate->ctm,
- &gstate->ctm_inverse,
- gstate->tolerance,
- &traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (path,
+ &gstate->stroke_style,
+ &gstate->ctm,
+ &gstate->ctm_inverse,
+ gstate->tolerance,
+ &traps);
if (unlikely (status))
goto BAIL;
@@ -1465,12 +1465,12 @@ _cairo_gstate_stroke_extents (cairo_gstate_t *gstate,
cairo_traps_t traps;
_cairo_traps_init (&traps);
- status = _cairo_path_fixed_stroke_to_traps (path,
- &gstate->stroke_style,
- &gstate->ctm,
- &gstate->ctm_inverse,
- gstate->tolerance,
- &traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (path,
+ &gstate->stroke_style,
+ &gstate->ctm,
+ &gstate->ctm_inverse,
+ gstate->tolerance,
+ &traps);
empty = traps.num_traps == 0;
if (! empty)
_cairo_traps_extents (&traps, &extents);
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index 768e3a5..be3db98 100644
--- a/src/cairo-image-compositor.c
+++ b/src/cairo-image-compositor.c
@@ -1538,6 +1538,7 @@ typedef struct _cairo_image_span_renderer {
pixman_image_t *dst;
int src_x, src_y;
int mask_x, mask_y;
+ int run_length;
} composite;
struct finish {
cairo_rectangle_int_t extents;
@@ -1546,7 +1547,8 @@ typedef struct _cairo_image_span_renderer {
uint8_t *data;
} mask;
} u;
- uint8_t buf[sizeof(cairo_abstract_span_renderer_t)-128];
+ uint8_t _buf[0];
+#define SZ_BUF (sizeof (cairo_abstract_span_renderer_t) - sizeof (cairo_image_span_renderer_t))
} cairo_image_span_renderer_t;
COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t));
@@ -2186,7 +2188,7 @@ _fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h,
uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
if (a == 0xff) {
if (len > 31) {
- pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
+ pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
spans[0].x, y, len, 1, r->u.fill.pixel);
} else {
uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
@@ -2206,7 +2208,7 @@ _fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h,
if (a) {
if (a == 0xff) {
if (spans[1].x - spans[0].x > 16) {
- pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp,
+ pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32,
spans[0].x, y, spans[1].x - spans[0].x, h,
r->u.fill.pixel);
} else {
@@ -2250,7 +2252,7 @@ _fill_a8_lerp_spans (void *abstract_renderer, int y, int h,
if (likely(h == 1)) {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int len = spans[1].x - spans[0].x;
uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x;
@@ -2265,7 +2267,7 @@ _fill_a8_lerp_spans (void *abstract_renderer, int y, int h,
} while (--num_spans > 1);
} else {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int yy = y, hh = h;
uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f;
@@ -2298,7 +2300,7 @@ _fill_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
if (likely(h == 1)) {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int len = spans[1].x - spans[0].x;
uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4);
@@ -2311,7 +2313,7 @@ _fill_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
} while (--num_spans > 1);
} else {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int yy = y, hh = h;
do {
@@ -2344,7 +2346,7 @@ _blit_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride;
uint8_t *dst = r->u.blit.data + y*r->u.blit.stride;
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
uint32_t *s = (uint32_t*)src + spans[0].x;
uint32_t *d = (uint32_t*)dst + spans[0].x;
@@ -2365,7 +2367,7 @@ _blit_xrgb32_lerp_spans (void *abstract_renderer, int y, int h,
} while (--num_spans > 1);
} else {
do {
- uint8_t a = mul8_8 (spans[0].coverage, r->op);
+ uint8_t a = mul8_8 (spans[0].coverage, r->bpp);
if (a) {
int yy = y, hh = h;
do {
@@ -2417,31 +2419,111 @@ _inplace_spans (void *abstract_renderer,
}
mask = (uint8_t *)pixman_image_get_data (r->mask);
- x0 = spans[0].x;
+ x1 = x0 = spans[0].x;
do {
int len = spans[1].x - spans[0].x;
*mask++ = spans[0].coverage;
if (len > 1) {
- memset (mask, spans[0].coverage, --len);
- mask += len;
+ if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
+ if (x1 != x0) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ }
+ pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst,
+ spans[0].x + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ spans[0].x, y,
+ len, h);
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x0 = spans[1].x;
+ } else if (spans[0].coverage == 0x0 &&
+ x1 - x0 > r->u.composite.run_length) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x0 = spans[1].x;
+ }else {
+ memset (mask, spans[0].coverage, --len);
+ mask += len;
+ }
}
x1 = spans[1].x;
spans++;
} while (--num_spans > 1);
- pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
- x0 + r->u.composite.src_x,
- y + r->u.composite.src_y,
- 0, 0,
- x0, y,
- x1 - x0, h);
+ if (x1 != x0) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ }
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-_inplace_src_spans (void *abstract_renderer,
- int y, int h,
+_inplace_opacity_spans (void *abstract_renderer, int y, int h,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+ uint8_t *mask;
+ int x0, x1;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x1 = x0 = spans[0].x;
+ do {
+ int len = spans[1].x - spans[0].x;
+ uint8_t m = mul8_8(spans[0].coverage, r->bpp);
+ *mask++ = m;
+ if (len > 1) {
+ if (m == 0 &&
+ x1 - x0 > r->u.composite.run_length) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x0 = spans[1].x;
+ }else {
+ memset (mask, m, --len);
+ mask += len;
+ }
+ }
+ x1 = spans[1].x;
+ spans++;
+ } while (--num_spans > 1);
+
+ if (x1 != x0) {
+ pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ x1 - x0, h);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_inplace_src_spans (void *abstract_renderer, int y, int h,
const cairo_half_open_span_t *spans,
unsigned num_spans)
{
@@ -2453,10 +2535,10 @@ _inplace_src_spans (void *abstract_renderer,
return CAIRO_STATUS_SUCCESS;
x0 = spans[0].x;
- m = r->buf;
+ m = r->_buf;
do {
int len = spans[1].x - spans[0].x;
- if (spans[0].coverage == 0xff) {
+ if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) {
if (spans[0].x != x0) {
#if PIXMAN_HAS_OP_LERP
pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
@@ -2491,7 +2573,7 @@ _inplace_src_spans (void *abstract_renderer,
spans[0].x, y,
spans[1].x - spans[0].x, h);
- m = r->buf;
+ m = r->_buf;
x0 = spans[1].x;
} else if (spans[0].coverage == 0x0) {
if (spans[0].x != x0) {
@@ -2520,7 +2602,7 @@ _inplace_src_spans (void *abstract_renderer,
#endif
}
- m = r->buf;
+ m = r->_buf;
x0 = spans[1].x;
} else {
*m++ = spans[0].coverage;
@@ -2561,6 +2643,96 @@ _inplace_src_spans (void *abstract_renderer,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_status_t
+_inplace_src_opacity_spans (void *abstract_renderer, int y, int h,
+ const cairo_half_open_span_t *spans,
+ unsigned num_spans)
+{
+ cairo_image_span_renderer_t *r = abstract_renderer;
+ uint8_t *mask;
+ int x0;
+
+ if (num_spans == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ x0 = spans[0].x;
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ do {
+ int len = spans[1].x - spans[0].x;
+ uint8_t m = mul8_8(spans[0].coverage, r->bpp);
+ if (m == 0) {
+ if (spans[0].x != x0) {
+#if PIXMAN_HAS_OP_LERP
+ pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
+ r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+#else
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ r->mask, NULL, r->u.composite.dst,
+ 0, 0,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+#endif
+ }
+
+ mask = (uint8_t *)pixman_image_get_data (r->mask);
+ x0 = spans[1].x;
+ } else {
+ *mask++ = m;
+ if (len > 1) {
+ memset (mask, m, --len);
+ mask += len;
+ }
+ }
+ spans++;
+ } while (--num_spans > 1);
+
+ if (spans[0].x != x0) {
+#if PIXMAN_HAS_OP_LERP
+ pixman_image_composite32 (PIXMAN_OP_LERP_SRC,
+ r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+#else
+ pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE,
+ r->mask, NULL, r->u.composite.dst,
+ 0, 0,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ r->src, r->mask, r->u.composite.dst,
+ x0 + r->u.composite.src_x,
+ y + r->u.composite.src_y,
+ 0, 0,
+ x0, y,
+ spans[0].x - x0, h);
+#endif
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void free_pixels (pixman_image_t *image, void *data)
+{
+ free (data);
+}
+
static cairo_int_status_t
inplace_renderer_init (cairo_image_span_renderer_t *r,
const cairo_composite_rectangles_t *composite,
@@ -2568,12 +2740,13 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
cairo_bool_t needs_clip)
{
cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface;
+ uint8_t *buf;
if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
r->base.render_rows = NULL;
- r->op = composite->mask_pattern.solid.color.alpha_short >> 8;
+ r->bpp = composite->mask_pattern.solid.color.alpha_short >> 8;
if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
const cairo_color_t *color;
@@ -2588,7 +2761,7 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
* typically small, too small to payback the startup overheads of
* using SSE2 etc.
*/
- if (r->op == 0xff) {
+ if (r->bpp == 0xff) {
switch (dst->format) {
case CAIRO_FORMAT_A8:
r->base.render_rows = _fill_a8_lerp_opaque_spans;
@@ -2650,24 +2823,26 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
}
}
if (r->base.render_rows == NULL) {
- unsigned int width;
const cairo_pattern_t *src = &composite->source_pattern.base;
-
- if (r->op != 0xff)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ unsigned int width;
if (composite->is_bounded == 0)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ r->base.render_rows = r->bpp == 0xff ? _inplace_spans : _inplace_opacity_spans;
width = (composite->bounded.width + 3) & ~3;
- r->base.render_rows = _inplace_spans;
+
+ r->u.composite.run_length = 8;
+ if (src->type == CAIRO_PATTERN_TYPE_LINEAR ||
+ src->type == CAIRO_PATTERN_TYPE_RADIAL)
+ r->u.composite.run_length = 256;
if (dst->base.is_clear &&
(composite->op == CAIRO_OPERATOR_SOURCE ||
composite->op == CAIRO_OPERATOR_OVER ||
composite->op == CAIRO_OPERATOR_ADD)) {
r->op = PIXMAN_OP_SRC;
} else if (composite->op == CAIRO_OPERATOR_SOURCE) {
- r->base.render_rows = _inplace_src_spans;
+ r->base.render_rows = r->bpp == 0xff ? _inplace_src_spans : _inplace_src_opacity_spans;
r->u.composite.mask_y = r->composite->unbounded.y;
width = (composite->unbounded.width + 3) & ~3;
} else if (composite->op == CAIRO_OPERATOR_CLEAR) {
@@ -2677,9 +2852,6 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
r->op = _pixman_operator (composite->op);
}
- if (width > sizeof (r->buf))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
r->src = _pixman_image_for_pattern (dst, src, FALSE,
&composite->bounded,
&composite->source_sample_area,
@@ -2688,19 +2860,30 @@ inplace_renderer_init (cairo_image_span_renderer_t *r,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* Create an effectively unbounded mask by repeating the single line */
+ buf = r->_buf;
+ if (width > SZ_BUF) {
+ buf = malloc (width);
+ if (unlikely (buf == NULL)) {
+ pixman_image_unref (r->src);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ }
r->mask = pixman_image_create_bits (PIXMAN_a8,
width, composite->unbounded.height,
- (uint32_t *)r->buf, 0);
+ (uint32_t *)buf, 0);
if (unlikely (r->mask == NULL)) {
pixman_image_unref (r->src);
+ if (buf != r->_buf)
+ free (buf);
return _cairo_error(CAIRO_STATUS_NO_MEMORY);
}
+ if (buf != r->_buf)
+ pixman_image_set_destroy_function (r->mask, free_pixels, buf);
+
r->u.composite.dst = dst->pixman_image;
}
- r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format);
-
return CAIRO_INT_STATUS_SUCCESS;
}
@@ -2716,7 +2899,8 @@ span_renderer_init (cairo_abstract_span_renderer_t *_r,
cairo_operator_t op = composite->op;
cairo_int_status_t status;
- TRACE ((stderr, "%s\n", __FUNCTION__));
+ TRACE ((stderr, "%s: antialias=%d, needs_clip=%d\n", __FUNCTION__,
+ antialias, needs_clip));
if (needs_clip)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2749,11 +2933,19 @@ span_renderer_init (cairo_abstract_span_renderer_t *_r,
op == CAIRO_OPERATOR_ADD)) {
op = PIXMAN_OP_SRC;
} else if (op == CAIRO_OPERATOR_SOURCE) {
+ if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
+ &composite->source_sample_area))
+ {
+ op = PIXMAN_OP_OVER;
+ }
+ else
+ {
#if PIXMAN_HAS_OP_LERP
- op = PIXMAN_OP_LERP_SRC;
+ op = PIXMAN_OP_LERP_SRC;
#else
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
#endif
+ }
} else {
op = _pixman_operator (op);
}
@@ -2801,7 +2993,7 @@ span_renderer_init (cairo_abstract_span_renderer_t *_r,
r->u.mask.extents = composite->unbounded;
r->u.mask.stride = (r->u.mask.extents.width + 3) & ~3;
- if (r->u.mask.extents.height * r->u.mask.stride > (int)sizeof (r->buf)) {
+ if (r->u.mask.extents.height * r->u.mask.stride > (int)sizeof (r->_buf)) {
r->mask = pixman_image_create_bits (PIXMAN_a8,
r->u.mask.extents.width,
r->u.mask.extents.height,
@@ -2813,7 +3005,7 @@ span_renderer_init (cairo_abstract_span_renderer_t *_r,
r->mask = pixman_image_create_bits (PIXMAN_a8,
r->u.mask.extents.width,
r->u.mask.extents.height,
- (uint32_t *)r->buf, r->u.mask.stride);
+ (uint32_t *)r->_buf, r->u.mask.stride);
r->base.render_rows = _cairo_image_spans_and_zero;
r->base.finish = _cairo_image_finish_spans_and_zero;
diff --git a/src/cairo-image-surface-private.h b/src/cairo-image-surface-private.h
index 6a159d8..8ca694c 100644
--- a/src/cairo-image-surface-private.h
+++ b/src/cairo-image-surface-private.h
@@ -226,6 +226,13 @@ cairo_private cairo_image_surface_t *
_cairo_image_surface_clone_subimage (cairo_surface_t *surface,
const cairo_rectangle_int_t *extents);
+/* Similar to clone; but allow format conversion */
+cairo_private cairo_image_surface_t *
+_cairo_image_surface_create_from_image (cairo_image_surface_t *other,
+ pixman_format_code_t format,
+ int x, int y, int width, int height,
+ int stride);
+
CAIRO_END_DECLS
#endif /* CAIRO_IMAGE_SURFACE_PRIVATE_H */
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 3fe6e43..49f6e18 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1088,6 +1088,61 @@ _cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface,
return clone;
}
+cairo_image_surface_t *
+_cairo_image_surface_create_from_image (cairo_image_surface_t *other,
+ pixman_format_code_t format,
+ int x, int y,
+ int width, int height, int stride)
+{
+ cairo_image_surface_t *surface;
+ cairo_status_t status;
+ pixman_image_t *image;
+ void *mem = NULL;
+
+ status = other->base.status;
+ if (unlikely (status))
+ goto cleanup;
+
+ if (stride) {
+ mem = _cairo_malloc_ab (height, stride);
+ if (unlikely (mem == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto cleanup;
+ }
+ }
+
+ image = pixman_image_create_bits (format, width, height, mem, stride);
+ if (unlikely (image == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto cleanup_mem;
+ }
+
+ surface = (cairo_image_surface_t *)
+ _cairo_image_surface_create_for_pixman_image (image, format);
+ if (unlikely (surface->base.status)) {
+ status = surface->base.status;
+ goto cleanup_image;
+ }
+
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ other->pixman_image, NULL, image,
+ x, y,
+ 0, 0,
+ 0, 0,
+ width, height);
+ surface->base.is_clear = FALSE;
+ surface->owns_data = mem != NULL;
+
+ return surface;
+
+cleanup_image:
+ pixman_image_unref (image);
+cleanup_mem:
+ free (mem);
+cleanup:
+ return (cairo_image_surface_t *) _cairo_surface_create_in_error (status);
+}
+
cairo_image_transparency_t
_cairo_image_analyze_transparency (cairo_image_surface_t *image)
{
@@ -1240,7 +1295,14 @@ _cairo_image_surface_clone_subimage (cairo_surface_t *surface,
if (unlikely (status))
goto error;
- _cairo_image_surface_set_parent (to_image_surface (image), surface);
+ /* We use the parent as a flag during map-to-image/umap-image that the
+ * resultant image came from a fallback rather than as direct call
+ * to the backend's map_to_image(). Whilst we use it as a simple flag,
+ * we need to make sure the parent surface obeys the reference counting
+ * semantics and is consistent for all callers.
+ */
+ _cairo_image_surface_set_parent (to_image_surface (image),
+ cairo_surface_reference (surface));
return to_image_surface (image);
diff --git a/src/cairo-mask-compositor.c b/src/cairo-mask-compositor.c
index 7976a79..d0be144 100644
--- a/src/cairo-mask-compositor.c
+++ b/src/cairo-mask-compositor.c
@@ -172,7 +172,7 @@ create_composite_mask (const cairo_mask_compositor_t *compositor,
status = compositor->acquire (surface);
if (unlikely (status)) {
cairo_surface_destroy (surface);
- return _cairo_surface_create_in_error (status);
+ return _cairo_int_surface_create_in_error (status);
}
if (!surface->is_clear) {
@@ -239,7 +239,7 @@ error:
compositor->release (surface);
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
cairo_surface_destroy (surface);
- surface = _cairo_surface_create_in_error (status);
+ surface = _cairo_int_surface_create_in_error (status);
}
return surface;
}
@@ -298,6 +298,38 @@ clip_and_composite_with_mask (const cairo_mask_compositor_t *compositor,
return CAIRO_STATUS_SUCCESS;
}
+static cairo_surface_t *
+get_clip_source (const cairo_mask_compositor_t *compositor,
+ cairo_clip_t *clip,
+ cairo_surface_t *dst,
+ const cairo_rectangle_int_t *bounds,
+ int *out_x, int *out_y)
+{
+ cairo_surface_pattern_t pattern;
+ cairo_rectangle_int_t r;
+ cairo_surface_t *surface;
+
+ surface = _cairo_clip_get_image (clip, dst, bounds);
+ if (unlikely (surface->status))
+ return surface;
+
+ _cairo_pattern_init_for_surface (&pattern, surface);
+ pattern.base.filter = CAIRO_FILTER_NEAREST;
+ cairo_surface_destroy (surface);
+
+ r.x = r.y = 0;
+ r.width = bounds->width;
+ r.height = bounds->height;
+
+ surface = compositor->pattern_to_surface (dst, &pattern.base, TRUE,
+ &r, &r, out_x, out_y);
+ _cairo_pattern_fini (&pattern.base);
+
+ *out_x += -bounds->x;
+ *out_y += -bounds->y;
+ return surface;
+}
+
/* Handles compositing with a clip surface when we have to do the operation
* in two pieces and combine them together.
*/
@@ -312,6 +344,7 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
cairo_surface_t *dst = extents->surface;
cairo_surface_t *tmp, *clip;
cairo_status_t status;
+ int clip_x, clip_y;
tmp = _cairo_surface_create_similar_scratch (dst, dst->content,
extents->bounded.width,
@@ -332,20 +365,22 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
if (unlikely (status))
goto cleanup;
- clip = _cairo_clip_get_image (extents->clip, dst, &extents->bounded);
+ clip = get_clip_source (compositor,
+ extents->clip, dst, &extents->bounded,
+ &clip_x, &clip_y);
if (unlikely ((status = clip->status)))
goto cleanup;
if (dst->is_clear) {
compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip,
0, 0,
- 0, 0,
+ clip_x, clip_y,
extents->bounded.x, extents->bounded.y,
extents->bounded.width, extents->bounded.height);
} else {
/* Punch the clip out of the destination */
compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, clip, NULL,
- 0, 0,
+ clip_x, clip_y,
0, 0,
extents->bounded.x, extents->bounded.y,
extents->bounded.width, extents->bounded.height);
@@ -353,7 +388,7 @@ clip_and_composite_combine (const cairo_mask_compositor_t *compositor,
/* Now add the two results together */
compositor->composite (dst, CAIRO_OPERATOR_ADD, tmp, clip,
0, 0,
- 0, 0,
+ clip_x, clip_y,
extents->bounded.x, extents->bounded.y,
extents->bounded.width, extents->bounded.height);
}
@@ -515,17 +550,15 @@ fixup_unbounded_with_mask (const cairo_mask_compositor_t *compositor,
cairo_surface_t *dst,
const cairo_composite_rectangles_t *extents)
{
- cairo_clip_t *clip = extents->clip;
cairo_surface_t *mask;
int mask_x, mask_y;
- mask = _cairo_clip_get_image (clip, dst, &extents->unbounded);
+ mask = get_clip_source (compositor,
+ extents->clip, dst, &extents->unbounded,
+ &mask_x, &mask_y);
if (unlikely (mask->status))
return mask->status;
- mask_x = -extents->unbounded.x;
- mask_y = -extents->unbounded.y;
-
/* top */
if (extents->bounded.y != extents->unbounded.y) {
int x = extents->unbounded.x;
@@ -870,8 +903,9 @@ composite_boxes (const cairo_mask_compositor_t *compositor,
int mask_x = 0, mask_y = 0;
if (need_clip_mask) {
- mask = _cairo_clip_get_image (extents->clip, dst,
- &extents->bounded);
+ mask = get_clip_source (compositor,
+ extents->clip, dst, &extents->bounded,
+ &mask_x, &mask_y);
if (unlikely (mask->status))
return mask->status;
@@ -879,9 +913,6 @@ composite_boxes (const cairo_mask_compositor_t *compositor,
source = NULL;
op = CAIRO_OPERATOR_DEST_OUT;
}
-
- mask_x = -extents->bounded.x;
- mask_y = -extents->bounded.y;
}
if (source || mask == NULL) {
@@ -960,6 +991,10 @@ _cairo_mask_compositor_paint (const cairo_compositor_t *_compositor,
cairo_boxes_t boxes;
cairo_int_status_t status;
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return status;
+
_cairo_clip_steal_boxes (extents->clip, &boxes);
status = clip_and_composite_boxes (compositor, extents, &boxes);
_cairo_clip_unsteal_boxes (extents->clip, &boxes);
@@ -1210,9 +1245,13 @@ _cairo_mask_compositor_mask (const cairo_compositor_t *_compositor,
const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return status;
+
if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
extents->clip->path == NULL &&
- ! _cairo_clip_is_region (extents->clip)) {
+ _cairo_clip_is_region (extents->clip)) {
status = clip_and_composite (compositor,
composite_opacity_boxes,
composite_opacity_boxes,
@@ -1242,9 +1281,12 @@ _cairo_mask_compositor_stroke (const cairo_compositor_t *_compositor,
const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
cairo_surface_t *mask;
cairo_surface_pattern_t pattern;
- cairo_int_status_t status;
+ cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return status;
- status = CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
cairo_boxes_t boxes;
@@ -1311,9 +1353,12 @@ _cairo_mask_compositor_fill (const cairo_compositor_t *_compositor,
const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
cairo_surface_t *mask;
cairo_surface_pattern_t pattern;
- cairo_int_status_t status;
+ cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return status;
- status = CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_path_fixed_fill_is_rectilinear (path)) {
cairo_boxes_t boxes;
@@ -1374,10 +1419,15 @@ _cairo_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
int num_glyphs,
cairo_bool_t overlap)
{
+ const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor;
cairo_surface_t *mask;
cairo_surface_pattern_t pattern;
cairo_int_status_t status;
+ status = compositor->check_composite (extents);
+ if (unlikely (status))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
mask = cairo_surface_create_similar_image (extents->surface,
CAIRO_FORMAT_A8,
extents->bounded.width,
diff --git a/src/cairo-mempool.c b/src/cairo-mempool.c
index 296b739..96e4a62 100644
--- a/src/cairo-mempool.c
+++ b/src/cairo-mempool.c
@@ -283,9 +283,18 @@ _cairo_mempool_init (cairo_mempool_t *pool,
void *base, size_t bytes,
int min_bits, int num_sizes)
{
+ unsigned long tmp;
int num_blocks;
int i;
+ /* Align the start to an integral chunk */
+ tmp = ((unsigned long) base) & ((1 << min_bits) - 1);
+ if (tmp) {
+ tmp = (1 << min_bits) - tmp;
+ base = (char *)base + tmp;
+ bytes -= tmp;
+ }
+
assert ((((unsigned long) base) & ((1 << min_bits) - 1)) == 0);
assert (num_sizes < ARRAY_LENGTH (pool->free));
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
index 9b7b403..cf7cd08 100644
--- a/src/cairo-path-fixed-private.h
+++ b/src/cairo-path-fixed-private.h
@@ -59,6 +59,20 @@ typedef char cairo_path_op_t;
#define CAIRO_PATH_BUF_SIZE ((512 - sizeof (cairo_path_buf_t)) \
/ (2 * sizeof (cairo_point_t) + sizeof (cairo_path_op_t)))
+#define cairo_path_head(path__) (&(path__)->buf.base)
+#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__))
+
+#define cairo_path_buf_next(pos__) \
+ cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link)
+#define cairo_path_buf_prev(pos__) \
+ cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link)
+
+#define cairo_path_foreach_buf_start(pos__, path__) \
+ pos__ = cairo_path_head (path__); do
+#define cairo_path_foreach_buf_end(pos__, path__) \
+ while ((pos__ = cairo_path_buf_next (pos__)) != cairo_path_head (path__))
+
+
typedef struct _cairo_path_buf {
cairo_list_t link;
unsigned int num_ops;
@@ -186,4 +200,7 @@ cairo_private cairo_bool_t
_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
cairo_box_t *box);
+cairo_private cairo_bool_t
+_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path);
+
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index c7b1cab..66fbdfe 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -69,19 +69,6 @@ _cairo_path_buf_add_points (cairo_path_buf_t *buf,
const cairo_point_t *points,
int num_points);
-#define cairo_path_head(path__) (&(path__)->buf.base)
-#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__))
-
-#define cairo_path_buf_next(pos__) \
- cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link)
-#define cairo_path_buf_prev(pos__) \
- cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link)
-
-#define cairo_path_foreach_buf_start(pos__, path__) \
- pos__ = cairo_path_head (path__); do
-#define cairo_path_foreach_buf_end(pos__, path__) \
- while ((pos__ = cairo_path_buf_next (pos__)) != cairo_path_head (path__))
-
void
_cairo_path_fixed_init (cairo_path_fixed_t *path)
{
@@ -1219,18 +1206,11 @@ _canonical_box (cairo_box_t *box,
}
}
-/*
- * Check whether the given path contains a single rectangle.
- */
-cairo_bool_t
-_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
- cairo_box_t *box)
+static inline cairo_bool_t
+_path_is_quad (const cairo_path_fixed_t *path)
{
const cairo_path_buf_t *buf = cairo_path_head (path);
- if (! path->fill_is_rectilinear)
- return FALSE;
-
/* Do we have the right number of ops? */
if (buf->num_ops < 4 || buf->num_ops > 6)
return FALSE;
@@ -1265,22 +1245,87 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
}
}
- /* Ok, we may have a box, if the points line up */
- if (buf->points[0].y == buf->points[1].y &&
- buf->points[1].x == buf->points[2].x &&
- buf->points[2].y == buf->points[3].y &&
- buf->points[3].x == buf->points[0].x)
- {
+ return TRUE;
+}
+
+static inline cairo_bool_t
+_points_form_rect (const cairo_point_t *points)
+{
+ if (points[0].y == points[1].y &&
+ points[1].x == points[2].x &&
+ points[2].y == points[3].y &&
+ points[3].x == points[0].x)
+ return TRUE;
+ if (points[0].x == points[1].x &&
+ points[1].y == points[2].y &&
+ points[2].x == points[3].x &&
+ points[3].y == points[0].y)
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Check whether the given path contains a single rectangle.
+ */
+cairo_bool_t
+_cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
+ cairo_box_t *box)
+{
+ const cairo_path_buf_t *buf;
+
+ if (! path->fill_is_rectilinear)
+ return FALSE;
+
+ if (! _path_is_quad (path))
+ return FALSE;
+
+ buf = cairo_path_head (path);
+ if (_points_form_rect (buf->points)) {
_canonical_box (box, &buf->points[0], &buf->points[2]);
return TRUE;
}
- if (buf->points[0].x == buf->points[1].x &&
- buf->points[1].y == buf->points[2].y &&
- buf->points[2].x == buf->points[3].x &&
- buf->points[3].y == buf->points[0].y)
- {
- _canonical_box (box, &buf->points[0], &buf->points[2]);
+ return FALSE;
+}
+
+/* Determine whether two lines A->B and C->D intersect based on the
+ * algorithm described here: http://paulbourke.net/geometry/lineline2d/ */
+static inline cairo_bool_t
+_lines_intersect_or_are_coincident (cairo_point_t a,
+ cairo_point_t b,
+ cairo_point_t c,
+ cairo_point_t d)
+{
+ cairo_int64_t numerator_a, numerator_b, denominator;
+
+ denominator = _cairo_int64_sub (_cairo_int32x32_64_mul (d.y - c.y, b.x - a.x),
+ _cairo_int32x32_64_mul (d.x - c.x, b.y - a.y));
+ numerator_a = _cairo_int64_sub (_cairo_int32x32_64_mul (d.x - c.x, a.y - c.y),
+ _cairo_int32x32_64_mul (d.y - c.y, a.x - c.x));
+ numerator_b = _cairo_int64_sub (_cairo_int32x32_64_mul (b.x - a.x, a.y - c.y),
+ _cairo_int32x32_64_mul (b.y - a.y, a.x - c.x));
+
+ if (_cairo_int64_is_zero (denominator)) {
+ /* If the denominator and numerators are both zero,
+ * the lines are coincident. */
+ if (_cairo_int64_is_zero (numerator_a) && _cairo_int64_is_zero (numerator_b))
+ return TRUE;
+
+ /* Otherwise, a zero denominator indicates the lines are
+ * parallel and never intersect. */
+ return FALSE;
+ }
+
+ /* If either division would produce a number between 0 and 1, i.e.
+ * the numerator is smaller than the denominator and their signs are
+ * the same, then the lines intersect. */
+ if (_cairo_int64_lt (numerator_a, denominator) &&
+ ! (_cairo_int64_negative (numerator_a) ^ _cairo_int64_negative(denominator))) {
+ return TRUE;
+ }
+
+ if (_cairo_int64_lt (numerator_b, denominator) &&
+ ! (_cairo_int64_negative (numerator_b) ^ _cairo_int64_negative(denominator))) {
return TRUE;
}
@@ -1288,6 +1333,29 @@ _cairo_path_fixed_is_box (const cairo_path_fixed_t *path,
}
cairo_bool_t
+_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path)
+{
+ const cairo_point_t *points;
+
+ if (! _path_is_quad (path))
+ return FALSE;
+
+ points = cairo_path_head (path)->points;
+ if (_points_form_rect (points))
+ return TRUE;
+
+ if (_lines_intersect_or_are_coincident (points[0], points[1],
+ points[3], points[2]))
+ return FALSE;
+
+ if (_lines_intersect_or_are_coincident (points[0], points[3],
+ points[1], points[2]))
+ return FALSE;
+
+ return TRUE;
+}
+
+cairo_bool_t
_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path,
cairo_box_t *box)
{
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index f6e81e0..2c8fe5e 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -1169,7 +1169,7 @@ curve_to (void *closure,
cairo_stroke_face_t face;
if (stroker->has_bounds &&
- ! _cairo_spline_intersects (&stroker->current_face.point, b, c, b,
+ ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
&stroker->bounds))
return line_to (closure, d);
diff --git a/src/cairo-path-stroke-traps.c b/src/cairo-path-stroke-traps.c
new file mode 100644
index 0000000..304dea7
--- /dev/null
+++ b/src/cairo-path-stroke-traps.c
@@ -0,0 +1,1122 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-box-inline.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-slope-private.h"
+#include "cairo-stroke-dash-private.h"
+#include "cairo-traps-private.h"
+
+#include <float.h>
+
+struct stroker {
+ const cairo_stroke_style_t *style;
+
+ const cairo_matrix_t *ctm;
+ const cairo_matrix_t *ctm_inverse;
+ double spline_cusp_tolerance;
+ double half_line_width;
+ double tolerance;
+ double ctm_determinant;
+ cairo_bool_t ctm_det_positive;
+ cairo_line_join_t line_join;
+
+ cairo_traps_t *traps;
+
+ cairo_pen_t pen;
+
+ cairo_point_t first_point;
+
+ cairo_bool_t has_initial_sub_path;
+
+ cairo_bool_t has_current_face;
+ cairo_stroke_face_t current_face;
+
+ cairo_bool_t has_first_face;
+ cairo_stroke_face_t first_face;
+
+ cairo_stroker_dash_t dash;
+
+ cairo_bool_t has_bounds;
+ cairo_box_t tight_bounds;
+ cairo_box_t line_bounds;
+ cairo_box_t join_bounds;
+};
+
+static cairo_status_t
+stroker_init (struct stroker *stroker,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps)
+{
+ cairo_status_t status;
+
+ stroker->style = style;
+ stroker->ctm = ctm;
+ stroker->ctm_inverse = NULL;
+ if (! _cairo_matrix_is_identity (ctm_inverse))
+ stroker->ctm_inverse = ctm_inverse;
+ stroker->line_join = style->line_join;
+ stroker->half_line_width = style->line_width / 2.0;
+ stroker->tolerance = tolerance;
+ stroker->traps = traps;
+
+ /* To test whether we need to join two segments of a spline using
+ * a round-join or a bevel-join, we can inspect the angle between the
+ * two segments. If the difference between the chord distance
+ * (half-line-width times the cosine of the bisection angle) and the
+ * half-line-width itself is greater than tolerance then we need to
+ * inject a point.
+ */
+ stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width;
+ stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
+ stroker->spline_cusp_tolerance *= 2;
+ stroker->spline_cusp_tolerance -= 1;
+
+ stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
+ stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
+
+ status = _cairo_pen_init (&stroker->pen,
+ stroker->half_line_width,
+ tolerance, ctm);
+ if (unlikely (status))
+ return status;
+
+ stroker->has_current_face = FALSE;
+ stroker->has_first_face = FALSE;
+ stroker->has_initial_sub_path = FALSE;
+
+ _cairo_stroker_dash_init (&stroker->dash, style);
+
+ stroker->has_bounds = traps->num_limits;
+ if (stroker->has_bounds) {
+ /* Extend the bounds in each direction to account for the maximum area
+ * we might generate trapezoids, to capture line segments that are outside
+ * of the bounds but which might generate rendering that's within bounds.
+ */
+ double dx, dy;
+ cairo_fixed_t fdx, fdy;
+
+ stroker->tight_bounds = traps->bounds;
+
+ _cairo_stroke_style_max_distance_from_path (stroker->style, path,
+ stroker->ctm, &dx, &dy);
+
+ _cairo_stroke_style_max_line_distance_from_path (stroker->style, path,
+ stroker->ctm, &dx, &dy);
+
+ fdx = _cairo_fixed_from_double (dx);
+ fdy = _cairo_fixed_from_double (dy);
+
+ stroker->line_bounds = stroker->tight_bounds;
+ stroker->line_bounds.p1.x -= fdx;
+ stroker->line_bounds.p2.x += fdx;
+ stroker->line_bounds.p1.y -= fdy;
+ stroker->line_bounds.p2.y += fdy;
+
+ _cairo_stroke_style_max_join_distance_from_path (stroker->style, path,
+ stroker->ctm, &dx, &dy);
+
+ fdx = _cairo_fixed_from_double (dx);
+ fdy = _cairo_fixed_from_double (dy);
+
+ stroker->join_bounds = stroker->tight_bounds;
+ stroker->join_bounds.p1.x -= fdx;
+ stroker->join_bounds.p2.x += fdx;
+ stroker->join_bounds.p1.y -= fdy;
+ stroker->join_bounds.p2.y += fdy;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+stroker_fini (struct stroker *stroker)
+{
+ _cairo_pen_fini (&stroker->pen);
+}
+
+static void
+translate_point (cairo_point_t *point, cairo_point_t *offset)
+{
+ point->x += offset->x;
+ point->y += offset->y;
+}
+
+static int
+join_is_clockwise (const cairo_stroke_face_t *in,
+ const cairo_stroke_face_t *out)
+{
+ return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0;
+}
+
+static int
+slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
+{
+ double c = dx1 * dy2 - dx2 * dy1;
+ if (c > 0) return 1;
+ if (c < 0) return -1;
+ return 0;
+}
+
+static cairo_bool_t
+stroker_intersects_join (const struct stroker *stroker,
+ const cairo_point_t *in,
+ const cairo_point_t *out)
+{
+ cairo_line_t segment;
+
+ if (! stroker->has_bounds)
+ return TRUE;
+
+ segment.p1 = *in;
+ segment.p2 = *out;
+ return _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment);
+}
+
+static void
+join (struct stroker *stroker,
+ cairo_stroke_face_t *in,
+ cairo_stroke_face_t *out)
+{
+ int clockwise = join_is_clockwise (out, in);
+ cairo_point_t *inpt, *outpt;
+
+ if (in->cw.x == out->cw.x &&
+ in->cw.y == out->cw.y &&
+ in->ccw.x == out->ccw.x &&
+ in->ccw.y == out->ccw.y)
+ {
+ return;
+ }
+
+ if (clockwise) {
+ inpt = &in->ccw;
+ outpt = &out->ccw;
+ } else {
+ inpt = &in->cw;
+ outpt = &out->cw;
+ }
+
+ if (! stroker_intersects_join (stroker, inpt, outpt))
+ return;
+
+ switch (stroker->line_join) {
+ case CAIRO_LINE_JOIN_ROUND:
+ /* construct a fan around the common midpoint */
+ if ((in->dev_slope.x * out->dev_slope.x +
+ in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
+ {
+ int start, stop;
+ cairo_point_t tri[3];
+ cairo_pen_t *pen = &stroker->pen;
+
+ tri[0] = in->point;
+ tri[1] = *inpt;
+ if (clockwise) {
+ _cairo_pen_find_active_ccw_vertices (pen,
+ &in->dev_vector, &out->dev_vector,
+ &start, &stop);
+ while (start != stop) {
+ tri[2] = in->point;
+ translate_point (&tri[2], &pen->vertices[start].point);
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ tri[1] = tri[2];
+
+ if (start-- == 0)
+ start += pen->num_vertices;
+ }
+ } else {
+ _cairo_pen_find_active_cw_vertices (pen,
+ &in->dev_vector, &out->dev_vector,
+ &start, &stop);
+ while (start != stop) {
+ tri[2] = in->point;
+ translate_point (&tri[2], &pen->vertices[start].point);
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ tri[1] = tri[2];
+
+ if (++start == pen->num_vertices)
+ start = 0;
+ }
+ }
+ tri[2] = *outpt;
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ break;
+ }
+
+ case CAIRO_LINE_JOIN_MITER:
+ default: {
+ /* dot product of incoming slope vector with outgoing slope vector */
+ double in_dot_out = (-in->usr_vector.x * out->usr_vector.x +
+ -in->usr_vector.y * out->usr_vector.y);
+ double ml = stroker->style->miter_limit;
+
+ /* Check the miter limit -- lines meeting at an acute angle
+ * can generate long miters, the limit converts them to bevel
+ *
+ * Consider the miter join formed when two line segments
+ * meet at an angle psi:
+ *
+ * /.\
+ * /. .\
+ * /./ \.\
+ * /./psi\.\
+ *
+ * We can zoom in on the right half of that to see:
+ *
+ * |\
+ * | \ psi/2
+ * | \
+ * | \
+ * | \
+ * | \
+ * miter \
+ * length \
+ * | \
+ * | .\
+ * | . \
+ * |. line \
+ * \ width \
+ * \ \
+ *
+ *
+ * The right triangle in that figure, (the line-width side is
+ * shown faintly with three '.' characters), gives us the
+ * following expression relating miter length, angle and line
+ * width:
+ *
+ * 1 /sin (psi/2) = miter_length / line_width
+ *
+ * The right-hand side of this relationship is the same ratio
+ * in which the miter limit (ml) is expressed. We want to know
+ * when the miter length is within the miter limit. That is
+ * when the following condition holds:
+ *
+ * 1/sin(psi/2) <= ml
+ * 1 <= ml sin(psi/2)
+ * 1 <= ml² sin²(psi/2)
+ * 2 <= ml² 2 sin²(psi/2)
+ * 2·sin²(psi/2) = 1-cos(psi)
+ * 2 <= ml² (1-cos(psi))
+ *
+ * in · out = |in| |out| cos (psi)
+ *
+ * in and out are both unit vectors, so:
+ *
+ * in · out = cos (psi)
+ *
+ * 2 <= ml² (1 - in · out)
+ *
+ */
+ if (2 <= ml * ml * (1 - in_dot_out)) {
+ double x1, y1, x2, y2;
+ double mx, my;
+ double dx1, dx2, dy1, dy2;
+ cairo_point_t outer;
+ cairo_point_t quad[4];
+ double ix, iy;
+ double fdx1, fdy1, fdx2, fdy2;
+ double mdx, mdy;
+
+ /*
+ * we've got the points already transformed to device
+ * space, but need to do some computation with them and
+ * also need to transform the slope from user space to
+ * device space
+ */
+ /* outer point of incoming line face */
+ x1 = _cairo_fixed_to_double (inpt->x);
+ y1 = _cairo_fixed_to_double (inpt->y);
+ dx1 = in->usr_vector.x;
+ dy1 = in->usr_vector.y;
+ cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1);
+
+ /* outer point of outgoing line face */
+ x2 = _cairo_fixed_to_double (outpt->x);
+ y2 = _cairo_fixed_to_double (outpt->y);
+ dx2 = out->usr_vector.x;
+ dy2 = out->usr_vector.y;
+ cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+
+ /*
+ * Compute the location of the outer corner of the miter.
+ * That's pretty easy -- just the intersection of the two
+ * outer edges. We've got slopes and points on each
+ * of those edges. Compute my directly, then compute
+ * mx by using the edge with the larger dy; that avoids
+ * dividing by values close to zero.
+ */
+ my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) /
+ (dx1 * dy2 - dx2 * dy1));
+ if (fabs (dy1) >= fabs (dy2))
+ mx = (my - y1) * dx1 / dy1 + x1;
+ else
+ mx = (my - y2) * dx2 / dy2 + x2;
+
+ /*
+ * When the two outer edges are nearly parallel, slight
+ * perturbations in the position of the outer points of the lines
+ * caused by representing them in fixed point form can cause the
+ * intersection point of the miter to move a large amount. If
+ * that moves the miter intersection from between the two faces,
+ * then draw a bevel instead.
+ */
+
+ ix = _cairo_fixed_to_double (in->point.x);
+ iy = _cairo_fixed_to_double (in->point.y);
+
+ /* slope of one face */
+ fdx1 = x1 - ix; fdy1 = y1 - iy;
+
+ /* slope of the other face */
+ fdx2 = x2 - ix; fdy2 = y2 - iy;
+
+ /* slope from the intersection to the miter point */
+ mdx = mx - ix; mdy = my - iy;
+
+ /*
+ * Make sure the miter point line lies between the two
+ * faces by comparing the slopes
+ */
+ if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) !=
+ slope_compare_sgn (fdx2, fdy2, mdx, mdy))
+ {
+ /*
+ * Draw the quadrilateral
+ */
+ outer.x = _cairo_fixed_from_double (mx);
+ outer.y = _cairo_fixed_from_double (my);
+
+ quad[0] = in->point;
+ quad[1] = *inpt;
+ quad[2] = outer;
+ quad[3] = *outpt;
+
+ _cairo_traps_tessellate_convex_quad (stroker->traps, quad);
+ break;
+ }
+ }
+ /* fall through ... */
+ }
+
+ case CAIRO_LINE_JOIN_BEVEL: {
+ cairo_point_t tri[3];
+ tri[0] = in->point;
+ tri[1] = *inpt;
+ tri[2] = *outpt;
+
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ break;
+ }
+ }
+}
+
+static void
+add_cap (struct stroker *stroker, cairo_stroke_face_t *f)
+{
+ switch (stroker->style->line_cap) {
+ case CAIRO_LINE_CAP_ROUND: {
+ int start, stop;
+ cairo_slope_t in_slope, out_slope;
+ cairo_point_t tri[3];
+ cairo_pen_t *pen = &stroker->pen;
+
+ in_slope = f->dev_vector;
+ out_slope.dx = -in_slope.dx;
+ out_slope.dy = -in_slope.dy;
+ _cairo_pen_find_active_cw_vertices (pen, &in_slope, &out_slope,
+ &start, &stop);
+ tri[0] = f->point;
+ tri[1] = f->cw;
+ while (start != stop) {
+ tri[2] = f->point;
+ translate_point (&tri[2], &pen->vertices[start].point);
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+
+ tri[1] = tri[2];
+ if (++start == pen->num_vertices)
+ start = 0;
+ }
+ tri[2] = f->ccw;
+ _cairo_traps_tessellate_triangle (stroker->traps, tri);
+ break;
+ }
+
+ case CAIRO_LINE_CAP_SQUARE: {
+ double dx, dy;
+ cairo_slope_t fvector;
+ cairo_point_t quad[4];
+
+ dx = f->usr_vector.x;
+ dy = f->usr_vector.y;
+ dx *= stroker->half_line_width;
+ dy *= stroker->half_line_width;
+ cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
+ fvector.dx = _cairo_fixed_from_double (dx);
+ fvector.dy = _cairo_fixed_from_double (dy);
+
+ quad[0] = f->cw;
+ quad[1].x = f->cw.x + fvector.dx;
+ quad[1].y = f->cw.y + fvector.dy;
+ quad[2].x = f->ccw.x + fvector.dx;
+ quad[2].y = f->ccw.y + fvector.dy;
+ quad[3] = f->ccw;
+
+ _cairo_traps_tessellate_convex_quad (stroker->traps, quad);
+ break;
+ }
+
+ case CAIRO_LINE_CAP_BUTT:
+ default:
+ break;
+ }
+}
+
+static void
+add_leading_cap (struct stroker *stroker,
+ cairo_stroke_face_t *face)
+{
+ cairo_stroke_face_t reversed;
+ cairo_point_t t;
+
+ reversed = *face;
+
+ /* The initial cap needs an outward facing vector. Reverse everything */
+ reversed.usr_vector.x = -reversed.usr_vector.x;
+ reversed.usr_vector.y = -reversed.usr_vector.y;
+ reversed.dev_vector.dx = -reversed.dev_vector.dx;
+ reversed.dev_vector.dy = -reversed.dev_vector.dy;
+ t = reversed.cw;
+ reversed.cw = reversed.ccw;
+ reversed.ccw = t;
+
+ add_cap (stroker, &reversed);
+}
+
+static void
+add_trailing_cap (struct stroker *stroker, cairo_stroke_face_t *face)
+{
+ add_cap (stroker, face);
+}
+
+static inline double
+normalize_slope (double *dx, double *dy)
+{
+ double dx0 = *dx, dy0 = *dy;
+
+ if (dx0 == 0.0 && dy0 == 0.0)
+ return 0;
+
+ if (dx0 == 0.0) {
+ *dx = 0.0;
+ if (dy0 > 0.0) {
+ *dy = 1.0;
+ return dy0;
+ } else {
+ *dy = -1.0;
+ return -dy0;
+ }
+ } else if (dy0 == 0.0) {
+ *dy = 0.0;
+ if (dx0 > 0.0) {
+ *dx = 1.0;
+ return dx0;
+ } else {
+ *dx = -1.0;
+ return -dx0;
+ }
+ } else {
+ double mag = hypot (dx0, dy0);
+ *dx = dx0 / mag;
+ *dy = dy0 / mag;
+ return mag;
+ }
+}
+
+static void
+compute_face (const cairo_point_t *point,
+ const cairo_slope_t *dev_slope,
+ struct stroker *stroker,
+ cairo_stroke_face_t *face)
+{
+ double face_dx, face_dy;
+ cairo_point_t offset_ccw, offset_cw;
+ double slope_dx, slope_dy;
+
+ slope_dx = _cairo_fixed_to_double (dev_slope->dx);
+ slope_dy = _cairo_fixed_to_double (dev_slope->dy);
+ face->length = normalize_slope (&slope_dx, &slope_dy);
+ face->dev_slope.x = slope_dx;
+ face->dev_slope.y = slope_dy;
+
+ /*
+ * rotate to get a line_width/2 vector along the face, note that
+ * the vector must be rotated the right direction in device space,
+ * but by 90° in user space. So, the rotation depends on
+ * whether the ctm reflects or not, and that can be determined
+ * by looking at the determinant of the matrix.
+ */
+ if (stroker->ctm_inverse) {
+ cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
+ normalize_slope (&slope_dx, &slope_dy);
+
+ if (stroker->ctm_det_positive) {
+ face_dx = - slope_dy * stroker->half_line_width;
+ face_dy = slope_dx * stroker->half_line_width;
+ } else {
+ face_dx = slope_dy * stroker->half_line_width;
+ face_dy = - slope_dx * stroker->half_line_width;
+ }
+
+ /* back to device space */
+ cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy);
+ } else {
+ face_dx = - slope_dy * stroker->half_line_width;
+ face_dy = slope_dx * stroker->half_line_width;
+ }
+
+ offset_ccw.x = _cairo_fixed_from_double (face_dx);
+ offset_ccw.y = _cairo_fixed_from_double (face_dy);
+ offset_cw.x = -offset_ccw.x;
+ offset_cw.y = -offset_ccw.y;
+
+ face->ccw = *point;
+ translate_point (&face->ccw, &offset_ccw);
+
+ face->point = *point;
+
+ face->cw = *point;
+ translate_point (&face->cw, &offset_cw);
+
+ face->usr_vector.x = slope_dx;
+ face->usr_vector.y = slope_dy;
+
+ face->dev_vector = *dev_slope;
+}
+
+static void
+add_caps (struct stroker *stroker)
+{
+ /* check for a degenerative sub_path */
+ if (stroker->has_initial_sub_path &&
+ !stroker->has_first_face &&
+ !stroker->has_current_face &&
+ stroker->style->line_cap == CAIRO_LINE_CAP_ROUND)
+ {
+ /* pick an arbitrary slope to use */
+ cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
+ cairo_stroke_face_t face;
+
+ /* arbitrarily choose first_point
+ * first_point and current_point should be the same */
+ compute_face (&stroker->first_point, &slope, stroker, &face);
+
+ add_leading_cap (stroker, &face);
+ add_trailing_cap (stroker, &face);
+ }
+
+ if (stroker->has_first_face)
+ add_leading_cap (stroker, &stroker->first_face);
+
+ if (stroker->has_current_face)
+ add_trailing_cap (stroker, &stroker->current_face);
+}
+
+static cairo_bool_t
+stroker_intersects_edge (const struct stroker *stroker,
+ const cairo_stroke_face_t *start,
+ const cairo_stroke_face_t *end)
+{
+ cairo_box_t box;
+
+ if (! stroker->has_bounds)
+ return TRUE;
+
+ if (_cairo_box_contains_point (&stroker->tight_bounds, &start->cw))
+ return TRUE;
+ box.p2 = box.p1 = start->cw;
+
+ if (_cairo_box_contains_point (&stroker->tight_bounds, &start->ccw))
+ return TRUE;
+ _cairo_box_add_point (&box, &start->ccw);
+
+ if (_cairo_box_contains_point (&stroker->tight_bounds, &end->cw))
+ return TRUE;
+ _cairo_box_add_point (&box, &end->cw);
+
+ if (_cairo_box_contains_point (&stroker->tight_bounds, &end->ccw))
+ return TRUE;
+ _cairo_box_add_point (&box, &end->ccw);
+
+ return (box.p2.x > stroker->tight_bounds.p1.x &&
+ box.p1.x < stroker->tight_bounds.p2.x &&
+ box.p2.y > stroker->tight_bounds.p1.y &&
+ box.p1.y < stroker->tight_bounds.p2.y);
+}
+
+static void
+add_sub_edge (struct stroker *stroker,
+ const cairo_point_t *p1, const cairo_point_t *p2,
+ const cairo_slope_t *dev_slope,
+ cairo_stroke_face_t *start, cairo_stroke_face_t *end)
+{
+ cairo_point_t rectangle[4];
+
+ compute_face (p1, dev_slope, stroker, start);
+
+ *end = *start;
+ end->point = *p2;
+ rectangle[0].x = p2->x - p1->x;
+ rectangle[0].y = p2->y - p1->y;
+ translate_point (&end->ccw, &rectangle[0]);
+ translate_point (&end->cw, &rectangle[0]);
+
+ if (p1->x == p2->x && p1->y == p2->y)
+ return;
+
+ if (! stroker_intersects_edge (stroker, start, end))
+ return;
+
+ rectangle[0] = start->cw;
+ rectangle[1] = start->ccw;
+ rectangle[2] = end->ccw;
+ rectangle[3] = end->cw;
+
+ _cairo_traps_tessellate_convex_quad (stroker->traps, rectangle);
+}
+
+static cairo_status_t
+move_to (void *closure, const cairo_point_t *point)
+{
+ struct stroker *stroker = closure;
+
+ /* Cap the start and end of the previous sub path as needed */
+ add_caps (stroker);
+
+ stroker->first_point = *point;
+ stroker->current_face.point = *point;
+
+ stroker->has_first_face = FALSE;
+ stroker->has_current_face = FALSE;
+ stroker->has_initial_sub_path = FALSE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+move_to_dashed (void *closure, const cairo_point_t *point)
+{
+ /* reset the dash pattern for new sub paths */
+ struct stroker *stroker = closure;
+
+ _cairo_stroker_dash_start (&stroker->dash);
+ return move_to (closure, point);
+}
+
+static cairo_status_t
+line_to (void *closure, const cairo_point_t *point)
+{
+ struct stroker *stroker = closure;
+ cairo_stroke_face_t start, end;
+ const cairo_point_t *p1 = &stroker->current_face.point;
+ const cairo_point_t *p2 = point;
+ cairo_slope_t dev_slope;
+
+ stroker->has_initial_sub_path = TRUE;
+
+ if (p1->x == p2->x && p1->y == p2->y)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_slope_init (&dev_slope, p1, p2);
+ add_sub_edge (stroker, p1, p2, &dev_slope, &start, &end);
+
+ if (stroker->has_current_face) {
+ /* Join with final face from previous segment */
+ join (stroker, &stroker->current_face, &start);
+ } else if (!stroker->has_first_face) {
+ /* Save sub path's first face in case needed for closing join */
+ stroker->first_face = start;
+ stroker->has_first_face = TRUE;
+ }
+ stroker->current_face = end;
+ stroker->has_current_face = TRUE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/*
+ * Dashed lines. Cap each dash end, join around turns when on
+ */
+static cairo_status_t
+line_to_dashed (void *closure, const cairo_point_t *point)
+{
+ struct stroker *stroker = closure;
+ double mag, remain, step_length = 0;
+ double slope_dx, slope_dy;
+ double dx2, dy2;
+ cairo_stroke_face_t sub_start, sub_end;
+ const cairo_point_t *p1 = &stroker->current_face.point;
+ const cairo_point_t *p2 = point;
+ cairo_slope_t dev_slope;
+ cairo_line_t segment;
+ cairo_bool_t fully_in_bounds;
+
+ stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
+
+ if (p1->x == p2->x && p1->y == p2->y)
+ return CAIRO_STATUS_SUCCESS;
+
+ fully_in_bounds = TRUE;
+ if (stroker->has_bounds &&
+ (! _cairo_box_contains_point (&stroker->join_bounds, p1) ||
+ ! _cairo_box_contains_point (&stroker->join_bounds, p2)))
+ {
+ fully_in_bounds = FALSE;
+ }
+
+ _cairo_slope_init (&dev_slope, p1, p2);
+
+ slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
+ slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
+
+ if (stroker->ctm_inverse)
+ cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
+ mag = normalize_slope (&slope_dx, &slope_dy);
+ if (mag <= DBL_EPSILON)
+ return CAIRO_STATUS_SUCCESS;
+
+ remain = mag;
+ segment.p1 = *p1;
+ while (remain) {
+ step_length = MIN (stroker->dash.dash_remain, remain);
+ remain -= step_length;
+ dx2 = slope_dx * (mag - remain);
+ dy2 = slope_dy * (mag - remain);
+ cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
+ segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
+ segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
+
+ if (stroker->dash.dash_on &&
+ (fully_in_bounds ||
+ (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
+ _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment)))
+ {
+ add_sub_edge (stroker,
+ &segment.p1, &segment.p2,
+ &dev_slope,
+ &sub_start, &sub_end);
+
+ if (stroker->has_current_face) {
+ /* Join with final face from previous segment */
+ join (stroker, &stroker->current_face, &sub_start);
+
+ stroker->has_current_face = FALSE;
+ } else if (! stroker->has_first_face && stroker->dash.dash_starts_on) {
+ /* Save sub path's first face in case needed for closing join */
+ stroker->first_face = sub_start;
+ stroker->has_first_face = TRUE;
+ } else {
+ /* Cap dash start if not connecting to a previous segment */
+ add_leading_cap (stroker, &sub_start);
+ }
+
+ if (remain) {
+ /* Cap dash end if not at end of segment */
+ add_trailing_cap (stroker, &sub_end);
+ } else {
+ stroker->current_face = sub_end;
+ stroker->has_current_face = TRUE;
+ }
+ } else {
+ if (stroker->has_current_face) {
+ /* Cap final face from previous segment */
+ add_trailing_cap (stroker, &stroker->current_face);
+
+ stroker->has_current_face = FALSE;
+ }
+ }
+
+ _cairo_stroker_dash_step (&stroker->dash, step_length);
+ segment.p1 = segment.p2;
+ }
+
+ if (stroker->dash.dash_on && ! stroker->has_current_face) {
+ /* This segment ends on a transition to dash_on, compute a new face
+ * and add cap for the beginning of the next dash_on step.
+ *
+ * Note: this will create a degenerate cap if this is not the last line
+ * in the path. Whether this behaviour is desirable or not is debatable.
+ * On one side these degenerate caps can not be reproduced with regular
+ * path stroking.
+ * On the other hand, Acroread 7 also produces the degenerate caps.
+ */
+ compute_face (point, &dev_slope, stroker, &stroker->current_face);
+
+ add_leading_cap (stroker, &stroker->current_face);
+
+ stroker->has_current_face = TRUE;
+ } else
+ stroker->current_face.point = *point;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+spline_to (void *closure,
+ const cairo_point_t *point,
+ const cairo_slope_t *tangent)
+{
+ struct stroker *stroker = closure;
+ cairo_stroke_face_t face;
+
+ if ((tangent->dx | tangent->dy) == 0) {
+ cairo_point_t t;
+
+ face = stroker->current_face;
+
+ face.usr_vector.x = -face.usr_vector.x;
+ face.usr_vector.y = -face.usr_vector.y;
+ face.dev_slope.x = -face.dev_slope.x;
+ face.dev_slope.y = -face.dev_slope.y;
+ face.dev_vector.dx = -face.dev_vector.dx;
+ face.dev_vector.dy = -face.dev_vector.dy;
+
+ t = face.cw;
+ face.cw = face.ccw;
+ face.ccw = t;
+
+ join (stroker, &stroker->current_face, &face);
+ } else {
+ cairo_point_t rectangle[4];
+
+ compute_face (&stroker->current_face.point, tangent, stroker, &face);
+
+ join (stroker, &stroker->current_face, &face);
+
+ rectangle[0] = face.cw;
+ rectangle[1] = face.ccw;
+
+ rectangle[2].x = point->x - face.point.x;
+ rectangle[2].y = point->y - face.point.y;
+ face.point = *point;
+ translate_point (&face.ccw, &rectangle[2]);
+ translate_point (&face.cw, &rectangle[2]);
+
+ rectangle[2] = face.ccw;
+ rectangle[3] = face.cw;
+
+ _cairo_traps_tessellate_convex_quad (stroker->traps, rectangle);
+ }
+
+ stroker->current_face = face;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+curve_to (void *closure,
+ const cairo_point_t *b,
+ const cairo_point_t *c,
+ const cairo_point_t *d)
+{
+ struct stroker *stroker = closure;
+ cairo_line_join_t line_join_save;
+ cairo_spline_t spline;
+ cairo_stroke_face_t face;
+ cairo_status_t status;
+
+ if (stroker->has_bounds &&
+ ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d,
+ &stroker->line_bounds))
+ return line_to (closure, d);
+
+ if (! _cairo_spline_init (&spline, spline_to, stroker,
+ &stroker->current_face.point, b, c, d))
+ return line_to (closure, d);
+
+ compute_face (&stroker->current_face.point, &spline.initial_slope,
+ stroker, &face);
+
+ if (stroker->has_current_face) {
+ /* Join with final face from previous segment */
+ join (stroker, &stroker->current_face, &face);
+ } else {
+ if (! stroker->has_first_face) {
+ /* Save sub path's first face in case needed for closing join */
+ stroker->first_face = face;
+ stroker->has_first_face = TRUE;
+ }
+ stroker->has_current_face = TRUE;
+ }
+ stroker->current_face = face;
+
+ /* Temporarily modify the stroker to use round joins to guarantee
+ * smooth stroked curves. */
+ line_join_save = stroker->line_join;
+ stroker->line_join = CAIRO_LINE_JOIN_ROUND;
+
+ status = _cairo_spline_decompose (&spline, stroker->tolerance);
+
+ stroker->line_join = line_join_save;
+
+ return status;
+}
+
+static cairo_status_t
+curve_to_dashed (void *closure,
+ const cairo_point_t *b,
+ const cairo_point_t *c,
+ const cairo_point_t *d)
+{
+ struct stroker *stroker = closure;
+ cairo_spline_t spline;
+ cairo_line_join_t line_join_save;
+ cairo_spline_add_point_func_t func;
+ cairo_status_t status;
+
+ func = (cairo_spline_add_point_func_t)line_to_dashed;
+
+ if (stroker->has_bounds &&
+ ! _cairo_spline_intersects (&stroker->current_face.point, b, c, b,
+ &stroker->line_bounds))
+ return func (closure, d, NULL);
+
+ if (! _cairo_spline_init (&spline, func, stroker,
+ &stroker->current_face.point, b, c, d))
+ return func (closure, d, NULL);
+
+ /* Temporarily modify the stroker to use round joins to guarantee
+ * smooth stroked curves. */
+ line_join_save = stroker->line_join;
+ stroker->line_join = CAIRO_LINE_JOIN_ROUND;
+
+ status = _cairo_spline_decompose (&spline, stroker->tolerance);
+
+ stroker->line_join = line_join_save;
+
+ return status;
+}
+
+static cairo_status_t
+_close_path (struct stroker *stroker)
+{
+ if (stroker->has_first_face && stroker->has_current_face) {
+ /* Join first and final faces of sub path */
+ join (stroker, &stroker->current_face, &stroker->first_face);
+ } else {
+ /* Cap the start and end of the sub path as needed */
+ add_caps (stroker);
+ }
+
+ stroker->has_initial_sub_path = FALSE;
+ stroker->has_first_face = FALSE;
+ stroker->has_current_face = FALSE;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+close_path (void *closure)
+{
+ struct stroker *stroker = closure;
+ cairo_status_t status;
+
+ status = line_to (stroker, &stroker->first_point);
+ if (unlikely (status))
+ return status;
+
+ return _close_path (stroker);
+}
+
+static cairo_status_t
+close_path_dashed (void *closure)
+{
+ struct stroker *stroker = closure;
+ cairo_status_t status;
+
+ status = line_to_dashed (stroker, &stroker->first_point);
+ if (unlikely (status))
+ return status;
+
+ return _close_path (stroker);
+}
+
+cairo_int_status_t
+_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps)
+{
+ struct stroker stroker;
+ cairo_status_t status;
+
+ status = stroker_init (&stroker, path, style,
+ ctm, ctm_inverse, tolerance,
+ traps);
+ if (unlikely (status))
+ return status;
+
+ if (stroker.dash.dashed)
+ status = _cairo_path_fixed_interpret (path,
+ move_to_dashed,
+ line_to_dashed,
+ curve_to_dashed,
+ close_path_dashed,
+ &stroker);
+ else
+ status = _cairo_path_fixed_interpret (path,
+ move_to,
+ line_to,
+ curve_to,
+ close_path,
+ &stroker);
+ assert(status == CAIRO_STATUS_SUCCESS);
+ add_caps (&stroker);
+
+ stroker_fini (&stroker);
+
+ return traps->status;
+}
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index 66ab3bd..cd6b3a2 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -52,6 +52,7 @@ typedef struct cairo_stroker {
const cairo_matrix_t *ctm;
const cairo_matrix_t *ctm_inverse;
+ double half_line_width;
double tolerance;
double ctm_determinant;
cairo_bool_t ctm_det_positive;
@@ -134,13 +135,13 @@ _cairo_stroker_init (cairo_stroker_t *stroker,
stroker->ctm = ctm;
stroker->ctm_inverse = ctm_inverse;
stroker->tolerance = tolerance;
+ stroker->half_line_width = stroke_style->line_width / 2.0;
stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
status = _cairo_pen_init (&stroker->pen,
- stroke_style->line_width / 2.0,
- tolerance, ctm);
+ stroker->half_line_width, tolerance, ctm);
if (unlikely (status))
return status;
@@ -637,8 +638,8 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker,
dx = f->usr_vector.x;
dy = f->usr_vector.y;
- dx *= stroker->style.line_width / 2.0;
- dy *= stroker->style.line_width / 2.0;
+ dx *= stroker->half_line_width;
+ dy *= stroker->half_line_width;
cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
fvector.dx = _cairo_fixed_from_double (dx);
fvector.dy = _cairo_fixed_from_double (dy);
@@ -776,13 +777,13 @@ _compute_face (const cairo_point_t *point, cairo_slope_t *dev_slope,
*/
if (stroker->ctm_det_positive)
{
- face_dx = - slope_dy * (stroker->style.line_width / 2.0);
- face_dy = slope_dx * (stroker->style.line_width / 2.0);
+ face_dx = - slope_dy * stroker->half_line_width;
+ face_dy = slope_dx * stroker->half_line_width;
}
else
{
- face_dx = slope_dy * (stroker->style.line_width / 2.0);
- face_dy = - slope_dx * (stroker->style.line_width / 2.0);
+ face_dx = slope_dy * stroker->half_line_width;
+ face_dy = - slope_dx * stroker->half_line_width;
}
/* back to device space */
@@ -1340,12 +1341,12 @@ BAIL:
}
cairo_int_status_t
-_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_traps_t *traps)
+_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps)
{
cairo_int_status_t status;
cairo_polygon_t polygon;
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index cf441c4..61be0e8 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -284,7 +284,7 @@ _cairo_pen_vertices_needed (double tolerance,
radius);
int num_vertices;
- if (tolerance >= 2*major_axis) {
+ if (tolerance >= 4*major_axis) { /* XXX relaxed from 2*major for inkscape */
num_vertices = 1;
} else if (tolerance >= major_axis) {
num_vertices = 4;
@@ -412,21 +412,23 @@ _cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen,
i = 0;
*start = i;
- lo = i;
- hi = i + pen->num_vertices;
- i = (lo + hi) >> 1;
- do {
- int j = i;
- if (j >= pen->num_vertices)
- j -= pen->num_vertices;
- if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
- hi = i;
- else
- lo = i;
+ if (_cairo_slope_compare (out, &pen->vertices[i].slope_ccw) >= 0) {
+ lo = i;
+ hi = i + pen->num_vertices;
i = (lo + hi) >> 1;
- } while (hi - lo > 1);
- if (i >= pen->num_vertices)
- i -= pen->num_vertices;
+ do {
+ int j = i;
+ if (j >= pen->num_vertices)
+ j -= pen->num_vertices;
+ if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
+ hi = i;
+ else
+ lo = i;
+ i = (lo + hi) >> 1;
+ } while (hi - lo > 1);
+ if (i >= pen->num_vertices)
+ i -= pen->num_vertices;
+ }
*stop = i;
}
@@ -452,20 +454,22 @@ _cairo_pen_find_active_ccw_vertices (const cairo_pen_t *pen,
i = 0;
*start = i;
- lo = i;
- hi = i + pen->num_vertices;
- i = (lo + hi) >> 1;
- do {
- int j = i;
- if (j >= pen->num_vertices)
- j -= pen->num_vertices;
- if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0)
- hi = i;
- else
- lo = i;
+ if (_cairo_slope_compare (&pen->vertices[i].slope_cw, out) <= 0) {
+ lo = i;
+ hi = i + pen->num_vertices;
i = (lo + hi) >> 1;
- } while (hi - lo > 1);
- if (i >= pen->num_vertices)
- i -= pen->num_vertices;
+ do {
+ int j = i;
+ if (j >= pen->num_vertices)
+ j -= pen->num_vertices;
+ if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0)
+ hi = i;
+ else
+ lo = i;
+ i = (lo + hi) >> 1;
+ } while (hi - lo > 1);
+ if (i >= pen->num_vertices)
+ i -= pen->num_vertices;
+ }
*stop = i;
}
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index c714b32..b0424f6 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -390,11 +390,6 @@ _add_clipped_edge (cairo_polygon_t *polygon,
cairo_fixed_t left_y, right_y;
cairo_bool_t top_left_to_bottom_right;
- left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
- limits->p1.x);
- right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
- limits->p2.x);
-
/*
* The edge intersects the lines corresponding to the left
* and right sides of the limit box at left_y and right_y,
@@ -420,11 +415,16 @@ _add_clipped_edge (cairo_polygon_t *polygon,
* inside the box if it is clipped to this vertical range.
*/
- top_left_to_bottom_right = (p1->x < p2->x) == (p1->y < p2->y);
-
+ top_left_to_bottom_right = (p1->x <= p2->x) == (p1->y <= p2->y);
if (top_left_to_bottom_right) {
- if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x)
- left_y++;
+ if (pleft >= limits->p1.x) {
+ left_y = top_y;
+ } else {
+ left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+ limits->p1.x);
+ if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x)
+ left_y++;
+ }
left_y = MIN (left_y, bot_y);
if (top_y < left_y) {
@@ -434,8 +434,14 @@ _add_clipped_edge (cairo_polygon_t *polygon,
top_y = left_y;
}
- if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p1.y)
- right_y--;
+ if (pright <= limits->p2.x) {
+ right_y = bot_y;
+ } else {
+ right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+ limits->p2.x);
+ if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x)
+ right_y--;
+ }
right_y = MAX (right_y, top_y);
if (bot_y > right_y) {
@@ -445,8 +451,14 @@ _add_clipped_edge (cairo_polygon_t *polygon,
bot_y = right_y;
}
} else {
- if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x)
- right_y++;
+ if (pright <= limits->p2.x) {
+ right_y = top_y;
+ } else {
+ right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+ limits->p2.x);
+ if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x)
+ right_y++;
+ }
right_y = MIN (right_y, bot_y);
if (top_y < right_y) {
@@ -456,8 +468,14 @@ _add_clipped_edge (cairo_polygon_t *polygon,
top_y = right_y;
}
- if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x)
- left_y--;
+ if (pleft >= limits->p1.x) {
+ left_y = bot_y;
+ } else {
+ left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2,
+ limits->p1.x);
+ if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x)
+ left_y--;
+ }
left_y = MAX (left_y, top_y);
if (bot_y > left_y) {
diff --git a/src/cairo-qt-surface.cpp b/src/cairo-qt-surface.cpp
index b75f522..ce05dba 100644
--- a/src/cairo-qt-surface.cpp
+++ b/src/cairo-qt-surface.cpp
@@ -48,6 +48,7 @@
#include "cairo-image-surface-private.h"
#include "cairo-pattern-private.h"
#include "cairo-surface-backend-private.h"
+#include "cairo-surface-fallback-private.h"
#include "cairo-ft.h"
#include "cairo-qt.h"
@@ -64,7 +65,7 @@
#include <QWidget>
#include <QtCore/QVarLengthArray>
-#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)
+#if ((QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)) && 0
extern void qt_draw_glyphs(QPainter *, const quint32 *glyphs, const QPointF *positions, int count);
#endif
@@ -197,6 +198,9 @@ _qpainter_compositionmode_from_cairo_op (cairo_operator_t op)
static bool
_op_is_supported (cairo_qt_surface_t *qs, cairo_operator_t op)
{
+ if (qs->p == NULL)
+ return false;
+
if (qs->supports_porter_duff) {
switch (op) {
case CAIRO_OPERATOR_CLEAR:
@@ -555,32 +559,105 @@ _cairo_qt_surface_release_source_image (void *abstract_surface,
cairo_surface_destroy (&image->base);
}
-static cairo_status_t
-_cairo_qt_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect,
- void **image_extra)
+struct _qimage_surface {
+ cairo_image_surface_t image;
+ QImage *qimg;
+};
+
+static cairo_surface_t *
+map_qimage_to_image (QImage *qimg, const cairo_rectangle_int_t *extents)
{
- cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
- QImage *qimg = NULL;
+ struct _qimage_surface *surface;
+ pixman_image_t *pixman_image;
+ pixman_format_code_t pixman_format;
+ uint8_t *data;
- D(fprintf(stderr, "q[%p] acquire_dest_image\n", abstract_surface));
+ if (qimg == NULL)
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
- *image_extra = NULL;
+ switch (qimg->format()) {
+ case QImage::Format_ARGB32_Premultiplied:
+ pixman_format = PIXMAN_a8r8g8b8;
+ break;
+ case QImage::Format_RGB32:
+ pixman_format = PIXMAN_x8r8g8b8;
+ break;
+ case QImage::Format_Indexed8: // XXX not quite
+ pixman_format = PIXMAN_a8;
+ break;
+#ifdef WORDS_BIGENDIAN
+ case QImage::Format_Mono:
+#else
+ case QImage::Format_MonoLSB:
+#endif
+ pixman_format = PIXMAN_a1;
+ break;
- if (qs->image_equiv) {
- *image_out = (cairo_image_surface_t*)
- cairo_surface_reference (qs->image_equiv);
+ case QImage::Format_Invalid:
+#ifdef WORDS_BIGENDIAN
+ case QImage::Format_MonoLSB:
+#else
+ case QImage::Format_Mono:
+#endif
+ case QImage::Format_ARGB32:
+ case QImage::Format_RGB16:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_RGB666:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_RGB555:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_RGB888:
+ case QImage::Format_RGB444:
+ case QImage::Format_ARGB4444_Premultiplied:
+ case QImage::NImageFormats:
+ default:
+ delete qimg;
+ return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT);
+ }
- image_rect->x = qs->window.x();
- image_rect->y = qs->window.y();
- image_rect->width = qs->window.width();
- image_rect->height = qs->window.height();
+ data = qimg->bits();
+ data += extents->y * qimg->bytesPerLine();
+ data += extents->x * PIXMAN_FORMAT_BPP (pixman_format) / 8;
+
+ pixman_image = pixman_image_create_bits (pixman_format,
+ extents->width,
+ extents->height,
+ (uint32_t *)data,
+ qimg->bytesPerLine());
+ if (pixman_image == NULL) {
+ delete qimg;
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ }
- return CAIRO_STATUS_SUCCESS;
+ surface = (struct _qimage_surface *) malloc (sizeof(*surface));
+ if (unlikely (surface == NULL)) {
+ pixman_image_unref (pixman_image);
+ delete qimg;
+ return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
}
+ _cairo_image_surface_init (&surface->image, pixman_image, pixman_format);
+ surface->qimg = qimg;
+
+ cairo_surface_set_device_offset (&surface->image.base,
+ -extents->x, -extents->y);
+
+ return &surface->image.base;
+}
+
+static cairo_image_surface_t *
+_cairo_qt_surface_map_to_image (void *abstract_surface,
+ const cairo_rectangle_int_t *extents)
+{
+ cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
+ QImage *qimg = NULL;
+
+ D(fprintf(stderr, "q[%p] acquire_dest_image\n", abstract_surface));
+
+ if (qs->image_equiv)
+ return _cairo_image_surface_map_to_image (qs->image_equiv,
+ extents);
+
QPoint offset;
if (qs->pixmap) {
@@ -590,7 +667,7 @@ _cairo_qt_surface_acquire_dest_image (void *abstract_surface,
// how we can grab an image from it
QPaintDevice *pd = qs->p->device();
if (!pd)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_image_surface_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
QPaintDevice *rpd = QPainter::redirected(pd, &offset);
if (rpd)
@@ -605,50 +682,42 @@ _cairo_qt_surface_acquire_dest_image (void *abstract_surface,
}
}
- if (qimg == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- *image_out = (cairo_image_surface_t*)
- cairo_image_surface_create_for_data (qimg->bits(),
- _cairo_format_from_qimage_format (qimg->format()),
- qimg->width(), qimg->height(),
- qimg->bytesPerLine());
- *image_extra = qimg;
-
- image_rect->x = qs->window.x() + offset.x();
- image_rect->y = qs->window.y() + offset.y();
- image_rect->width = qs->window.width() - offset.x();
- image_rect->height = qs->window.height() - offset.y();
-
- return CAIRO_STATUS_SUCCESS;
+ return (cairo_image_surface_t *) map_qimage_to_image (qimg, extents);
}
-static void
-_cairo_qt_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
+static cairo_int_status_t
+_cairo_qt_surface_unmap_image (void *abstract_surface,
+ cairo_image_surface_t *image)
{
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
- D(fprintf(stderr, "q[%p] release_dest_image\n", abstract_surface));
- cairo_surface_destroy (&image->base);
+ D(fprintf(stderr, "q[%p] release_dest_image\n", abstract_surface));
- if (image_extra) {
- QImage *qimg = (QImage*) image_extra;
+ if (!qs->image_equiv) {
+ struct _qimage_surface *qimage = (struct _qimage_surface *)image;
// XXX should I be using setBackgroundMode here instead of setCompositionMode?
if (qs->supports_porter_duff)
qs->p->setCompositionMode (QPainter::CompositionMode_Source);
- qs->p->drawImage (image_rect->x, image_rect->y, *qimg);
+ qs->p->drawImage ((int)qimage->image.base.device_transform.x0,
+ (int)qimage->image.base.device_transform.y0,
+ *qimage->qimg,
+ (int)qimage->image.base.device_transform.x0,
+ (int)qimage->image.base.device_transform.y0,
+ (int)qimage->image.width,
+ (int)qimage->image.height);
if (qs->supports_porter_duff)
qs->p->setCompositionMode (QPainter::CompositionMode_SourceOver);
- delete qimg;
+ delete qimage->qimg;
}
+
+ cairo_surface_finish (&image->base);
+ cairo_surface_destroy (&image->base);
+
+ return CAIRO_INT_STATUS_SUCCESS;
}
static cairo_bool_t
@@ -1212,11 +1281,8 @@ _cairo_qt_surface_paint (void *abstract_surface,
D(fprintf(stderr, "q[%p] paint op:%s\n", abstract_surface, _opstr(op)));
- if (!qs->p)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
if (! _op_is_supported (qs, op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return _cairo_surface_fallback_paint (abstract_surface, op, source, clip);
status = _cairo_qt_surface_set_clip (qs, clip);
if (unlikely (status))
@@ -1250,11 +1316,10 @@ _cairo_qt_surface_fill (void *abstract_surface,
D(fprintf(stderr, "q[%p] fill op:%s\n", abstract_surface, _opstr(op)));
- if (!qs->p)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
if (! _op_is_supported (qs, op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return _cairo_surface_fallback_fill (abstract_surface, op,
+ source, path, fill_rule,
+ tolerance, antialias, clip);
cairo_int_status_t status = _cairo_qt_surface_set_clip (qs, clip);
if (unlikely (status))
@@ -1297,17 +1362,16 @@ _cairo_qt_surface_stroke (void *abstract_surface,
D(fprintf(stderr, "q[%p] stroke op:%s\n", abstract_surface, _opstr(op)));
- if (!qs->p)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
if (! _op_is_supported (qs, op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return _cairo_surface_fallback_stroke (abstract_surface, op,
+ source, path, style, ctm,
+ ctm_inverse, tolerance,
+ antialias, clip);
cairo_int_status_t int_status = _cairo_qt_surface_set_clip (qs, clip);
if (unlikely (int_status))
return int_status;
-
QMatrix savedMatrix = qs->p->worldMatrix();
if (qs->supports_porter_duff)
@@ -1342,7 +1406,7 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip)
{
-#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)
+#if ((QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)) || defined(QT_GLYPHS_API_BACKPORT)) && 0
cairo_qt_surface_t *qs = (cairo_qt_surface_t *) abstract_surface;
// pick out the colour to use from the cairo source
@@ -1374,7 +1438,9 @@ _cairo_qt_surface_show_glyphs (void *abstract_surface,
_cairo_scaled_font_thaw_cache(scaled_font);
return CAIRO_INT_STATUS_SUCCESS;
#else
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return _cairo_surface_fallback_glyphs (abstract_surface, op,
+ source, glyphs, num_glyphs,
+ scaled_font, clip);
#endif
}
@@ -1389,10 +1455,7 @@ _cairo_qt_surface_mask (void *abstract_surface,
D(fprintf(stderr, "q[%p] mask op:%s\n", abstract_surface, _opstr(op)));
- if (!qs->p)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
+ if (qs->p && mask->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
cairo_int_status_t result;
@@ -1406,7 +1469,7 @@ _cairo_qt_surface_mask (void *abstract_surface,
}
// otherwise skip for now
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return _cairo_surface_fallback_mask (abstract_surface, op, source, mask, clip);
}
static cairo_status_t
@@ -1429,21 +1492,28 @@ _cairo_qt_surface_mark_dirty (void *abstract_surface,
static const cairo_surface_backend_t cairo_qt_surface_backend = {
CAIRO_SURFACE_TYPE_QT,
_cairo_qt_surface_finish,
+
_cairo_default_context_create, /* XXX */
+
_cairo_qt_surface_create_similar,
NULL, /* similar image */
- NULL, /* map to image */
- NULL, /* unmap image */
+ _cairo_qt_surface_map_to_image,
+ _cairo_qt_surface_unmap_image,
+
_cairo_surface_default_source,
_cairo_qt_surface_acquire_source_image,
_cairo_qt_surface_release_source_image,
NULL, /* snapshot */
+
NULL, /* copy_page */
NULL, /* show_page */
+
_cairo_qt_surface_get_extents,
NULL, /* get_font_options */
+
NULL, /* flush */
_cairo_qt_surface_mark_dirty,
+
_cairo_qt_surface_paint,
_cairo_qt_surface_mask,
_cairo_qt_surface_stroke,
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 73fc48a..edbeed7 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -210,7 +210,10 @@ bbtree_add (struct bbtree *bbt,
if (box->p1.x == bbt->extents.p1.x && box->p1.y == bbt->extents.p1.y &&
box->p2.x == bbt->extents.p2.x && box->p2.y == bbt->extents.p2.y)
{
- header->chain = bbt->chain;
+ cairo_command_header_t *last = header;
+ while (last->chain) /* expected to be infrequent */
+ last = last->chain;
+ last->chain = bbt->chain;
bbt->chain = header;
return CAIRO_STATUS_SUCCESS;
}
@@ -1431,7 +1434,7 @@ _cairo_recording_surface_snapshot (void *abstract_other)
surface->extents = other->extents;
surface->unbounded = other->unbounded;
- surface->base.is_clear = TRUE;
+ surface->base.is_clear = other->base.is_clear;
surface->bbtree.left = surface->bbtree.right = NULL;
surface->bbtree.chain = INVALID_CHAIN;
@@ -1441,7 +1444,7 @@ _cairo_recording_surface_snapshot (void *abstract_other)
surface->optimize_clears = TRUE;
_cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
- status = _cairo_recording_surface_copy (other, surface);
+ status = _cairo_recording_surface_copy (surface, other);
if (unlikely (status)) {
cairo_surface_destroy (&surface->base);
return _cairo_surface_create_in_error (status);
@@ -1536,12 +1539,12 @@ _cairo_recording_surface_get_path (cairo_surface_t *abstract_surface,
_cairo_traps_init (&traps);
/* XXX call cairo_stroke_to_path() when that is implemented */
- status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
- &command->stroke.style,
- &command->stroke.ctm,
- &command->stroke.ctm_inverse,
- command->stroke.tolerance,
- &traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (&command->stroke.path,
+ &command->stroke.style,
+ &command->stroke.ctm,
+ &command->stroke.ctm_inverse,
+ command->stroke.tolerance,
+ &traps);
if (status == CAIRO_INT_STATUS_SUCCESS)
status = _cairo_traps_path (&traps, path);
diff --git a/src/cairo-rectangle.c b/src/cairo-rectangle.c
index 47f2837..2d51d7b 100644
--- a/src/cairo-rectangle.c
+++ b/src/cairo-rectangle.c
@@ -189,7 +189,7 @@ _cairo_rectangle_union (cairo_rectangle_int_t *dst,
*/
cairo_bool_t
-_cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line)
+_cairo_box_intersects_line_segment (const cairo_box_t *box, cairo_line_t *line)
{
cairo_fixed_t t1=0, t2=0, t3=0, t4=0;
cairo_int64_t t1y, t2y, t3x, t4x;
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index e7eb4cc..97460c2 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -449,16 +449,16 @@ _cairo_scaled_font_map_destroy (void)
CLEANUP_MUTEX_LOCK:
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
+
static void
-_cairo_scaled_glyph_page_destroy (void *closure)
+_cairo_scaled_glyph_page_destroy (cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_page_t *page)
{
- cairo_scaled_glyph_page_t *page = closure;
- cairo_scaled_font_t *scaled_font;
unsigned int n;
- assert (! cairo_list_is_empty (&page->link));
+ assert (!scaled_font->cache_frozen);
+ assert (!scaled_font->global_cache_frozen);
- scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
for (n = 0; n < page->num_glyphs; n++) {
_cairo_hash_table_remove (scaled_font->glyphs,
&page->glyphs[n].hash_entry);
@@ -466,10 +466,24 @@ _cairo_scaled_glyph_page_destroy (void *closure)
}
cairo_list_del (&page->link);
-
free (page);
}
+static void
+_cairo_scaled_glyph_page_pluck (void *closure)
+{
+ cairo_scaled_glyph_page_t *page = closure;
+ cairo_scaled_font_t *scaled_font;
+
+ assert (! cairo_list_is_empty (&page->link));
+
+ scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
+
+ CAIRO_MUTEX_LOCK (scaled_font->mutex);
+ _cairo_scaled_glyph_page_destroy (scaled_font, page);
+ CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+}
+
/* If a scaled font wants to unlock the font map while still being
* created (needed for user-fonts), we need to take extra care not
* ending up with multiple identical scaled fonts being created.
@@ -788,32 +802,40 @@ _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
void
_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
{
- scaled_font->cache_frozen = FALSE;
+ assert (scaled_font->cache_frozen);
if (scaled_font->global_cache_frozen) {
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
_cairo_cache_thaw (&cairo_scaled_glyph_page_cache);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
-
scaled_font->global_cache_frozen = FALSE;
}
+ scaled_font->cache_frozen = FALSE;
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
}
void
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
{
+ CAIRO_MUTEX_LOCK (scaled_font->mutex);
assert (! scaled_font->cache_frozen);
-
+ assert (! scaled_font->global_cache_frozen);
CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
while (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
- _cairo_cache_remove (&cairo_scaled_glyph_page_cache,
- &cairo_list_first_entry (&scaled_font->glyph_pages,
- cairo_scaled_glyph_page_t,
- link)->cache_entry);
+ cairo_scaled_glyph_page_t *page =
+ cairo_list_first_entry (&scaled_font->glyph_pages,
+ cairo_scaled_glyph_page_t,
+ link);
+
+ cairo_scaled_glyph_page_cache.size -= page->cache_entry.size;
+ _cairo_hash_table_remove (cairo_scaled_glyph_page_cache.hash_table,
+ (cairo_hash_entry_t *) &page->cache_entry);
+
+ _cairo_scaled_glyph_page_destroy (scaled_font, page);
}
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
+ CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
}
cairo_status_t
@@ -848,6 +870,8 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
static void
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
{
+ assert (! scaled_font->cache_frozen);
+ assert (! scaled_font->global_cache_frozen);
scaled_font->finished = TRUE;
_cairo_scaled_font_reset_cache (scaled_font);
@@ -1139,6 +1163,8 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
* ft-font-faces
*/
assert (scaled_font->font_face == font_face);
+ assert (! scaled_font->cache_frozen);
+ assert (! scaled_font->global_cache_frozen);
scaled_font->original_font_face =
cairo_font_face_reference (original_font_face);
@@ -1288,6 +1314,9 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count))
return;
+ assert (! scaled_font->cache_frozen);
+ assert (! scaled_font->global_cache_frozen);
+
font_map = _cairo_scaled_font_map_lock ();
assert (font_map != NULL);
@@ -2131,36 +2160,37 @@ _cairo_scaled_font_single_glyph_device_extents (cairo_scaled_font_t *scaled_fon
const cairo_glyph_t *glyph,
cairo_rectangle_int_t *extents)
{
- cairo_round_glyph_positions_t round_xy;
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
- cairo_box_t box;
- cairo_fixed_t v;
+ _cairo_scaled_font_freeze_cache (scaled_font);
status = _cairo_scaled_glyph_lookup (scaled_font,
glyph->index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
- if (unlikely (status))
- return status;
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ cairo_bool_t round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options) == CAIRO_ROUND_GLYPH_POS_ON;
+ cairo_box_t box;
+ cairo_fixed_t v;
- round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options);
- if (round_xy == CAIRO_ROUND_GLYPH_POS_ON)
- v = _cairo_fixed_from_int (_cairo_lround (glyph->x));
- else
- v = _cairo_fixed_from_double (glyph->x);
- box.p1.x = v + scaled_glyph->bbox.p1.x;
- box.p2.x = v + scaled_glyph->bbox.p2.x;
+ if (round_xy)
+ v = _cairo_fixed_from_int (_cairo_lround (glyph->x));
+ else
+ v = _cairo_fixed_from_double (glyph->x);
+ box.p1.x = v + scaled_glyph->bbox.p1.x;
+ box.p2.x = v + scaled_glyph->bbox.p2.x;
- if (round_xy == CAIRO_ROUND_GLYPH_POS_ON)
- v = _cairo_fixed_from_int (_cairo_lround (glyph->y));
- else
- v = _cairo_fixed_from_double (glyph->y);
- box.p1.y = v + scaled_glyph->bbox.p1.y;
- box.p2.y = v + scaled_glyph->bbox.p2.y;
+ if (round_xy)
+ v = _cairo_fixed_from_int (_cairo_lround (glyph->y));
+ else
+ v = _cairo_fixed_from_double (glyph->y);
+ box.p1.y = v + scaled_glyph->bbox.p1.y;
+ box.p2.y = v + scaled_glyph->bbox.p2.y;
- _cairo_box_round_to_rectangle (&box, extents);
- return CAIRO_STATUS_SUCCESS;
+ _cairo_box_round_to_rectangle (&box, extents);
+ }
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ return status;
}
/*
@@ -2805,6 +2835,8 @@ _cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_page_t *page;
cairo_status_t status;
+ assert (scaled_font->cache_frozen);
+
/* only the first page in the list may contain available slots */
if (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
page = cairo_list_last_entry (&scaled_font->glyph_pages,
@@ -2830,7 +2862,7 @@ _cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
status = _cairo_cache_init (&cairo_scaled_glyph_page_cache,
NULL,
_cairo_scaled_glyph_page_can_remove,
- _cairo_scaled_glyph_page_destroy,
+ _cairo_scaled_glyph_page_pluck,
MAX_GLYPH_PAGES_CACHED);
if (unlikely (status)) {
CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
@@ -2922,6 +2954,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
return scaled_font->status;
assert (CAIRO_MUTEX_IS_LOCKED(scaled_font->mutex));
+ assert (scaled_font->cache_frozen);
if (CAIRO_INJECT_FAULT ())
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -3004,7 +3037,8 @@ _cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
* hold true for all possible cases.
*
* Return value: The #cairo_font_face_t with which @scaled_font was
- * created.
+ * created. This object is owned by cairo. To keep a reference to it,
+ * you must call cairo_scaled_font_reference().
*
* Since: 1.2
**/
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 2149e7e..b84aed9 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -3390,8 +3390,10 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
glyphs[n].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
- if (unlikely (status))
+ if (unlikely (status)) {
+ _cairo_scaled_font_thaw_cache (scaled_font);
goto BAIL;
+ }
if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) {
if (fabs (glyphs[n].y - y) < 1e-5) {
diff --git a/src/cairo-spans-compositor-private.h b/src/cairo-spans-compositor-private.h
index d8b94fb..0babebd 100644
--- a/src/cairo-spans-compositor-private.h
+++ b/src/cairo-spans-compositor-private.h
@@ -46,7 +46,7 @@ CAIRO_BEGIN_DECLS
typedef struct _cairo_abstract_span_renderer {
cairo_span_renderer_t base;
- char data[2048];
+ char data[4096];
} cairo_abstract_span_renderer_t;
struct cairo_spans_compositor {
diff --git a/src/cairo-spans-compositor.c b/src/cairo-spans-compositor.c
index ffbf56f..cb3e973 100644
--- a/src/cairo-spans-compositor.c
+++ b/src/cairo-spans-compositor.c
@@ -557,8 +557,10 @@ composite_aligned_boxes (const cairo_spans_compositor_t *compositor,
TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n",
__FUNCTION__, need_clip_mask, extents->is_bounded));
- if (need_clip_mask && ! extents->is_bounded)
+ if (need_clip_mask && ! extents->is_bounded) {
+ TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color);
@@ -570,8 +572,10 @@ composite_aligned_boxes (const cairo_spans_compositor_t *compositor,
if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
/* SOURCE with a mask is actually a LERP in cairo semantics */
- if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0)
+ if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0) {
+ TRACE ((stderr, "%s: unsupported lerp\n", __FUNCTION__));
return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
}
/* Are we just copying a recording surface? */
@@ -700,8 +704,10 @@ composite_boxes (const cairo_spans_compositor_t *compositor,
TRACE ((stderr, "%s\n", __FUNCTION__));
_cairo_box_from_rectangle (&box, &extents->unbounded);
- if (composite_needs_clip (extents, &box))
+ if (composite_needs_clip (extents, &box)) {
+ TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
_cairo_rectangular_scan_converter_init (&converter, &extents->unbounded);
for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
@@ -738,10 +744,13 @@ composite_polygon (const cairo_spans_compositor_t *compositor,
cairo_bool_t needs_clip;
cairo_int_status_t status;
- needs_clip = ! extents->is_bounded &&
- (! _clip_is_region (extents->clip) || extents->clip->num_boxes > 1);
+ if (extents->is_bounded)
+ needs_clip = extents->clip->path != NULL;
+ else
+ needs_clip = !_clip_is_region (extents->clip) || extents->clip->num_boxes > 1;
TRACE ((stderr, "%s - needs_clip=%d\n", __FUNCTION__, needs_clip));
if (needs_clip) {
+ TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
return CAIRO_INT_STATUS_UNSUPPORTED;
converter = _cairo_clip_tor_scan_converter_create (extents->clip,
polygon,
@@ -992,7 +1001,9 @@ _cairo_spans_compositor_stroke (const cairo_compositor_t *_compositor,
const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
cairo_int_status_t status;
+ TRACE ((stderr, "%s\n", __FUNCTION__));
TRACE_ (_cairo_debug_print_path (stderr, path));
+ TRACE_ (_cairo_debug_print_clip (stderr, extents->clip));
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c
index 3ebaf01..51c9414 100644
--- a/src/cairo-stroke-style.c
+++ b/src/cairo-stroke-style.c
@@ -127,6 +127,45 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
}
}
+void
+_cairo_stroke_style_max_line_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm,
+ double *dx, double *dy)
+{
+ double style_expansion = 0.5 * style->line_width;
+ if (_cairo_matrix_has_unity_scale (ctm)) {
+ *dx = *dy = style_expansion;
+ } else {
+ *dx = style_expansion * hypot (ctm->xx, ctm->xy);
+ *dy = style_expansion * hypot (ctm->yy, ctm->yx);
+ }
+}
+
+void
+_cairo_stroke_style_max_join_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm,
+ double *dx, double *dy)
+{
+ double style_expansion = 0.5;
+
+ if (style->line_join == CAIRO_LINE_JOIN_MITER &&
+ ! path->stroke_is_rectilinear &&
+ style_expansion < M_SQRT2 * style->miter_limit)
+ {
+ style_expansion = M_SQRT2 * style->miter_limit;
+ }
+
+ style_expansion *= style->line_width;
+
+ if (_cairo_matrix_has_unity_scale (ctm)) {
+ *dx = *dy = style_expansion;
+ } else {
+ *dx = style_expansion * hypot (ctm->xx, ctm->xy);
+ *dy = style_expansion * hypot (ctm->yy, ctm->yx);
+ }
+}
/*
* Computes the period of a dashed stroke style.
* Returns 0 for non-dashed styles.
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index c11e9e7..5c6969c 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1096,6 +1096,10 @@ void *
cairo_surface_get_user_data (cairo_surface_t *surface,
const cairo_user_data_key_t *key)
{
+ /* Prevent reads of the array during teardown */
+ if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count))
+ return NULL;
+
return _cairo_user_data_array_get_data (&surface->user_data, key);
}
@@ -1126,6 +1130,9 @@ cairo_surface_set_user_data (cairo_surface_t *surface,
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return surface->status;
+ if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count))
+ return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
+
return _cairo_user_data_array_set_data (&surface->user_data,
key, user_data, destroy);
}
@@ -1154,7 +1161,9 @@ cairo_surface_get_mime_data (cairo_surface_t *surface,
*data = NULL;
*length = 0;
- if (unlikely (surface->status))
+
+ /* Prevent reads of the array during teardown */
+ if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count))
return;
/* The number of mime-types attached to a surface is usually small,
@@ -1252,7 +1261,8 @@ _cairo_mime_data_destroy (void *ptr)
* memory and disk space.
*
* The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG,
- * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI.
+ * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI,
+ * %CAIRO_MIME_TYPE_UNIQUE_ID.
*
* See corresponding backend surface docs for details about which MIME
* types it can handle. Caution: the associated MIME data will be
@@ -1275,6 +1285,12 @@ cairo_surface_set_mime_data (cairo_surface_t *surface,
cairo_status_t status;
cairo_mime_data_t *mime_data;
+ if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
+ return surface->status;
+
+ if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count))
+ return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
+
if (unlikely (surface->status))
return surface->status;
if (unlikely (surface->finished))
diff --git a/src/cairo-traps-compositor.c b/src/cairo-traps-compositor.c
index eeee20c..02fbe75 100644
--- a/src/cairo-traps-compositor.c
+++ b/src/cairo-traps-compositor.c
@@ -1570,7 +1570,7 @@ clip_and_composite_polygon (const cairo_traps_compositor_t *compositor,
* The clip will trim that overestimate to our expectations.
*/
if (! extents->is_bounded)
- flags |= FORCE_CLIP_REGION;
+ flags |= FORCE_CLIP_REGION;
traps.antialias = antialias;
status = clip_and_composite (compositor, extents,
@@ -1791,7 +1791,8 @@ composite_traps_as_boxes (const cairo_traps_compositor_t *compositor,
static cairo_int_status_t
clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
cairo_composite_rectangles_t *extents,
- composite_traps_info_t *info)
+ composite_traps_info_t *info,
+ unsigned flags)
{
cairo_int_status_t status;
@@ -1801,10 +1802,10 @@ clip_and_composite_traps (const cairo_traps_compositor_t *compositor,
if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
return status;
- status = composite_traps_as_boxes (compositor, extents, info);
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if ((flags & FORCE_CLIP_REGION) == 0)
+ status = composite_traps_as_boxes (compositor, extents, info);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- unsigned int flags = 0;
-
/* For unbounded operations, the X11 server will estimate the
* affected rectangle and apply the operation to that. However,
* there are cases where this is an overestimate (e.g. the
@@ -2152,16 +2153,32 @@ _cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor,
}
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ cairo_int_status_t (*func) (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps);
composite_traps_info_t info;
+ unsigned flags = 0;
+
+ if (antialias == CAIRO_ANTIALIAS_BEST || antialias == CAIRO_ANTIALIAS_GOOD) {
+ func = _cairo_path_fixed_stroke_polygon_to_traps;
+ } else {
+ func = _cairo_path_fixed_stroke_to_traps;
+ if (extents->clip->num_boxes > 1 ||
+ extents->mask.width > extents->unbounded.width ||
+ extents->mask.height > extents->unbounded.height)
+ {
+ flags = NEED_CLIP_REGION | FORCE_CLIP_REGION;
+ }
+ }
info.antialias = antialias;
_cairo_traps_init_with_clip (&info.traps, extents->clip);
- status = _cairo_path_fixed_stroke_to_traps (path, style,
- ctm, ctm_inverse,
- tolerance,
- &info.traps);
+ status = func (path, style, ctm, ctm_inverse, tolerance, &info.traps);
if (likely (status == CAIRO_INT_STATUS_SUCCESS))
- status = clip_and_composite_traps (compositor, extents, &info);
+ status = clip_and_composite_traps (compositor, extents, &info, flags);
_cairo_traps_fini (&info.traps);
}
diff --git a/src/cairo-traps-private.h b/src/cairo-traps-private.h
index 62c0fe7..7fef062 100644
--- a/src/cairo-traps-private.h
+++ b/src/cairo-traps-private.h
@@ -47,6 +47,7 @@ CAIRO_BEGIN_DECLS
struct _cairo_traps {
cairo_status_t status;
+ cairo_box_t bounds;
const cairo_box_t *limits;
int num_limits;
@@ -89,6 +90,14 @@ _cairo_traps_fini (cairo_traps_t *traps);
cairo_private void
_cairo_traps_translate (cairo_traps_t *traps, int x, int y);
+cairo_private void
+_cairo_traps_tessellate_triangle (cairo_traps_t *traps,
+ const cairo_point_t t[3]);
+
+cairo_private void
+_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
+ const cairo_point_t q[4]);
+
cairo_private cairo_status_t
_cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
const cairo_point_t *top_left,
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 48eaf98..9f1d4a7 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -39,6 +39,7 @@
#include "cairoint.h"
+#include "cairo-box-inline.h"
#include "cairo-boxes-private.h"
#include "cairo-error-private.h"
#include "cairo-region-private.h"
@@ -73,8 +74,14 @@ _cairo_traps_limit (cairo_traps_t *traps,
const cairo_box_t *limits,
int num_limits)
{
+ int i;
+
traps->limits = limits;
traps->num_limits = num_limits;
+
+ traps->bounds = limits[0];
+ for (i = 1; i < num_limits; i++)
+ _cairo_box_add_box (&traps->bounds, &limits[i]);
}
void
@@ -158,6 +165,245 @@ _cairo_traps_add_trap (cairo_traps_t *traps,
trap->right = *right;
}
+static void
+_cairo_traps_add_clipped_trap (cairo_traps_t *traps,
+ cairo_fixed_t _top, cairo_fixed_t _bottom,
+ cairo_line_t *_left, cairo_line_t *_right)
+{
+ /* Note: With the goofy trapezoid specification, (where an
+ * arbitrary two points on the lines can specified for the left
+ * and right edges), these limit checks would not work in
+ * general. For example, one can imagine a trapezoid entirely
+ * within the limits, but with two points used to specify the left
+ * edge entirely to the right of the limits. Fortunately, for our
+ * purposes, cairo will never generate such a crazy
+ * trapezoid. Instead, cairo always uses for its points the
+ * extreme positions of the edge that are visible on at least some
+ * trapezoid. With this constraint, it's impossible for both
+ * points to be outside the limits while the relevant edge is
+ * entirely inside the limits.
+ */
+ if (traps->num_limits) {
+ const cairo_box_t *b = &traps->bounds;
+ cairo_fixed_t top = _top, bottom = _bottom;
+ cairo_line_t left = *_left, right = *_right;
+
+ /* Trivially reject if trapezoid is entirely to the right or
+ * to the left of the limits. */
+ if (left.p1.x >= b->p2.x && left.p2.x >= b->p2.x)
+ return;
+
+ if (right.p1.x <= b->p1.x && right.p2.x <= b->p1.x)
+ return;
+
+ /* And reject if the trapezoid is entirely above or below */
+ if (top >= b->p2.y || bottom <= b->p1.y)
+ return;
+
+ /* Otherwise, clip the trapezoid to the limits. We only clip
+ * where an edge is entirely outside the limits. If we wanted
+ * to be more clever, we could handle cases where a trapezoid
+ * edge intersects the edge of the limits, but that would
+ * require slicing this trapezoid into multiple trapezoids,
+ * and I'm not sure the effort would be worth it. */
+ if (top < b->p1.y)
+ top = b->p1.y;
+
+ if (bottom > b->p2.y)
+ bottom = b->p2.y;
+
+ if (left.p1.x <= b->p1.x && left.p2.x <= b->p1.x)
+ left.p1.x = left.p2.x = b->p1.x;
+
+ if (right.p1.x >= b->p2.x && right.p2.x >= b->p2.x)
+ right.p1.x = right.p2.x = b->p2.x;
+
+ /* Trivial discards for empty trapezoids that are likely to
+ * be produced by our tessellators (most notably convex_quad
+ * when given a simple rectangle).
+ */
+ if (top >= bottom)
+ return;
+
+ /* cheap colinearity check */
+ if (right.p1.x <= left.p1.x && right.p1.y == left.p1.y &&
+ right.p2.x <= left.p2.x && right.p2.y == left.p2.y)
+ return;
+
+ _cairo_traps_add_trap (traps, top, bottom, &left, &right);
+ } else
+ _cairo_traps_add_trap (traps, _top, _bottom, _left, _right);
+}
+
+static int
+_compare_point_fixed_by_y (const void *av, const void *bv)
+{
+ const cairo_point_t *a = av, *b = bv;
+ int ret = a->y - b->y;
+ if (ret == 0)
+ ret = a->x - b->x;
+ return ret;
+}
+
+void
+_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps,
+ const cairo_point_t q[4])
+{
+ int a, b, c, d;
+ int i;
+ cairo_slope_t ab, ad;
+ cairo_bool_t b_left_of_d;
+ cairo_line_t left;
+ cairo_line_t right;
+
+ /* Choose a as a point with minimal y */
+ a = 0;
+ for (i = 1; i < 4; i++)
+ if (_compare_point_fixed_by_y (&q[i], &q[a]) < 0)
+ a = i;
+
+ /* b and d are adjacent to a, while c is opposite */
+ b = (a + 1) % 4;
+ c = (a + 2) % 4;
+ d = (a + 3) % 4;
+
+ /* Choose between b and d so that b.y is less than d.y */
+ if (_compare_point_fixed_by_y (&q[d], &q[b]) < 0) {
+ b = (a + 3) % 4;
+ d = (a + 1) % 4;
+ }
+
+ /* Without freedom left to choose anything else, we have four
+ * cases to tessellate.
+ *
+ * First, we have to determine the Y-axis sort of the four
+ * vertices, (either abcd or abdc). After that we need to detemine
+ * which edges will be "left" and which will be "right" in the
+ * resulting trapezoids. This can be determined by computing a
+ * slope comparison of ab and ad to determine if b is left of d or
+ * not.
+ *
+ * Note that "left of" here is in the sense of which edges should
+ * be the left vs. right edges of the trapezoid. In particular, b
+ * left of d does *not* mean that b.x is less than d.x.
+ *
+ * This should hopefully be made clear in the lame ASCII art
+ * below. Since the same slope comparison is used in all cases, we
+ * compute it before testing for the Y-value sort. */
+
+ /* Note: If a == b then the ab slope doesn't give us any
+ * information. In that case, we can replace it with the ac (or
+ * equivalenly the bc) slope which gives us exactly the same
+ * information we need. At worst the names of the identifiers ab
+ * and b_left_of_d are inaccurate in this case, (would be ac, and
+ * c_left_of_d). */
+ if (q[a].x == q[b].x && q[a].y == q[b].y)
+ _cairo_slope_init (&ab, &q[a], &q[c]);
+ else
+ _cairo_slope_init (&ab, &q[a], &q[b]);
+
+ _cairo_slope_init (&ad, &q[a], &q[d]);
+
+ b_left_of_d = _cairo_slope_compare (&ab, &ad) > 0;
+
+ if (q[c].y <= q[d].y) {
+ if (b_left_of_d) {
+ /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad))
+ *
+ * top bot left right
+ * _a a a
+ * / / /| |\ a.y b.y ab ad
+ * b / b | b \
+ * / / | | \ \ b.y c.y bc ad
+ * c / c | c \
+ * | / \| \ \ c.y d.y cd ad
+ * d d d
+ */
+ left.p1 = q[a]; left.p2 = q[b];
+ right.p1 = q[a]; right.p2 = q[d];
+ _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+ left.p1 = q[b]; left.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
+ left.p1 = q[c]; left.p2 = q[d];
+ _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
+ } else {
+ /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad))
+ *
+ * a a a_
+ * /| |\ \ \ a.y b.y ad ab
+ * / b | b \ b
+ * / / | | \ \ b.y c.y ad bc
+ * / c | c \ c
+ * / / |/ \ | c.y d.y ad cd
+ * d d d
+ */
+ left.p1 = q[a]; left.p2 = q[d];
+ right.p1 = q[a]; right.p2 = q[b];
+ _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+ right.p1 = q[b]; right.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right);
+ right.p1 = q[c]; right.p2 = q[d];
+ _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right);
+ }
+ } else {
+ if (b_left_of_d) {
+ /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad))
+ *
+ * a a a
+ * // / \ |\ a.y b.y ab ad
+ * /b/ b \ b \
+ * / / \ \ \ \ b.y d.y bc ad
+ * /d/ \ d \ d
+ * // \ / \| d.y c.y bc dc
+ * c c c
+ */
+ left.p1 = q[a]; left.p2 = q[b];
+ right.p1 = q[a]; right.p2 = q[d];
+ _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+ left.p1 = q[b]; left.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
+ right.p1 = q[d]; right.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
+ } else {
+ /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad))
+ *
+ * a a a
+ * /| / \ \\ a.y b.y ad ab
+ * / b / b \b\
+ * / / / / \ \ b.y d.y ad bc
+ * d / d / \d\
+ * |/ \ / \\ d.y c.y dc bc
+ * c c c
+ */
+ left.p1 = q[a]; left.p2 = q[d];
+ right.p1 = q[a]; right.p2 = q[b];
+ _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right);
+ right.p1 = q[b]; right.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right);
+ left.p1 = q[d]; left.p2 = q[c];
+ _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right);
+ }
+ }
+}
+
+/* A triangle is simply a degenerate case of a convex
+ * quadrilateral. We would not benefit from having any distinct
+ * implementation of triangle vs. quadrilateral tessellation here. */
+void
+_cairo_traps_tessellate_triangle (cairo_traps_t *traps,
+ const cairo_point_t t[3])
+{
+ cairo_point_t quad[4];
+
+ quad[0] = t[0];
+ quad[1] = t[0];
+ quad[2] = t[1];
+ quad[3] = t[2];
+
+ _cairo_traps_tessellate_convex_quad (traps, quad);
+}
+
+
/**
* _cairo_traps_init_boxes:
* @traps: a #cairo_traps_t
@@ -240,6 +486,9 @@ _cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
cairo_bool_t reversed;
int n;
+ if (top >= traps->bounds.p2.y || bottom <= traps->bounds.p1.y)
+ return CAIRO_STATUS_SUCCESS;
+
/* support counter-clockwise winding for rectangular tessellation */
reversed = top_left->x > bottom_right->x;
if (reversed) {
@@ -247,6 +496,9 @@ _cairo_traps_tessellate_rectangle (cairo_traps_t *traps,
left.p1.x = left.p2.x = bottom_right->x;
}
+ if (left.p1.x >= traps->bounds.p2.x || right.p1.x <= traps->bounds.p1.x)
+ return CAIRO_STATUS_SUCCESS;
+
for (n = 0; n < traps->num_limits; n++) {
const cairo_box_t *limits = &traps->limits[n];
cairo_line_t _left, _right;
diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index c19773d..383c99a 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -53,6 +53,7 @@
#include "cairo-output-stream-private.h"
#include <ctype.h>
+#include <locale.h>
#define TYPE1_STACKSIZE 24 /* Defined in Type 1 Font Format */
@@ -114,6 +115,8 @@ typedef struct _cairo_type1_font_subset {
const char *rd, *nd, *np;
+ int lenIV;
+
char *type1_data;
unsigned int type1_length;
char *type1_end;
@@ -134,11 +137,13 @@ typedef struct _cairo_type1_font_subset {
int hex_column;
struct {
- int stack[TYPE1_STACKSIZE], sp, top_value;
+ double stack[TYPE1_STACKSIZE];
+ int sp;
} build_stack;
struct {
- int other_subr_args[TYPE1_STACKSIZE], num_other_subr_args, cur_other_subr_arg;
+ int stack[TYPE1_STACKSIZE];
+ int sp;
} ps_stack;
@@ -302,8 +307,17 @@ cairo_type1_font_subset_get_matrix (cairo_type1_font_subset_t *font,
double *d)
{
const char *start, *end, *segment_end;
- int ret;
+ int ret, s_max, i, j;
char *s;
+ struct lconv *locale_data;
+ const char *decimal_point;
+ int decimal_point_len;
+
+ locale_data = localeconv ();
+ decimal_point = locale_data->decimal_point;
+ decimal_point_len = strlen (decimal_point);
+
+ assert (decimal_point_len != 0);
segment_end = font->header_segment + font->header_segment_size;
start = find_token (font->header_segment, segment_end, name);
@@ -314,12 +328,23 @@ cairo_type1_font_subset_get_matrix (cairo_type1_font_subset_t *font,
if (end == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
- s = malloc (end - start + 1);
+ s_max = end - start + 5*decimal_point_len + 1;
+ s = malloc (s_max);
if (unlikely (s == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- strncpy (s, start, end - start);
- s[end - start] = 0;
+ i = 0;
+ j = 0;
+ while (i < end - start && j < s_max - decimal_point_len) {
+ if (start[i] == '.') {
+ strncpy(s + j, decimal_point, decimal_point_len);
+ i++;
+ j += decimal_point_len;
+ } else {
+ s[j++] = start[i++];
+ }
+ }
+ s[j] = 0;
start = strpbrk (s, "{[");
if (!start) {
@@ -508,13 +533,12 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
if (font->scaled_font_subset->is_latin) {
for (i = 1; i < 256; i++) {
int subset_glyph = font->scaled_font_subset->latin_to_subset_glyph_index[i];
- int glyph_num = font->subset_index_to_glyphs[subset_glyph];
if (subset_glyph > 0) {
_cairo_output_stream_printf (font->output,
"dup %d /%s put\n",
i,
- font->glyph_names[glyph_num]);
+ _cairo_winansi_to_glyphname (i));
}
}
} else {
@@ -719,17 +743,37 @@ use_standard_encoding_glyph (cairo_type1_font_subset_t *font, int index)
return CAIRO_INT_STATUS_UNSUPPORTED;
}
-#define TYPE1_CHARSTRING_COMMAND_ESCAPE 0x0c
-#define TYPE1_CHARSTRING_COMMAND_SEAC 0x0c06
-#define TYPE1_CHARSTRING_COMMAND_SBW 0x0c07
-#define TYPE1_CHARSTRING_COMMAND_HSBW 0x0d
-#define TYPE1_CHARSTRING_COMMAND_CALLSUBR 0x0a
-#define TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR 0x0c10
-#define TYPE1_CHARSTRING_COMMAND_POP 0x0c11
-
-
-/* Get glyph width and look for seac operatorParse charstring */
+#define TYPE1_CHARSTRING_COMMAND_HSTEM 0x01
+#define TYPE1_CHARSTRING_COMMAND_VSTEM 0x03
+#define TYPE1_CHARSTRING_COMMAND_VMOVETO 0x04
+#define TYPE1_CHARSTRING_COMMAND_RLINETO 0x05
+#define TYPE1_CHARSTRING_COMMAND_HLINETO 0x06
+#define TYPE1_CHARSTRING_COMMAND_VLINETO 0x07
+#define TYPE1_CHARSTRING_COMMAND_RRCURVETO 0x08
+#define TYPE1_CHARSTRING_COMMAND_CLOSEPATH 0x09
+#define TYPE1_CHARSTRING_COMMAND_CALLSUBR 0x0a
+#define TYPE1_CHARSTRING_COMMAND_RETURN 0x0b
+#define TYPE1_CHARSTRING_COMMAND_ESCAPE 0x0c
+#define TYPE1_CHARSTRING_COMMAND_HSBW 0x0d
+#define TYPE1_CHARSTRING_COMMAND_ENDCHAR 0x0e
+#define TYPE1_CHARSTRING_COMMAND_RMOVETO 0x15
+#define TYPE1_CHARSTRING_COMMAND_HMOVETO 0x16
+#define TYPE1_CHARSTRING_COMMAND_VHCURVETO 0x1e
+#define TYPE1_CHARSTRING_COMMAND_HVCURVETO 0x1f
+#define TYPE1_CHARSTRING_COMMAND_DOTSECTION 0x0c00
+#define TYPE1_CHARSTRING_COMMAND_VSTEM3 0x0c01
+#define TYPE1_CHARSTRING_COMMAND_HSTEM3 0x0c02
+#define TYPE1_CHARSTRING_COMMAND_SEAC 0x0c06
+#define TYPE1_CHARSTRING_COMMAND_SBW 0x0c07
+#define TYPE1_CHARSTRING_COMMAND_DIV 0x0c0c
+#define TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR 0x0c10
+#define TYPE1_CHARSTRING_COMMAND_POP 0x0c11
+#define TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT 0x0c21
+
+/* Parse the charstring, including recursing into subroutines. Find
+ * the glyph width, subroutines called, and glyphs required by the
+ * SEAC operator. */
static cairo_status_t
cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
int glyph,
@@ -740,9 +784,7 @@ cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
unsigned char *charstring;
const unsigned char *end;
const unsigned char *p;
- cairo_bool_t last_op_was_integer;
int command;
- int subr_num, i;
charstring = malloc (encrypted_charstring_length);
if (unlikely (charstring == NULL))
@@ -753,45 +795,72 @@ cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
encrypted_charstring_length,
charstring);
end = charstring + encrypted_charstring_length;
-
- p = charstring + 4;
-
- last_op_was_integer = FALSE;
-
+ p = charstring + font->lenIV;
+ status = CAIRO_STATUS_SUCCESS;
while (p < end) {
if (*p < 32) {
command = *p++;
switch (command) {
- case TYPE1_CHARSTRING_COMMAND_HSBW:
- if (! last_op_was_integer)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- font->glyphs[glyph].width = font->build_stack.stack[1]/font->base.units_per_em;
+ case TYPE1_CHARSTRING_COMMAND_HSTEM:
+ case TYPE1_CHARSTRING_COMMAND_VSTEM:
+ case TYPE1_CHARSTRING_COMMAND_VMOVETO:
+ case TYPE1_CHARSTRING_COMMAND_RLINETO:
+ case TYPE1_CHARSTRING_COMMAND_HLINETO:
+ case TYPE1_CHARSTRING_COMMAND_VLINETO:
+ case TYPE1_CHARSTRING_COMMAND_RRCURVETO:
+ case TYPE1_CHARSTRING_COMMAND_CLOSEPATH:
+ case TYPE1_CHARSTRING_COMMAND_RMOVETO:
+ case TYPE1_CHARSTRING_COMMAND_HMOVETO:
+ case TYPE1_CHARSTRING_COMMAND_VHCURVETO:
+ case TYPE1_CHARSTRING_COMMAND_HVCURVETO:
+ case TYPE1_CHARSTRING_COMMAND_RETURN:
+ case TYPE1_CHARSTRING_COMMAND_ENDCHAR:
+ default:
+ /* stack clearing operator */
font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
break;
case TYPE1_CHARSTRING_COMMAND_CALLSUBR:
- if (font->subset_subrs &&
- last_op_was_integer &&
- font->build_stack.top_value >= 0 &&
- font->build_stack.top_value < font->num_subrs)
- {
- subr_num = font->build_stack.top_value;
- font->subrs[subr_num].used = TRUE;
- last_op_was_integer = FALSE;
- status = cairo_type1_font_subset_parse_charstring (font,
- glyph,
- font->subrs[subr_num].subr_string,
- font->subrs[subr_num].subr_length);
- } else {
- font->subset_subrs = FALSE;
+ if (font->subset_subrs && font->build_stack.sp > 0) {
+ double int_val;
+ if (modf(font->build_stack.stack[--font->build_stack.sp], &int_val) == 0.0) {
+ int subr_num = int_val;
+ if (subr_num >= 0 && subr_num < font->num_subrs) {
+ font->subrs[subr_num].used = TRUE;
+ status = cairo_type1_font_subset_parse_charstring (
+ font,
+ glyph,
+ font->subrs[subr_num].subr_string,
+ font->subrs[subr_num].subr_length);
+ break;
+ }
+ }
}
+ font->subset_subrs = FALSE;
+ break;
+
+ case TYPE1_CHARSTRING_COMMAND_HSBW:
+ if (font->build_stack.sp < 2) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ font->glyphs[glyph].width = font->build_stack.stack[1]/font->base.units_per_em;
+ font->build_stack.sp = 0;
break;
case TYPE1_CHARSTRING_COMMAND_ESCAPE:
command = command << 8 | *p++;
switch (command) {
+ case TYPE1_CHARSTRING_COMMAND_DOTSECTION:
+ case TYPE1_CHARSTRING_COMMAND_VSTEM3:
+ case TYPE1_CHARSTRING_COMMAND_HSTEM3:
+ case TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT:
+ default:
+ /* stack clearing operator */
+ font->build_stack.sp = 0;
+ break;
+
case TYPE1_CHARSTRING_COMMAND_SEAC:
/* The seac command takes five integer arguments. The
* last two are glyph indices into the PS standard
@@ -799,69 +868,92 @@ cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font,
* glyph is composed from. All we need to do is to
* make sure those glyphs are present in the subset
* under their standard names. */
+ if (font->build_stack.sp < 5) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
status = use_standard_encoding_glyph (font, font->build_stack.stack[3]);
if (unlikely (status))
- return status;
+ goto cleanup;
status = use_standard_encoding_glyph (font, font->build_stack.stack[4]);
if (unlikely (status))
- return status;
+ goto cleanup;
font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
break;
case TYPE1_CHARSTRING_COMMAND_SBW:
- if (! last_op_was_integer)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (font->build_stack.sp < 4) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
font->glyphs[glyph].width = font->build_stack.stack[2]/font->base.units_per_em;
font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
break;
- case TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR:
- for (i = 0; i < font->build_stack.sp; i++)
- font->ps_stack.other_subr_args[i] = font->build_stack.stack[i];
- font->ps_stack.num_other_subr_args = font->build_stack.sp;
- font->ps_stack.cur_other_subr_arg = 0;
- font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
+ case TYPE1_CHARSTRING_COMMAND_DIV:
+ if (font->build_stack.sp < 2) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ } else {
+ double num1 = font->build_stack.stack[font->build_stack.sp - 2];
+ double num2 = font->build_stack.stack[font->build_stack.sp - 1];
+ font->build_stack.sp--;
+ if (num2 == 0.0) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+ font->build_stack.stack[font->build_stack.sp - 1] = num1/num2;
+ }
break;
+ case TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR:
+ if (font->build_stack.sp < 1) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ font->build_stack.sp--;
+ font->ps_stack.sp = 0;
+ while (font->build_stack.sp)
+ font->ps_stack.stack[font->ps_stack.sp++] = font->build_stack.stack[--font->build_stack.sp];
+
+ break;
+
case TYPE1_CHARSTRING_COMMAND_POP:
- if (font->ps_stack.num_other_subr_args > font->ps_stack.cur_other_subr_arg) {
- font->build_stack.top_value = font->ps_stack.other_subr_args[font->ps_stack.cur_other_subr_arg++];
- last_op_was_integer = TRUE;
- } else {
- font->subset_subrs = FALSE;
+ if (font->ps_stack.sp < 1) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
}
- break;
- default:
- font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
+ /* T1 spec states that if the interpreter does not
+ * support executing the callothersub, the results
+ * must be taken from the callothersub arguments. */
+ font->build_stack.stack[font->build_stack.sp++] = font->ps_stack.stack[--font->ps_stack.sp];
break;
}
break;
-
- default:
- font->build_stack.sp = 0;
- last_op_was_integer = FALSE;
- break;
}
- } else {
+ } else {
/* integer argument */
- p = cairo_type1_font_subset_decode_integer (p, &font->build_stack.top_value);
- last_op_was_integer = TRUE;
- if (font->build_stack.sp < TYPE1_STACKSIZE)
- font->build_stack.stack[font->build_stack.sp++] = font->build_stack.top_value;
- }
+ if (font->build_stack.sp < TYPE1_STACKSIZE) {
+ int val;
+ p = cairo_type1_font_subset_decode_integer (p, &val);
+ font->build_stack.stack[font->build_stack.sp++] = val;
+ } else {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+ }
}
+cleanup:
free (charstring);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_status_t
@@ -1036,10 +1128,26 @@ write_used_glyphs (cairo_type1_font_subset_t *font,
cairo_status_t status;
char buffer[256];
int length;
+ int subset_id;
+ int ch;
if (font->glyphs[glyph_number].subset_index < 0)
return CAIRO_STATUS_SUCCESS;
+ if (font->scaled_font_subset->is_latin) {
+ /* When using the WinAnsi encoding in PDF, the /Encoding array
+ * is ignored and instead glyphs are keyed by glyph names. To
+ * ensure correct rendering we replace the glyph name in the
+ * font with the standard name.
+ **/
+ subset_id = font->glyphs[glyph_number].subset_index;
+ if (subset_id > 0) {
+ ch = font->scaled_font_subset->to_latin_char[subset_id];
+ name = _cairo_winansi_to_glyphname (ch);
+ name_length = strlen(name);
+ }
+ }
+
length = snprintf (buffer, sizeof buffer,
"/%.*s %d %s ",
name_length, name, charstring_length, font->rd);
@@ -1137,9 +1245,9 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
{
cairo_status_t status;
const char *p, *subrs, *charstrings, *array_start, *array_end, *dict_start, *dict_end;
- const char *closefile_token;
- char buffer[32], *subr_count_end, *glyph_count_end;
- int length;
+ const char *lenIV_start, *lenIV_end, *closefile_token;
+ char buffer[32], *lenIV_str, *subr_count_end, *glyph_count_end;
+ int ret, lenIV, length;
const cairo_scaled_font_backend_t *backend;
unsigned int i;
int glyph, j;
@@ -1161,6 +1269,38 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
* subroutines and charstrings not required.
*/
+ /* Determine lenIV, the number of random characters at the start of
+ each encrypted charstring. The defaults is 4, but this can be
+ overridden in the private dict. */
+ font->lenIV = 4;
+ if ((lenIV_start = find_token (font->cleartext, font->cleartext_end, "/lenIV")) != NULL) {
+ lenIV_start += 6;
+ lenIV_end = find_token (lenIV_start, font->cleartext_end, "def");
+ if (lenIV_end == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ lenIV_str = malloc (lenIV_end - lenIV_start + 1);
+ if (unlikely (lenIV_str == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ strncpy (lenIV_str, lenIV_start, lenIV_end - lenIV_start);
+ lenIV_str[lenIV_end - lenIV_start] = 0;
+
+ ret = sscanf(lenIV_str, "%d", &lenIV);
+ free(lenIV_str);
+
+ if (unlikely (ret <= 0))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Apparently some fonts signal unencrypted charstrings with a negative lenIV,
+ though this is not part of the Type 1 Font Format specification. See, e.g.
+ http://lists.gnu.org/archive/html/freetype-devel/2000-06/msg00064.html. */
+ if (unlikely (lenIV < 0))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ font->lenIV = lenIV;
+ }
+
/* Find start of Subrs */
subrs = find_token (font->cleartext, font->cleartext_end, "/Subrs");
if (subrs == NULL) {
@@ -1265,7 +1405,7 @@ skip_subrs:
for (j = 0; j < font->num_glyphs; j++) {
glyph = font->subset_index_to_glyphs[j];
font->build_stack.sp = 0;
- font->ps_stack.num_other_subr_args = 0;
+ font->ps_stack.sp = 0;
status = cairo_type1_font_subset_parse_charstring (font,
glyph,
font->glyphs[glyph].encrypted_charstring,
@@ -1274,6 +1414,12 @@ skip_subrs:
return status;
}
+ /* Always include the first five subroutines in case the Flex/hint mechanism is
+ * being used. */
+ for (j = 0; j < MIN (font->num_subrs, 5); j++) {
+ font->subrs[j].used = TRUE;
+ }
+
closefile_token = find_token (dict_end, font->cleartext_end, "closefile");
if (closefile_token == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1549,6 +1695,8 @@ _cairo_type1_font_subset_fini (cairo_type1_font_subset_t *font)
free (font->subset_index_to_glyphs);
+ free (font->cleartext);
+
return status;
}
diff --git a/src/cairo-xcb-connection-core.c b/src/cairo-xcb-connection-core.c
index 0eb2b84..ae7c023 100644
--- a/src/cairo-xcb-connection-core.c
+++ b/src/cairo-xcb-connection-core.c
@@ -159,20 +159,20 @@ _cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
}
}
-void
-_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
- xcb_drawable_t dst,
- xcb_gcontext_t gc,
- int16_t src_x,
- int16_t src_y,
- uint16_t width,
- uint16_t height,
- uint16_t cpp,
- int stride,
- int16_t dst_x,
- int16_t dst_y,
- uint8_t depth,
- void *_data)
+static void
+_cairo_xcb_connection_do_put_subimage (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint16_t cpp,
+ int stride,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ void *_data)
{
xcb_protocol_request_t xcb_req = {
0 /* count */,
@@ -239,6 +239,50 @@ _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
free (vec);
}
+void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+ xcb_drawable_t dst,
+ xcb_gcontext_t gc,
+ int16_t src_x,
+ int16_t src_y,
+ uint16_t width,
+ uint16_t height,
+ uint16_t cpp,
+ int stride,
+ int16_t dst_x,
+ int16_t dst_y,
+ uint8_t depth,
+ void *_data)
+{
+ const uint32_t req_size = sizeof(xcb_put_image_request_t);
+ uint32_t length = height * cpp * width;
+ uint32_t len = (req_size + length) >> 2;
+
+ if (len < connection->maximum_request_length) {
+ _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
+ width, height, cpp, stride, dst_x, dst_y, depth, _data);
+ } else {
+ int rows = (connection->maximum_request_length - req_size - 4) / (cpp * width);
+ if (rows > 0) {
+ do {
+ if (rows > height)
+ rows = height;
+
+ length = rows * cpp * width;
+
+ _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
+ width, rows, cpp, stride, dst_x, dst_y, depth, _data);
+
+ height -= rows;
+ dst_y += rows;
+ _data = (char *) _data + stride * rows;
+ } while (height);
+ } else {
+ ASSERT_NOT_REACHED;
+ }
+ }
+}
+
cairo_status_t
_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
xcb_drawable_t src,
diff --git a/src/cairo-xcb-shm.c b/src/cairo-xcb-shm.c
index 7c2a675..2be2dac 100644
--- a/src/cairo-xcb-shm.c
+++ b/src/cairo-xcb-shm.c
@@ -63,6 +63,7 @@ typedef enum {
struct _cairo_xcb_shm_mem_pool {
int shmid;
uint32_t shmseg;
+ void *shm;
cairo_mempool_t mem;
@@ -74,7 +75,7 @@ _cairo_xcb_shm_mem_pool_destroy (cairo_xcb_shm_mem_pool_t *pool)
{
cairo_list_del (&pool->link);
- shmdt (pool->mem.base);
+ shmdt (pool->shm);
_cairo_mempool_fini (&pool->mem);
free (pool);
@@ -160,7 +161,6 @@ _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
size_t shm_allocated = 0;
void *mem = NULL;
cairo_status_t status;
- void *base;
assert (connection->flags & CAIRO_XCB_HAS_SHM);
@@ -240,18 +240,18 @@ _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- base = shmat (pool->shmid, NULL, 0);
- if (unlikely (base == (char *) -1)) {
+ pool->shm = shmat (pool->shmid, NULL, 0);
+ if (unlikely (pool->shm == (char *) -1)) {
shmctl (pool->shmid, IPC_RMID, NULL);
free (pool);
CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- status = _cairo_mempool_init (&pool->mem, base, bytes,
+ status = _cairo_mempool_init (&pool->mem, pool->shm, bytes,
minbits, maxbits - minbits + 1);
if (unlikely (status)) {
- shmdt (base);
+ shmdt (pool->shm);
free (pool);
CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
return status;
@@ -275,7 +275,7 @@ _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
shm_info->pool = pool;
shm_info->shm = pool->shmseg;
shm_info->size = size;
- shm_info->offset = (char *) mem - (char *) pool->mem.base;
+ shm_info->offset = (char *) mem - (char *) pool->shm;
shm_info->mem = mem;
shm_info->sync.sequence = XCB_NONE;
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index dff62af..cce95a1 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -3617,14 +3617,6 @@ _cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst,
return status;
}
-static void
-_clear_image (cairo_surface_t *surface)
-{
- cairo_image_surface_t *image = (cairo_image_surface_t *) surface;
- memset (image->data, 0, image->stride * image->height);
- surface->is_clear = TRUE;
-}
-
static cairo_status_t
_cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
cairo_operator_t op,
@@ -3650,8 +3642,6 @@ _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
if (unlikely (image->status))
return image->status;
- _clear_image (image);
-
clip = _cairo_clip_copy_region (extents->clip);
status = _cairo_surface_offset_stroke (image, x, y,
CAIRO_OPERATOR_ADD,
@@ -3792,8 +3782,6 @@ _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst,
if (unlikely (image->status))
return image->status;
- _clear_image (image);
-
clip = _cairo_clip_copy_region (extents->clip);
status = _cairo_surface_offset_fill (image, x, y,
CAIRO_OPERATOR_ADD,
@@ -3904,8 +3892,6 @@ _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst,
if (unlikely (image->status))
return image->status;
- _clear_image (image);
-
clip = _cairo_clip_copy_region (extents->clip);
status = _cairo_surface_offset_glyphs (image, x, y,
CAIRO_OPERATOR_ADD,
@@ -4179,10 +4165,8 @@ _cairo_xcb_font_close (cairo_xcb_font_t *font)
scaled_font = font->scaled_font;
- CAIRO_MUTEX_LOCK (scaled_font->mutex);
//scaled_font->surface_private = NULL;
_cairo_scaled_font_reset_cache (scaled_font);
- CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
_cairo_xcb_font_destroy (font);
}
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index bde03ff..746fb45 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -190,6 +190,11 @@ _cairo_xcb_surface_create_similar_image (void *abstract_other,
if (unlikely (status))
return _cairo_surface_create_in_error (status);
+ if (! image->base.is_clear) {
+ memset (image->data, 0, image->stride * image->height);
+ image->base.is_clear = TRUE;
+ }
+
return &image->base;
}
diff --git a/src/cairo-xlib-core-compositor.c b/src/cairo-xlib-core-compositor.c
index aaa71d5..9398079 100644
--- a/src/cairo-xlib-core-compositor.c
+++ b/src/cairo-xlib-core-compositor.c
@@ -83,6 +83,7 @@ struct _fill_box {
Display *dpy;
Drawable drawable;
GC gc;
+ //cairo_surface_t *dither = NULL;
};
static cairo_bool_t fill_box (cairo_box_t *box, void *closure)
@@ -128,27 +129,25 @@ color_to_pixel (cairo_xlib_surface_t *dst,
}
static cairo_int_status_t
-fill_boxes (cairo_xlib_surface_t *dst,
- const cairo_color_t *color,
- cairo_boxes_t *boxes)
+_fill_box_init (struct _fill_box *fb,
+ cairo_xlib_surface_t *dst,
+ const cairo_color_t *color)
{
- cairo_surface_t *dither = NULL;
- cairo_status_t status;
- struct _fill_box fb;
+ cairo_int_status_t status;
- status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb.gc);
+ status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb->gc);
if (unlikely (status))
return status;
- fb.dpy = dst->display->display;
- fb.drawable = dst->drawable;
+ fb->dpy = dst->display->display;
+ fb->drawable = dst->drawable;
if (dst->visual && dst->visual->class != TrueColor && 0) {
+#if 0
cairo_solid_pattern_t solid;
cairo_surface_attributes_t attrs;
_cairo_pattern_init_solid (&solid, color);
-#if 0
status = _cairo_pattern_acquire_surface (&solid.base, &dst->base,
0, 0,
ARRAY_LENGTH (dither_pattern[0]),
@@ -160,27 +159,70 @@ fill_boxes (cairo_xlib_surface_t *dst,
_cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
return status;
}
-#endif
- XSetTSOrigin (fb.dpy, fb.gc,
+ XSetTSOrigin (fb->dpy, fb->gc,
- (dst->base.device_transform.x0 + attrs.x_offset),
- (dst->base.device_transform.y0 + attrs.y_offset));
- XSetTile (fb.dpy, fb.gc, ((cairo_xlib_surface_t *) dither)->drawable);
+ XSetTile (fb->dpy, fb->gc, ((cairo_xlib_surface_t *) dither)->drawable);
+#endif
} else {
XGCValues gcv;
gcv.foreground = color_to_pixel (dst, color);
gcv.fill_style = FillSolid;
- XChangeGC (fb.dpy, fb.gc, GCFillStyle | GCForeground, &gcv);
+ XChangeGC (fb->dpy, fb->gc, GCFillStyle | GCForeground, &gcv);
}
+ return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static void
+_fill_box_fini (struct _fill_box *fb,
+ cairo_xlib_surface_t *dst)
+{
+ _cairo_xlib_surface_put_gc (dst->display, dst, fb->gc);
+ //cairo_surface_destroy (fb->dither);
+}
+
+cairo_int_status_t
+_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes)
+{
+ cairo_int_status_t status;
+ struct _fill_box fb;
+
+ status = _fill_box_init (&fb, dst, color);
+ if (unlikely (status))
+ return status;
+
_cairo_boxes_for_each_box (boxes, fill_box, &fb);
- _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc);
+ _fill_box_fini (&fb, dst);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_int_status_t
+_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color,
+ int num_rects,
+ cairo_rectangle_int_t *rects)
+{
+ cairo_int_status_t status;
+ struct _fill_box fb;
+ int i;
+
+ status = _fill_box_init (&fb, dst, color);
+ if (unlikely (status))
+ return status;
- cairo_surface_destroy (dither);
+ for (i = 0; i < num_rects; i++)
+ XFillRectangle (fb.dpy, fb.drawable, fb.gc,
+ rects[i].x, rects[i].y,
+ rects[i].width, rects[i].height);
+ _fill_box_fini (&fb, dst);
return CAIRO_STATUS_SUCCESS;
}
@@ -495,9 +537,8 @@ draw_boxes (cairo_composite_rectangles_t *extents,
return status;
if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
- status = fill_boxes (dst,
- &((cairo_solid_pattern_t *) src)->color,
- boxes);
+ status = _cairo_xlib_core_fill_boxes
+ (dst, &((cairo_solid_pattern_t *) src)->color, boxes);
} else {
status = upload_image_inplace (dst, src, boxes);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index f23a655..04c89b2 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -213,6 +213,13 @@ _cairo_xlib_device_create (Display *dpy)
goto UNLOCK;
}
+ _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
+
+ display->display = dpy;
+ cairo_list_init (&display->screens);
+ cairo_list_init (&display->fonts);
+ display->closed = FALSE;
+
/* Xlib calls out to the extension close_display hooks in LIFO
* order. So we have to ensure that all extensions that we depend
* on in our close_display hook are properly initialized before we
@@ -240,23 +247,6 @@ _cairo_xlib_device_create (Display *dpy)
_cairo_xlib_display_select_compositor (display);
- codes = XAddExtension (dpy);
- if (unlikely (codes == NULL)) {
- device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
- free (display);
- goto UNLOCK;
- }
-
- _cairo_device_init (&display->base, &_cairo_xlib_device_backend);
-
- XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
-
- cairo_device_reference (&display->base); /* add one for the CloseDisplay */
- display->display = dpy;
- cairo_list_init (&display->screens);
- cairo_list_init (&display->fonts);
- display->closed = FALSE;
-
display->white = NULL;
memset (display->alpha, 0, sizeof (display->alpha));
memset (display->solid, 0, sizeof (display->solid));
@@ -325,7 +315,7 @@ _cairo_xlib_device_create (Display *dpy)
* safest to just blacklist all old-versioning-scheme X servers,
* (just using VendorRelease < 70000000), as buggy_repeat=TRUE.
*/
- if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
+ if (_cairo_xlib_vendor_is_xorg (dpy)) {
if (VendorRelease (dpy) >= 60700000) {
if (VendorRelease (dpy) < 70000000)
display->buggy_repeat = TRUE;
@@ -352,6 +342,16 @@ _cairo_xlib_device_create (Display *dpy)
display->buggy_pad_reflect = TRUE;
}
+ codes = XAddExtension (dpy);
+ if (unlikely (codes == NULL)) {
+ device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+ free (display);
+ goto UNLOCK;
+ }
+
+ XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display);
+ cairo_device_reference (&display->base); /* add one for the CloseDisplay */
+
display->next = _cairo_xlib_display_list;
_cairo_xlib_display_list = display;
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index d2bd588..4fd725f 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -50,6 +50,7 @@
#include "cairo-surface-private.h"
#include <pixman.h>
+#include <string.h>
typedef struct _cairo_xlib_display cairo_xlib_display_t;
typedef struct _cairo_xlib_shm_display cairo_xlib_shm_display_t;
@@ -170,6 +171,7 @@ struct _cairo_xlib_surface {
cairo_surface_t base;
Picture picture;
+ Drawable drawable;
const cairo_compositor_t *compositor;
cairo_surface_t *shm;
@@ -180,7 +182,6 @@ struct _cairo_xlib_surface {
cairo_list_t link;
Display *dpy; /* only valid between acquire/release */
- Drawable drawable;
cairo_bool_t owns_pixmap;
Visual *visual;
@@ -202,6 +203,7 @@ struct _cairo_xlib_surface {
cairo_surface_t base;
Picture picture;
+ Pixmap pixmap;
Display *dpy;
unsigned int filter:3;
@@ -216,6 +218,13 @@ struct _cairo_xlib_proxy {
cairo_surface_t *owner;
};
+inline static cairo_bool_t
+_cairo_xlib_vendor_is_xorg (Display *dpy)
+{
+ const char *const vendor = ServerVendor (dpy);
+ return strstr (vendor, "X.Org") || strstr (vendor, "Xorg");
+}
+
cairo_private cairo_status_t
_cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
cairo_xlib_surface_t *surface,
@@ -387,6 +396,17 @@ _cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst,
return dst->screen == src->screen;
}
+cairo_private cairo_int_status_t
+_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color,
+ cairo_boxes_t *boxes);
+
+cairo_private cairo_int_status_t
+_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst,
+ const cairo_color_t *color,
+ int num_rects,
+ cairo_rectangle_int_t *rects);
+
static inline void
_cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
cairo_xlib_surface_t *surface,
@@ -445,5 +465,4 @@ _cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface);
cairo_private pixman_format_code_t
_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface);
-
#endif /* CAIRO_XLIB_PRIVATE_H */
diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c
index e325382..013e2af 100644
--- a/src/cairo-xlib-render-compositor.c
+++ b/src/cairo-xlib-render-compositor.c
@@ -55,6 +55,17 @@
#include "cairo-tristrip-private.h"
static cairo_int_status_t
+check_composite (const cairo_composite_rectangles_t *extents)
+{
+ cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
+
+ if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
acquire (void *abstract_dst)
{
cairo_xlib_surface_t *dst = abstract_dst;
@@ -157,6 +168,7 @@ copy_image_boxes (void *_dst,
int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
+ _cairo_xlib_shm_surface_mark_active (&image->base);
XCopyArea (dst->dpy, src, dst->drawable, gc,
x1 + dx, y1 + dy,
x2 - x1, y2 - y1,
@@ -179,29 +191,26 @@ copy_image_boxes (void *_dst,
int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
- rects[j].x = x1;
- rects[j].y = y1;
- rects[j].width = x2 - x1;
- rects[j].height = y2 - y1;
- j++;
+ if (x2 > x1 && y2 > y1) {
+ rects[j].x = x1;
+ rects[j].y = y1;
+ rects[j].width = x2 - x1;
+ rects[j].height = y2 - y1;
+ j++;
+ }
}
}
- assert (j == boxes->num_boxes);
XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
-
+ _cairo_xlib_shm_surface_mark_active (&image->base);
XCopyArea (dst->dpy, src, dst->drawable, gc,
- dx, dy,
- image->width, image->height,
- 0, 0);
-
+ 0, 0, image->width, image->height, -dx, -dy);
XSetClipMask (dst->dpy, gc, None);
if (rects != stack_rects)
free (rects);
}
- _cairo_xlib_shm_surface_mark_active (&image->base);
_cairo_xlib_surface_put_gc (dst->display, dst, gc);
release (dst);
return CAIRO_STATUS_SUCCESS;
@@ -237,16 +246,20 @@ draw_image_boxes (void *_dst,
{
cairo_xlib_surface_t *dst = _dst;
struct _cairo_boxes_chunk *chunk;
- cairo_image_surface_t *shm;
+ cairo_image_surface_t *shm = NULL;
cairo_int_status_t status;
int i;
- if (image->base.device == dst->base.device &&
- image->depth == dst->depth &&
- _cairo_xlib_shm_surface_get_pixmap (&image->base))
+ if (image->base.device == dst->base.device) {
+ if (image->depth != dst->depth)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (_cairo_xlib_shm_surface_get_pixmap (&image->base))
return copy_image_boxes (dst, image, boxes, dx, dy);
- shm = NULL;
+ goto draw_image_boxes;
+ }
+
if (boxes_cover_surface (boxes, dst))
shm = (cairo_image_surface_t *) _cairo_xlib_surface_get_shm (dst, TRUE);
if (shm) {
@@ -337,11 +350,13 @@ draw_image_boxes (void *_dst,
if (_cairo_xlib_shm_surface_get_pixmap (&image->base)) {
status = copy_image_boxes (dst, image, boxes, dx, dy);
- goto out;
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ goto out;
}
}
}
+draw_image_boxes:
status = CAIRO_STATUS_SUCCESS;
for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
for (i = 0; i < chunk->count; i++) {
@@ -350,10 +365,10 @@ draw_image_boxes (void *_dst,
int y1 = _cairo_fixed_integer_part (b->p1.y);
int x2 = _cairo_fixed_integer_part (b->p2.x);
int y2 = _cairo_fixed_integer_part (b->p2.y);
- if ( _cairo_xlib_surface_draw_image (dst, image,
- x1 + dx, y1 + dy,
- x2 - x1, y2 - y1,
- x1, y1)) {
+ if (_cairo_xlib_surface_draw_image (dst, image,
+ x1 + dx, y1 + dy,
+ x2 - x1, y2 - y1,
+ x1, y1)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto out;
}
@@ -599,14 +614,23 @@ fill_rectangles (void *abstract_surface,
//X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable));
+ if (fill_reduces_to_source (op, color, dst))
+ op = CAIRO_OPERATOR_SOURCE;
+
+ if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (op == CAIRO_OPERATOR_SOURCE)
+ status = _cairo_xlib_core_fill_rectangles (dst, color, num_rects, rects);
+ return status;
+ }
+
render_color.red = color->red_short;
render_color.green = color->green_short;
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
- if (fill_reduces_to_source (op, color, dst))
- op = CAIRO_OPERATOR_SOURCE;
-
_cairo_xlib_surface_ensure_picture (dst);
if (num_rects == 1) {
/* Take advantage of the protocol compaction that libXrender performs
@@ -656,14 +680,23 @@ fill_boxes (void *abstract_surface,
cairo_xlib_surface_t *dst = abstract_surface;
XRenderColor render_color;
+ if (fill_reduces_to_source (op, color, dst))
+ op = CAIRO_OPERATOR_SOURCE;
+
+ if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+ cairo_int_status_t status;
+
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (op == CAIRO_OPERATOR_SOURCE)
+ status = _cairo_xlib_core_fill_boxes (dst, color, boxes);
+ return status;
+ }
+
render_color.red = color->red_short;
render_color.green = color->green_short;
render_color.blue = color->blue_short;
render_color.alpha = color->alpha_short;
- if (fill_reduces_to_source (op, color, dst))
- op = CAIRO_OPERATOR_SOURCE;
-
_cairo_xlib_surface_ensure_picture (dst);
if (boxes->num_boxes == 1) {
int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
@@ -1436,14 +1469,14 @@ _emit_glyphs_chunk (cairo_xlib_display_t *display,
*/
if (_start_new_glyph_elt (j, &glyphs[i])) {
if (j) {
- elts[nelt].nchars = n;
- nelt++;
- n = 0;
+ elts[nelt].nchars = n;
+ nelt++;
+ n = 0;
}
elts[nelt].chars = char8 + size * j;
elts[nelt].glyphset = info->glyphset;
- elts[nelt].xOff = glyphs[i].i.x - dst_x;
- elts[nelt].yOff = glyphs[i].i.y - dst_y;
+ elts[nelt].xOff = glyphs[i].i.x;
+ elts[nelt].yOff = glyphs[i].i.y;
}
switch (width) {
@@ -1491,6 +1524,8 @@ check_composite_glyphs (const cairo_composite_rectangles_t *extents,
cairo_xlib_display_t *display = dst->display;
int max_request_size, size;
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1544,7 +1579,7 @@ composite_glyphs (void *surface,
cairo_xlib_display_t *display = dst->display;
cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
cairo_scaled_glyph_t *glyph;
- cairo_fixed_t x = 0, y = 0;
+ cairo_fixed_t x = dst_x, y = dst_y;
cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info;
unsigned long max_index = 0;
@@ -1697,7 +1732,7 @@ _cairo_xlib_mask_compositor_get (void)
compositor.fill_rectangles = fill_rectangles;
compositor.fill_boxes = fill_boxes;
compositor.copy_boxes = copy_boxes;
- //compositor.check_composite = check_composite;
+ compositor.check_composite = check_composite;
compositor.composite = composite;
//compositor.check_composite_boxes = check_composite_boxes;
compositor.composite_boxes = composite_boxes;
@@ -1928,17 +1963,6 @@ composite_tristrip (void *abstract_dst,
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-check_composite (const cairo_composite_rectangles_t *extents)
-{
- cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display;
-
- if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
const cairo_compositor_t *
_cairo_xlib_traps_compositor_get (void)
{
diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index 42fc46a..56dff65 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -46,7 +46,7 @@
#include "cairo-xlib-surface-private.h"
#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
+#include "cairo-image-surface-inline.h"
#include "cairo-paginated-private.h"
#include "cairo-pattern-inline.h"
#include "cairo-recording-surface-private.h"
@@ -71,6 +71,8 @@ _cairo_xlib_source_finish (void *abstract_surface)
cairo_xlib_source_t *source = abstract_surface;
XRenderFreePicture (source->dpy, source->picture);
+ if (source->pixmap)
+ XFreePixmap (source->dpy, source->pixmap);
return CAIRO_STATUS_SUCCESS;
}
@@ -85,8 +87,10 @@ _cairo_xlib_proxy_finish (void *abstract_surface)
{
cairo_xlib_proxy_t *proxy = abstract_surface;
- XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
_cairo_xlib_shm_surface_mark_active (proxy->owner);
+ XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
+ if (proxy->source.pixmap)
+ XFreePixmap (proxy->source.dpy, proxy->source.pixmap);
cairo_surface_destroy (proxy->owner);
return CAIRO_STATUS_SUCCESS;
}
@@ -98,16 +102,18 @@ static const cairo_surface_backend_t cairo_xlib_proxy_backend = {
};
static cairo_surface_t *
-source (cairo_xlib_surface_t *dst, Picture picture)
+source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap)
{
cairo_xlib_source_t *source;
if (picture == None)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- source = malloc (sizeof (cairo_image_surface_t));
+ source = malloc (sizeof (*source));
if (unlikely (source == NULL)) {
XRenderFreePicture (dst->display->display, picture);
+ if (pixmap)
+ XFreePixmap (dst->display->display, pixmap);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
@@ -118,6 +124,7 @@ source (cairo_xlib_surface_t *dst, Picture picture)
/* The source exists only within an operation */
source->picture = picture;
+ source->pixmap = pixmap;
source->dpy = dst->display->display;
return &source->base;
@@ -433,22 +440,65 @@ gradient_source (cairo_xlib_surface_t *dst,
return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y);
}
- return source (dst, picture);
+ return source (dst, picture, None);
}
static cairo_surface_t *
color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color)
{
- XRenderColor xrender_color;
+ Display *dpy = dst->display->display;
+ XRenderColor xcolor;
+ Picture picture;
+ Pixmap pixmap = None;
+
+ xcolor.red = color->red_short;
+ xcolor.green = color->green_short;
+ xcolor.blue = color->blue_short;
+ xcolor.alpha = color->alpha_short;
- xrender_color.red = color->red_short;
- xrender_color.green = color->green_short;
- xrender_color.blue = color->blue_short;
- xrender_color.alpha = color->alpha_short;
+ if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) {
+ picture = XRenderCreateSolidFill (dpy, &xcolor);
+ } else {
+ XRenderPictureAttributes pa;
+ int mask = 0;
+
+ pa.repeat = RepeatNormal;
+ mask |= CPRepeat;
- return source (dst,
- XRenderCreateSolidFill (dst->display->display,
- &xrender_color));
+ pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32);
+ picture = XRenderCreatePicture (dpy, pixmap,
+ _cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32),
+ mask, &pa);
+
+ if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) {
+ XRectangle r = { 0, 0, 1, 1};
+ XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1);
+ } else {
+ XGCValues gcv;
+ GC gc;
+
+ gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen,
+ 32, pixmap);
+ if (unlikely (gc == NULL)) {
+ XFreePixmap (dpy, pixmap);
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+ }
+
+ gcv.foreground = 0;
+ gcv.foreground |= color->alpha_short >> 8 << 24;
+ gcv.foreground |= color->red_short >> 8 << 16;
+ gcv.foreground |= color->green_short >> 8 << 8;
+ gcv.foreground |= color->blue_short >> 8 << 0;
+ gcv.fill_style = FillSolid;
+
+ XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv);
+ XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1);
+
+ _cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc);
+ }
+ }
+
+ return source (dst, picture, pixmap);
}
static cairo_surface_t *
@@ -897,8 +947,7 @@ surface_source (cairo_xlib_surface_t *dst,
cairo_xlib_surface_t *xsrc;
cairo_surface_pattern_t local_pattern;
cairo_status_t status;
- cairo_rectangle_int_t upload, limit, map_extents;
- cairo_matrix_t m;
+ cairo_rectangle_int_t upload, limit;
src = pattern->surface;
if (src->type == CAIRO_SURFACE_TYPE_IMAGE &&
@@ -906,31 +955,27 @@ surface_source (cairo_xlib_surface_t *dst,
_cairo_xlib_shm_surface_get_pixmap (src)) {
cairo_xlib_proxy_t *proxy;
- cairo_surface_reference (src);
-
-prepare_shm_image:
proxy = malloc (sizeof(*proxy));
- if (unlikely (proxy == NULL)) {
- cairo_surface_destroy (src);
+ if (unlikely (proxy == NULL))
return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
- }
_cairo_surface_init (&proxy->source.base,
&cairo_xlib_proxy_backend,
dst->base.device,
- CAIRO_CONTENT_COLOR_ALPHA);
+ src->content);
proxy->source.dpy = dst->display->display;
proxy->source.picture = XRenderCreatePicture (proxy->source.dpy,
_cairo_xlib_shm_surface_get_pixmap (src),
_cairo_xlib_shm_surface_get_xrender_format (src),
0, NULL);
+ proxy->source.pixmap = None;
proxy->source.has_component_alpha = 0;
proxy->source.has_matrix = 0;
proxy->source.filter = CAIRO_FILTER_NEAREST;
proxy->source.extend = CAIRO_EXTEND_NONE;
- proxy->owner = src;
+ proxy->owner = cairo_surface_reference (src);
return embedded_source (dst, pattern, extents, src_x, src_y,
&proxy->source);
@@ -952,31 +997,54 @@ prepare_shm_image:
}
}
- src = _cairo_xlib_surface_create_similar_shm (&dst->base,
- _cairo_format_from_content (pattern->surface->content),
- upload.width,
- upload.height);
+ xsrc = (cairo_xlib_surface_t *)
+ _cairo_surface_create_similar_scratch (&dst->base,
+ src->content,
+ upload.width,
+ upload.height);
+ if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+ cairo_surface_destroy (src);
+ cairo_surface_destroy (&xsrc->base);
+ return None;
+ }
- _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
- cairo_matrix_init_translate (&local_pattern.base.matrix,
- upload.x, upload.y);
+ if (_cairo_surface_is_image (src)) {
+ status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
+ upload.x, upload.y,
+ upload.width, upload.height,
+ 0, 0);
+ } else {
+ cairo_image_surface_t *image;
+ cairo_rectangle_int_t map_extents = { 0,0, upload.width,upload.height };
- map_extents = upload;
- map_extents.x = map_extents.y = 0;
+ image = _cairo_surface_map_to_image (&xsrc->base, &map_extents);
- status = _cairo_surface_paint (src,
- CAIRO_OPERATOR_SOURCE,
- &local_pattern.base,
- NULL);
- _cairo_pattern_fini (&local_pattern.base);
+ _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
+ cairo_matrix_init_translate (&local_pattern.base.matrix,
+ upload.x, upload.y);
- if (unlikely (status)) {
- cairo_surface_destroy (src);
- return _cairo_surface_create_in_error (status);
+ status = _cairo_surface_paint (&image->base,
+ CAIRO_OPERATOR_SOURCE,
+ &local_pattern.base,
+ NULL);
+ _cairo_pattern_fini (&local_pattern.base);
+
+ status = _cairo_surface_unmap_image (&xsrc->base, image);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&xsrc->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ status = _cairo_xlib_surface_put_shm (xsrc);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&xsrc->base);
+ return _cairo_surface_create_in_error (status);
+ }
}
_cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base);
if (upload.x | upload.y) {
+ cairo_matrix_t m;
cairo_matrix_init_translate (&m, -upload.x, -upload.y);
cairo_matrix_multiply (&local_pattern.base.matrix,
&local_pattern.base.matrix,
@@ -984,29 +1052,6 @@ prepare_shm_image:
}
*src_x = *src_y = 0;
- if (src->device == dst->base.device &&
- _cairo_xlib_shm_surface_get_pixmap (src)) {
- pattern = &local_pattern;
- goto prepare_shm_image;
- }
-
- xsrc = (cairo_xlib_surface_t *)
- _cairo_surface_create_similar_scratch (&dst->base,
- src->content,
- upload.width,
- upload.height);
- if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
- cairo_surface_destroy (src);
- cairo_surface_destroy (&xsrc->base);
- return None;
- }
-
- status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
- 0, 0,
- upload.width, upload.height,
- 0, 0);
- cairo_surface_destroy (src);
-
_cairo_xlib_surface_ensure_picture (xsrc);
if (! picture_set_properties (xsrc->display,
xsrc->picture,
diff --git a/src/cairo-xlib-surface-shm.c b/src/cairo-xlib-surface-shm.c
index 08169f2..fa7d3eb 100644
--- a/src/cairo-xlib-surface-shm.c
+++ b/src/cairo-xlib-surface-shm.c
@@ -41,17 +41,114 @@
#include "cairo-xlib-private.h"
#include "cairo-xlib-surface-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-mempool-private.h"
+
+#if !HAVE_X11_EXTENSIONS_XSHM_H || !(HAVE_X11_EXTENSIONS_SHMPROTO_H || HAVE_X11_EXTENSIONS_SHMSTR_H)
+void _cairo_xlib_display_init_shm (cairo_xlib_display_t *display) {}
+
+cairo_surface_t *
+_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface,
+ cairo_bool_t overwrite)
+{
+ return NULL;
+}
+
+cairo_int_status_t
+_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
+{
+ assert (!surface->fallback);
+ return CAIRO_INT_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
+ pixman_format_code_t format,
+ int width, int height)
+{
+ return NULL;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
+ pixman_format_code_t format,
+ int width, int height)
+{
+ return NULL;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_similar_shm (void *other,
+ cairo_format_t format,
+ int width, int height)
+{
+ return cairo_image_surface_create (format, width, height);
+}
+
+void
+_cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
+{
+ ASSERT_NOT_REACHED;
+}
+
+void
+_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
+ XImage *ximage)
+{
+ ASSERT_NOT_REACHED;
+}
+
+void *
+_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return NULL;
+}
+
+Pixmap
+_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return 0;
+}
+
+XRenderPictFormat *
+_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return NULL;
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return FALSE;
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
+{
+ ASSERT_NOT_REACHED;
+ return TRUE;
+}
+
+void _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display) {}
+
+#else
#include "cairo-damage-private.h"
#include "cairo-default-context-private.h"
+#include "cairo-image-surface-private.h"
#include "cairo-list-inline.h"
+#include "cairo-mempool-private.h"
#include <X11/Xlibint.h>
#include <X11/Xproto.h>
#include <X11/extensions/XShm.h>
+#if HAVE_X11_EXTENSIONS_SHMPROTO_H
#include <X11/extensions/shmproto.h>
+#elif HAVE_X11_EXTENSIONS_SHMSTR_H
+#include <X11/extensions/shmstr.h>
+#endif
#include <sys/ipc.h>
#include <sys/shm.h>
@@ -109,6 +206,8 @@ struct _cairo_xlib_shm_display {
int event;
Window window;
+ unsigned long last_request;
+ unsigned long last_event;
cairo_list_t surfaces;
@@ -119,9 +218,21 @@ struct _cairo_xlib_shm_display {
static inline cairo_bool_t
seqno_passed (unsigned long a, unsigned long b)
{
+ return (long)(b - a) >= 0;
+}
+
+static inline cairo_bool_t
+seqno_before (unsigned long a, unsigned long b)
+{
return (long)(b - a) > 0;
}
+static inline cairo_bool_t
+seqno_after (unsigned long a, unsigned long b)
+{
+ return (long)(a - b) > 0;
+}
+
static inline cairo_status_t
_pqueue_init (struct pqueue *pq)
{
@@ -305,11 +416,6 @@ peek_processed (cairo_device_t *device)
return LastKnownRequestProcessed (peek_display(device));
}
-static unsigned next_request (cairo_device_t *device)
-{
- return NextRequest (peek_display (device));
-}
-
static void
_cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
cairo_xlib_shm_t *pool)
@@ -324,6 +430,43 @@ _cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
free (pool);
}
+static void send_event(cairo_xlib_display_t *display,
+ cairo_xlib_shm_info_t *info,
+ unsigned long seqno)
+{
+ XShmCompletionEvent ev;
+
+ if (! seqno_after (seqno, display->shm->last_event))
+ return;
+
+ ev.type = display->shm->event;
+ ev.send_event = 1; /* XXX or lie? */
+ ev.serial = NextRequest (display->display);
+ ev.drawable = display->shm->window;
+ ev.major_code = display->shm->opcode;
+ ev.minor_code = X_ShmPutImage;
+ ev.shmseg = info->pool->shm.shmid;
+ ev.offset = (char *)info->mem - (char *)info->pool->shm.shmaddr;
+
+ XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev);
+
+ display->shm->last_event = ev.serial;
+}
+
+static void sync (cairo_xlib_display_t *display)
+{
+ cairo_xlib_shm_info_t *info;
+ struct pqueue *pq = &display->shm->info;
+
+ XSync (display->display, False);
+
+ while ((info = PQ_TOP(pq))) {
+ _cairo_mempool_free (&info->pool->mem, info->mem);
+ _pqueue_pop (&display->shm->info);
+ free (info);
+ }
+}
+
static void
_cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
{
@@ -340,8 +483,10 @@ _cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
info = PQ_TOP(pq);
do {
- if (! seqno_passed (info->last_request, processed))
- break;
+ if (! seqno_passed (info->last_request, processed)) {
+ send_event (display, info, display->shm->last_request);
+ return;
+ }
_cairo_mempool_free (&info->pool->mem, info->mem);
_pqueue_pop (&display->shm->info);
@@ -349,9 +494,9 @@ _cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
} while ((info = PQ_TOP(pq)));
}
-static cairo_xlib_shm_info_t *
-_cairo_xlib_shm_info_find (cairo_xlib_display_t *display,
- size_t size, unsigned long *last_request)
+static cairo_xlib_shm_t *
+_cairo_xlib_shm_info_find (cairo_xlib_display_t *display, size_t size,
+ void **ptr, unsigned long *last_request)
{
cairo_xlib_shm_info_t *info;
struct pqueue *pq = &display->shm->info;
@@ -361,14 +506,21 @@ _cairo_xlib_shm_info_find (cairo_xlib_display_t *display,
info = PQ_TOP(pq);
do {
- _pqueue_pop (&display->shm->info);
-
- if (info->size >= size && size <= 2*info->size)
- return info;
+ cairo_xlib_shm_t *pool = info->pool;
*last_request = info->last_request;
- _cairo_mempool_free (&info->pool->mem, info->mem);
+
+ _pqueue_pop (&display->shm->info);
+ _cairo_mempool_free (&pool->mem, info->mem);
free (info);
+
+ if (pool->mem.free_bytes >= size) {
+ void *mem = _cairo_mempool_alloc (&pool->mem, size);
+ if (mem != NULL) {
+ *ptr = mem;
+ return pool;
+ }
+ }
} while ((info = PQ_TOP(pq)));
return NULL;
@@ -449,6 +601,9 @@ _cairo_xlib_shm_pool_create(cairo_xlib_display_t *display,
pool->attached = NextRequest (dpy);
success = XShmAttach (dpy, &pool->shm);
+#if !IPC_RMID_DEFERRED_RELEASE
+ XSync (dpy, FALSE);
+#endif
shmctl (pool->shm.shmid, IPC_RMID, NULL);
if (! success)
@@ -482,15 +637,12 @@ _cairo_xlib_shm_info_create (cairo_xlib_display_t *display,
unsigned long last_request = 0;
void *mem = NULL;
- if (will_sync) {
- info = _cairo_xlib_shm_info_find (display, size, &last_request);
- if (info)
- return info;
- }
-
_cairo_xlib_shm_info_cleanup (display);
pool = _cairo_xlib_shm_pool_find (display, size, &mem);
_cairo_xlib_shm_pool_cleanup (display);
+
+ if (pool == NULL && will_sync)
+ pool = _cairo_xlib_shm_info_find (display, size, &mem, &last_request);
if (pool == NULL)
pool = _cairo_xlib_shm_pool_create (display, size, &mem);
if (pool == NULL)
@@ -517,6 +669,7 @@ _cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags)
{
cairo_xlib_shm_surface_t *shm = abstract_surface;
cairo_xlib_display_t *display;
+ Display *dpy;
cairo_status_t status;
if (shm->active == 0)
@@ -534,10 +687,15 @@ _cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags)
if (unlikely (status))
return status;
- XEventsQueued (display->display, QueuedAfterReading);
- if (!seqno_passed (shm->active,
- LastKnownRequestProcessed (display->display)))
- XSync (display->display, False);
+ send_event (display, shm->info, shm->active);
+
+ dpy = display->display;
+ XEventsQueued (dpy, QueuedAfterReading);
+ while (! seqno_passed (shm->active, LastKnownRequestProcessed (dpy))) {
+ LockDisplay(dpy);
+ _XReadEvents(dpy);
+ UnlockDisplay(dpy);
+ }
cairo_device_release (&display->base);
shm->active = 0;
@@ -549,7 +707,7 @@ static inline cairo_bool_t
active (cairo_xlib_shm_surface_t *shm, Display *dpy)
{
return (shm->active &&
- !seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
+ ! seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
}
static cairo_status_t
@@ -559,6 +717,11 @@ _cairo_xlib_shm_surface_finish (void *abstract_surface)
cairo_xlib_display_t *display;
cairo_status_t status;
+ if (shm->image.base.damage) {
+ _cairo_damage_destroy (shm->image.base.damage);
+ shm->image.base.damage = _cairo_damage_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
+ }
+
status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
if (unlikely (status))
return status;
@@ -569,6 +732,8 @@ _cairo_xlib_shm_surface_finish (void *abstract_surface)
if (active (shm, display->display)) {
shm->info->last_request = shm->active;
_pqueue_push (&display->shm->info, shm->info);
+ if (seqno_before (display->shm->last_request, shm->active))
+ display->shm->last_request = shm->active;
} else {
_cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
free (shm->info);
@@ -579,7 +744,7 @@ _cairo_xlib_shm_surface_finish (void *abstract_surface)
cairo_list_del (&shm->link);
cairo_device_release (&display->base);
- return CAIRO_STATUS_SUCCESS;
+ return _cairo_image_surface_finish (abstract_surface);
}
static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = {
@@ -720,6 +885,13 @@ _cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
if (_cairo_xlib_surface_get_gc (display, surface, &gc))
goto cleanup_display;
+ if (! surface->owns_pixmap) {
+ XGCValues gcv;
+
+ gcv.subwindow_mode = IncludeInferiors;
+ XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
+ }
+
if (damage->region) {
XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
XRectangle *rects = stack_rects;
@@ -770,7 +942,14 @@ _cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
0, 0);
}
- XSync (display->display, False);
+ if (! surface->owns_pixmap) {
+ XGCValues gcv;
+
+ gcv.subwindow_mode = ClipByChildren;
+ XChangeGC (display->display, gc, GCSubwindowMode, &gcv);
+ }
+
+ sync (display);
shm->active = 0;
shm->idle--;
@@ -899,10 +1078,6 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
damage = _cairo_damage_reduce (shm->image.base.damage);
shm->image.base.damage = _cairo_damage_create ();
- status = _cairo_xlib_surface_get_gc (display, surface, &gc);
- if (unlikely (status))
- goto out;
-
TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
damage->region ? cairo_region_num_rectangles (damage->region) : 0));
if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) {
@@ -912,9 +1087,16 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
int n_rects, i;
n_rects = cairo_region_num_rectangles (damage->region);
- if (n_rects == 0) {
- } else if (n_rects == 1) {
+ if (n_rects == 0)
+ goto out;
+
+ status = _cairo_xlib_surface_get_gc (display, surface, &gc);
+ if (unlikely (status))
+ goto out;
+
+ if (n_rects == 1) {
cairo_region_get_rectangle (damage->region, 0, &r);
+ _cairo_xlib_shm_surface_mark_active (surface->shm);
XCopyArea (display->display,
shm->pixmap, surface->drawable, gc,
r.x, r.y,
@@ -925,6 +1107,7 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
if (unlikely (rects == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ _cairo_xlib_surface_put_gc (display, surface, gc);
goto out;
}
}
@@ -938,6 +1121,7 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
}
XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
+ _cairo_xlib_shm_surface_mark_active (surface->shm);
XCopyArea (display->display,
shm->pixmap, surface->drawable, gc,
0, 0,
@@ -947,12 +1131,12 @@ _cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
XSetClipMask (display->display, gc, None);
}
+
+ _cairo_xlib_surface_put_gc (display, surface, gc);
}
- _cairo_damage_destroy (damage);
- _cairo_xlib_shm_surface_mark_active (surface->shm);
- _cairo_xlib_surface_put_gc (display, surface, gc);
out:
+ _cairo_damage_destroy (damage);
cairo_device_release (&display->base);
}
@@ -968,9 +1152,8 @@ _cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other,
surface = NULL;
if (has_shm (other))
- surface = &_cairo_xlib_shm_surface_create (other, format,
- width, height, FALSE,
- has_shm_pixmaps (other))->image.base;
+ surface = &_cairo_xlib_shm_surface_create (other, format, width, height,
+ FALSE, has_shm_pixmaps (other))->image.base;
return surface;
}
@@ -983,9 +1166,8 @@ _cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface,
if (! has_shm(surface))
return NULL;
- return &_cairo_xlib_shm_surface_create (surface, format,
- surface->width, surface->height,
- TRUE, 0)->image.base;
+ return &_cairo_xlib_shm_surface_create (surface, format, width, height,
+ FALSE, 0)->image.base;
}
cairo_surface_t *
@@ -1016,17 +1198,8 @@ _cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm)
{
cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) _shm;
cairo_xlib_display_t *display = (cairo_xlib_display_t *) _shm->device;
- XShmCompletionEvent ev;
-
- ev.type = display->shm->event;
- ev.drawable = display->shm->window;
- ev.major_code = display->shm->opcode;
- ev.minor_code = X_ShmPutImage;
- ev.shmseg = shm->info->pool->shm.shmid;
- ev.offset = (char *)shm->info->mem - (char *)shm->info->pool->shm.shmaddr;
shm->active = NextRequest (display->display);
- XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev);
}
void
@@ -1065,10 +1238,10 @@ _cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
void *
_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
{
- cairo_xlib_shm_surface_t *shm;
+ cairo_xlib_display_t *display = (cairo_xlib_display_t *) surface->device;
+ cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
- shm = (cairo_xlib_shm_surface_t *) surface;
- shm->active = next_request (surface->device);
+ display->shm->last_event = shm->active = NextRequest (display->display);
return &shm->info->pool->shm;
}
@@ -1121,6 +1294,85 @@ _cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
return shm->idle > 0;
}
+#define XORG_VERSION_ENCODE(major,minor,patch,snap) \
+ (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap)
+
+static cairo_bool_t
+has_broken_send_shm_event (cairo_xlib_display_t *display,
+ cairo_xlib_shm_display_t *shm)
+{
+ Display *dpy = display->display;
+ int (*old_handler) (Display *display, XErrorEvent *event);
+ XShmCompletionEvent ev;
+ XShmSegmentInfo info;
+
+ info.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
+ if (info.shmid == -1)
+ return TRUE;
+
+ info.readOnly = FALSE;
+ info.shmaddr = shmat (info.shmid, NULL, 0);
+ if (info.shmaddr == (char *) -1) {
+ shmctl (info.shmid, IPC_RMID, NULL);
+ return TRUE;
+ }
+
+ ev.type = shm->event;
+ ev.send_event = 1;
+ ev.serial = 1;
+ ev.drawable = shm->window;
+ ev.major_code = shm->opcode;
+ ev.minor_code = X_ShmPutImage;
+
+ ev.shmseg = info.shmid;
+ ev.offset = 0;
+
+ assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex));
+ _x_error_occurred = FALSE;
+
+ XLockDisplay (dpy);
+ XSync (dpy, False);
+ old_handler = XSetErrorHandler (_check_error_handler);
+
+ XShmAttach (dpy, &info);
+ XSendEvent (dpy, ev.drawable, False, 0, (XEvent *)&ev);
+ XShmDetach (dpy, &info);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XUnlockDisplay (dpy);
+
+ shmctl (info.shmid, IPC_RMID, NULL);
+ shmdt (info.shmaddr);
+
+ return _x_error_occurred;
+}
+
+static cairo_bool_t
+xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t *display,
+ cairo_xlib_shm_display_t *shm)
+{
+ Display *dpy = display->display;
+
+ /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent,
+ * the Xserver may crash if it does not take care when processing
+ * the event type. For instance versions of Xorg prior to 1.11.1
+ * exhibited this bug, and was fixed by:
+ *
+ * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39
+ * Author: Sam Spilsbury <sam.spilsbury@canonical.com>
+ * Date: Wed Sep 14 09:58:34 2011 +0800
+ *
+ * Remove the SendEvent bit (0x80) before doing range checks on event type.
+ */
+ if (_cairo_xlib_vendor_is_xorg (dpy) &&
+ VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1))
+ return TRUE;
+
+ /* For everyone else check that no error is generated */
+ return has_broken_send_shm_event (display, shm);
+}
+
void
_cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
{
@@ -1138,6 +1390,15 @@ _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
if (unlikely (shm == NULL))
return;
+ codes = XInitExtension (display->display, SHMNAME);
+ if (codes == NULL) {
+ free (shm);
+ return;
+ }
+
+ shm->opcode = codes ->major_opcode;
+ shm->event = codes->first_event;
+
if (unlikely (_pqueue_init (&shm->info))) {
free (shm);
return;
@@ -1152,14 +1413,15 @@ _cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
InputOutput,
DefaultVisual (display->display, scr),
CWOverrideRedirect, &attr);
+ shm->last_event = 0;
+ shm->last_request = 0;
+
+ if (xorg_has_buggy_send_shm_completion_event(display, shm))
+ has_pixmap = 0;
shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
cairo_list_init (&shm->pool);
- codes = XInitExtension (display->display, SHMNAME);
- shm->opcode = codes ->major_opcode;
- shm->event = codes->first_event;
-
cairo_list_init (&shm->surfaces);
display->shm = shm;
@@ -1193,5 +1455,5 @@ _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display)
free (shm);
display->shm = NULL;
}
-
+#endif
#endif
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index e9e647a..96ba3ad 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1090,9 +1090,10 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
XImage ximage;
cairo_format_masks_t image_masks;
int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
+ cairo_surface_t *shm_image = NULL;
pixman_image_t *pixman_image = NULL;
cairo_status_t status;
- cairo_bool_t own_data;
+ cairo_bool_t own_data = FALSE;
cairo_bool_t is_rgb_image;
GC gc;
@@ -1127,9 +1128,39 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
ximage.bits_per_pixel = image_masks.bpp;
ximage.bytes_per_line = image->stride;
ximage.data = (char *)image->data;
- if (image->base.device == surface->base.device)
+ if (image->base.device != surface->base.device) {
+ /* If PutImage will break the image up into chunks, prefer to
+ * send it all in one pass with ShmPutImage. For larger images,
+ * it is further advantageous to reduce the number of copies,
+ * albeit at the expense of more SHM bookkeeping.
+ */
+ int max_request_size = XExtendedMaxRequestSize (display->display);
+ if (max_request_size == 0)
+ max_request_size = XMaxRequestSize (display->display);
+ if (max_request_size > 8192)
+ max_request_size = 8192;
+ if (width * height * 4 > max_request_size) {
+ shm_image = _cairo_xlib_surface_create_shm__image (surface,
+ image->pixman_format,
+ width, height);
+ if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
+ cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image, NULL, clone->pixman_image,
+ src_x, src_y,
+ 0, 0,
+ 0, 0,
+ width, height);
+ ximage.obdata = _cairo_xlib_shm_surface_get_obdata (shm_image);
+ ximage.data = (char *)clone->data;
+ ximage.bytes_per_line = clone->stride;
+ ximage.width = width;
+ ximage.height = height;
+ src_x = src_y = 0;
+ }
+ }
+ } else
ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&image->base);
- own_data = FALSE;
ret = XInitImage (&ximage);
assert (ret != 0);
@@ -1147,29 +1178,48 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
ret = _pixman_format_from_masks (&image_masks, &intermediate_format);
assert (ret);
- own_data = FALSE;
-
- pixman_image = pixman_image_create_bits (intermediate_format,
- width, height, NULL, 0);
- if (pixman_image == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL;
- }
+ shm_image = _cairo_xlib_surface_create_shm__image (surface,
+ intermediate_format,
+ width, height);
+ if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) {
+ cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image;
+
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image,
+ NULL,
+ clone->pixman_image,
+ src_x, src_y,
+ 0, 0,
+ 0, 0,
+ width, height);
+
+ ximage.data = (char *) clone->data;
+ ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&clone->base);
+ ximage.bytes_per_line = clone->stride;
+ } else {
+ pixman_image = pixman_image_create_bits (intermediate_format,
+ width, height, NULL, 0);
+ if (pixman_image == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
- pixman_image_composite32 (PIXMAN_OP_SRC,
- image->pixman_image,
- NULL,
- pixman_image,
- src_x, src_y,
- 0, 0,
- 0, 0,
- width, height);
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ image->pixman_image,
+ NULL,
+ pixman_image,
+ src_x, src_y,
+ 0, 0,
+ 0, 0,
+ width, height);
+
+ ximage.data = (char *) pixman_image_get_data (pixman_image);
+ ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
+ }
ximage.width = width;
ximage.height = height;
ximage.bits_per_pixel = image_masks.bpp;
- ximage.data = (char *) pixman_image_get_data (pixman_image);
- ximage.bytes_per_line = pixman_image_get_stride (pixman_image);
ret = XInitImage (&ximage);
assert (ret != 0);
@@ -1195,7 +1245,6 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
ximage.bytes_per_line = stride;
ximage.data = _cairo_malloc_ab (stride, ximage.height);
if (unlikely (ximage.data == NULL)) {
- own_data = FALSE;
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
@@ -1296,7 +1345,7 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
if (ximage.obdata)
XShmPutImage (display->display, surface->drawable, gc, &ximage,
- src_x, src_y, dst_x, dst_y, width, height, TRUE);
+ src_x, src_y, dst_x, dst_y, width, height, True);
else
XPutImage (display->display, surface->drawable, gc, &ximage,
src_x, src_y, dst_x, dst_y, width, height);
@@ -1308,6 +1357,8 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface,
if (own_data)
free (ximage.data);
+ if (shm_image)
+ cairo_surface_destroy (shm_image);
if (pixman_image)
pixman_image_unref (pixman_image);
diff --git a/src/cairoint.h b/src/cairoint.h
index 7463595..861e2f7 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -337,7 +337,7 @@ _cairo_rectangle_union (cairo_rectangle_int_t *dst,
const cairo_rectangle_int_t *src);
cairo_private cairo_bool_t
-_cairo_box_intersects_line_segment (cairo_box_t *box,
+_cairo_box_intersects_line_segment (const cairo_box_t *box,
cairo_line_t *line) cairo_pure;
cairo_private cairo_bool_t
@@ -1086,6 +1086,14 @@ _cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path,
double tolerance,
cairo_traps_t *traps);
+cairo_private cairo_int_status_t
+_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_traps_t *traps);
+
cairo_private cairo_status_t
_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path,
const cairo_stroke_style_t *stroke_style,
@@ -1232,6 +1240,17 @@ _cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style,
const cairo_path_fixed_t *path,
const cairo_matrix_t *ctm,
double *dx, double *dy);
+cairo_private void
+_cairo_stroke_style_max_line_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm,
+ double *dx, double *dy);
+
+cairo_private void
+_cairo_stroke_style_max_join_distance_from_path (const cairo_stroke_style_t *style,
+ const cairo_path_fixed_t *path,
+ const cairo_matrix_t *ctm,
+ double *dx, double *dy);
cairo_private double
_cairo_stroke_style_dash_period (const cairo_stroke_style_t *style);
@@ -1897,6 +1916,7 @@ slim_hidden_proto (cairo_pattern_set_matrix);
slim_hidden_proto (cairo_pop_group);
slim_hidden_proto (cairo_push_group_with_content);
slim_hidden_proto_no_warn (cairo_path_destroy);
+slim_hidden_proto (cairo_recording_surface_create);
slim_hidden_proto (cairo_rel_line_to);
slim_hidden_proto (cairo_restore);
slim_hidden_proto (cairo_save);
@@ -2032,7 +2052,7 @@ cairo_private void
_cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip);
#if 0
-#define TRACE(x) fprintf x
+#define TRACE(x) fprintf (stderr, "%s: ", __FILE__), fprintf x
#define TRACE_(x) x
#else
#define TRACE(x)
diff --git a/src/test-base-compositor-surface.c b/src/test-base-compositor-surface.c
index f8fa517..ff84b10 100644
--- a/src/test-base-compositor-surface.c
+++ b/src/test-base-compositor-surface.c
@@ -662,10 +662,10 @@ base_compositor_stroke (const cairo_compositor_t *_compositor,
info.antialias = antialias;
_cairo_traps_init_with_clip (&info.traps, extents->clip);
- status = _cairo_path_fixed_stroke_to_traps (path, style,
- ctm, ctm_inverse,
- tolerance,
- &info.traps);
+ status = _cairo_path_fixed_stroke_polygon_to_traps (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &info.traps);
if (likely (status == CAIRO_INT_STATUS_SUCCESS))
status = trim_extents_to_traps (extents, &info.traps);
if (likely (status == CAIRO_INT_STATUS_SUCCESS))
diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index b3ee573..741e49e 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -106,9 +106,9 @@ static cairo_bool_t is_win98 (void)
os.dwOSVersionInfoSize = sizeof (os);
GetVersionEx (&os);
- return (VER_PLATFORM_WIN32_WINDOWS != os.dwPlatformId &&
- os.dwMajorVersion != 4 &&
- os.dwMinorVersion != 10);
+ return (VER_PLATFORM_WIN32_WINDOWS == os.dwPlatformId &&
+ os.dwMajorVersion == 4 &&
+ os.dwMinorVersion == 10);
}
static void *
diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c
index 2c5374c..ccd285d 100644
--- a/src/win32/cairo-win32-display-surface.c
+++ b/src/win32/cairo-win32-display-surface.c
@@ -392,6 +392,7 @@ _cairo_win32_display_surface_create_similar_image (void *abstract_other,
int height)
{
cairo_win32_display_surface_t *surface = abstract_other;
+ cairo_image_surface_t *image;
surface = (cairo_win32_display_surface_t *)
_cairo_win32_display_surface_create_for_dc (surface->win32.dc,
@@ -399,7 +400,14 @@ _cairo_win32_display_surface_create_similar_image (void *abstract_other,
if (surface->win32.base.status)
return &surface->win32.base;
- return surface->image;
+ /* And clear in order to comply with our user API semantics */
+ image = (cairo_image_surface_t *) surface->image;
+ if (! image->base.is_clear) {
+ memset (image->data, 0, image->stride * height);
+ image->base.is_clear = TRUE;
+ }
+
+ return &image->base;
}
static cairo_status_t
@@ -497,6 +505,7 @@ _cairo_win32_display_surface_unmap_image (void *abstract_surf
__FUNCTION__, r.x, r.y, r.width, r.height));
surface->fallback->damage =
_cairo_damage_add_rectangle (surface->fallback->damage, &r);
+ surface = to_win32_display_surface (surface->fallback);
}
return _cairo_surface_unmap_image (surface->image, image);