[cairo-commit] 3 commits - src/cairo-debug.c src/cairoint.h src/cairo-mutex-list-private.h src/cairo-ps-surface.c src/cairo-win32-font.c src/cairo-win32-printing-surface.c src/cairo-win32-private.h src/cairo-win32-surface.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Tue Nov 16 05:42:35 PST 2010


 src/cairo-debug.c                  |    4 
 src/cairo-mutex-list-private.h     |    4 
 src/cairo-ps-surface.c             |    5 -
 src/cairo-win32-font.c             |  163 +++++++++++++++++++++++++++++++++++--
 src/cairo-win32-printing-surface.c |  157 +++++++++++++++++++++--------------
 src/cairo-win32-private.h          |   11 ++
 src/cairo-win32-surface.c          |   54 +++++++-----
 src/cairoint.h                     |    3 
 8 files changed, 313 insertions(+), 88 deletions(-)

New commits:
commit 653ceb517fe756b042a3cf8322a36cbfe71ddbd8
Author: Koji Otani <sho at bbr.jp>
Date:   Wed Nov 17 00:07:03 2010 +1030

    PS: fix embedding of grayscale jpegs
    
    https://bugs.freedesktop.org/show_bug.cgi?id=31632

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 71d8398..0be68bf 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -2377,11 +2377,12 @@ _cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t    *surface,
 				 "  /Width %d def\n"
 				 "  /Height %d def\n"
 				 "  /BitsPerComponent %d def\n"
-				 "  /Decode [ 0 1 0 1 0 1 ] def\n",
+				 "  /Decode [ %s ] def\n",
 				 info.num_components == 1 ? "DeviceGray" : "DeviceRGB",
 				 info.width,
 				 info.height,
-				 info.bits_per_component);
+				 info.bits_per_component,
+                                 info.num_components == 1 ? "0 1" : "0 1 0 1 0 1");
 
     if (surface->use_string_datasource) {
 	_cairo_output_stream_printf (surface->stream,
commit d5656394787c29daf31fff085639066287b0f7b7
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Nov 16 23:53:05 2010 +1030

    win32-print: print as unicode where possible
    
    One of the problems identified in
    https://bugzilla.mozilla.org/show_bug.cgi?id=454532 is that there are
    some older printer drivers that do not work with ExtTextOut and the
    ETO_GLYPH_INDEX option.
    
    Fix this by where possible mapping glyph indices back to unicode and
    calling ExtTextOut without ETO_GLYPH_INDEX. Glyphs that can not be
    mapped back to unicode are printed with ETO_GLYPH_INDEX.

diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 1e8bd26..806cab8 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1431,6 +1431,94 @@ _cairo_win32_printing_surface_fill (void		        *abstract_surface,
 }
 
 static cairo_int_status_t
+_cairo_win32_printing_surface_emit_win32_glyphs (cairo_win32_surface_t 	*surface,
+						 cairo_operator_t	 op,
+						 const cairo_pattern_t  *source,
+						 cairo_glyph_t        	*glyphs,
+						 int			 num_glyphs,
+						 cairo_scaled_font_t  	*scaled_font,
+						 cairo_clip_t		*clip,
+						 int			*remaining_glyphs)
+{
+    cairo_matrix_t ctm;
+    cairo_glyph_t  *unicode_glyphs;
+    cairo_scaled_font_subsets_glyph_t subset_glyph;
+    int i, first;
+    cairo_bool_t sequence_is_unicode;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    /* Where possible reverse the glyph indices back to unicode
+     * characters. Strings of glyphs that could not be reversed to
+     * unicode will be printed with ETO_GLYPH_INDEX.
+     *
+     * As _cairo_win32_scaled_font_index_to_ucs4() is a slow
+     * operation, the font subsetting function
+     * _cairo_scaled_font_subsets_map_glyph() is used to obtain
+     * the unicode value because it caches the reverse mapping in
+     * the subsets.
+     */
+
+    if (surface->has_ctm) {
+	for (i = 0; i < num_glyphs; i++)
+	    cairo_matrix_transform_point (&surface->ctm, &glyphs[i].x, &glyphs[i].y);
+	cairo_matrix_multiply (&ctm, &scaled_font->ctm, &surface->ctm);
+	scaled_font = cairo_scaled_font_create (scaled_font->font_face,
+						&scaled_font->font_matrix,
+						&ctm,
+						&scaled_font->options);
+    }
+
+    unicode_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
+    if (unicode_glyphs == NULL)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    memcpy (unicode_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
+    for (i = 0; i < num_glyphs; i++) {
+	status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
+						       scaled_font,
+						       glyphs[i].index,
+						       NULL, 0,
+						       &subset_glyph);
+	if (status)
+	    goto fail;
+
+	unicode_glyphs[i].index = subset_glyph.unicode;
+    }
+
+    i = 0;
+    first = 0;
+    sequence_is_unicode = unicode_glyphs[0].index <= 0xffff;
+    while (i < num_glyphs) {
+	if (i == num_glyphs - 1 ||
+	    ((unicode_glyphs[i + 1].index < 0xffff) != sequence_is_unicode))
+	{
+	    status = _cairo_win32_surface_show_glyphs_internal (
+		surface,
+		op,
+		source,
+		sequence_is_unicode ? &unicode_glyphs[first] : &glyphs[first],
+		i - first + 1,
+		scaled_font,
+		clip,
+		remaining_glyphs,
+		! sequence_is_unicode);
+	    first = i + 1;
+	    if (i < num_glyphs - 1)
+		sequence_is_unicode = unicode_glyphs[i + 1].index <= 0xffff;
+	}
+	i++;
+    }
+
+fail:
+    if (surface->has_ctm)
+	cairo_scaled_font_destroy (scaled_font);
+
+    free (unicode_glyphs);
+
+    return status;
+}
+
+static cairo_int_status_t
 _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surface,
                                            cairo_operator_t	 op,
                                            const cairo_pattern_t *source,
@@ -1514,67 +1602,14 @@ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surfac
     if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
 	source->type == CAIRO_PATTERN_TYPE_SOLID)
     {
-	cairo_matrix_t ctm;
-	cairo_glyph_t  *type1_glyphs = NULL;
-	cairo_scaled_font_subsets_glyph_t subset_glyph;
-
-	/* Calling ExtTextOutW() with ETO_GLYPH_INDEX and a Type 1
-	 * font on a printer DC prints garbled text. The text displays
-	 * correctly on a display DC. When using a printer
-	 * DC, ExtTextOutW() only works with characters and not glyph
-	 * indices.
-	 *
-	 * For Type 1 fonts the glyph indices are converted back to
-	 * unicode characters before calling _cairo_win32_surface_show_glyphs().
-	 *
-	 * As _cairo_win32_scaled_font_index_to_ucs4() is a slow
-	 * operation, the font subsetting function
-	 * _cairo_scaled_font_subsets_map_glyph() is used to obtain
-	 * the unicode value because it caches the reverse mapping in
-	 * the subsets.
-	 */
-	if (_cairo_win32_scaled_font_is_type1 (scaled_font)) {
-	    type1_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
-	    if (type1_glyphs == NULL)
-		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	    memcpy (type1_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
-	    for (i = 0; i < num_glyphs; i++) {
-		status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
-							       scaled_font,
-							       type1_glyphs[i].index,
-							       NULL, 0,
-							       &subset_glyph);
-		if (status)
-		    return status;
-
-		type1_glyphs[i].index = subset_glyph.unicode;
-	    }
-	    glyphs = type1_glyphs;
-	}
-
-	if (surface->has_ctm || surface->has_gdi_ctm) {
-	    cairo_matrix_multiply (&ctm, &surface->ctm, &surface->gdi_ctm);
-	    for (i = 0; i < num_glyphs; i++)
-		cairo_matrix_transform_point (&ctm, &glyphs[i].x, &glyphs[i].y);
-	    cairo_matrix_multiply (&ctm, &scaled_font->ctm, &ctm);
-	    scaled_font = cairo_scaled_font_create (scaled_font->font_face,
-						    &scaled_font->font_matrix,
-						    &ctm,
-						    &scaled_font->options);
-	}
-	status = _cairo_win32_surface_show_glyphs (surface, op,
-						   source, glyphs,
-						   num_glyphs, scaled_font,
-						   clip,
-						   remaining_glyphs);
-	if (surface->has_ctm)
-	    cairo_scaled_font_destroy (scaled_font);
-
-	if (type1_glyphs != NULL)
-	    free (type1_glyphs);
-
-	return status;
+	return _cairo_win32_printing_surface_emit_win32_glyphs (surface,
+								op,
+								source,
+								glyphs,
+								num_glyphs,
+								scaled_font,
+								clip,
+								remaining_glyphs);
     }
 #endif
 
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index cde27b7..efb0c1e 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -156,6 +156,17 @@ _cairo_win32_surface_set_clip_region (void           *abstract_surface,
 				      cairo_region_t *region);
 
 cairo_int_status_t
+_cairo_win32_surface_show_glyphs_internal (void			 *surface,
+					   cairo_operator_t	  op,
+					   const cairo_pattern_t *source,
+					   cairo_glyph_t	 *glyphs,
+					   int			  num_glyphs,
+					   cairo_scaled_font_t	 *scaled_font,
+					   cairo_clip_t		 *clip,
+					   int			 *remaining_glyphs,
+					   cairo_bool_t		  glyph_indices);
+
+cairo_int_status_t
 _cairo_win32_surface_show_glyphs (void			*surface,
 				  cairo_operator_t	 op,
 				  const cairo_pattern_t	*source,
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 660aaba..c335d97 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1494,14 +1494,15 @@ _cairo_win32_surface_flush (void *abstract_surface)
 #define STACK_GLYPH_SIZE 256
 
 cairo_int_status_t
-_cairo_win32_surface_show_glyphs (void			*surface,
-				  cairo_operator_t	 op,
-				  const cairo_pattern_t	*source,
-				  cairo_glyph_t		*glyphs,
-				  int			 num_glyphs,
-				  cairo_scaled_font_t	*scaled_font,
-				  cairo_clip_t		*clip,
-				  int			*remaining_glyphs)
+_cairo_win32_surface_show_glyphs_internal (void			 *surface,
+					   cairo_operator_t	  op,
+					   const cairo_pattern_t *source,
+					   cairo_glyph_t	 *glyphs,
+					   int			  num_glyphs,
+					   cairo_scaled_font_t	 *scaled_font,
+					   cairo_clip_t		 *clip,
+					   int			 *remaining_glyphs,
+					   cairo_bool_t		  glyph_indexing)
 {
 #if CAIRO_HAS_WIN32_FONT
     cairo_win32_surface_t *dst = surface;
@@ -1616,19 +1617,10 @@ _cairo_win32_surface_show_glyphs (void			*surface,
         }
     }
 
-    /* Using glyph indices for a Type 1 font does not work on a
-     * printer DC. The win32 printing surface will convert the the
-     * glyph indices of Type 1 fonts to the unicode values.
-     */
-    if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
-	_cairo_win32_scaled_font_is_type1 (scaled_font))
-    {
-	glyph_index_option = 0;
-    }
-    else
-    {
+    if (glyph_indexing)
 	glyph_index_option = ETO_GLYPH_INDEX;
-    }
+    else
+	glyph_index_option = 0;
 
     win_result = ExtTextOutW(dst->dc,
                              start_x,
@@ -1656,6 +1648,28 @@ _cairo_win32_surface_show_glyphs (void			*surface,
 
 #undef STACK_GLYPH_SIZE
 
+cairo_int_status_t
+_cairo_win32_surface_show_glyphs (void			*surface,
+				  cairo_operator_t	 op,
+				  const cairo_pattern_t *source,
+				  cairo_glyph_t	 	*glyphs,
+				  int			 num_glyphs,
+				  cairo_scaled_font_t	*scaled_font,
+				  cairo_clip_t          *clip,
+				  int		      	*remaining_glyphs)
+{
+    return _cairo_win32_surface_show_glyphs_internal (surface,
+						      op,
+						      source,
+						      glyphs,
+						      num_glyphs,
+						      scaled_font,
+						      clip,
+						      remaining_glyphs,
+						      TRUE);
+}
+
+
 /**
  * cairo_win32_surface_create:
  * @hdc: the DC to create a surface for
commit eb29a25dd6dddc511388bf883c9b95843ecdb823
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Tue Nov 16 23:48:39 2010 +1030

    win32: Use a font_face hash table to provide unique font faces
    
    Similar to the freetype and toy font backends, use a hash table
    to map logfont,hfont to font faces.
    
    This fixes the multiple embedding of the same font in PDF.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=24849

diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index c956753..e9e72b6 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -69,6 +69,10 @@ cairo_debug_reset_static_data (void)
     _cairo_ft_font_reset_static_data ();
 #endif
 
+#if CAIRO_HAS_WIN32_FONT
+    _cairo_win32_font_reset_static_data ();
+#endif
+
     _cairo_intern_string_reset_static_data ();
 
     _cairo_scaled_font_reset_static_data ();
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index 5827667..7d5ba02 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -51,6 +51,10 @@ CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
 #endif
 
+#if CAIRO_HAS_WIN32_FONT
+CAIRO_MUTEX_DECLARE (_cairo_win32_font_face_mutex)
+#endif
+
 #if CAIRO_HAS_XLIB_SURFACE
 CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
 #endif
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 479c672..a585163 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -47,6 +47,8 @@
 #include "cairo-win32-private.h"
 #include "cairo-error-private.h"
 
+#include <wchar.h>
+
 #ifndef SPI_GETFONTSMOOTHINGTYPE
 #define SPI_GETFONTSMOOTHINGTYPE 0x200a
 #endif
@@ -1934,6 +1936,120 @@ const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
     _cairo_win32_font_face_scaled_font_create
 };
 
+/* We maintain a hash table from LOGFONT,HFONT => #cairo_font_face_t.
+ * The primary purpose of this mapping is to provide unique
+ * #cairo_font_face_t values so that our cache and mapping from
+ * #cairo_font_face_t => #cairo_scaled_font_t works. Once the
+ * corresponding #cairo_font_face_t objects fall out of downstream
+ * caches, we don't need them in this hash table anymore.
+ *
+ * Modifications to this hash table are protected by
+ * _cairo_win32_font_face_mutex.
+ */
+
+static cairo_hash_table_t *cairo_win32_font_face_hash_table = NULL;
+
+static int
+_cairo_win32_font_face_keys_equal (const void *key_a,
+				   const void *key_b);
+
+static void
+_cairo_win32_font_face_hash_table_destroy (void)
+{
+    cairo_win32_font_face_t *font_face;
+
+    CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex);
+
+    if (cairo_win32_font_face_hash_table) {
+	/* This is rather inefficient, but destroying the hash table
+	 * is something we only do during debugging, (during
+	 * cairo_debug_reset_static_data), when efficiency is not
+	 * relevant. */
+        while (1) {
+	    font_face= _cairo_hash_table_random_entry (cairo_win32_font_face_hash_table,
+						       NULL);
+	    if (font_face == NULL)
+		break;
+	    _cairo_hash_table_remove (cairo_win32_font_face_hash_table,
+				      &font_face->base.hash_entry);
+
+	    cairo_font_face_destroy (&font_face->base);
+	}
+
+	_cairo_hash_table_destroy (cairo_win32_font_face_hash_table);
+
+	cairo_win32_font_face_hash_table = NULL;
+    }
+
+    CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex);
+}
+
+static cairo_hash_table_t *
+_cairo_win32_font_face_hash_table_lock (void)
+{
+    CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex);
+
+    if (unlikely (cairo_win32_font_face_hash_table == NULL))
+    {
+	cairo_win32_font_face_hash_table =
+	_cairo_hash_table_create (_cairo_win32_font_face_keys_equal);
+
+	if (unlikely (cairo_win32_font_face_hash_table == NULL)) {
+	    CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex);
+	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	    return NULL;
+	}
+    }
+
+    return cairo_win32_font_face_hash_table;
+}
+
+static void
+_cairo_win32_font_face_hash_table_unlock (void)
+{
+    CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex);
+}
+
+static void
+_cairo_win32_font_face_init_key (cairo_win32_font_face_t *key,
+				 LOGFONTW                *logfont,
+				 HFONT                    font)
+{
+    unsigned long hash = _CAIRO_HASH_INIT_VALUE;
+
+    key->logfont = *logfont;
+    key->hfont = font;
+
+    hash = _cairo_hash_bytes (0, logfont->lfFaceName, wcslen(logfont->lfFaceName));
+    hash = _cairo_hash_bytes (hash, &logfont->lfWeight, sizeof(logfont->lfWeight));
+    hash = _cairo_hash_bytes (hash, &logfont->lfItalic, sizeof(logfont->lfItalic));
+    hash = _cairo_hash_bytes (hash, &font, sizeof(font));
+
+    key->base.hash_entry.hash = hash;
+}
+
+static int
+_cairo_win32_font_face_keys_equal (const void *key_a,
+				   const void *key_b)
+{
+    const cairo_win32_font_face_t *face_a = key_a;
+    const cairo_win32_font_face_t *face_b = key_b;
+
+    if (face_a->logfont.lfWeight         == face_b->logfont.lfWeight &&
+	face_a->logfont.lfItalic         == face_b->logfont.lfItalic &&
+	face_a->logfont.lfUnderline      == face_b->logfont.lfUnderline &&
+	face_a->logfont.lfStrikeOut      == face_b->logfont.lfStrikeOut &&
+	face_a->logfont.lfCharSet        == face_b->logfont.lfCharSet &&
+	face_a->logfont.lfOutPrecision   == face_b->logfont.lfOutPrecision &&
+	face_a->logfont.lfClipPrecision  == face_b->logfont.lfClipPrecision &&
+	face_a->logfont.lfPitchAndFamily == face_b->logfont.lfPitchAndFamily &&
+	(wcscmp (face_a->logfont.lfFaceName, face_a->logfont.lfFaceName) == 0) &&
+	face_a->hfont                    == face_b->hfont)
+	return TRUE;
+    else
+	return FALSE;
+}
+
 /**
  * cairo_win32_font_face_create_for_logfontw_hfont:
  * @logfont: A #LOGFONTW structure specifying the font to use.
@@ -1956,20 +2072,51 @@ const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
 cairo_font_face_t *
 cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font)
 {
-    cairo_win32_font_face_t *font_face;
+    cairo_win32_font_face_t *font_face, key;
+    cairo_hash_table_t *hash_table;
+    cairo_status_t status;
+
+    hash_table = _cairo_win32_font_face_hash_table_lock ();
+    if (unlikely (hash_table == NULL)) {
+        _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	return (cairo_font_face_t *)&_cairo_font_face_nil;
+    }
+
+    _cairo_win32_font_face_init_key (&key, logfont, font);
+
+    /* Return existing unscaled font if it exists in the hash table. */
+    font_face = _cairo_hash_table_lookup (hash_table,
+					 &key.base.hash_entry);
+    if (font_face != NULL) {
+	cairo_font_face_reference (&font_face->base);
+	goto DONE;
+    }
 
+    /* Otherwise create it and insert into hash table. */
     font_face = malloc (sizeof (cairo_win32_font_face_t));
     if (!font_face) {
         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-        return (cairo_font_face_t *)&_cairo_font_face_nil;
+	goto FAIL;
     }
 
-    font_face->logfont = *logfont;
-    font_face->hfont = font;
-
+    _cairo_win32_font_face_init_key (font_face, logfont, font);
     _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend);
 
+    assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash);
+    status = _cairo_hash_table_insert (hash_table,
+				       &font_face->base.hash_entry);
+    if (unlikely (status))
+	goto FAIL;
+
+DONE:
+    _cairo_win32_font_face_hash_table_unlock ();
+
     return &font_face->base;
+
+FAIL:
+    _cairo_win32_font_face_hash_table_unlock ();
+
+    return (cairo_font_face_t *)&_cairo_font_face_nil;
 }
 
 /**
@@ -2178,3 +2325,9 @@ cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font,
     }
     *device_to_logical = win_font->device_to_logical;
 }
+
+void
+_cairo_win32_font_reset_static_data (void)
+{
+    _cairo_win32_font_face_hash_table_destroy ();
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 539d92e..e2946cf 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -407,6 +407,9 @@ _cairo_toy_font_face_reset_static_data (void);
 cairo_private void
 _cairo_ft_font_reset_static_data (void);
 
+cairo_private void
+_cairo_win32_font_reset_static_data (void);
+
 /* the font backend interface */
 
 struct _cairo_unscaled_font_backend {


More information about the cairo-commit mailing list