[cairo-commit] 2 commits - src/cairo-win32-font.c src/cairo-win32-surface.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Tue Jan 8 07:51:27 PST 2008


 src/cairo-win32-font.c    |  261 ++++++++++++++++++++++++++++++++++++++--------
 src/cairo-win32-surface.c |    4 
 2 files changed, 220 insertions(+), 45 deletions(-)

New commits:
commit f20a1a40c3f6d95b4dc89ae4198ad81b7092450c
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Jan 9 01:20:34 2008 +1030

    Fix MSVC 2008 compiler warnings - bug 13698

diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index dd99b8f..2342230 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -91,7 +91,7 @@ _cairo_win32_print_gdi_error (const char *context)
 			 NULL,
 			 last_error,
 			 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
-			 (LPTSTR) &lpMsgBuf,
+			 (LPSTR) &lpMsgBuf,
 			 0, NULL)) {
 	fprintf (stderr, "%s: Unknown GDI error", context);
     } else {
@@ -745,7 +745,7 @@ _composite_alpha_blend (cairo_win32_surface_t *dst,
 	if (VER_PLATFORM_WIN32_WINDOWS != os.dwPlatformId ||
 	    os.dwMajorVersion != 4 || os.dwMinorVersion != 10)
 	{
-	    HMODULE msimg32_dll = LoadLibrary ("msimg32");
+	    HMODULE msimg32_dll = LoadLibraryA ("msimg32");
 
 	    if (msimg32_dll != NULL)
 		alpha_blend = (cairo_alpha_blend_func_t)GetProcAddress (msimg32_dll,
commit 47bebc8f1d0b6524f8d1eff1fa3f981f1e4c4c33
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Jan 9 01:18:44 2008 +1030

    Fix win32-font problems with Type 1 fonts
    
    This should fix the problems reported in
    
    http://lists.cairographics.org/archives/cairo/2007-November/012172.html
    
    The problem is that GetCharacterPlacement() used in
    _win32_scaled_font_text_to_glyphs returns utf16 instead of glyph
    indices when Type 1 fonts are used.
    
    This has been fixed by using GetGlyphIndices instead of
    GetCharacterPlacement if the font is a Type 1.
    
    _win32_scaled_font_map_glyphs_to_unicode has been fixed work with Type 1
    glyph indices. It now uses GetFontUnicodeRanges and GetGlyphIndices
    to do the reverse lookup.

diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 769f155..19c494d 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -33,6 +33,15 @@
  * Contributor(s):
  */
 
+#define WIN32_LEAN_AND_MEAN
+/* We require Windows 2000 features such as GetGlyphIndices */
+#if !defined(WINVER) || (WINVER < 0x0500)
+# define WINVER 0x0500
+#endif
+#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
+# define _WIN32_WINNT 0x0500
+#endif
+
 #include "cairoint.h"
 
 #include "cairo-win32-private.h"
@@ -50,7 +59,7 @@
 #define TT_PRIM_CSPLINE 3
 #endif
 
-#define OPENTYPE_CFF_TAG 0x20464643
+#define CMAP_TAG 0x70616d63
 
 const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend;
 
@@ -99,10 +108,8 @@ typedef struct {
     HFONT scaled_hfont;
     HFONT unscaled_hfont;
 
-    cairo_bool_t is_truetype;
-    cairo_bool_t glyph_indexing;
     cairo_bool_t is_bitmap;
-
+    cairo_bool_t is_type1;
     cairo_bool_t delete_scaled_hfont;
 } cairo_win32_scaled_font_t;
 
@@ -571,6 +578,92 @@ _cairo_win32_scaled_font_fini (void *abstract_font)
 }
 
 static cairo_int_status_t
+_cairo_win32_scaled_font_type1_text_to_glyphs (cairo_win32_scaled_font_t *scaled_font,
+					       double		          x,
+					       double		          y,
+					       const char	         *utf8,
+					       cairo_glyph_t            **glyphs,
+					       int		         *num_glyphs)
+{
+    uint16_t *utf16;
+    int n16;
+    int i;
+    WORD *glyph_indices = NULL;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    double x_pos, y_pos;
+    HDC hdc = NULL;
+    cairo_matrix_t mat;
+
+    status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &n16);
+    if (status)
+	return status;
+
+    glyph_indices = _cairo_malloc_ab (n16 + 1, sizeof (WORD));
+    if (!glyph_indices) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FAIL1;
+    }
+
+    hdc = _get_global_font_dc ();
+    if (!hdc) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FAIL2;
+    }
+
+    status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
+    if (status)
+	goto FAIL2;
+
+    if (GetGlyphIndicesW (hdc, utf16, n16, glyph_indices, 0) == GDI_ERROR) {
+	status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_type1_text_to_glyphs:GetGlyphIndicesW");
+	goto FAIL2;
+    }
+
+    *num_glyphs = n16;
+    *glyphs = _cairo_malloc_ab (n16, sizeof (cairo_glyph_t));
+    if (!*glyphs) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FAIL2;
+    }
+
+    x_pos = x;
+    y_pos = y;
+    mat = scaled_font->base.ctm;
+    cairo_matrix_invert (&mat);
+    for (i = 0; i < n16; i++) {
+	cairo_scaled_glyph_t *scaled_glyph;
+
+	(*glyphs)[i].index = glyph_indices[i];
+	(*glyphs)[i].x = x_pos;
+	(*glyphs)[i].y = y_pos;
+
+	status = _cairo_scaled_glyph_lookup (&scaled_font->base,
+					     glyph_indices[i],
+					     CAIRO_SCALED_GLYPH_INFO_METRICS,
+					     &scaled_glyph);
+	if (status) {
+	    free (*glyphs);
+	    goto FAIL2;
+	}
+
+	x = scaled_glyph->x_advance;
+	y = scaled_glyph->y_advance;
+	cairo_matrix_transform_distance (&mat, &x, &y);
+	x_pos += x;
+	y_pos += y;
+    }
+
+    cairo_win32_scaled_font_done_font (&scaled_font->base);
+
+FAIL2:
+    free (glyph_indices);
+FAIL1:
+    free (utf16);
+
+    return status;
+}
+
+static cairo_int_status_t
 _cairo_win32_scaled_font_text_to_glyphs (void		*abstract_font,
 					 double		x,
 					 double		y,
@@ -590,6 +683,16 @@ _cairo_win32_scaled_font_text_to_glyphs (void		*abstract_font,
     double x_incr, y_incr;
     HDC hdc = NULL;
 
+    /* GetCharacterPlacement() returns utf16 instead of glyph indices
+     * for Type 1 fonts. Use GetGlyphIndices for Type 1 fonts. */
+    if (scaled_font->is_type1)
+	 return _cairo_win32_scaled_font_type1_text_to_glyphs (scaled_font,
+							       x,
+							       y,
+							       utf8,
+							       glyphs,
+							       num_glyphs);
+
     /* Compute a vector in user space along the baseline of length one logical space unit */
     x_incr = 1;
     y_incr = 0;
@@ -747,16 +850,27 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font)
 
     }
 
-    if (metrics.tmPitchAndFamily & TMPF_VECTOR)
-	scaled_font->is_bitmap = FALSE;
-    else
-	scaled_font->is_bitmap = TRUE;
+    scaled_font->is_bitmap = !(metrics.tmPitchAndFamily & TMPF_VECTOR);
 
-    scaled_font->is_truetype = (metrics.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
-    scaled_font->glyph_indexing = scaled_font->is_truetype ||
-	(GetFontData (hdc, OPENTYPE_CFF_TAG, 0, NULL, 0) != GDI_ERROR);
-    // XXX in what situations does this OPENTYPE_CFF thing not have the
-    // TMPF_TRUETYPE flag? GetFontData says it only works on Truetype fonts...
+    /* Need to determine if this is a Type 1 font for the special
+     * handling in _text_to_glyphs.  Unlike TrueType or OpenType,
+     * Type1 fonts do not have a "cmap" table (or any other table).
+     * However GetFontData() will retrieve a Type1 font when
+     * requesting that GetFontData() retrieve data from the start of
+     * the file. This is to distinguish Type1 from stroke fonts such
+     * as "Script" and "Modern". The TMPF_TRUETYPE test is redundant
+     * but improves performance for the most common fonts.
+     */
+    scaled_font->is_type1 = FALSE;
+    if (!(metrics.tmPitchAndFamily & TMPF_TRUETYPE) &&
+	(metrics.tmPitchAndFamily & TMPF_VECTOR))
+    {
+	 if ((GetFontData (hdc, CMAP_TAG, 0, NULL, 0) == GDI_ERROR) &&
+	     (GetFontData (hdc, 0, 0, NULL, 0) != GDI_ERROR))
+	 {
+	      scaled_font->is_type1 = TRUE;
+	 }
+    }
 
     _cairo_scaled_font_set_metrics (&scaled_font->base, &extents);
 
@@ -777,7 +891,7 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
     if (!hdc)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    if (!scaled_font->is_truetype) {
+    if (scaled_font->is_bitmap) {
 	/* GetGlyphOutline will not work. Assume that the glyph does not extend outside the font box. */
 	cairo_font_extents_t font_extents;
 	INT width = 0;
@@ -890,7 +1004,6 @@ _cairo_win32_scaled_font_glyph_bbox (void		 *abstract_font,
 	GLYPHMETRICS metrics;
 	cairo_status_t status;
 	int i;
-        UINT glyph_index_option;
 
 	if (!hdc)
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -899,16 +1012,11 @@ _cairo_win32_scaled_font_glyph_bbox (void		 *abstract_font,
 	if (status)
 	    return status;
 
-        if (scaled_font->glyph_indexing)
-            glyph_index_option = GGO_GLYPH_INDEX;
-        else
-            glyph_index_option = 0;
-
 	for (i = 0; i < num_glyphs; i++) {
 	    int x = _cairo_lround (glyphs[i].x);
 	    int y = _cairo_lround (glyphs[i].y);
 
-	    GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | glyph_index_option,
+	    GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX,
 			     &metrics, 0, NULL, &matrix);
 
 	    if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x)
@@ -964,22 +1072,16 @@ _flush_glyphs (cairo_glyph_state_t *state)
     int dx = 0;
     WCHAR * elements;
     int * dx_elements;
-    UINT glyph_index_option;
 
     status = _cairo_array_append (&state->dx, &dx);
     if (status)
 	return status;
 
-    if (state->scaled_font->glyph_indexing)
-        glyph_index_option = ETO_GLYPH_INDEX;
-    else
-        glyph_index_option = 0;
-
     elements = _cairo_array_index (&state->glyphs, 0);
     dx_elements = _cairo_array_index (&state->dx, 0);
     if (!ExtTextOutW (state->hdc,
 		      state->start_x, state->last_y,
-		      glyph_index_option,
+		      ETO_GLYPH_INDEX,
 		      NULL,
 		      elements,
 		      state->glyphs.num_elements,
@@ -1330,18 +1432,97 @@ _cairo_win32_scaled_font_load_truetype_table (void	       *abstract_font,
 
 static cairo_int_status_t
 _cairo_win32_scaled_font_map_glyphs_to_unicode (void *abstract_font,
-                                                      cairo_scaled_font_subset_t *font_subset)
+						cairo_scaled_font_subset_t *font_subset)
 {
     cairo_win32_scaled_font_t *scaled_font = abstract_font;
-    unsigned int i;
+    GLYPHSET *glyph_set;
+    uint16_t *utf16 = NULL;
+    WORD *glyph_indices = NULL;
+    HDC hdc = NULL;
+    int res;
+    unsigned int i, j, k, count, num_glyphs;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
-    if (scaled_font->glyph_indexing)
-        return CAIRO_STATUS_SUCCESS; /* XXX ? */
+    hdc = _get_global_font_dc ();
+    if (!hdc)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    for (i = 0; i < font_subset->num_glyphs; i++)
-        font_subset->to_unicode[i] = font_subset->glyphs[i];
+    status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
+    if (status)
+	return status;
 
-    return CAIRO_STATUS_SUCCESS;
+    res = GetFontUnicodeRanges(hdc, NULL);
+    if (res == 0) {
+	status = _cairo_win32_print_gdi_error (
+	    "_cairo_win32_scaled_font_map_glyphs_to_unicode:GetFontUnicodeRanges");
+	goto fail1;
+    }
+
+    glyph_set = malloc (res);
+    if (glyph_set == NULL) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto fail1;
+    }
+
+    res = GetFontUnicodeRanges(hdc, glyph_set);
+    if (res == 0) {
+	status = _cairo_win32_print_gdi_error (
+	    "_cairo_win32_scaled_font_map_glyphs_to_unicode:GetFontUnicodeRanges");
+	goto fail2;
+    }
+
+    count = font_subset->num_glyphs;
+    for (i = 0; i < glyph_set->cRanges && count > 0; i++) {
+	num_glyphs = glyph_set->ranges[i].cGlyphs;
+
+	utf16 = _cairo_malloc_ab (num_glyphs + 1, sizeof (uint16_t));
+	if (utf16 == NULL) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto fail2;
+	}
+
+	glyph_indices = _cairo_malloc_ab (num_glyphs + 1, sizeof (WORD));
+	if (glyph_indices == NULL) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto fail2;
+	}
+
+	for (j = 0; j < num_glyphs; j++)
+	    utf16[j] = glyph_set->ranges[i].wcLow + j;
+	utf16[j] = 0;
+
+	if (GetGlyphIndicesW (hdc, utf16, num_glyphs, glyph_indices, 0) == GDI_ERROR) {
+	    status = _cairo_win32_print_gdi_error (
+		"_cairo_win32_scaled_font_map_glyphs_to_unicode:GetGlyphIndicesW");
+	    goto fail2;
+	}
+
+	for (j = 0; j < num_glyphs; j++) {
+	    for (k = 0; k < font_subset->num_glyphs; k++) {
+		if (font_subset->glyphs[k] == glyph_indices[j]) {
+		    font_subset->to_unicode[k] = utf16[j];
+		    count--;
+		    break;
+		}
+	    }
+	}
+
+	free (glyph_indices);
+	glyph_indices = NULL;
+	free (utf16);
+	utf16= NULL;
+    }
+
+fail2:
+    if (glyph_indices)
+	free (glyph_indices);
+    if (utf16)
+	free (utf16);
+    free (glyph_set);
+fail1:
+    cairo_win32_scaled_font_done_font (&scaled_font->base);
+
+    return status;
 }
 
 static cairo_status_t
@@ -1413,7 +1594,6 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
     cairo_path_fixed_t *path;
     cairo_matrix_t transform;
     cairo_fixed_t x, y;
-    UINT glyph_index_option;
 
     if (scaled_font->is_bitmap)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1437,13 +1617,8 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
     if (status)
         goto CLEANUP_PATH;
 
-    if (scaled_font->glyph_indexing)
-        glyph_index_option = GGO_GLYPH_INDEX;
-    else
-        glyph_index_option = 0;
-
     bytesGlyph = GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
-				   GGO_NATIVE | glyph_index_option,
+				   GGO_NATIVE | GGO_GLYPH_INDEX,
 				   &metrics, 0, NULL, &matrix);
 
     if (bytesGlyph == GDI_ERROR) {
@@ -1459,7 +1634,7 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
     }
 
     if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph),
-			  GGO_NATIVE | glyph_index_option,
+			  GGO_NATIVE | GGO_GLYPH_INDEX,
 			  &metrics, bytesGlyph, buffer, &matrix) == GDI_ERROR) {
 	status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path");
 	goto CLEANUP_BUFFER;


More information about the cairo-commit mailing list