[cairo-commit] 2 commits - src/cairo-atsui-font.c src/cairo-ft-font.c src/cairoint.h src/cairo-pdf-surface.c src/cairo-scaled-font-subsets.c src/cairo-scaled-font-subsets-private.h src/cairo-truetype-subset.c src/cairo-truetype-subset-private.h src/cairo-win32-font.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Wed Feb 7 04:56:04 PST 2007


 src/cairo-atsui-font.c                  |    2 
 src/cairo-ft-font.c                     |   33 ++++++
 src/cairo-pdf-surface.c                 |  146 ++++++++++++++++++++++++----
 src/cairo-scaled-font-subsets-private.h |   35 +++---
 src/cairo-scaled-font-subsets.c         |   13 ++
 src/cairo-truetype-subset-private.h     |   23 ++++
 src/cairo-truetype-subset.c             |  164 ++++++++++++++++++++++++++++++--
 src/cairo-win32-font.c                  |   17 +++
 src/cairoint.h                          |   18 +++
 9 files changed, 409 insertions(+), 42 deletions(-)

New commits:
diff-tree 2d1db24d1e7f3967b7ab498ce0ed29508c08a04b (from 274dfa4598bcb11b9f8330d23934a4ef1797fdbf)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Feb 7 23:10:47 2007 +1030

    PDF: Another fix for TrueType metrics
    
    Not all TrueType fonts have an em size of 2048.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 6ac6454..3e6aa58 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1966,7 +1966,7 @@ _cairo_pdf_surface_emit_type1_fallback_f
     return status;
 }
 
-#define GLYPH_TRUETYPE_TO_PDF  (1000.0/2048.0)
+#define PDF_UNITS_PER_EM 1000
 
 static cairo_status_t
 _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t		*surface,
@@ -2029,13 +2029,13 @@ _cairo_pdf_surface_emit_truetype_font_su
 				 "endobj\r\n",
 				 descriptor.id,
 				 subset.base_font,
-				 (long)(subset.x_min * GLYPH_TRUETYPE_TO_PDF),
-				 (long)(subset.y_min * GLYPH_TRUETYPE_TO_PDF),
-                                 (long)(subset.x_max * GLYPH_TRUETYPE_TO_PDF),
-				 (long)(subset.y_max * GLYPH_TRUETYPE_TO_PDF),
-				 (long)(subset.ascent * GLYPH_TRUETYPE_TO_PDF),
-				 (long)(subset.descent * GLYPH_TRUETYPE_TO_PDF),
-				 (long)(subset.y_max * GLYPH_TRUETYPE_TO_PDF),
+				 (long)(subset.x_min*PDF_UNITS_PER_EM),
+				 (long)(subset.y_min*PDF_UNITS_PER_EM),
+                                 (long)(subset.x_max*PDF_UNITS_PER_EM),
+				 (long)(subset.y_max*PDF_UNITS_PER_EM),
+				 (long)(subset.ascent*PDF_UNITS_PER_EM),
+				 (long)(subset.descent*PDF_UNITS_PER_EM),
+				 (long)(subset.y_max*PDF_UNITS_PER_EM),
 				 stream.id);
 
     encoding = _cairo_pdf_surface_new_object (surface);
@@ -2072,8 +2072,8 @@ _cairo_pdf_surface_emit_truetype_font_su
 
     for (i = 0; i < font_subset->num_glyphs; i++)
 	_cairo_output_stream_printf (surface->output,
-				     " %d",
-				     (int)(subset.widths[i] * GLYPH_TRUETYPE_TO_PDF));
+				     " %ld",
+				     (long)(subset.widths[i]*PDF_UNITS_PER_EM));
 
     _cairo_output_stream_printf (surface->output,
 				 " ]\r\n");
diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h
index 91148b3..88dbfbb 100644
--- a/src/cairo-scaled-font-subsets-private.h
+++ b/src/cairo-scaled-font-subsets-private.h
@@ -210,9 +210,9 @@ _cairo_cff_subset_fini (cairo_cff_subset
 
 typedef struct _cairo_truetype_subset {
     char *base_font;
-    int *widths;
-    long x_min, y_min, x_max, y_max;
-    long ascent, descent;
+    double *widths;
+    double x_min, y_min, x_max, y_max;
+    double ascent, descent;
     char *data;
     unsigned long data_length;
     unsigned long *string_offsets;
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c
index a7705c0..46e26be 100644
--- a/src/cairo-truetype-subset.c
+++ b/src/cairo-truetype-subset.c
@@ -56,6 +56,7 @@ typedef struct _cairo_truetype_font {
 	int *widths;
 	long x_min, y_min, x_max, y_max;
 	long ascent, descent;
+        int  units_per_em;
     } base;
 
     subset_glyph_t *glyphs;
@@ -202,6 +203,9 @@ _cairo_truetype_font_create (cairo_scale
     font->base.y_max = (int16_t) be16_to_cpu (head.y_max);
     font->base.ascent = (int16_t) be16_to_cpu (hhea.ascender);
     font->base.descent = (int16_t) be16_to_cpu (hhea.descender);
+    font->base.units_per_em = (int16_t) be16_to_cpu (head.units_per_em);
+    if (font->base.units_per_em == 0)
+        font->base.units_per_em = 2048;
 
     /* Extract the font name from the name table. At present this
      * just looks for the Mac platform/Roman encoded font name. It
@@ -845,19 +849,19 @@ _cairo_truetype_subset_init (cairo_truet
      * the glyphs in font_subset. The notdef glyph at index 0
      * and any subglyphs appended after font_subset->num_glyphs
      * are omitted. */
-    truetype_subset->widths = calloc (sizeof (int),
+    truetype_subset->widths = calloc (sizeof (double),
                                       font->scaled_font_subset->num_glyphs);
     if (truetype_subset->widths == NULL)
 	goto fail2;
     for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
-	truetype_subset->widths[i] = font->base.widths[i + 1];
+	truetype_subset->widths[i] = (double)font->base.widths[i + 1]/font->base.units_per_em;
 
-    truetype_subset->x_min = font->base.x_min;
-    truetype_subset->y_min = font->base.y_min;
-    truetype_subset->x_max = font->base.x_max;
-    truetype_subset->y_max = font->base.y_max;
-    truetype_subset->ascent = font->base.ascent;
-    truetype_subset->descent = font->base.descent;
+    truetype_subset->x_min = (double)font->base.x_min/font->base.units_per_em;
+    truetype_subset->y_min = (double)font->base.y_min/font->base.units_per_em;
+    truetype_subset->x_max = (double)font->base.x_max/font->base.units_per_em;
+    truetype_subset->y_max = (double)font->base.y_max/font->base.units_per_em;
+    truetype_subset->ascent = (double)font->base.ascent/font->base.units_per_em;
+    truetype_subset->descent = (double)font->base.descent/font->base.units_per_em;
 
     truetype_subset->data = malloc (length);
     if (truetype_subset->data == NULL)
diff-tree 274dfa4598bcb11b9f8330d23934a4ef1797fdbf (from 97a2522e0bbe8464028b9b42c79e0b3559b532be)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Feb 7 22:35:59 2007 +1030

    PDF: Make text selection and extraction work
    
    - Add a to_unicode array to the scaled_font_subsets
      for mapping glyphs to unicode characters
    
    - Add a function to the TrueType subsetting for
      performing a reverse cmap for mapping glyph indices
      to unicode characters.
    
    - Add a new scaled font backend function for mapping
      glyph indices to unicode characters. Provide FreeType
      and Win32 implementations of the font backend mapping
      function.
    
    - Modify the PDF backend to embed ToUnicode streams
      into each font. The unicode mapping is obtained by
      first trying the reverse cmap. If this fails the font
      backend mapping function is called.

diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index 4841eaa..94f431b 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -1088,5 +1088,7 @@ const cairo_scaled_font_backend_t cairo_
     _cairo_atsui_font_text_to_glyphs,
     NULL, /* ucs4_to_index */
     _cairo_atsui_font_old_show_glyphs,
+    NULL, /* load_truetype_table */
+    NULL, /* map_glyphs_to_unicode */
 };
 
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 57e3853..4d66274 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -2013,6 +2013,38 @@ _cairo_ft_load_truetype_table (void	    
     return status;
 }
 
+static void
+_cairo_ft_map_glyphs_to_unicode (void	                    *abstract_font,
+                                 cairo_scaled_font_subset_t *font_subset)
+{
+    cairo_ft_scaled_font_t *scaled_font = abstract_font;
+    cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
+    FT_Face face;
+    FT_UInt glyph;
+    unsigned long charcode;
+    unsigned int i;
+    int count;
+
+    face = _cairo_ft_unscaled_font_lock_face (unscaled);
+    if (!face)
+	return;
+
+    count = font_subset->num_glyphs;
+    charcode = FT_Get_First_Char( face, &glyph);
+    while (glyph != 0 && count > 0)
+    {
+        for (i = 0; i < font_subset->num_glyphs; i++) {
+            if (font_subset->glyphs[i] == glyph) {
+                font_subset->to_unicode[i] = charcode;
+                count--;
+                break;
+            }
+        }
+        charcode = FT_Get_Next_Char(face, charcode, &glyph);
+    }
+    _cairo_ft_unscaled_font_unlock_face (unscaled);
+}
+
 const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
     CAIRO_FONT_TYPE_FT,
     _cairo_ft_scaled_font_create_toy,
@@ -2022,6 +2054,7 @@ const cairo_scaled_font_backend_t cairo_
     _cairo_ft_ucs4_to_index,
     NULL, 			/* show_glyphs */
     _cairo_ft_load_truetype_table,
+    _cairo_ft_map_glyphs_to_unicode,
 };
 
 /* cairo_ft_font_face_t */
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 93face3..6ac6454 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1629,11 +1629,87 @@ _cairo_pdf_surface_write_pages (cairo_pd
 				 "endobj\r\n");
 }
 
+static cairo_pdf_resource_t
+_cairo_pdf_surface_emit_toUnicode_stream (cairo_pdf_surface_t		*surface,
+                                          cairo_scaled_font_subset_t	*font_subset)
+{
+    const cairo_scaled_font_backend_t *backend;
+    cairo_pdf_resource_t stream;
+    unsigned int i;
+
+    if (font_subset->to_unicode == NULL) {
+        stream.id = 0;
+        return stream;
+    }
+
+    if (_cairo_truetype_create_glyph_to_unicode_map (font_subset) != CAIRO_STATUS_SUCCESS) {
+        backend = font_subset->scaled_font->backend;
+        if (backend->map_glyphs_to_unicode == NULL) {
+            stream.id = 0;
+            return stream;
+        }
+        backend->map_glyphs_to_unicode (font_subset->scaled_font, font_subset);
+    }
+
+    stream = _cairo_pdf_surface_open_stream (surface, FALSE, NULL);
+    _cairo_output_stream_printf (surface->output,
+                                 "/CIDInit /ProcSet findresource begin\r\n"
+                                 "12 dict begin\r\n"
+                                 "begincmap\r\n"
+                                 "/CIDSystemInfo\r\n"
+                                 "<< /Registry (Adobe)\r\n"
+                                 "   /Ordering (UCS)\r\n"
+                                 "   /Supplement 0\r\n"
+                                 ">> def\r\n"
+                                 "/CMapName /Adobe-Identity-UCS def\r\n"
+                                 "/CMapType 2 def\r\n"
+                                 "1 begincodespacerange\r\n"
+                                 "<00> <ff>\r\n"
+                                 "endcodespacerange\r\n",
+                                 stream.id);
+
+    /* The CMap specification has a limit of 100 characters per beginbfchar operator */
+    _cairo_output_stream_printf (surface->output,
+                                 "%d beginbfchar\r\n",
+                                 font_subset->num_glyphs > 100 ? 100 : font_subset->num_glyphs);
+    for (i = 0; i < font_subset->num_glyphs; i++) {
+        if (i != 0 && i % 100 == 0) {
+            _cairo_output_stream_printf (surface->output,
+                                         "endbfchar\r\n"
+                                         "%d beginbfchar\r\n",
+                                         font_subset->num_glyphs - i > 100 ? 100 : font_subset->num_glyphs - i);
+        }
+        _cairo_output_stream_printf (surface->output,
+                                     "<%02x> <%04x>\r\n",
+                                     i, font_subset->to_unicode[i]);
+    }
+    _cairo_output_stream_printf (surface->output,
+                                 "endbfchar\r\n");
+
+    if (font_subset->num_glyphs < 256) {
+        _cairo_output_stream_printf (surface->output,
+                                     "1 beginnotdefrange\r\n"
+                                     "<%02x> <ff> 0\r\n"
+                                     "endnotdefrange\r\n",
+                                     font_subset->num_glyphs);
+    }
+
+    _cairo_output_stream_printf (surface->output,
+                                "endcmap\r\n"
+                                "CMapName currentdict /CMap defineresource pop\r\n"
+                                "end\r\n"
+                                 "end\r\n");
+
+    _cairo_pdf_surface_close_stream (surface);
+
+    return stream;
+}
+
 static cairo_status_t
 _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t		*surface,
                                          cairo_scaled_font_subset_t	*font_subset)
 {
-    cairo_pdf_resource_t stream, descriptor, subset_resource;
+    cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
     cairo_status_t status;
     cairo_pdf_font_t font;
     cairo_cff_subset_t subset;
@@ -1671,6 +1747,8 @@ _cairo_pdf_surface_emit_cff_font_subset 
 				 "endobj\r\n");
     free (compressed);
 
+    to_unicode_stream = _cairo_pdf_surface_emit_toUnicode_stream (surface, font_subset);
+
     descriptor = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
@@ -1718,7 +1796,14 @@ _cairo_pdf_surface_emit_cff_font_subset 
 				     subset.widths[i]);
 
     _cairo_output_stream_printf (surface->output,
-				 " ]\r\n"
+				 " ]\r\n");
+
+    if (to_unicode_stream.id != 0)
+        _cairo_output_stream_printf (surface->output,
+                                     "    /ToUnicode %d 0 R\r\n",
+                                     to_unicode_stream.id);
+
+    _cairo_output_stream_printf (surface->output,
 				 ">>\r\n"
 				 "endobj\r\n");
 
@@ -1737,7 +1822,7 @@ _cairo_pdf_surface_emit_type1_font (cair
                                     cairo_scaled_font_subset_t	*font_subset,
                                     cairo_type1_subset_t        *subset)
 {
-    cairo_pdf_resource_t stream, descriptor, subset_resource;
+    cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
     cairo_pdf_font_t font;
     unsigned long length, compressed_length;
     char *compressed;
@@ -1771,6 +1856,8 @@ _cairo_pdf_surface_emit_type1_font (cair
 				 "endobj\r\n");
     free (compressed);
 
+    to_unicode_stream = _cairo_pdf_surface_emit_toUnicode_stream (surface, font_subset);
+
     descriptor = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
@@ -1818,7 +1905,14 @@ _cairo_pdf_surface_emit_type1_font (cair
 				     subset->widths[i]);
 
     _cairo_output_stream_printf (surface->output,
-				 " ]\r\n"
+				 " ]\r\n");
+
+    if (to_unicode_stream.id != 0)
+        _cairo_output_stream_printf (surface->output,
+                                     "    /ToUnicode %d 0 R\r\n",
+                                     to_unicode_stream.id);
+
+    _cairo_output_stream_printf (surface->output,
 				 ">>\r\n"
 				 "endobj\r\n");
 
@@ -1878,7 +1972,7 @@ static cairo_status_t
 _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t		*surface,
 					      cairo_scaled_font_subset_t	*font_subset)
 {
-    cairo_pdf_resource_t stream, descriptor, encoding, subset_resource;
+    cairo_pdf_resource_t stream, descriptor, encoding, subset_resource, to_unicode_stream;
     cairo_status_t status;
     cairo_pdf_font_t font;
     cairo_truetype_subset_t subset;
@@ -1915,11 +2009,13 @@ _cairo_pdf_surface_emit_truetype_font_su
 				 "endobj\r\n");
     free (compressed);
 
+    to_unicode_stream = _cairo_pdf_surface_emit_toUnicode_stream (surface, font_subset);
+
     descriptor = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Type /FontDescriptor\r\n"
-				 "   /FontName /7%s\r\n"
+				 "   /FontName /%s\r\n"
 				 "   /Flags 4\r\n"
 				 "   /FontBBox [ %ld %ld %ld %ld ]\r\n"
 				 "   /ItalicAngle 0\r\n"
@@ -1980,7 +2076,14 @@ _cairo_pdf_surface_emit_truetype_font_su
 				     (int)(subset.widths[i] * GLYPH_TRUETYPE_TO_PDF));
 
     _cairo_output_stream_printf (surface->output,
-				 " ]\r\n"
+				 " ]\r\n");
+
+    if (to_unicode_stream.id != 0)
+        _cairo_output_stream_printf (surface->output,
+                                     "    /ToUnicode %d 0 R\r\n",
+                                     to_unicode_stream.id);
+
+    _cairo_output_stream_printf (surface->output,
 				 ">>\r\n"
 				 "endobj\r\n");
 
@@ -2138,7 +2241,7 @@ static cairo_status_t
 _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t		*surface,
 					   cairo_scaled_font_subset_t	*font_subset)
 {
-    cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource;
+    cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource, to_unicode_stream;
     cairo_pdf_font_t font;
     cairo_matrix_t matrix;
     unsigned int i;
@@ -2183,6 +2286,8 @@ _cairo_pdf_surface_emit_type3_font_subse
 
     free (glyphs);
 
+    to_unicode_stream = _cairo_pdf_surface_emit_toUnicode_stream (surface, font_subset);
+
     subset_resource = _cairo_pdf_surface_new_object (surface);
     matrix = font_subset->scaled_font->scale;
     cairo_matrix_invert (&matrix);
@@ -2212,6 +2317,11 @@ _cairo_pdf_surface_emit_type3_font_subse
     _cairo_output_stream_printf (surface->output,
 				 "]\r\n");
 
+    if (to_unicode_stream.id != 0)
+        _cairo_output_stream_printf (surface->output,
+                                     "    /ToUnicode %d 0 R\r\n",
+                                     to_unicode_stream.id);
+
     _cairo_output_stream_printf (surface->output,
 				 ">>\r\n"
 				 "endobj\r\n");
diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h
index 2c81fdc..91148b3 100644
--- a/src/cairo-scaled-font-subsets-private.h
+++ b/src/cairo-scaled-font-subsets-private.h
@@ -41,18 +41,6 @@
 
 typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t;
 
-typedef struct _cairo_scaled_font_subset {
-    cairo_scaled_font_t *scaled_font;
-    unsigned int font_id;
-    unsigned int subset_id;
-
-    /* Index of glyphs array is subset_glyph_index.
-     * Value of glyphs array is scaled_font_glyph_index.
-     */
-    unsigned long *glyphs;
-    unsigned int num_glyphs;
-} cairo_scaled_font_subset_t;
-
 /**
  * _cairo_scaled_font_subsets_create:
  * @max_glyphs_per_subset: the maximum number of glyphs that should
@@ -361,4 +349,21 @@ _cairo_type1_fallback_init_hex (cairo_ty
 cairo_private void
 _cairo_type1_fallback_fini (cairo_type1_subset_t *subset);
 
+/**
+ * _cairo_truetype_create_glyph_to_unicode_map:
+ * @font_subset: the #cairo_scaled_font_subset_t to initialize from
+ *
+ * If possible (depending on the format of the underlying
+ * cairo_scaled_font_t and the font backend in use) assign
+ * the unicode character of each glyph in font_subset to
+ * fontsubset->to_unicode.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if successful,
+ * CAIRO_INT_STATUS_UNSUPPORTED if the unicode encoding of
+ * the glyphs is not available.  Possible  errors include
+ * CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_private cairo_int_status_t
+_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t	*font_subset);
+
 #endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 0c428e7..68a662a 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -273,6 +273,7 @@ _cairo_sub_font_collect (void *entry, vo
     cairo_sub_font_collection_t *collection = closure;
     cairo_scaled_font_subset_t subset;
     int i;
+    unsigned int j;
 
     for (i = 0; i <= sub_font->current_subset; i++) {
 	collection->subset_id = i;
@@ -291,9 +292,19 @@ _cairo_sub_font_collect (void *entry, vo
 	subset.subset_id = i;
 	subset.glyphs = collection->glyphs;
 	subset.num_glyphs = collection->num_glyphs;
+        /* No need to check for out of memory here. If to_unicode is NULL, the PDF
+         * surface does not emit an ToUnicode stream */
+        subset.to_unicode = malloc (collection->num_glyphs*sizeof(unsigned long));
+        for (j = 0; j < collection->num_glyphs; j++) {
+            /* default unicode character required when mapping fails */
+            subset.to_unicode[j] = 0xfffd;
+        }
 
-	(collection->font_subset_callback) (&subset,
+        (collection->font_subset_callback) (&subset,
 					    collection->font_subset_callback_closure);
+
+        if (subset.to_unicode != NULL)
+            free (subset.to_unicode);
     }
 }
 
diff --git a/src/cairo-truetype-subset-private.h b/src/cairo-truetype-subset-private.h
index e9b2c47..80baa28 100644
--- a/src/cairo-truetype-subset-private.h
+++ b/src/cairo-truetype-subset-private.h
@@ -65,6 +65,29 @@
 #define TT_TAG_prep   MAKE_TT_TAG('p','r','e','p')
 
 /* All tt_* structs are big-endian */
+typedef struct _tt_cmap_index {
+    uint16_t platform;
+    uint16_t encoding;
+    uint32_t offset;
+} tt_cmap_index_t;
+
+typedef struct _tt_cmap {
+    uint16_t        version;
+    uint16_t        num_tables;
+    tt_cmap_index_t index[];
+} tt_cmap_t;
+
+typedef struct _segment_map {
+    uint16_t format;
+    uint16_t length;
+    uint16_t version;
+    uint16_t segCountX2;
+    uint16_t searchRange;
+    uint16_t entrySelector;
+    uint16_t rangeShift;
+    uint16_t endCount[];
+} tt_segment_map_t;
+
 typedef struct _tt_head {
     int16_t     version_1;
     int16_t     version_2;
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c
index de878e8..a7705c0 100644
--- a/src/cairo-truetype-subset.c
+++ b/src/cairo-truetype-subset.c
@@ -114,6 +114,8 @@ be32_to_cpu(uint32_t v)
 
 #endif
 
+
+
 static cairo_status_t
 _cairo_truetype_font_create (cairo_scaled_font_subset_t  *scaled_font_subset,
 			     cairo_truetype_font_t      **font_return)
@@ -897,3 +899,145 @@ _cairo_truetype_subset_fini (cairo_truet
     free (subset->string_offsets);
 }
 
+static cairo_int_status_t
+_cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset,
+                                       unsigned long               table_offset)
+{
+    cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+    const cairo_scaled_font_backend_t *backend;
+    tt_segment_map_t *map;
+    char buf[4];
+    unsigned int num_segments, i, j;
+    unsigned long size;
+    uint16_t *start_code;
+    uint16_t *end_code;
+    uint16_t *delta;
+    uint16_t *range_offset;
+    uint16_t *glyph_array;
+    uint16_t  g_id, c;
+
+    backend = font_subset->scaled_font->backend;
+    size = 4;
+    if (backend->load_truetype_table (font_subset->scaled_font,
+                                      TT_TAG_cmap, table_offset,
+                                      (unsigned char *) &buf,
+                                      &size) != CAIRO_STATUS_SUCCESS) {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    /* All table formats have the same first two words */
+    map = (tt_segment_map_t *) buf;
+    if (be16_to_cpu (map->format) != 4)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    size = be16_to_cpu (map->length);
+    map = malloc (size);
+    if (map == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+    if (backend->load_truetype_table (font_subset->scaled_font,
+                                      TT_TAG_cmap, table_offset,
+                                      (unsigned char *) map,
+                                      &size) != CAIRO_STATUS_SUCCESS) {
+	goto fail;
+    }
+
+    num_segments = be16_to_cpu (map->segCountX2)/2;
+    end_code = map->endCount;
+    start_code = &(end_code[num_segments + 1]);
+    delta = &(start_code[num_segments]);
+    range_offset = &(delta[num_segments]);
+    glyph_array = &(range_offset[num_segments]);
+
+    i = 0;
+    while (i < font_subset->num_glyphs) {
+        g_id = (uint16_t) font_subset->glyphs[i];
+
+        /* search for glyph in segments
+         * with rangeOffset=0 */
+        for (j = 0; j < num_segments; j++) {
+            c = g_id - be16_to_cpu (delta[j]);
+            if (range_offset[j] == 0 &&
+                c >= be16_to_cpu (start_code[j]) &&
+                c <= be16_to_cpu (end_code[j]))
+            {
+                font_subset->to_unicode[i] = c;
+                goto next_glyph;
+            }
+        }
+
+        /* search for glyph in segments with rangeOffset=1 */
+        for (j = 0; j < num_segments; j++) {
+            if (range_offset[j] != 0) {
+                uint16_t *glyph_ids = &range_offset[j] + be16_to_cpu (range_offset[j])/2;
+                int range_size = be16_to_cpu (end_code[j]) - be16_to_cpu (start_code[j]) + 1;
+                uint16_t g_id_be = cpu_to_be16 (g_id);
+                int k;
+
+                for (k = 0; k < range_size; k++) {
+                    if (glyph_ids[k] == g_id_be) {
+                        font_subset->to_unicode[i] = be16_to_cpu (start_code[j]) + k;
+                        goto next_glyph;
+                    }
+                }
+            }
+        }
+
+    next_glyph:
+        i++;
+    }
+    status = CAIRO_STATUS_SUCCESS;
+fail:
+    free (map);
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t	*font_subset)
+{
+    cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
+    const cairo_scaled_font_backend_t *backend;
+    tt_cmap_t *cmap;
+    char buf[4];
+    int num_tables, i;
+    unsigned long size;
+
+    backend = font_subset->scaled_font->backend;
+    if (!backend->load_truetype_table)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    size = 4;
+    if (backend->load_truetype_table (font_subset->scaled_font,
+                                      TT_TAG_cmap, 0, (unsigned char *) &buf,
+                                      &size) != CAIRO_STATUS_SUCCESS)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    cmap = (tt_cmap_t *) buf;
+    num_tables = be16_to_cpu (cmap->num_tables);
+    size = 4 + num_tables*sizeof(tt_cmap_index_t);
+    cmap = malloc (size);
+    if (cmap == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+    if (backend->load_truetype_table (font_subset->scaled_font,
+                                      TT_TAG_cmap, 0, (unsigned char *) cmap,
+                                      &size) != CAIRO_STATUS_SUCCESS) {
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+        goto cleanup;
+    }
+
+    /* Find a table with Unicode mapping */
+    for (i = 0; i < num_tables; i++) {
+        if (be16_to_cpu (cmap->index[i].platform) == 3 &&
+            be16_to_cpu (cmap->index[i].encoding) == 1) {
+            status = _cairo_truetype_map_glyphs_to_unicode (font_subset,
+                                                            be32_to_cpu (cmap->index[i].offset));
+            if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+                goto cleanup;
+        }
+    }
+
+cleanup:
+    free (cmap);
+
+    return status;
+}
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 139a73b..e1f5e2c 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -1281,6 +1281,22 @@ _cairo_win32_scaled_font_load_truetype_t
     return status;
 }
 
+static cairo_int_status_t
+_cairo_win32_scaled_font_map_glyphs_to_unicode (void *abstract_font,
+                                                      cairo_scaled_font_subset_t *font_subset)
+{
+    cairo_win32_scaled_font_t *scaled_font = abstract_font;
+    unsigned int i;
+
+    if (scaled_font->glyph_indexing)
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    for (i = 0; i < font_subset->num_glyphs; i++)
+        font_subset->to_unicode[i] = font_subset->glyphs[i];
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static void
 _cairo_win32_transform_FIXED_to_fixed (cairo_matrix_t *matrix,
                                        FIXED Fx, FIXED Fy,
@@ -1467,6 +1483,7 @@ const cairo_scaled_font_backend_t cairo_
     NULL,			/* ucs4_to_index */
     _cairo_win32_scaled_font_show_glyphs,
     _cairo_win32_scaled_font_load_truetype_table,
+    _cairo_win32_scaled_font_map_glyphs_to_unicode,
 };
 
 /* cairo_win32_font_face_t */
diff --git a/src/cairoint.h b/src/cairoint.h
index 5b6120f..c8949f4 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -651,6 +651,19 @@ typedef enum _cairo_scaled_glyph_info {
     CAIRO_SCALED_GLYPH_INFO_PATH	= (1 << 2)
 } cairo_scaled_glyph_info_t;
 
+typedef struct _cairo_scaled_font_subset {
+    cairo_scaled_font_t *scaled_font;
+    unsigned int font_id;
+    unsigned int subset_id;
+
+    /* Index of glyphs array is subset_glyph_index.
+     * Value of glyphs array is scaled_font_glyph_index.
+     */
+    unsigned long *glyphs;
+    unsigned long *to_unicode;
+    unsigned int num_glyphs;
+} cairo_scaled_font_subset_t;
+
 struct _cairo_scaled_font_backend {
     cairo_font_type_t type;
 
@@ -704,6 +717,11 @@ struct _cairo_scaled_font_backend {
                            long                  offset,
                            unsigned char        *buffer,
                            unsigned long        *length);
+
+    void
+    (*map_glyphs_to_unicode)(void                       *scaled_font,
+                                   cairo_scaled_font_subset_t *font_subset);
+
 };
 
 struct _cairo_font_face_backend {


More information about the cairo-commit mailing list