[cairo-commit] 6 commits - perf/cairo-perf-trace.c src/cairo-scaled-font.c src/cairo-script-surface.c util/cairo-script

Chris Wilson ickle at kemper.freedesktop.org
Tue Jan 8 07:05:39 PST 2013


 perf/cairo-perf-trace.c                      |   16 -
 src/cairo-scaled-font.c                      |   74 +++-
 src/cairo-script-surface.c                   |    4 
 util/cairo-script/cairo-script-interpreter.h |    7 
 util/cairo-script/cairo-script-operators.c   |  410 +++++++++++++++------------
 5 files changed, 317 insertions(+), 194 deletions(-)

New commits:
commit c4ea7b13b406bf0ea1dc9b337010131d3704bc4a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jan 8 13:35:43 2013 +0000

    scaled-font: Assert if attempting to finish a frozen font
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index d4eef55..ac8dc0a 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -780,6 +780,7 @@ _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
 {
     /* ensure we do not modify an error object */
     assert (scaled_font->status == CAIRO_STATUS_SUCCESS);
+    assert (! scaled_font->cache_frozen);
 
     CAIRO_MUTEX_LOCK (scaled_font->mutex);
     scaled_font->cache_frozen = TRUE;
@@ -788,6 +789,7 @@ _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
 void
 _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
 {
+    assert (scaled_font->cache_frozen);
     scaled_font->cache_frozen = FALSE;
 
     if (scaled_font->global_cache_frozen) {
@@ -867,6 +869,8 @@ _cairo_scaled_font_fini_pages (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_fini_pages (scaled_font);
@@ -1158,6 +1162,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);
@@ -1307,6 +1313,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);
 
@@ -2825,6 +2834,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,
@@ -2942,6 +2953,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);
commit 4d4bf8fddff49d349e03282ffa827f6f4659e3fe
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jan 8 14:56:07 2013 +0000

    scaled-font: Free the cached glyphs from the font before taking the global lock
    
    In the case of a recording surface we may recurse into the global glyph
    cache so we need to be careful and stage the ordering of how we free the
    glyphs. So first we finish any information and surfaces from the scaled
    font glyph cache (and so triggering recursion into other scaled fonts)
    and then take the global cache and remove our pages.
    
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=54950
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 9b0fc92..d4eef55 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -846,11 +846,30 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t	    *scaled_font,
 }
 
 static void
+_cairo_scaled_font_fini_pages (cairo_scaled_font_t *scaled_font)
+{
+    cairo_scaled_glyph_page_t *page;
+    unsigned int i;
+
+    cairo_list_foreach_entry (page, cairo_scaled_glyph_page_t,
+			      &scaled_font->glyph_pages, link) {
+	for (i = 0; i < page->num_glyphs; i++) {
+	    _cairo_hash_table_remove (scaled_font->glyphs,
+				      &page->glyphs[i].hash_entry);
+	    _cairo_scaled_glyph_fini (scaled_font, &page->glyphs[i]);
+	}
+	page->num_glyphs = 0;
+    }
+
+    _cairo_scaled_font_reset_cache (scaled_font);
+}
+
+static void
 _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
 {
     scaled_font->finished = TRUE;
 
-    _cairo_scaled_font_reset_cache (scaled_font);
+    _cairo_scaled_font_fini_pages (scaled_font);
     _cairo_hash_table_destroy (scaled_font->glyphs);
 
     cairo_font_face_destroy (scaled_font->font_face);
commit 44a093eb95c950b0e8f2d7d1cdb9719cb8a550f7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jan 8 14:58:41 2013 +0000

    scaled-font: Always hold the mutex even for single glyph probes
    
    The freeze/thaw routines have a side-effect of managing the global glyph
    cache in addition to taking the mutex on the font. If we don't call
    them, we may end up indefinitely keeping the global glyph cache frozen
    (effectively leaking glyphs to the maximum of all open fonts) and
    triggering asserts.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index dc6a6fd..9b0fc92 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -2131,36 +2131,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;
 }
 
 /*
commit 80cc532271d7e94ad02732841fbcdc811cce8754
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jan 8 13:47:23 2013 +0000

    script: Thaw the scaled font cache on the error path
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

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) {
commit e1307da8616027004dd6c901017a667b1503781d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jan 8 12:53:24 2013 +0000

    script: Simply exchange source/dest images for _set_source_image
    
    But note we can only do the exchange if they do indeed match and
    there are no other references (the objects are only on the stack).
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index efc1970..71d2b79 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -5356,11 +5356,20 @@ _set_source_image (csi_t *ctx)
      * principally to remove the pixman ops from the profiles.
      */
     if (_csi_likely (_matching_images (surface, source))) {
-	cairo_surface_flush (surface);
-	memcpy (cairo_image_surface_get_data (surface),
-		cairo_image_surface_get_data (source),
-		cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
-	cairo_surface_mark_dirty (surface);
+	if (cairo_surface_get_reference_count (surface) == 1 &&
+	    cairo_surface_get_reference_count (source) == 1)
+	{
+	    _csi_peek_ostack (ctx, 0)->datum.surface = surface;
+	    _csi_peek_ostack (ctx, 1)->datum.surface = source;
+	}
+	else
+	{
+	    cairo_surface_flush (surface);
+	    memcpy (cairo_image_surface_get_data (surface),
+		    cairo_image_surface_get_data (source),
+		    cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source));
+	    cairo_surface_mark_dirty (surface);
+	}
     } else {
 	cairo_t *cr;
 
commit 146da77d85b304651949a819bc8b0a74819f0416
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Jan 8 12:19:33 2013 +0000

    script: Attempt to decompress images in place
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/perf/cairo-perf-trace.c b/perf/cairo-perf-trace.c
index bd0cb07..4b8c85e 100644
--- a/perf/cairo-perf-trace.c
+++ b/perf/cairo-perf-trace.c
@@ -299,6 +299,19 @@ _similar_surface_create (void		 *closure,
     return surface;
 }
 
+static cairo_surface_t *
+_source_image_create (void		*closure,
+		      cairo_format_t	 format,
+		      int		 width,
+		      int		 height,
+		      long		 uid)
+{
+    struct trace *args = closure;
+
+    return cairo_surface_create_similar_image (args->surface,
+					       format, width, height);
+}
+
 static cairo_t *
 _context_create (void		 *closure,
 		 cairo_surface_t *surface)
@@ -643,7 +656,8 @@ cairo_perf_trace (cairo_perf_t			   *perf,
 	_context_create,
 	NULL, /* context_destroy */
 	NULL, /* show_page */
-	NULL /* copy_page */
+	NULL, /* copy_page */
+	_source_image_create,
     };
 
     args.tile_size = perf->tile_size;
diff --git a/util/cairo-script/cairo-script-interpreter.h b/util/cairo-script/cairo-script-interpreter.h
index bbdd15d..27fb986 100644
--- a/util/cairo-script/cairo-script-interpreter.h
+++ b/util/cairo-script/cairo-script-interpreter.h
@@ -65,6 +65,12 @@ typedef void
 (*csi_copy_page_func_t) (void *closure,
 			 cairo_t *cr);
 
+typedef cairo_surface_t *
+(*csi_create_source_image_t) (void *closure,
+			      cairo_format_t format,
+			      int width, int height,
+			      long uid);
+
 typedef struct _cairo_script_interpreter_hooks {
     void *closure;
     csi_surface_create_func_t surface_create;
@@ -73,6 +79,7 @@ typedef struct _cairo_script_interpreter_hooks {
     csi_destroy_func_t context_destroy;
     csi_show_page_func_t show_page;
     csi_copy_page_func_t copy_page;
+    csi_create_source_image_t create_source_image;
 } cairo_script_interpreter_hooks_t;
 
 cairo_public cairo_script_interpreter_t *
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index 9ba24f8..efc1970 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -2892,7 +2892,8 @@ _ifelse (csi_t *ctx)
 }
 
 static csi_status_t
-_image_read_raw (csi_file_t *src,
+_image_read_raw (csi_t *ctx,
+		 csi_object_t *src,
 		 cairo_format_t format,
 		 int width, int height,
 		 cairo_surface_t **image_out)
@@ -2902,20 +2903,34 @@ _image_read_raw (csi_file_t *src,
     int rem, len, ret, x, rowlen, instride, stride;
     cairo_status_t status;
 
-    stride = cairo_format_stride_for_width (format, width);
-    data = malloc (stride * height);
-    if (data == NULL)
-	return CAIRO_STATUS_NO_MEMORY;
+    if (width == 0 || height == 0) {
+	*image_out = cairo_image_surface_create (format, 0, 0);
+	return CSI_STATUS_SUCCESS;
+    }
 
-    image = cairo_image_surface_create_for_data (data, format,
-						 width, height, stride);
-    status = cairo_surface_set_user_data (image,
-					  (const cairo_user_data_key_t *) image,
-					  data, free);
-    if (status) {
-	cairo_surface_destroy (image);
-	free (image);
-	return status;
+    if (ctx->hooks.create_source_image != NULL) {
+	image = ctx->hooks.create_source_image (ctx->hooks.closure,
+						format, width, height,
+						0);
+
+	stride = cairo_image_surface_get_stride (image);
+	data = cairo_image_surface_get_data (image);
+    } else {
+	stride = cairo_format_stride_for_width (format, width);
+	data = malloc (stride * height);
+	if (data == NULL)
+	    return CAIRO_STATUS_NO_MEMORY;
+
+	image = cairo_image_surface_create_for_data (data, format,
+						     width, height, stride);
+	status = cairo_surface_set_user_data (image,
+					      (const cairo_user_data_key_t *) image,
+					      data, free);
+	if (status) {
+	    cairo_surface_destroy (image);
+	    free (image);
+	    return status;
+	}
     }
 
     switch (format) {
@@ -2941,192 +2956,236 @@ _image_read_raw (csi_file_t *src,
     }
     len = rowlen * height;
 
-    bp = data;
-    rem = len;
-    while (rem) {
-	ret = csi_file_read (src, bp, rem);
-	if (_csi_unlikely (ret == 0)) {
+    if (rowlen == instride &&
+	src->type == CSI_OBJECT_TYPE_STRING &&
+	len == src->datum.string->deflate)
+    {
+	csi_string_t *s = src->datum.string;
+	unsigned long out;
+
+	switch (s->method) {
+	default:
+	case NONE:
+err_decompress:
 	    cairo_surface_destroy (image);
 	    return _csi_error (CSI_STATUS_READ_ERROR);
+
+#if HAVE_ZLIB
+	case ZLIB:
+	    if (uncompress ((Bytef *) data, &out,
+			    (Bytef *) s->string, s->len) != Z_OK)
+		goto err_decompress;
+	    break;
+#endif
+
+#if HAVE_LZO
+	case LZO:
+	    if (lzo2a_decompress ((Bytef *) s->string, s->len,
+				  (Bytef *) data, &out,
+				  NULL))
+		goto err_decompress;
+	    break;
+#endif
 	}
-	rem -= ret;
-	bp += ret;
     }
+    else
+    {
+	csi_object_t file;
+
+	status = csi_object_as_file (ctx, src, &file);
+	if (_csi_unlikely (status)) {
+	    cairo_surface_destroy (image);
+	    return status;
+	}
+
+	bp = data;
+	rem = len;
+	while (rem) {
+	    ret = csi_file_read (file.datum.file, bp, rem);
+	    if (_csi_unlikely (ret == 0)) {
+		cairo_surface_destroy (image);
+		return _csi_error (CSI_STATUS_READ_ERROR);
+	    }
+	    rem -= ret;
+	    bp += ret;
+	}
 
-    if (len != height * stride) {
-	while (--height) {
-	    uint8_t *row = data + height * stride;
+	if (len != height * stride) {
+	    while (--height) {
+		uint8_t *row = data + height * stride;
+
+		/* XXX pixel conversion */
+		switch (format) {
+		case CAIRO_FORMAT_A1:
+		    for (x = rowlen; x--; ) {
+			uint8_t byte = *--bp;
+			row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
+		    }
+		    break;
+		case CAIRO_FORMAT_A8:
+		    for (x = width; x--; )
+			row[x] = *--bp;
+		    break;
+		case CAIRO_FORMAT_RGB16_565:
+		    for (x = width; x--; ) {
+#ifdef WORDS_BIGENDIAN
+			row[2*x + 1] = *--bp;
+			row[2*x + 0] = *--bp;
+#else
+			row[2*x + 0] = *--bp;
+			row[2*x + 1] = *--bp;
+#endif
+		    }
+		    break;
+		case CAIRO_FORMAT_RGB24:
+		    for (x = width; x--; ) {
+#ifdef WORDS_BIGENDIAN
+			row[4*x + 3] = *--bp;
+			row[4*x + 2] = *--bp;
+			row[4*x + 1] = *--bp;
+			row[4*x + 0] = 0xff;
+#else
+			row[4*x + 0] = *--bp;
+			row[4*x + 1] = *--bp;
+			row[4*x + 2] = *--bp;
+			row[4*x + 3] = 0xff;
+#endif
+		    }
+		    break;
+		case CAIRO_FORMAT_RGB30:
+		case CAIRO_FORMAT_INVALID:
+		case CAIRO_FORMAT_ARGB32:
+		    /* stride == width */
+		    break;
+		}
 
-	    /* XXX pixel conversion */
+		memset (row + instride, 0, stride - instride);
+	    }
+
+	    /* need to treat last row carefully */
 	    switch (format) {
 	    case CAIRO_FORMAT_A1:
 		for (x = rowlen; x--; ) {
 		    uint8_t byte = *--bp;
-		    row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
+		    data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
 		}
 		break;
 	    case CAIRO_FORMAT_A8:
 		for (x = width; x--; )
-		    row[x] = *--bp;
+		    data[x] = *--bp;
 		break;
 	    case CAIRO_FORMAT_RGB16_565:
 		for (x = width; x--; ) {
 #ifdef WORDS_BIGENDIAN
-		    row[2*x + 1] = *--bp;
-		    row[2*x + 0] = *--bp;
+		    data[2*x + 1] = *--bp;
+		    data[2*x + 0] = *--bp;
 #else
-		    row[2*x + 0] = *--bp;
-		    row[2*x + 1] = *--bp;
+		    data[2*x + 0] = *--bp;
+		    data[2*x + 1] = *--bp;
 #endif
 		}
 		break;
 	    case CAIRO_FORMAT_RGB24:
-		for (x = width; x--; ) {
+		for (x = width; --x>1; ) {
 #ifdef WORDS_BIGENDIAN
-		    row[4*x + 3] = *--bp;
-		    row[4*x + 2] = *--bp;
-		    row[4*x + 1] = *--bp;
-		    row[4*x + 0] = 0xff;
+		    data[4*x + 3] = *--bp;
+		    data[4*x + 2] = *--bp;
+		    data[4*x + 1] = *--bp;
+		    data[4*x + 0] = 0xff;
 #else
-		    row[4*x + 0] = *--bp;
-		    row[4*x + 1] = *--bp;
-		    row[4*x + 2] = *--bp;
-		    row[4*x + 3] = 0xff;
+		    data[4*x + 0] = *--bp;
+		    data[4*x + 1] = *--bp;
+		    data[4*x + 2] = *--bp;
+		    data[4*x + 3] = 0xff;
 #endif
 		}
-		break;
-	    case CAIRO_FORMAT_RGB30:
-	    case CAIRO_FORMAT_INVALID:
-	    case CAIRO_FORMAT_ARGB32:
-		/* stride == width */
-		break;
-	    }
-
-	    memset (row + instride, 0, stride - instride);
-	}
-
-	/* need to treat last row carefully */
-	switch (format) {
-	case CAIRO_FORMAT_A1:
-	    for (x = rowlen; x--; ) {
-		uint8_t byte = *--bp;
-		data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
-	    }
-	    break;
-	case CAIRO_FORMAT_A8:
-	    for (x = width; x--; )
-		data[x] = *--bp;
-	    break;
-	case CAIRO_FORMAT_RGB16_565:
-	    for (x = width; x--; ) {
+		if (width > 1) {
+		    uint8_t rgb[2][3];
+		    /* shuffle the last couple of overlapping pixels */
+		    rgb[1][0] = data[5];
+		    rgb[1][1] = data[4];
+		    rgb[1][2] = data[3];
+		    rgb[0][0] = data[2];
+		    rgb[0][1] = data[1];
+		    rgb[0][2] = data[0];
 #ifdef WORDS_BIGENDIAN
-		data[2*x + 1] = *--bp;
-		data[2*x + 0] = *--bp;
+		    data[4] = 0xff;
+		    data[5] = rgb[1][2];
+		    data[6] = rgb[1][1];
+		    data[7] = rgb[1][0];
+		    data[0] = 0xff;
+		    data[1] = rgb[0][2];
+		    data[2] = rgb[0][1];
+		    data[3] = rgb[0][0];
 #else
-		data[2*x + 0] = *--bp;
-		data[2*x + 1] = *--bp;
+		    data[7] = 0xff;
+		    data[6] = rgb[1][2];
+		    data[5] = rgb[1][1];
+		    data[4] = rgb[1][0];
+		    data[3] = 0xff;
+		    data[2] = rgb[0][2];
+		    data[1] = rgb[0][1];
+		    data[0] = rgb[0][0];
 #endif
-	    }
-	    break;
-	case CAIRO_FORMAT_RGB24:
-	    for (x = width; --x>1; ) {
-#ifdef WORDS_BIGENDIAN
-		data[4*x + 3] = *--bp;
-		data[4*x + 2] = *--bp;
-		data[4*x + 1] = *--bp;
-		data[4*x + 0] = 0xff;
-#else
-		data[4*x + 0] = *--bp;
-		data[4*x + 1] = *--bp;
-		data[4*x + 2] = *--bp;
-		data[4*x + 3] = 0xff;
-#endif
-	    }
-	    if (width > 1) {
-		uint8_t rgb[2][3];
-		/* shuffle the last couple of overlapping pixels */
-		rgb[1][0] = data[5];
-		rgb[1][1] = data[4];
-		rgb[1][2] = data[3];
-		rgb[0][0] = data[2];
-		rgb[0][1] = data[1];
-		rgb[0][2] = data[0];
-#ifdef WORDS_BIGENDIAN
-		data[4] = 0xff;
-		data[5] = rgb[1][2];
-		data[6] = rgb[1][1];
-		data[7] = rgb[1][0];
-		data[0] = 0xff;
-		data[1] = rgb[0][2];
-		data[2] = rgb[0][1];
-		data[3] = rgb[0][0];
-#else
-		data[7] = 0xff;
-		data[6] = rgb[1][2];
-		data[5] = rgb[1][1];
-		data[4] = rgb[1][0];
-		data[3] = 0xff;
-		data[2] = rgb[0][2];
-		data[1] = rgb[0][1];
-		data[0] = rgb[0][0];
-#endif
-	    } else {
+		} else {
 #ifdef WORDS_BIGENDIAN
-		data[0] = 0xff;
-		data[1] = data[0];
-		data[2] = data[1];
-		data[3] = data[2];
+		    data[0] = 0xff;
+		    data[1] = data[0];
+		    data[2] = data[1];
+		    data[3] = data[2];
 #else
-		data[3] = data[0];
-		data[0] = data[2];
-		data[2] = data[3];
-		data[3] = 0xff;
+		    data[3] = data[0];
+		    data[0] = data[2];
+		    data[2] = data[3];
+		    data[3] = 0xff;
 #endif
+		}
+		break;
+	    case CAIRO_FORMAT_RGB30:
+	    case CAIRO_FORMAT_INVALID:
+	    case CAIRO_FORMAT_ARGB32:
+		/* stride == width */
+		break;
 	    }
-	    break;
-	case CAIRO_FORMAT_RGB30:
-	case CAIRO_FORMAT_INVALID:
-	case CAIRO_FORMAT_ARGB32:
-	    /* stride == width */
-	    break;
-	}
-	memset (data + instride, 0, stride - instride);
-    } else {
+	    memset (data + instride, 0, stride - instride);
+	} else {
 #ifndef WORDS_BIGENDIAN
-	switch (format) {
-	case CAIRO_FORMAT_A1:
-	    for (x = 0; x < len; x++) {
-		uint8_t byte = data[x];
-		data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
-	    }
-	    break;
-	case CAIRO_FORMAT_RGB16_565:
-	    {
-		uint32_t *rgba = (uint32_t *) data;
-		for (x = len/2; x--; rgba++) {
-		    *rgba = bswap_16 (*rgba);
+	    switch (format) {
+	    case CAIRO_FORMAT_A1:
+		for (x = 0; x < len; x++) {
+		    uint8_t byte = data[x];
+		    data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
 		}
-	    }
-	    break;
-	case CAIRO_FORMAT_ARGB32:
-	    {
-		uint32_t *rgba = (uint32_t *) data;
-		for (x = len/4; x--; rgba++) {
-		    *rgba = bswap_32 (*rgba);
+		break;
+	    case CAIRO_FORMAT_RGB16_565:
+		{
+		    uint32_t *rgba = (uint32_t *) data;
+		    for (x = len/2; x--; rgba++) {
+			*rgba = bswap_16 (*rgba);
+		    }
 		}
-	    }
-	    break;
+		break;
+	    case CAIRO_FORMAT_ARGB32:
+		{
+		    uint32_t *rgba = (uint32_t *) data;
+		    for (x = len/4; x--; rgba++) {
+			*rgba = bswap_32 (*rgba);
+		    }
+		}
+		break;
 
-	case CAIRO_FORMAT_A8:
-	    break;
+	    case CAIRO_FORMAT_A8:
+		break;
 
-	case CAIRO_FORMAT_RGB30:
-	case CAIRO_FORMAT_RGB24:
-	case CAIRO_FORMAT_INVALID:
-	default:
-	    break;
-	}
+	    case CAIRO_FORMAT_RGB30:
+	    case CAIRO_FORMAT_RGB24:
+	    case CAIRO_FORMAT_INVALID:
+	    default:
+		break;
+	    }
 #endif
+	}
+	csi_object_free (ctx, &file);
     }
 
     cairo_surface_mark_dirty (image);
@@ -3303,22 +3362,22 @@ _image_load_from_dictionary (csi_t *ctx,
 		mime_type = MIME_TYPE_PNG;
 	}
 
-	status = csi_object_as_file (ctx, &obj, &file);
-	if (_csi_unlikely (status))
-	    return status;
 
 	/* XXX hook for general mime-type decoder */
 
 	switch (mime_type) {
 	case MIME_TYPE_NONE:
-	    status = _image_read_raw (file.datum.file,
-				      format, width, height, &image);
+	    status = _image_read_raw (ctx, &obj, format, width, height, &image);
 	    break;
 	case MIME_TYPE_PNG:
+	    status = csi_object_as_file (ctx, &obj, &file);
+	    if (_csi_unlikely (status))
+		return status;
+
 	    status = _image_read_png (file.datum.file, &image);
+	    csi_object_free (ctx, &file);
 	    break;
 	}
-	csi_object_free (ctx, &file);
 	if (_csi_unlikely (status))
 	    return status;
 


More information about the cairo-commit mailing list