summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-08-12 19:10:04 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-08-12 19:10:04 +0100
commit95b7f4fe3a5deea6766538d843c75626e4bb68cf (patch)
treefddfa0863d53deb39a28e1972b499cf47c70eabc
parent16426dab486767cb16dfaf5158c5d4b3317546b0 (diff)
image: Temporarily resurrect the old non-pixman glyph compositor
As the easiest approach to making another snapshot that only depends upon a stable pixman, make the new dependency a compile time option. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--configure.ac7
-rw-r--r--src/cairo-image-compositor.c285
2 files changed, 291 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index a721cdfe..0067bfc9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -619,7 +619,7 @@ CAIRO_ENABLE(test_surfaces, test surfaces, no)
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [
- pixman_REQUIRES="pixman-1 >= 0.27.1"
+ pixman_REQUIRES="pixman-1 >= 0.26.0"
PKG_CHECK_MODULES(pixman, $pixman_REQUIRES, , [AC_MSG_RESULT(no)
use_image="no (requires $pixman_REQUIRES http://cairographics.org/releases/)"])
image_REQUIRES=$pixman_REQUIRES
@@ -627,6 +627,11 @@ CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [
image_LIBS=$pixman_LIBS
])
+if pkg-config --exists 'pixman-1 >= 0.27.1'; then
+ AC_DEFINE([HAS_PIXMAN_GLYPHS], 1, [Enable pixman glyph cache])
+fi
+
+
dnl ===========================================================================
CAIRO_ENABLE_SURFACE_BACKEND(mime, mime, always)
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index 14e982de..1ec98386 100644
--- a/src/cairo-image-compositor.c
+++ b/src/cairo-image-compositor.c
@@ -785,6 +785,7 @@ check_composite_glyphs (const cairo_composite_rectangles_t *extents,
return CAIRO_STATUS_SUCCESS;
}
+#if HAS_PIXMAN_GLYPHS
static cairo_int_status_t
composite_glyphs (void *_dst,
cairo_operator_t op,
@@ -894,6 +895,290 @@ out_unlock:
CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex);
return status;
}
+#else
+static cairo_int_status_t
+composite_one_glyph (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info)
+{
+ cairo_image_surface_t *glyph_surface;
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_status_t status;
+ int x, y;
+
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
+ status = _cairo_scaled_glyph_lookup (info->font,
+ info->glyphs[0].index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+
+ if (unlikely (status))
+ return status;
+
+ glyph_surface = scaled_glyph->surface;
+ if (glyph_surface->width == 0 || glyph_surface->height == 0)
+ return CAIRO_INT_STATUS_NOTHING_TO_DO;
+
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (info->glyphs[0].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (info->glyphs[0].y -
+ glyph_surface->base.device_transform.y0);
+
+ pixman_image_composite32 (_pixman_operator (op),
+ ((cairo_image_source_t *)_src)->pixman_image,
+ glyph_surface->pixman_image,
+ to_pixman_image (_dst),
+ x + src_x, y + src_y,
+ 0, 0,
+ x - dst_x, y - dst_y,
+ glyph_surface->width,
+ glyph_surface->height);
+
+ return CAIRO_INT_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_glyphs_via_mask (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info)
+{
+ cairo_scaled_glyph_t *glyph_cache[64];
+ pixman_image_t *white = _pixman_image_for_color (CAIRO_COLOR_WHITE);
+ cairo_scaled_glyph_t *scaled_glyph;
+ uint8_t buf[2048];
+ pixman_image_t *mask;
+ pixman_format_code_t format;
+ cairo_status_t status;
+ int i;
+
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
+ if (unlikely (white == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit
+ * optimised paths through pixman. Should we increase the bit
+ * depth of the target surface, we should reconsider the appropriate
+ * mask formats.
+ */
+
+ status = _cairo_scaled_glyph_lookup (info->font,
+ info->glyphs[0].index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+ if (unlikely (status)) {
+ pixman_image_unref (white);
+ return status;
+ }
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+ glyph_cache[info->glyphs[0].index % ARRAY_LENGTH (glyph_cache)] = scaled_glyph;
+
+ format = PIXMAN_a8;
+ i = (info->extents.width + 3) & ~3;
+ if (scaled_glyph->surface->base.content & CAIRO_CONTENT_COLOR) {
+ format = PIXMAN_a8r8g8b8;
+ i = info->extents.width * 4;
+ }
+
+ if (i * info->extents.height > (int) sizeof (buf)) {
+ mask = pixman_image_create_bits (format,
+ info->extents.width,
+ info->extents.height,
+ NULL, 0);
+ } else {
+ memset (buf, 0, i * info->extents.height);
+ mask = pixman_image_create_bits (format,
+ info->extents.width,
+ info->extents.height,
+ (uint32_t *)buf, i);
+ }
+ if (unlikely (mask == NULL)) {
+ pixman_image_unref (white);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ status = CAIRO_STATUS_SUCCESS;
+ for (i = 0; i < info->num_glyphs; i++) {
+ unsigned long glyph_index = info->glyphs[i].index;
+ int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+ cairo_image_surface_t *glyph_surface;
+ int x, y;
+
+ scaled_glyph = glyph_cache[cache_index];
+ if (scaled_glyph == NULL ||
+ _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+ {
+ status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+
+ if (unlikely (status)) {
+ pixman_image_unref (mask);
+ pixman_image_unref (white);
+ return status;
+ }
+
+ glyph_cache[cache_index] = scaled_glyph;
+ }
+
+ glyph_surface = scaled_glyph->surface;
+ if (glyph_surface->width && glyph_surface->height) {
+ if (glyph_surface->base.content & CAIRO_CONTENT_COLOR &&
+ format == PIXMAN_a8) {
+ pixman_image_t *ca_mask;
+
+ format = PIXMAN_a8r8g8b8;
+ ca_mask = pixman_image_create_bits (format,
+ info->extents.width,
+ info->extents.height,
+ NULL, 0);
+ if (unlikely (ca_mask == NULL)) {
+ pixman_image_unref (mask);
+ pixman_image_unref (white);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ pixman_image_composite32 (PIXMAN_OP_SRC,
+ white, mask, ca_mask,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ info->extents.width,
+ info->extents.height);
+ pixman_image_unref (mask);
+ mask = ca_mask;
+ }
+
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (info->glyphs[i].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (info->glyphs[i].y -
+ glyph_surface->base.device_transform.y0);
+
+ if (glyph_surface->pixman_format == format) {
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ glyph_surface->pixman_image, NULL, mask,
+ 0, 0,
+ 0, 0,
+ x - info->extents.x, y - info->extents.y,
+ glyph_surface->width,
+ glyph_surface->height);
+ } else {
+ pixman_image_composite32 (PIXMAN_OP_ADD,
+ white, glyph_surface->pixman_image, mask,
+ 0, 0,
+ 0, 0,
+ x - info->extents.x, y - info->extents.y,
+ glyph_surface->width,
+ glyph_surface->height);
+ }
+ }
+ }
+
+ if (format == PIXMAN_a8r8g8b8)
+ pixman_image_set_component_alpha (mask, TRUE);
+
+ pixman_image_composite32 (_pixman_operator (op),
+ ((cairo_image_source_t *)_src)->pixman_image,
+ mask,
+ to_pixman_image (_dst),
+ info->extents.x + src_x, info->extents.y + src_y,
+ 0, 0,
+ info->extents.x - dst_x, info->extents.y - dst_y,
+ info->extents.width, info->extents.height);
+ pixman_image_unref (mask);
+ pixman_image_unref (white);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+composite_glyphs (void *_dst,
+ cairo_operator_t op,
+ cairo_surface_t *_src,
+ int src_x,
+ int src_y,
+ int dst_x,
+ int dst_y,
+ cairo_composite_glyphs_info_t *info)
+{
+ cairo_scaled_glyph_t *glyph_cache[64];
+ pixman_image_t *dst, *src;
+ cairo_status_t status;
+ int i;
+
+ TRACE ((stderr, "%s\n", __FUNCTION__));
+
+ if (info->num_glyphs == 1)
+ return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+
+ if (info->use_mask)
+ return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info);
+
+ op = _pixman_operator (op);
+ dst = to_pixman_image (_dst);
+ src = ((cairo_image_source_t *)_src)->pixman_image;
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+ status = CAIRO_STATUS_SUCCESS;
+
+ for (i = 0; i < info->num_glyphs; i++) {
+ int x, y;
+ cairo_image_surface_t *glyph_surface;
+ cairo_scaled_glyph_t *scaled_glyph;
+ unsigned long glyph_index = info->glyphs[i].index;
+ int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+
+ scaled_glyph = glyph_cache[cache_index];
+ if (scaled_glyph == NULL ||
+ _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+ {
+ status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+
+ if (unlikely (status))
+ break;
+
+ glyph_cache[cache_index] = scaled_glyph;
+ }
+
+ glyph_surface = scaled_glyph->surface;
+ if (glyph_surface->width && glyph_surface->height) {
+ /* round glyph locations to the nearest pixel */
+ /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
+ x = _cairo_lround (info->glyphs[i].x -
+ glyph_surface->base.device_transform.x0);
+ y = _cairo_lround (info->glyphs[i].y -
+ glyph_surface->base.device_transform.y0);
+
+ pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst,
+ x + src_x, y + src_y,
+ 0, 0,
+ x - dst_x, y - dst_y,
+ glyph_surface->width,
+ glyph_surface->height);
+ }
+ }
+
+ return status;
+}
+#endif
static cairo_int_status_t
check_composite (const cairo_composite_rectangles_t *extents)