[cairo-commit] 7 commits - src/cairo-cff-subset.c src/cairoint.h src/cairo-output-stream.c src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-scaled-font-subsets.c src/cairo-scaled-font-subsets-private.h src/cairo-svg-surface.c src/cairo-truetype-subset.c src/cairo-type1-fallback.c src/cairo-type1-subset.c

Adrian Johnson ajohnson at kemper.freedesktop.org
Fri Apr 20 08:28:40 PDT 2007


 src/cairo-cff-subset.c                  | 1075 ++++++++++++++++++++++----------
 src/cairo-output-stream.c               |   27 
 src/cairo-pdf-surface.c                 |  312 +++++----
 src/cairo-ps-surface.c                  |   13 
 src/cairo-scaled-font-subsets-private.h |  138 +++-
 src/cairo-scaled-font-subsets.c         |  188 +++--
 src/cairo-svg-surface.c                 |    2 
 src/cairo-truetype-subset.c             |   21 
 src/cairo-type1-fallback.c              |  215 ++++--
 src/cairo-type1-subset.c                |   30 
 src/cairoint.h                          |    1 
 11 files changed, 1424 insertions(+), 598 deletions(-)

New commits:
diff-tree fc455c53ecb0aa496915b1eae68dc0275af78e09 (from 9d8eb42c013d197b3365af88e372d1c2c1617173)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Apr 21 00:26:25 2007 +0930

    Ensure _cairo_scaled_font_subsets_map_glyph() returns correct values
    
    The CID font subsetting exposed a bug where the subset_glyph->is_scaled
    return argument of _cairo_scaled_font_subsets_map_glyph() is sometimes
    not assigned a value.

diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index b0521e3..fa5a8b4 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -265,11 +265,9 @@ _cairo_sub_font_pluck (void *entry, void
 }
 
 static cairo_status_t
-_cairo_sub_font_lookup_glyph (cairo_sub_font_t	*sub_font,
-                              unsigned long	 scaled_font_glyph_index,
-                              unsigned int	*subset_id,
-                              unsigned int	*subset_glyph_index,
-                              double            *x_advance)
+_cairo_sub_font_lookup_glyph (cairo_sub_font_t	                *sub_font,
+                              unsigned long	                 scaled_font_glyph_index,
+                              cairo_scaled_font_subsets_glyph_t *subset_glyph)
 {
     cairo_sub_font_glyph_t key, *sub_font_glyph;
 
@@ -277,9 +275,12 @@ _cairo_sub_font_lookup_glyph (cairo_sub_
     if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
 				    (cairo_hash_entry_t **) &sub_font_glyph))
     {
-        *subset_id = sub_font_glyph->subset_id;
-        *subset_glyph_index = sub_font_glyph->subset_glyph_index;
-        *x_advance = sub_font_glyph->x_advance;
+        subset_glyph->font_id = sub_font->font_id;
+        subset_glyph->subset_id = sub_font_glyph->subset_id;
+        subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
+        subset_glyph->is_scaled = sub_font->is_scaled;
+        subset_glyph->is_composite = sub_font->is_composite;
+        subset_glyph->x_advance = sub_font_glyph->x_advance;
 
         return CAIRO_STATUS_SUCCESS;
     }
@@ -290,9 +291,7 @@ _cairo_sub_font_lookup_glyph (cairo_sub_
 static cairo_status_t
 _cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
 			   unsigned long	 scaled_font_glyph_index,
-			   unsigned int		*subset_id,
-			   unsigned int		*subset_glyph_index,
-                           double               *x_advance)
+                           cairo_scaled_font_subsets_glyph_t *subset_glyph)
 {
     cairo_sub_font_glyph_t key, *sub_font_glyph;
     cairo_status_t status;
@@ -343,9 +342,12 @@ _cairo_sub_font_map_glyph (cairo_sub_fon
 	    return status;
     }
 
-    *subset_id = sub_font_glyph->subset_id;
-    *subset_glyph_index = sub_font_glyph->subset_glyph_index;
-    *x_advance = sub_font_glyph->x_advance;
+    subset_glyph->font_id = sub_font->font_id;
+    subset_glyph->subset_id = sub_font_glyph->subset_id;
+    subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
+    subset_glyph->is_scaled = sub_font->is_scaled;
+    subset_glyph->is_composite = sub_font->is_composite;
+    subset_glyph->x_advance = sub_font_glyph->x_advance;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -485,15 +487,9 @@ _cairo_scaled_font_subsets_map_glyph (ca
         {
             status = _cairo_sub_font_lookup_glyph (sub_font,
                                                    scaled_font_glyph_index,
-                                                   &subset_glyph->subset_id,
-                                                   &subset_glyph->subset_glyph_index,
-                                                   &subset_glyph->x_advance);
-            if (status == CAIRO_STATUS_SUCCESS) {
-                subset_glyph->font_id = sub_font->font_id;
-                subset_glyph->is_scaled = FALSE;
-                subset_glyph->is_composite = sub_font->is_composite;
+                                                   subset_glyph);
+            if (status == CAIRO_STATUS_SUCCESS)
                 return CAIRO_STATUS_SUCCESS;
-            }
         }
     }
 
@@ -505,15 +501,9 @@ _cairo_scaled_font_subsets_map_glyph (ca
     {
         status = _cairo_sub_font_lookup_glyph (sub_font,
                                                scaled_font_glyph_index,
-                                               &subset_glyph->subset_id,
-                                               &subset_glyph->subset_glyph_index,
-                                               &subset_glyph->x_advance);
-        if (status == CAIRO_STATUS_SUCCESS) {
-            subset_glyph->font_id = sub_font->font_id;
-            subset_glyph->is_scaled = TRUE;
-            subset_glyph->is_composite = sub_font->is_composite;
+                                               subset_glyph);
+        if (status == CAIRO_STATUS_SUCCESS)
             return CAIRO_STATUS_SUCCESS;
-        }
     }
 
     /* Glyph not found. Determine whether the glyph is outline or
@@ -598,13 +588,10 @@ _cairo_scaled_font_subsets_map_glyph (ca
                 return status;
         }
     }
-    subset_glyph->font_id = sub_font->font_id;
 
     return _cairo_sub_font_map_glyph (sub_font,
                                       scaled_font_glyph_index,
-                                      &subset_glyph->subset_id,
-                                      &subset_glyph->subset_glyph_index,
-                                      &subset_glyph->x_advance);
+                                      subset_glyph);
 }
 
 static cairo_status_t
diff-tree 9d8eb42c013d197b3365af88e372d1c2c1617173 (from 56ad56263b86a9678387fe8dd994e77c183c6328)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Fri Apr 20 22:45:12 2007 +0930

    Exclude Type1 fonts from CID subsets
    
    Make cairo-scaled-font-subsets.c limit Type1 font subsets to
    256 glyphs. This allows Type1 subsetting to be enabled again
    with type1-fallback as the fallback option for Type1 fonts.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b2128d0..f4e6f90 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2493,31 +2493,29 @@ _cairo_pdf_surface_emit_unscaled_font_su
     cairo_pdf_surface_t *surface = closure;
     cairo_status_t status;
 
-    status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return;
-
+    if (font_subset->is_composite) {
+        status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
+        if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+            return;
+
+        status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
+        if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+            return;
+
+        status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset);
+        if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+            return;
+    } else {
 #if CAIRO_HAS_FT_FONT
-#if 0
-    status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return;
-#endif
+        status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
+        if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+            return;
 #endif
 
-    status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return;
-
-    status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return;
-
-#if 0
-    status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
-    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-	return;
-#endif
+        status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
+        if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+            return;
+    }
 }
 
 static void
diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h
index 03076c8..e4e320c 100644
--- a/src/cairo-scaled-font-subsets-private.h
+++ b/src/cairo-scaled-font-subsets-private.h
@@ -97,7 +97,7 @@ _cairo_scaled_font_subsets_create_simple
  *
  * Glyphs with an outline path available will be mapped to one font
  * subset for each font face. Each unscaled subset has a maximum of
- * 65536 glyphs.
+ * 65536 glyphs except for Type1 fonts which have a maximum of 256 glyphs.
  *
  * Glyphs from bitmap fonts will mapped to separate font subsets for
  * each cairo_scaled_font_t object. Each unscaled subset has a maximum
@@ -425,6 +425,15 @@ cairo_private void
 _cairo_type1_subset_fini (cairo_type1_subset_t *subset);
 
 /**
+ * _cairo_type1_scaled_font_is_type1:
+ * @scaled_font: a #cairo_scaled_font_t
+ *
+ * Return TRUE if @scaled_font is a Type 1 font, otherwise return FALSE.
+ **/
+cairo_private cairo_bool_t
+_cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t	*scaled_font);
+
+/**
  * _cairo_type1_fallback_init_binary:
  * @type1_subset: a #cairo_type1_subset_t to initialize
  * @font_subset: the #cairo_scaled_font_subset_t to initialize from
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 47260c8..b0521e3 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -67,6 +67,7 @@ typedef struct _cairo_sub_font {
     cairo_hash_entry_t base;
 
     cairo_bool_t is_scaled;
+    cairo_bool_t is_composite;
     cairo_scaled_font_subsets_t *parent;
     cairo_scaled_font_t *scaled_font;
     unsigned int font_id;
@@ -207,7 +208,8 @@ _cairo_sub_font_create (cairo_scaled_fon
 			cairo_scaled_font_t		*scaled_font,
 			unsigned int			 font_id,
 			int				 max_glyphs_per_subset,
-                        cairo_bool_t                     is_scaled)
+                        cairo_bool_t                     is_scaled,
+                        cairo_bool_t                     is_composite)
 {
     cairo_sub_font_t *sub_font;
 
@@ -216,6 +218,7 @@ _cairo_sub_font_create (cairo_scaled_fon
 	return NULL;
 
     sub_font->is_scaled = is_scaled;
+    sub_font->is_composite = is_composite;
     _cairo_sub_font_init_key (sub_font, scaled_font);
 
     sub_font->parent = parent;
@@ -376,6 +379,7 @@ _cairo_sub_font_collect (void *entry, vo
 	assert (collection->num_glyphs == collection->max_glyph + 1);
 
 	subset.scaled_font = sub_font->scaled_font;
+	subset.is_composite = sub_font->is_composite;
 	subset.font_id = sub_font->font_id;
 	subset.subset_id = i;
 	subset.glyphs = collection->glyphs;
@@ -470,6 +474,7 @@ _cairo_scaled_font_subsets_map_glyph (ca
     cairo_scaled_font_t	*unscaled_font;
     cairo_status_t status;
     int max_glyphs;
+    cairo_bool_t type1_font;
 
     /* Lookup glyph in unscaled subsets */
     if (subsets->type != CAIRO_SUBSETS_SCALED) {
@@ -486,6 +491,7 @@ _cairo_scaled_font_subsets_map_glyph (ca
             if (status == CAIRO_STATUS_SUCCESS) {
                 subset_glyph->font_id = sub_font->font_id;
                 subset_glyph->is_scaled = FALSE;
+                subset_glyph->is_composite = sub_font->is_composite;
                 return CAIRO_STATUS_SUCCESS;
             }
         }
@@ -505,6 +511,7 @@ _cairo_scaled_font_subsets_map_glyph (ca
         if (status == CAIRO_STATUS_SUCCESS) {
             subset_glyph->font_id = sub_font->font_id;
             subset_glyph->is_scaled = TRUE;
+            subset_glyph->is_composite = sub_font->is_composite;
             return CAIRO_STATUS_SUCCESS;
         }
     }
@@ -535,16 +542,25 @@ _cairo_scaled_font_subsets_map_glyph (ca
                                                       &identity,
                                                       &font_options);
 
-            if (subsets->type == CAIRO_SUBSETS_COMPOSITE)
+            subset_glyph->is_scaled = FALSE;
+            type1_font = FALSE;
+#if CAIRO_HAS_FT_FONT
+            type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
+#endif
+            if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
                 max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
-            else
+                subset_glyph->is_composite = TRUE;
+            } else {
                 max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
+                subset_glyph->is_composite = FALSE;
+            }
 
             sub_font = _cairo_sub_font_create (subsets,
                                                unscaled_font,
                                                subsets->num_sub_fonts++,
                                                max_glyphs,
-                                               FALSE);
+                                               subset_glyph->is_scaled,
+                                               subset_glyph->is_composite);
             if (sub_font == NULL)
                 return CAIRO_STATUS_NO_MEMORY;
 
@@ -553,11 +569,6 @@ _cairo_scaled_font_subsets_map_glyph (ca
             if (status)
                 return status;
         }
-        subset_glyph->is_scaled = FALSE;
-        if (subsets->type == CAIRO_SUBSETS_COMPOSITE)
-            subset_glyph->is_composite = TRUE;
-        else
-            subset_glyph->is_composite = FALSE;
     } else {
         /* No path available. Add to scaled subset. */
         key.is_scaled = TRUE;
@@ -565,6 +576,8 @@ _cairo_scaled_font_subsets_map_glyph (ca
         if (! _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
                                         (cairo_hash_entry_t **) &sub_font))
         {
+            subset_glyph->is_scaled = TRUE;
+            subset_glyph->is_composite = FALSE;
             if (subsets->type == CAIRO_SUBSETS_SCALED)
                 max_glyphs = INT_MAX;
             else
@@ -574,7 +587,8 @@ _cairo_scaled_font_subsets_map_glyph (ca
                                                cairo_scaled_font_reference (scaled_font),
                                                subsets->num_sub_fonts++,
                                                max_glyphs,
-                                               TRUE);
+                                               subset_glyph->is_scaled,
+                                               subset_glyph->is_composite);
             if (sub_font == NULL)
                 return CAIRO_STATUS_NO_MEMORY;
 
@@ -583,8 +597,6 @@ _cairo_scaled_font_subsets_map_glyph (ca
             if (status)
                 return status;
         }
-        subset_glyph->is_scaled = TRUE;
-        subset_glyph->is_composite = FALSE;
     }
     subset_glyph->font_id = sub_font->font_id;
 
diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index 40c212e..2b07dfe 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -1192,3 +1192,30 @@ _cairo_type1_subset_fini (cairo_type1_su
     free (subset->widths);
     free (subset->data);
 }
+
+cairo_bool_t
+_cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font)
+{
+    cairo_ft_unscaled_font_t *unscaled;
+    FT_Face face;
+    PS_FontInfoRec font_info;
+    cairo_bool_t is_type1 = FALSE;
+
+    unscaled = (cairo_ft_unscaled_font_t *) _cairo_ft_scaled_font_get_unscaled_font (scaled_font);
+    face = _cairo_ft_unscaled_font_lock_face (unscaled);
+    if (!face)
+        return FALSE;
+
+    if (FT_Get_PS_Font_Info(face, &font_info) == 0)
+        is_type1 = TRUE;
+
+    /* OpenType/CFF fonts also have a PS_FontInfoRec */
+#if HAVE_FT_LOAD_SFNT_TABLE
+    if (FT_IS_SFNT (face))
+        is_type1 = FALSE;
+#endif
+
+    _cairo_ft_unscaled_font_unlock_face (unscaled);
+
+    return is_type1;
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 76397e2..549cc51 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -640,6 +640,7 @@ typedef struct _cairo_scaled_font_subset
     unsigned long *glyphs;
     unsigned long *to_unicode;
     unsigned int num_glyphs;
+    cairo_bool_t is_composite;
 } cairo_scaled_font_subset_t;
 
 struct _cairo_scaled_font_backend {
diff-tree 56ad56263b86a9678387fe8dd994e77c183c6328 (from ca3662d6fc630e5390b3a8f8dbaa1d65aebc3fe8)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Fri Apr 20 22:44:04 2007 +0930

    Enable embedding of CID fonts in PDF
    
    Update cairo-pdf-surface.c to embed CFF and TrueType fonts
    as CID fonts. Update the ToUnicode CMap to handle CID fonts.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 7a164e0..b2128d0 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -277,7 +277,7 @@ _cairo_pdf_surface_create_for_stream_int
     _cairo_array_init (&surface->streams, sizeof (cairo_pdf_resource_t));
     _cairo_array_init (&surface->alphas, sizeof (double));
 
-    surface->font_subsets = _cairo_scaled_font_subsets_create_simple();
+    surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
     if (! surface->font_subsets) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	free (surface);
@@ -1681,11 +1681,12 @@ _cairo_pdf_surface_write_pages (cairo_pd
 
 static cairo_pdf_resource_t
 _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t		*surface,
-					   cairo_scaled_font_subset_t	*font_subset)
+					   cairo_scaled_font_subset_t	*font_subset,
+                                           cairo_bool_t                  is_composite)
 {
     const cairo_scaled_font_backend_t *backend;
     cairo_pdf_resource_t stream;
-    unsigned int i;
+    unsigned int i, num_bfchar;
     cairo_status_t status;
 
     if (font_subset->to_unicode == NULL) {
@@ -1708,50 +1709,54 @@ _cairo_pdf_surface_emit_to_unicode_strea
                                  "12 dict begin\r\n"
                                  "begincmap\r\n"
                                  "/CIDSystemInfo\r\n"
-                                 "<< /Registry (Cairo)\r\n"
-                                 "   /Ordering (ToUnicode-%d-%d)\r\n"
+                                 "<< /Registry (Adobe)\r\n"
+                                 "   /Ordering (UCS)\r\n"
                                  "   /Supplement 0\r\n"
                                  ">> def\r\n"
-                                 "/CMapName /Cairo-ToUnicode-%d-%d 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",
-                                 font_subset->font_id,
-                                 font_subset->subset_id,
-                                 font_subset->font_id,
-                                 font_subset->subset_id);
+                                 "1 begincodespacerange\r\n");
+
+    if (is_composite) {
+        _cairo_output_stream_printf (surface->output,
+                                     "<0000> <ffff>\r\n");
+    } else {
+        _cairo_output_stream_printf (surface->output,
+                                     "<00> <ff>\r\n");
+    }
+
+    _cairo_output_stream_printf (surface->output,
+                                  "endcodespacerange\r\n");
 
+    num_bfchar = font_subset->num_glyphs - 1;
     /* 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++) {
+                                 num_bfchar > 100 ? 100 : num_bfchar);
+    for (i = 0; i < num_bfchar; 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);
+                                         num_bfchar - i > 100 ? 100 : num_bfchar - i);
+        }
+        if (is_composite) {
+            _cairo_output_stream_printf (surface->output,
+                                         "<%04x> <%04x>\r\n",
+                                         i + 1, font_subset->to_unicode[i + 1]);
+        } else {
+            _cairo_output_stream_printf (surface->output,
+                                         "<%02x> <%04x>\r\n",
+                                         i + 1, font_subset->to_unicode[i + 1]);
         }
-        _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"
+                                 "endcmap\r\n"
+                                 "CMapName currentdict /CMap defineresource pop\r\n"
+                                 "end\r\n"
                                  "end\r\n");
 
     status = _cairo_pdf_surface_close_stream (surface);
@@ -1762,36 +1767,28 @@ _cairo_pdf_surface_emit_to_unicode_strea
 }
 
 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_surface_emit_cff_font (cairo_pdf_surface_t		*surface,
+                                  cairo_scaled_font_subset_t	*font_subset,
+                                  cairo_cff_subset_t            *subset)
 {
-    cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream;
-    cairo_status_t status;
+    cairo_pdf_resource_t stream, descriptor, cidfont_dict;
+    cairo_pdf_resource_t subset_resource, to_unicode_stream;
     cairo_pdf_font_t font;
-    cairo_cff_subset_t subset;
     unsigned long compressed_length;
     char *compressed;
     unsigned int i;
-    char name[64];
-
-    snprintf (name, sizeof name, "CairoFont-%d-%d",
-	      font_subset->font_id, font_subset->subset_id);
-    status = _cairo_cff_subset_init (&subset, name, font_subset);
-    if (status)
-	return status;
+    cairo_status_t status;
 
-    compressed = compress_dup (subset.data, subset.data_length, &compressed_length);
-    if (compressed == NULL) {
-	_cairo_cff_subset_fini (&subset);
+    compressed = compress_dup (subset->data, subset->data_length, &compressed_length);
+    if (compressed == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
-    }
 
     stream = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Filter /FlateDecode\r\n"
 				 "   /Length %lu\r\n"
-				 "   /Subtype /Type1C\r\n"
+				 "   /Subtype /CIDFontType0C\r\n"
 				 ">>\r\n"
 				 "stream\r\n",
 				 stream.id,
@@ -1803,7 +1800,7 @@ _cairo_pdf_surface_emit_cff_font_subset 
 				 "endobj\r\n");
     free (compressed);
 
-    to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset);
+    to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, TRUE);
 
     descriptor = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
@@ -1822,41 +1819,57 @@ _cairo_pdf_surface_emit_cff_font_subset 
 				 ">>\r\n"
 				 "endobj\r\n",
 				 descriptor.id,
-				 subset.base_font,
-				 subset.x_min,
-				 subset.y_min,
-				 subset.x_max,
-				 subset.y_max,
-				 subset.ascent,
-				 subset.descent,
+				 subset->base_font,
+				 subset->x_min,
+				 subset->y_min,
+				 subset->x_max,
+				 subset->y_max,
+				 subset->ascent,
+				 subset->descent,
 				 stream.id);
 
-    subset_resource = _cairo_pdf_surface_new_object (surface);
+    cidfont_dict = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
-				 "%d 0 obj\r\n"
-				 "<< /Type /Font\r\n"
-				 "   /Subtype /Type1\r\n"
-				 "   /BaseFont /%s\r\n"
-				 "   /FirstChar 0\r\n"
-				 "   /LastChar %d\r\n"
-				 "   /FontDescriptor %d 0 R\r\n"
-				 "   /Widths [",
-				 subset_resource.id,
-				 subset.base_font,
-				 font_subset->num_glyphs - 1,
-				 descriptor.id);
+                                 "%d 0 obj\r\n"
+                                 "<< /Type /Font\r\n"
+                                 "   /Subtype /CIDFontType0\r\n"
+                                 "   /BaseFont /%s\r\n"
+                                 "   /CIDSystemInfo\r\n"
+                                 "   << /Registry (Adobe)\r\n"
+                                 "      /Ordering (Identity)\r\n"
+                                 "      /Supplement 0\r\n"
+                                 "   >>\r\n"
+                                 "   /FontDescriptor %d 0 R\r\n"
+                                 "   /W [0 [",
+                                 cidfont_dict.id,
+                                 subset->base_font,
+                                 descriptor.id);
 
     for (i = 0; i < font_subset->num_glyphs; i++)
 	_cairo_output_stream_printf (surface->output,
 				     " %d",
-				     subset.widths[i]);
+				     subset->widths[i]);
 
     _cairo_output_stream_printf (surface->output,
-				 " ]\r\n");
+                                 " ]]\r\n"
+				 ">>\r\n"
+				 "endobj\r\n");
+
+    subset_resource = _cairo_pdf_surface_new_object (surface);
+    _cairo_output_stream_printf (surface->output,
+				 "%d 0 obj\r\n"
+				 "<< /Type /Font\r\n"
+				 "   /Subtype /Type0\r\n"
+				 "   /BaseFont /%s\r\n"
+                                 "   /Encoding /Identity-H\r\n"
+				 "   /DescendantFonts [ %d 0 R]\r\n",
+				 subset_resource.id,
+				 subset->base_font,
+				 cidfont_dict.id);
 
     if (to_unicode_stream.id != 0)
         _cairo_output_stream_printf (surface->output,
-                                     "    /ToUnicode %d 0 R\r\n",
+                                     "   /ToUnicode %d 0 R\r\n",
                                      to_unicode_stream.id);
 
     _cairo_output_stream_printf (surface->output,
@@ -1868,12 +1881,52 @@ _cairo_pdf_surface_emit_cff_font_subset 
     font.subset_resource = subset_resource;
     status = _cairo_array_append (&surface->fonts, &font);
 
+    return status;
+}
+
+static cairo_status_t
+_cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t	     *surface,
+                                         cairo_scaled_font_subset_t  *font_subset)
+{
+    cairo_status_t status;
+    cairo_cff_subset_t subset;
+    char name[64];
+
+    snprintf (name, sizeof name, "CairoFont-%d-%d",
+              font_subset->font_id, font_subset->subset_id);
+    status = _cairo_cff_subset_init (&subset, name, font_subset);
+    if (status)
+        return status;
+
+    status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
+
     _cairo_cff_subset_fini (&subset);
 
     return status;
 }
 
 static cairo_status_t
+_cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t	       *surface,
+                                           cairo_scaled_font_subset_t  *font_subset)
+{
+    cairo_status_t status;
+    cairo_cff_subset_t subset;
+    char name[64];
+
+    snprintf (name, sizeof name, "CairoFont-%d-%d",
+              font_subset->font_id, font_subset->subset_id);
+    status = _cairo_cff_fallback_init (&subset, name, font_subset);
+    if (status)
+        return status;
+
+    status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
+
+    _cairo_cff_fallback_fini (&subset);
+
+    return status;
+}
+
+static cairo_status_t
 _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t		*surface,
                                     cairo_scaled_font_subset_t	*font_subset,
                                     cairo_type1_subset_t        *subset)
@@ -1912,7 +1965,7 @@ _cairo_pdf_surface_emit_type1_font (cair
 				 "endobj\r\n");
     free (compressed);
 
-    to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset);
+    to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, FALSE);
 
     descriptor = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
@@ -2026,7 +2079,8 @@ 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, to_unicode_stream;
+    cairo_pdf_resource_t stream, descriptor, cidfont_dict;
+    cairo_pdf_resource_t subset_resource, to_unicode_stream;
     cairo_status_t status;
     cairo_pdf_font_t font;
     cairo_truetype_subset_t subset;
@@ -2063,7 +2117,7 @@ _cairo_pdf_surface_emit_truetype_font_su
 				 "endobj\r\n");
     free (compressed);
 
-    to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset);
+    to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, TRUE);
 
     descriptor = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
@@ -2092,18 +2146,30 @@ _cairo_pdf_surface_emit_truetype_font_su
 				 (long)(subset.y_max*PDF_UNITS_PER_EM),
 				 stream.id);
 
-    encoding = _cairo_pdf_surface_new_object (surface);
+    cidfont_dict = _cairo_pdf_surface_new_object (surface);
     _cairo_output_stream_printf (surface->output,
-				 "%d 0 obj\r\n"
-				 "<< /Type /Encoding\r\n"
-				 "   /Differences [0 ",
-                                 encoding.id);
+                                 "%d 0 obj\r\n"
+                                 "<< /Type /Font\r\n"
+                                 "   /Subtype /CIDFontType2\r\n"
+                                 "   /BaseFont /%s\r\n"
+                                 "   /CIDSystemInfo\r\n"
+                                 "   << /Registry (Adobe)\r\n"
+                                 "      /Ordering (Identity)\r\n"
+                                 "      /Supplement 0\r\n"
+                                 "   >>\r\n"
+                                 "   /FontDescriptor %d 0 R\r\n"
+                                 "   /W [0 [",
+                                 cidfont_dict.id,
+                                 subset.base_font,
+                                 descriptor.id);
 
     for (i = 0; i < font_subset->num_glyphs; i++)
-            _cairo_output_stream_printf (surface->output, "/g%d ", i);
+        _cairo_output_stream_printf (surface->output,
+                                     " %ld",
+                                     (long)(subset.widths[i]*PDF_UNITS_PER_EM));
 
     _cairo_output_stream_printf (surface->output,
-                                 " ]\r\n"
+                                 " ]]\r\n"
 				 ">>\r\n"
 				 "endobj\r\n");
 
@@ -2111,30 +2177,17 @@ _cairo_pdf_surface_emit_truetype_font_su
     _cairo_output_stream_printf (surface->output,
 				 "%d 0 obj\r\n"
 				 "<< /Type /Font\r\n"
-				 "   /Subtype /TrueType\r\n"
+				 "   /Subtype /Type0\r\n"
 				 "   /BaseFont /%s\r\n"
-				 "   /FirstChar 0\r\n"
-				 "   /LastChar %d\r\n"
-				 "   /FontDescriptor %d 0 R\r\n"
-				 "   /Encoding %d 0 R\r\n"
-				 "   /Widths [",
+                                 "   /Encoding /Identity-H\r\n"
+				 "   /DescendantFonts [ %d 0 R]\r\n",
 				 subset_resource.id,
 				 subset.base_font,
-				 font_subset->num_glyphs - 1,
-				 descriptor.id,
-                                 encoding.id);
-
-    for (i = 0; i < font_subset->num_glyphs; i++)
-	_cairo_output_stream_printf (surface->output,
-				     " %ld",
-				     (long)(subset.widths[i]*PDF_UNITS_PER_EM));
-
-    _cairo_output_stream_printf (surface->output,
-				 " ]\r\n");
+				 cidfont_dict.id);
 
     if (to_unicode_stream.id != 0)
         _cairo_output_stream_printf (surface->output,
-                                     "    /ToUnicode %d 0 R\r\n",
+                                     "   /ToUnicode %d 0 R\r\n",
                                      to_unicode_stream.id);
 
     _cairo_output_stream_printf (surface->output,
@@ -2380,7 +2433,7 @@ _cairo_pdf_surface_emit_type3_font_subse
 
     free (glyphs);
 
-    to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset);
+    to_unicode_stream = _cairo_pdf_surface_emit_to_unicode_stream (surface, font_subset, FALSE);
 
     subset_resource = _cairo_pdf_surface_new_object (surface);
     matrix = font_subset->scaled_font->scale;
@@ -2440,25 +2493,31 @@ _cairo_pdf_surface_emit_unscaled_font_su
     cairo_pdf_surface_t *surface = closure;
     cairo_status_t status;
 
-#if 0
     status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return;
-#endif
 
 #if CAIRO_HAS_FT_FONT
+#if 0
     status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return;
 #endif
+#endif
 
     status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return;
 
+    status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return;
+
+#if 0
     status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return;
+#endif
 }
 
 static void
@@ -2922,7 +2981,7 @@ _cairo_pdf_surface_show_glyphs (void			*
     cairo_status_t status;
     double Tlm_x = 0, Tlm_y = 0;
     double Tm_x = 0, y;
-    int i;
+    int i, hex_width;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
 	return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -2950,6 +3009,11 @@ _cairo_pdf_surface_show_glyphs (void			*
 	if (status)
             return status;
 
+        if (subset_glyph.is_composite)
+            hex_width = 4;
+        else
+            hex_width = 2;
+
         if (subset_glyph.is_scaled == FALSE) {
             y = 0.0;
             cairo_matrix_transform_distance (&scaled_font->scale,
@@ -2999,7 +3063,8 @@ _cairo_pdf_surface_show_glyphs (void			*
                         Tm_x = Tlm_x;
                     }
                     _cairo_output_stream_printf (surface->output,
-                                                 "[<%02x",
+                                                 "[<%0*x",
+                                                 hex_width,
                                                  subset_glyph.subset_glyph_index);
                     Tm_x += subset_glyph.x_advance;
                     in_TJ = TRUE;
@@ -3013,7 +3078,8 @@ _cairo_pdf_surface_show_glyphs (void			*
                         Tm_x += delta;
                     }
                     _cairo_output_stream_printf (surface->output,
-                                                 "%02x",
+                                                 "%0*x",
+                                                 hex_width,
                                                  subset_glyph.subset_glyph_index);
                     Tm_x += subset_glyph.x_advance;
                 }
@@ -3030,7 +3096,8 @@ _cairo_pdf_surface_show_glyphs (void			*
                         Tm_x += delta;
                     }
                     _cairo_output_stream_printf (surface->output,
-                                                 "%02x>] TJ\r\n",
+                                                 "%0*x>] TJ\r\n",
+                                                 hex_width,
                                                  subset_glyph.subset_glyph_index);
                     Tm_x += subset_glyph.x_advance;
                     in_TJ = FALSE;
@@ -3045,14 +3112,16 @@ _cairo_pdf_surface_show_glyphs (void			*
                         Tm_x = Tlm_x;
                     }
                     _cairo_output_stream_printf (surface->output,
-                                                 "<%02x> Tj ",
+                                                 "<%0*x> Tj ",
+                                                 hex_width,
                                                  subset_glyph.subset_glyph_index);
                     Tm_x += subset_glyph.x_advance;
                 }
             }
         } else {
             _cairo_output_stream_printf (surface->output,
-                                         "<%02x> Tj\r\n",
+                                         "<%0*x> Tj\r\n",
+                                         hex_width,
                                          subset_glyph.subset_glyph_index);
         }
     }
diff-tree ca3662d6fc630e5390b3a8f8dbaa1d65aebc3fe8 (from 0c2a653033e0b631a1cb6591263cbd6125ccc00c)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Fri Apr 20 22:43:37 2007 +0930

    Make cairo-output-stream.c accept variable width printf fields

diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index 4401c5b..b9f0d38 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -281,7 +281,8 @@ _cairo_output_stream_vprintf (cairo_outp
     int single_fmt_length;
     char *p;
     const char *f, *start;
-    int length_modifier;
+    int length_modifier, width;
+    cairo_bool_t var_width;
 
     if (stream->status)
 	return;
@@ -305,6 +306,12 @@ _cairo_output_stream_vprintf (cairo_outp
 	if (*f == '0')
 	    f++;
 
+        var_width = FALSE;
+        if (*f == '*') {
+            var_width = TRUE;
+	    f++;
+        }
+
 	while (isdigit (*f))
 	    f++;
 
@@ -341,15 +348,27 @@ _cairo_output_stream_vprintf (cairo_outp
 	case 'o':
 	case 'x':
 	case 'X':
-	    snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
+            if (var_width) {
+                width = va_arg (ap, int);
+                snprintf (buffer, sizeof buffer,
+                          single_fmt, width, va_arg (ap, int));
+            } else {
+                snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int));
+            }
 	    break;
 	case 'd' | LENGTH_MODIFIER_LONG:
 	case 'u' | LENGTH_MODIFIER_LONG:
 	case 'o' | LENGTH_MODIFIER_LONG:
 	case 'x' | LENGTH_MODIFIER_LONG:
 	case 'X' | LENGTH_MODIFIER_LONG:
-	    snprintf (buffer, sizeof buffer,
-		      single_fmt, va_arg (ap, long int));
+            if (var_width) {
+                width = va_arg (ap, int);
+                snprintf (buffer, sizeof buffer,
+                          single_fmt, width, va_arg (ap, long int));
+            } else {
+                snprintf (buffer, sizeof buffer,
+                          single_fmt, va_arg (ap, long int));
+            }
 	    break;
 	case 's':
 	    snprintf (buffer, sizeof buffer,
diff-tree 0c2a653033e0b631a1cb6591263cbd6125ccc00c (from c68a2389f51880b0fa9df6750abdd840258666fc)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Fri Apr 20 22:30:55 2007 +0930

    Add CFF CID Fallback
    
    Switching to CID font embedding requires a fallback font for
    the case where CFF CID or TrueType CID subsetting fails.
    
    The new function _cairo_type2_charstrings_init() added to
    cairo-type1-fallback.c creates Type2 charstrings from glyph
    paths. _cairo_cff_fallback_init() in cairo-cff-subset.c
    wraps these charstrings in a CFF CID font.

diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index e4c8cfc..a448e37 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -1915,3 +1915,215 @@ _cairo_cff_subset_fini (cairo_cff_subset
     free (subset->widths);
     free (subset->data);
 }
+
+static cairo_int_status_t
+_cairo_cff_font_fallback_create (cairo_scaled_font_subset_t  *scaled_font_subset,
+                                 cairo_cff_font_t           **font_return,
+                                 const char                  *subset_name)
+{
+    cairo_status_t status;
+    cairo_cff_font_t *font;
+
+    font = malloc (sizeof (cairo_cff_font_t));
+    if (font == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
+
+    font->backend = NULL;
+    font->scaled_font_subset = scaled_font_subset;
+
+    _cairo_array_init (&font->output, sizeof (char));
+    status = _cairo_array_grow_by (&font->output, 4096);
+    if (status)
+	goto fail1;
+
+    font->subset_font_name = strdup (subset_name);
+    if (font->subset_font_name == NULL) {
+        status = CAIRO_STATUS_NO_MEMORY;
+	goto fail2;
+    }
+
+    font->font_name = strdup (subset_name);
+    if (font->subset_font_name == NULL) {
+        status = CAIRO_STATUS_NO_MEMORY;
+	goto fail3;
+    }
+
+    font->x_min = 0;
+    font->y_min = 0;
+    font->x_max = 0;
+    font->y_max = 0;
+    font->ascent = 0;
+    font->descent = 0;
+
+    font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int));
+    if (font->widths == NULL) {
+        status = CAIRO_STATUS_NO_MEMORY;
+        goto fail4;
+    }
+
+    font->data_length = 0;
+    font->data = NULL;
+    font->data_end = 0;
+
+    cff_dict_init (&font->top_dict);
+    cff_dict_init (&font->private_dict);
+    cff_index_init (&font->strings_index);
+    cff_index_init (&font->charstrings_index);
+    cff_index_init (&font->global_sub_index);
+    cff_index_init (&font->local_sub_index);
+    cff_index_init (&font->charstrings_subset_index);
+    cff_index_init (&font->strings_subset_index);
+    font->fdselect = NULL;
+    font->fd_dict = NULL;
+    font->fd_private_dict = NULL;
+    font->fd_local_sub_index = NULL;
+    font->fdselect_subset = NULL;
+    font->fd_subset_map = NULL;
+    font->private_dict_offset = NULL;
+
+    *font_return = font;
+
+    return CAIRO_STATUS_SUCCESS;
+
+fail4:
+    free (font->font_name);
+fail3:
+    free (font->subset_font_name);
+fail2:
+    _cairo_array_fini (&font->output);
+fail1:
+    free (font);
+    return status;
+}
+
+static cairo_int_status_t
+cairo_cff_font_fallback_generate (cairo_cff_font_t           *font,
+                                  cairo_type2_charstrings_t  *type2_subset,
+                                  const char                **data,
+                                  unsigned long              *length)
+{
+    cairo_int_status_t status;
+    cff_header_t header;
+    cairo_array_t *charstring;
+    unsigned char buf[40];
+    unsigned char *end_buf;
+    unsigned int i;
+
+    /* Create header */
+    header.major = 1;
+    header.minor = 0;
+    header.header_size = 4;
+    header.offset_size = 4;
+    font->header = &header;
+
+    /* Create Top Dict */
+    font->is_cid = FALSE;
+    end_buf = encode_integer (buf, type2_subset->x_min);
+    end_buf = encode_integer (end_buf, type2_subset->y_min);
+    end_buf = encode_integer (end_buf, type2_subset->x_max);
+    end_buf = encode_integer (end_buf, type2_subset->y_max);
+    cff_dict_set_operands (font->top_dict, FONTBBOX_OP, buf, end_buf - buf);
+    end_buf = encode_integer_max (buf, 0);
+    cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf);
+    cff_dict_set_operands (font->top_dict, FDSELECT_OP, buf, end_buf - buf);
+    cff_dict_set_operands (font->top_dict, FDARRAY_OP, buf, end_buf - buf);
+    cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf);
+    cairo_cff_font_set_ros_strings (font);
+
+    /* Create CID FD dictionary */
+    cairo_cff_font_create_cid_fontdict (font);
+
+    /* Create charstrings */
+    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+        charstring = _cairo_array_index(&type2_subset->charstrings, i);
+
+        status = cff_index_append (&font->charstrings_subset_index,
+                                   _cairo_array_index (charstring, 0),
+                                   _cairo_array_num_elements (charstring));
+
+        if (status)
+            return status;
+    }
+
+    status = cairo_cff_font_write_subset (font);
+    if (status)
+        return status;
+
+    *data = _cairo_array_index (&font->output, 0);
+    *length = _cairo_array_num_elements (&font->output);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_cff_fallback_init (cairo_cff_subset_t          *cff_subset,
+                          const char		      *subset_name,
+                          cairo_scaled_font_subset_t  *font_subset)
+{
+    cairo_cff_font_t *font = NULL; /* squelch bogus compiler warning */
+    cairo_status_t status;
+    const char *data = NULL; /* squelch bogus compiler warning */
+    unsigned long length = 0; /* squelch bogus compiler warning */
+    unsigned int i;
+    cairo_type2_charstrings_t type2_subset;
+
+    status = _cairo_cff_font_fallback_create (font_subset, &font, subset_name);
+    if (status)
+	return status;
+
+    status = _cairo_type2_charstrings_init (&type2_subset, font_subset);
+    if (status)
+	goto fail1;
+
+    status = cairo_cff_font_fallback_generate (font, &type2_subset, &data, &length);
+    if (status)
+	goto fail1;
+
+    cff_subset->base_font = strdup (font->font_name);
+    if (cff_subset->base_font == NULL)
+	goto fail1;
+
+    cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
+    if (cff_subset->widths == NULL)
+	goto fail2;
+    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
+        cff_subset->widths[i] = type2_subset.widths[i];
+
+    cff_subset->x_min = type2_subset.x_min;
+    cff_subset->y_min = type2_subset.y_min;
+    cff_subset->x_max = type2_subset.x_max;
+    cff_subset->y_max = type2_subset.y_max;
+    cff_subset->ascent = type2_subset.y_max;
+    cff_subset->descent = type2_subset.y_min;
+
+    _cairo_type2_charstrings_fini (&type2_subset);
+
+    cff_subset->data = malloc (length);
+    if (cff_subset->data == NULL)
+	goto fail3;
+
+    memcpy (cff_subset->data, data, length);
+    cff_subset->data_length = length;
+    cff_subset->data_length = length;
+
+    cairo_cff_font_destroy (font);
+
+    return CAIRO_STATUS_SUCCESS;
+
+ fail3:
+    free (cff_subset->widths);
+ fail2:
+    free (cff_subset->base_font);
+ fail1:
+    cairo_cff_font_destroy (font);
+
+    return status;
+}
+
+void
+_cairo_cff_fallback_fini (cairo_cff_subset_t *subset)
+{
+    free (subset->base_font);
+    free (subset->widths);
+    free (subset->data);
+}
diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h
index 4c8221e..03076c8 100644
--- a/src/cairo-scaled-font-subsets-private.h
+++ b/src/cairo-scaled-font-subsets-private.h
@@ -305,6 +305,37 @@ _cairo_cff_subset_init (cairo_cff_subset
 cairo_private void
 _cairo_cff_subset_fini (cairo_cff_subset_t *cff_subset);
 
+/**
+ * _cairo_cff_fallback_init:
+ * @cff_subset: a #cairo_cff_subset_t to initialize
+ * @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) generate a cff
+ * file corresponding to @font_subset and initialize @cff_subset
+ * with information about the subset and the cff data.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if successful,
+ * CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
+ * cff file, or an non-zero value indicating an error.  Possible
+ * errors include CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_private cairo_status_t
+_cairo_cff_fallback_init (cairo_cff_subset_t          *cff_subset,
+                          const char                  *name,
+                          cairo_scaled_font_subset_t  *font_subset);
+
+/**
+ * _cairo_cff_fallback_fini:
+ * @cff_subset: a #cairo_cff_subset_t
+ *
+ * Free all resources associated with @cff_subset.  After this
+ * call, @cff_subset should not be used again without a
+ * subsequent call to _cairo_cff_subset_init() again first.
+ **/
+cairo_private void
+_cairo_cff_fallback_fini (cairo_cff_subset_t *cff_subset);
+
 typedef struct _cairo_truetype_subset {
     char *base_font;
     double *widths;
@@ -446,6 +477,43 @@ _cairo_type1_fallback_init_hex (cairo_ty
 cairo_private void
 _cairo_type1_fallback_fini (cairo_type1_subset_t *subset);
 
+typedef struct _cairo_type2_charstrings {
+    int *widths;
+    long x_min, y_min, x_max, y_max;
+    long ascent, descent;
+    cairo_array_t charstrings;
+} cairo_type2_charstrings_t;
+
+/**
+ * _cairo_type2_charstrings_init:
+ * @type2_subset: a #cairo_type2_subset_t to initialize
+ * @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) generate type2
+ * charstrings to @font_subset and initialize @type2_subset
+ * with information about the subset.
+ *
+ * Return value: CAIRO_STATUS_SUCCESS if successful,
+ * CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type2
+ * charstrings, or an non-zero value indicating an error.  Possible errors
+ * include CAIRO_STATUS_NO_MEMORY.
+ **/
+cairo_private cairo_status_t
+_cairo_type2_charstrings_init (cairo_type2_charstrings_t   *charstrings,
+                               cairo_scaled_font_subset_t  *font_subset);
+
+/**
+ * _cairo_type2_charstrings_fini:
+ * @subset: a #cairo_type2_charstrings_t
+ *
+ * Free all resources associated with @type2_charstring.  After this call,
+ * @type2_charstring should not be used again without a subsequent call to
+ * _cairo_type2_charstring_init() again first.
+ **/
+cairo_private void
+_cairo_type2_charstrings_fini (cairo_type2_charstrings_t *charstrings);
+
 /**
  * _cairo_truetype_create_glyph_to_unicode_map:
  * @font_subset: the #cairo_scaled_font_subset_t to initialize from
diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c
index dcf55f4..3a0bd12 100644
--- a/src/cairo-type1-fallback.c
+++ b/src/cairo-type1-fallback.c
@@ -39,6 +39,11 @@
 #include "cairo-path-fixed-private.h"
 #include "cairo-output-stream-private.h"
 
+typedef enum {
+    CAIRO_CHARSTRING_TYPE1,
+    CAIRO_CHARSTRING_TYPE2,
+} cairo_charstring_type_t;
+
 typedef struct _cairo_type1_font {
     int *widths;
 
@@ -90,7 +95,7 @@ cairo_type1_font_create (cairo_scaled_fo
 
     font_face = cairo_scaled_font_get_font_face (scaled_font_subset->scaled_font);
 
-    cairo_matrix_init_scale (&font_matrix, 1000, 1000);
+    cairo_matrix_init_scale (&font_matrix, 1000, -1000);
     cairo_matrix_init_identity (&ctm);
 
     _cairo_font_options_init_default (&font_options);
@@ -156,7 +161,9 @@ charstring_encode_command (cairo_array_t
  * bytes that will be used is 5.
  */
 static void
-charstring_encode_integer (cairo_array_t *data, int i)
+charstring_encode_integer (cairo_array_t *data,
+                           int i,
+                           cairo_charstring_type_t type)
 {
     cairo_status_t status;
     int orig_size;
@@ -174,11 +181,19 @@ charstring_encode_integer (cairo_array_t
         *p++ = (i >> 8)+ 251;
         *p++ = i & 0xff;
     } else {
-        *p++ = 0xff;
-        *p++ = i >> 24;
-        *p++ = (i >> 16) & 0xff;
-        *p++ = (i >> 8)  & 0xff;
-        *p++ = i & 0xff;
+        if (type == CAIRO_CHARSTRING_TYPE1) {
+            *p++ = 0xff;
+            *p++ = i >> 24;
+            *p++ = (i >> 16) & 0xff;
+            *p++ = (i >> 8)  & 0xff;
+            *p++ = i & 0xff;
+        } else {
+            *p++ = 0xff;
+            *p++ = (i >> 8)  & 0xff;
+            *p++ = i & 0xff;
+            *p++ = 0;
+            *p++ = 0;
+        }
     }
 
     /* Ensure the array doesn't grow, which allows this function to
@@ -193,6 +208,7 @@ charstring_encode_integer (cairo_array_t
 typedef struct _ps_path_info {
     cairo_array_t *data;
     int current_x, current_y;
+    cairo_charstring_type_t type;
 } t1_path_info_t;
 
 static cairo_status_t
@@ -209,8 +225,8 @@ _charstring_move_to (void          *clos
 
     dx = _cairo_fixed_integer_part (point->x) - path_info->current_x;
     dy = _cairo_fixed_integer_part (point->y) - path_info->current_y;
-    charstring_encode_integer (path_info->data, dx);
-    charstring_encode_integer (path_info->data, dy);
+    charstring_encode_integer (path_info->data, dx, path_info->type);
+    charstring_encode_integer (path_info->data, dy, path_info->type);
     path_info->current_x += dx;
     path_info->current_y += dy;
 
@@ -233,8 +249,8 @@ _charstring_line_to (void          *clos
 
     dx = _cairo_fixed_integer_part (point->x) - path_info->current_x;
     dy = _cairo_fixed_integer_part (point->y) - path_info->current_y;
-    charstring_encode_integer (path_info->data, dx);
-    charstring_encode_integer (path_info->data, dy);
+    charstring_encode_integer (path_info->data, dx, path_info->type);
+    charstring_encode_integer (path_info->data, dy, path_info->type);
     path_info->current_x += dx;
     path_info->current_y += dy;
 
@@ -263,12 +279,12 @@ _charstring_curve_to (void	    *closure,
     dy2 = _cairo_fixed_integer_part (point2->y) - path_info->current_y - dy1;
     dx3 = _cairo_fixed_integer_part (point3->x) - path_info->current_x - dx1 - dx2;
     dy3 = _cairo_fixed_integer_part (point3->y) - path_info->current_y - dy1 - dy2;
-    charstring_encode_integer (path_info->data, dx1);
-    charstring_encode_integer (path_info->data, dy1);
-    charstring_encode_integer (path_info->data, dx2);
-    charstring_encode_integer (path_info->data, dy2);
-    charstring_encode_integer (path_info->data, dx3);
-    charstring_encode_integer (path_info->data, dy3);
+    charstring_encode_integer (path_info->data, dx1, path_info->type);
+    charstring_encode_integer (path_info->data, dy1, path_info->type);
+    charstring_encode_integer (path_info->data, dx2, path_info->type);
+    charstring_encode_integer (path_info->data, dy2, path_info->type);
+    charstring_encode_integer (path_info->data, dx3, path_info->type);
+    charstring_encode_integer (path_info->data, dy3, path_info->type);
     path_info->current_x += dx1 + dx2 + dx3;
     path_info->current_y += dy1 + dy2 + dy3;
     charstring_encode_command (path_info->data, CHARSTRING_rcurveto);
@@ -282,6 +298,9 @@ _charstring_close_path (void *closure)
     cairo_status_t status;
     t1_path_info_t *path_info = (t1_path_info_t *) closure;
 
+    if (path_info->type == CAIRO_CHARSTRING_TYPE2)
+        return CAIRO_STATUS_SUCCESS;
+
     status = _cairo_array_grow_by (path_info->data, 2);
     if (status)
 	return status;
@@ -309,7 +328,7 @@ charstring_encrypt (cairo_array_t *data)
 }
 
 static cairo_int_status_t
-create_notdef_charstring (cairo_array_t *data)
+create_notdef_charstring (cairo_array_t *data, cairo_charstring_type_t type)
 {
     cairo_status_t status;
 
@@ -320,13 +339,15 @@ create_notdef_charstring (cairo_array_t 
     if (status)
         return status;
 
-    charstring_encode_integer (data, 0);
-    charstring_encode_integer (data, 0);
-
-    /* The width and height is arbitrary. */
-    charstring_encode_integer (data, 500);
-    charstring_encode_integer (data, 500);
-    charstring_encode_command (data, CHARSTRING_sbw);
+    if (type == CAIRO_CHARSTRING_TYPE1) {
+        charstring_encode_integer (data, 0, type);
+        charstring_encode_integer (data, 0, type);
+
+        /* The width and height is arbitrary. */
+        charstring_encode_integer (data, 500, type);
+        charstring_encode_integer (data, 500, type);
+        charstring_encode_command (data, CHARSTRING_sbw);
+    }
 
     charstring_encode_command (data, CHARSTRING_endchar);
 
@@ -334,10 +355,11 @@ create_notdef_charstring (cairo_array_t 
 }
 
 static cairo_int_status_t
-cairo_type1_font_create_charstring (cairo_type1_font_t *font,
-                                    int                 subset_index,
-                                    int                 glyph_index,
-                                    cairo_array_t      *data)
+cairo_type1_font_create_charstring (cairo_type1_font_t      *font,
+                                    int                      subset_index,
+                                    int                      glyph_index,
+                                    cairo_charstring_type_t  type,
+                                    cairo_array_t           *data)
 {
     cairo_int_status_t status;
     cairo_scaled_glyph_t *scaled_glyph;
@@ -369,21 +391,29 @@ cairo_type1_font_create_charstring (cair
         if (metrics->y_bearing + metrics->height > font->y_max)
             font->y_max = metrics->y_bearing + metrics->height;
     }
-    font->widths[subset_index] = metrics->width;
+    font->widths[subset_index] = metrics->x_advance;
 
     status = _cairo_array_grow_by (data, 30);
     if (status)
         return status;
 
-    charstring_encode_integer (data, (int) scaled_glyph->metrics.x_bearing);
-    charstring_encode_integer (data, (int) scaled_glyph->metrics.y_bearing);
-    charstring_encode_integer (data, (int) scaled_glyph->metrics.width);
-    charstring_encode_integer (data, (int) scaled_glyph->metrics.height);
-    charstring_encode_command (data, CHARSTRING_sbw);
+    if (type == CAIRO_CHARSTRING_TYPE1) {
+        charstring_encode_integer (data, (int) scaled_glyph->metrics.x_bearing, type);
+        charstring_encode_integer (data, (int) scaled_glyph->metrics.y_bearing, type);
+        charstring_encode_integer (data, (int) scaled_glyph->metrics.width, type);
+        charstring_encode_integer (data, (int) scaled_glyph->metrics.height, type);
+        charstring_encode_command (data, CHARSTRING_sbw);
+
+        path_info.current_x = (int) scaled_glyph->metrics.x_bearing;
+        path_info.current_y = (int) scaled_glyph->metrics.y_bearing;
+    } else {
+        charstring_encode_integer (data, (int) scaled_glyph->metrics.width, type);
 
+        path_info.current_x = 0;
+        path_info.current_y = 0;
+    }
     path_info.data = data;
-    path_info.current_x = (int) scaled_glyph->metrics.x_bearing;
-    path_info.current_y = (int) scaled_glyph->metrics.y_bearing;
+    path_info.type = type;
     status = _cairo_path_fixed_interpret (scaled_glyph->path,
                                           CAIRO_DIRECTION_FORWARD,
                                           _charstring_move_to,
@@ -429,6 +459,7 @@ cairo_type1_font_write_charstrings (cair
             goto fail;
         status = cairo_type1_font_create_charstring (font, i,
 						     font->scaled_font_subset->glyphs[i],
+                                                     CAIRO_CHARSTRING_TYPE1,
 						     &data);
         if (status)
             goto fail;
@@ -448,7 +479,7 @@ cairo_type1_font_write_charstrings (cair
     status = _cairo_array_append_multiple (&data, zeros, 4);
     if (status)
         goto fail;
-    status = create_notdef_charstring (&data);
+    status = create_notdef_charstring (&data, CAIRO_CHARSTRING_TYPE1);
     if (status)
         goto fail;
     charstring_encrypt (&data);
@@ -464,35 +495,22 @@ fail:
     return status;
 }
 
-static cairo_status_t
+static void
 cairo_type1_font_write_header (cairo_type1_font_t *font,
                                const char         *name)
 {
-    cairo_matrix_t matrix;
-    cairo_status_t status;
     unsigned int i;
     const char spaces[50] = "                                                  ";
 
-    matrix = font->type1_scaled_font->scale;
-    matrix.xy = -matrix.xy;
-    matrix.yy = -matrix.yy;
-    status = cairo_matrix_invert (&matrix);
-    if (status)
-	return status;
-
     _cairo_output_stream_printf (font->output,
                                  "%%!FontType1-1.1 %s 1.0\n"
                                  "11 dict begin\n"
                                  "/FontName /%s def\n"
                                  "/PaintType 0 def\n"
                                  "/FontType 1 def\n"
-                                 "/FontMatrix [%f %f %f %f 0 0] readonly def\n",
-                                 name,
+                                  "/FontMatrix [0.001 0 0 0.001 0 0] readonly def\n",
                                  name,
-                                 matrix.xx,
-				 matrix.yx,
-				 matrix.xy,
-				 matrix.yy);
+                                 name);
 
     /* We don't know the bbox values until after the charstrings have
      * been generated.  Reserve some space and fill in the bbox
@@ -515,8 +533,6 @@ cairo_type1_font_write_header (cairo_typ
                                  "readonly def\n"
                                  "currentdict end\n"
                                  "currentfile eexec\n");
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
@@ -640,10 +656,7 @@ cairo_type1_font_write (cairo_type1_font
 {
     cairo_int_status_t status;
 
-    status = cairo_type1_font_write_header (font, name);
-    if (status)
-	return status;
-
+    cairo_type1_font_write_header (font, name);
     font->header_size = _cairo_output_stream_get_position (font->output);
 
     status = cairo_type1_font_write_private_dict (font, name);
@@ -798,3 +811,83 @@ _cairo_type1_fallback_fini (cairo_type1_
     free (subset->widths);
     free (subset->data);
 }
+
+cairo_status_t
+_cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset,
+                               cairo_scaled_font_subset_t *scaled_font_subset)
+{
+    cairo_type1_font_t *font;
+    cairo_status_t status;
+    unsigned int i;
+    cairo_array_t charstring;
+
+    status = cairo_type1_font_create (scaled_font_subset, &font, FALSE);
+    if (status)
+	return status;
+
+    _cairo_array_init (&type2_subset->charstrings, sizeof (cairo_array_t));
+
+    type2_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
+    if (type2_subset->widths == NULL) {
+        status = CAIRO_STATUS_NO_MEMORY;
+        goto fail1;
+    }
+
+    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+        _cairo_array_init (&charstring, sizeof (unsigned char));
+        status = _cairo_array_grow_by (&charstring, 32);
+        if (status)
+            goto fail2;
+
+        if (i == 0) {
+            status = create_notdef_charstring (&charstring, CAIRO_CHARSTRING_TYPE2);
+        } else {
+            status = cairo_type1_font_create_charstring (font, i,
+                                                         font->scaled_font_subset->glyphs[i],
+                                                         CAIRO_CHARSTRING_TYPE2,
+                                                         &charstring);
+        }
+        if (status)
+            goto fail2;
+
+        status = _cairo_array_append (&type2_subset->charstrings, &charstring);
+        if (status)
+            goto fail2;
+    }
+
+    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
+	type2_subset->widths[i] = font->widths[i];
+
+    type2_subset->x_min   = (int) font->x_min;
+    type2_subset->y_min   = (int) font->y_min;
+    type2_subset->x_max   = (int) font->x_max;
+    type2_subset->y_max   = (int) font->y_max;
+    type2_subset->ascent  = (int) font->y_max;
+    type2_subset->descent = (int) font->y_min;
+
+    cairo_type1_font_destroy (font);
+    return CAIRO_STATUS_SUCCESS;
+
+fail2:
+    _cairo_array_fini (&charstring);
+    _cairo_type2_charstrings_fini (type2_subset);
+fail1:
+    cairo_type1_font_destroy (font);
+    return status;
+}
+
+void
+_cairo_type2_charstrings_fini (cairo_type2_charstrings_t *type2_subset)
+{
+    unsigned int i, num_charstrings;
+    cairo_array_t *charstring;
+
+    num_charstrings = _cairo_array_num_elements (&type2_subset->charstrings);
+    for (i = 0; i < num_charstrings; i++) {
+        charstring = _cairo_array_index (&type2_subset->charstrings, i);
+        _cairo_array_fini (charstring);
+    }
+    _cairo_array_fini (&type2_subset->charstrings);
+
+    free (type2_subset->widths);
+}
diff-tree c68a2389f51880b0fa9df6750abdd840258666fc (from 073fce5a85ab90b1bc6915e41d6a420a47e540e6)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Fri Apr 20 22:30:05 2007 +0930

    Make CFF Subsetting create CID subsets
    
    OpenType/CFF fonts come in two types: CID and non CID.
    CFF CID font subsetting was previously disabled in cairo
    due 1) to the need to embed CFF CID fonts in PDF as a CID fonts
    and 2) there is no easy way to convert CFF CID to CFF non CID.
    
    With the switch to CID fonts cairo-cff-subset.c has been
    updated to subset CID fonts and to covert non CID fonts to
    CID. A further advantage of converting non CID CFF fonts
    to CID is the reduction in size due to not embedding the
    name of each glyph in the font subset.

diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index b0158fe..e4c8cfc 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -37,15 +37,20 @@
 #include "cairoint.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-truetype-subset-private.h"
+#include <string.h>
 
 /* CFF Dict Operators. If the high byte is 0 the command is encoded
  * with a single byte. */
 #define BASEFONTNAME_OP  0x0c16
+#define CIDCOUNT_OP      0x0c22
 #define CHARSET_OP       0x000f
 #define CHARSTRINGS_OP   0x0011
 #define COPYRIGHT_OP     0x0c00
 #define ENCODING_OP      0x0010
 #define FAMILYNAME_OP    0x0003
+#define FDARRAY_OP       0x0c24
+#define FDSELECT_OP      0x0c25
+#define FONTBBOX_OP      0x0005
 #define FONTNAME_OP      0x0c26
 #define FULLNAME_OP      0x0002
 #define LOCAL_SUB_OP     0x0013
@@ -80,13 +85,6 @@ typedef struct _cff_dict_operator {
     int            operand_offset;
 } cff_dict_operator_t;
 
-typedef struct _cff_charset {
-    cairo_bool_t         is_builtin;
-    const uint16_t      *sids;
-    const unsigned char *data;
-    int                  length;
-} cff_charset_t;
-
 typedef struct _cairo_cff_font {
 
     cairo_scaled_font_subset_t *scaled_font_subset;
@@ -106,14 +104,23 @@ typedef struct _cairo_cff_font {
     cairo_array_t        global_sub_index;
     cairo_array_t        local_sub_index;
     int                  num_glyphs;
-    cff_charset_t        charset;
-    int                  charset_offset;
+    cairo_bool_t         is_cid;
+
+    /* CID Font Data */
+    int                 *fdselect;
+    unsigned int         num_fontdicts;
+    cairo_hash_table_t **fd_dict;
+    cairo_hash_table_t **fd_private_dict;
+    cairo_array_t       *fd_local_sub_index;
 
     /* Subsetted Font Data */
     char                *subset_font_name;
     cairo_array_t        charstrings_subset_index;
     cairo_array_t        strings_subset_index;
-    cairo_array_t        charset_subset;
+    int                 *fdselect_subset;
+    unsigned int         num_subset_fontdicts;
+    int                 *fd_subset_map;
+    int                 *private_dict_offset;
     cairo_array_t        output;
 
     /* Subset Metrics */
@@ -345,7 +352,6 @@ cff_index_write (cairo_array_t *index, c
         status = _cairo_array_append_multiple (output, buf, offset_size);
         if (status)
             return status;
-
     }
 
     for (i = 0; i < num_elem; i++) {
@@ -372,7 +378,9 @@ cff_index_append (cairo_array_t *index, 
 }
 
 static cairo_status_t
-cff_index_append_copy (cairo_array_t *index, unsigned char *object , int length)
+cff_index_append_copy (cairo_array_t *index,
+                       const unsigned char *object,
+                       unsigned int length)
 {
     cff_index_element_t element;
 
@@ -486,6 +494,21 @@ fail:
     return status;
 }
 
+static void
+cff_dict_remove (cairo_hash_table_t *dict, unsigned short operator)
+{
+    cff_dict_operator_t key, *op;
+
+    _cairo_dict_init_key (&key, operator);
+    if (_cairo_hash_table_lookup (dict, &key.base,
+                                  (cairo_hash_entry_t **) &op))
+    {
+        free (op->operand);
+        _cairo_hash_table_remove (dict, (cairo_hash_entry_t *) op);
+        free (op);
+    }
+}
+
 static unsigned char *
 cff_dict_get_operands (cairo_hash_table_t *dict,
                        unsigned short      operator,
@@ -561,19 +584,12 @@ typedef struct _dict_write_info {
 } dict_write_info_t;
 
 static void
-_cairo_dict_collect (void *entry, void *closure)
+cairo_dict_write_operator (cff_dict_operator_t *op, dict_write_info_t *write_info)
 {
-    dict_write_info_t *write_info = closure;
-    cff_dict_operator_t *op = entry;
     unsigned char data;
 
-    if (write_info->status)
-        return;
-
     op->operand_offset = _cairo_array_num_elements (write_info->output);
-    write_info->status = _cairo_array_append_multiple (write_info->output,
-                                                       op->operand,
-                                                       op->operand_length);
+    write_info->status = _cairo_array_append_multiple (write_info->output, op->operand, op->operand_length);
     if (write_info->status)
         return;
 
@@ -587,13 +603,36 @@ _cairo_dict_collect (void *entry, void *
     write_info->status = _cairo_array_append (write_info->output, &data);
 }
 
+static void
+_cairo_dict_collect (void *entry, void *closure)
+{
+    dict_write_info_t   *write_info = closure;
+    cff_dict_operator_t *op = entry;
+
+    if (write_info->status)
+        return;
+
+    /* The ROS operator is handled separately in cff_dict_write() */
+    if (op->operator != ROS_OP)
+        cairo_dict_write_operator (op, write_info);
+}
+
 static cairo_status_t
 cff_dict_write (cairo_hash_table_t *dict, cairo_array_t *output)
 {
     dict_write_info_t write_info;
+    cff_dict_operator_t key, *op;
 
     write_info.output = output;
     write_info.status = CAIRO_STATUS_SUCCESS;
+
+    /* The CFF specification requires that the Top Dict of CID fonts
+     * begin with the ROS operator. */
+    _cairo_dict_init_key (&key, ROS_OP);
+    if (_cairo_hash_table_lookup (dict, &key.base,
+                                  (cairo_hash_entry_t **) &op))
+        cairo_dict_write_operator (op, &write_info);
+
     _cairo_hash_table_foreach (dict, _cairo_dict_collect, &write_info);
 
     return write_info.status;
@@ -644,6 +683,8 @@ cairo_cff_font_read_name (cairo_cff_font
 
 static cairo_int_status_t
 cairo_cff_font_read_private_dict (cairo_cff_font_t   *font,
+                                  cairo_hash_table_t *private_dict,
+                                  cairo_array_t      *local_sub_index,
                                   unsigned char      *ptr,
                                   int                 size)
 {
@@ -654,22 +695,141 @@ cairo_cff_font_read_private_dict (cairo_
     unsigned char *operand;
     unsigned char *p;
 
-    cff_dict_read (font->private_dict, ptr, size);
-    operand = cff_dict_get_operands (font->private_dict, LOCAL_SUB_OP, &i);
+    cff_dict_read (private_dict, ptr, size);
+    operand = cff_dict_get_operands (private_dict, LOCAL_SUB_OP, &i);
     if (operand) {
         decode_integer (operand, &offset);
         p = ptr + offset;
-        cff_index_read (&font->local_sub_index, &p, font->data_end);
+        cff_index_read (local_sub_index, &p, font->data_end);
 
         /* Use maximum sized encoding to reserve space for later modification. */
         end_buf = encode_integer_max (buf, 0);
-        cff_dict_set_operands (font->private_dict, LOCAL_SUB_OP, buf, end_buf - buf);
+        cff_dict_set_operands (private_dict, LOCAL_SUB_OP, buf, end_buf - buf);
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
+cairo_cff_font_read_fdselect (cairo_cff_font_t *font, unsigned char *p)
+{
+    int type, num_ranges, first, last, fd, i, j;
+
+    font->fdselect = calloc (font->num_glyphs, sizeof (int));
+    if (font->fdselect == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
+
+    type = *p++;
+    if (type == 0)
+    {
+        for (i = 0; i < font->num_glyphs; i++)
+            font->fdselect[i] = *p++;
+    } else if (type == 3) {
+        num_ranges = be16_to_cpu( *((uint16_t *)p) );
+        p += 2;
+        for  (i = 0; i < num_ranges; i++)
+        {
+            first = be16_to_cpu( *((uint16_t *)p) );
+            p += 2;
+            fd = *p++;
+            last = be16_to_cpu( *((uint16_t *)p) );
+            for (j = first; j < last; j++)
+                font->fdselect[j] = fd;
+        }
+    } else {
+        return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
+{
+    cairo_array_t index;
+    cff_index_element_t *element;
+    unsigned int i;
+    int size;
+    unsigned char *operand;
+    int offset;
+    cairo_int_status_t status;
+    unsigned char buf[100];
+    unsigned char *end_buf;
+
+    cff_index_init (&index);
+    status = cff_index_read (&index, &ptr, font->data_end);
+    if (status)
+        goto fail;
+
+    font->num_fontdicts = _cairo_array_num_elements (&index);
+
+    font->fd_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts);
+    if (font->fd_dict == NULL) {
+        status = CAIRO_STATUS_NO_MEMORY;
+        goto fail;
+    }
+
+    font->fd_private_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts);
+    if (font->fd_private_dict == NULL) {
+        status = CAIRO_STATUS_NO_MEMORY;
+        goto fail;
+    }
+
+    font->fd_local_sub_index = calloc (sizeof (cairo_array_t), font->num_fontdicts);
+    if (font->fd_local_sub_index == NULL) {
+        status = CAIRO_STATUS_NO_MEMORY;
+        goto fail;
+    }
+
+    for (i = 0; i < font->num_fontdicts; i++) {
+        cff_dict_init (&font->fd_dict[i]);
+        if (font->fd_dict[i] == NULL) {
+            status = CAIRO_STATUS_NO_MEMORY;
+            goto fail;
+        }
+        element = _cairo_array_index (&index, i);
+        status = cff_dict_read (font->fd_dict[i], element->data, element->length);
+        if (status)
+            goto fail;
+
+        operand = cff_dict_get_operands (font->fd_dict[i], PRIVATE_OP, &size);
+        if (operand == NULL) {
+            status = CAIRO_INT_STATUS_UNSUPPORTED;
+            goto fail;
+        }
+        operand = decode_integer (operand, &size);
+        decode_integer (operand, &offset);
+        cff_dict_init (&font->fd_private_dict[i]);
+        if (font->fd_private_dict[i] == NULL) {
+            status = CAIRO_STATUS_NO_MEMORY;
+            goto fail;
+        }
+        cff_index_init (&font->fd_local_sub_index[i]);
+        status = cairo_cff_font_read_private_dict (font,
+                                                   font->fd_private_dict[i],
+                                                   &font->fd_local_sub_index[i],
+                                                   font->data + offset,
+                                                   size);
+        if (status)
+            goto fail;
+        /* Set integer operand to max value to use max size encoding to reserve
+         * space for any value later */
+        end_buf = encode_integer_max (buf, 0);
+        end_buf = encode_integer_max (end_buf, 0);
+        status = cff_dict_set_operands (font->fd_dict[i], PRIVATE_OP, buf, end_buf - buf);
+        if (status)
+            goto fail;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+
+fail:
+    cff_index_fini (&index);
+
+    return status;
+}
+
+static cairo_int_status_t
 cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
 {
     cairo_array_t index;
@@ -688,13 +848,14 @@ cairo_cff_font_read_top_dict (cairo_cff_
         goto fail;
 
     element = _cairo_array_index (&index, 0);
-    cff_dict_read (font->top_dict, element->data, element->length);
-
-    /* CID fonts are NYI */
-    if (cff_dict_get_operands (font->top_dict, ROS_OP, &size) != NULL) {
-        status = CAIRO_INT_STATUS_UNSUPPORTED;
+    status = cff_dict_read (font->top_dict, element->data, element->length);
+    if (status)
         goto fail;
-    }
+
+    if (cff_dict_get_operands (font->top_dict, ROS_OP, &size) != NULL)
+        font->is_cid = TRUE;
+    else
+        font->is_cid = FALSE;
 
     operand = cff_dict_get_operands (font->top_dict, CHARSTRINGS_OP, &size);
     decode_integer (operand, &offset);
@@ -704,27 +865,34 @@ cairo_cff_font_read_top_dict (cairo_cff_
         goto fail;
     font->num_glyphs = _cairo_array_num_elements (&font->charstrings_index);
 
-    operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size);
-    operand = decode_integer (operand, &size);
-    decode_integer (operand, &offset);
-    cairo_cff_font_read_private_dict (font, font->data + offset, size);
+    if (font->is_cid) {
+        operand = cff_dict_get_operands (font->top_dict, FDSELECT_OP, &size);
+        decode_integer (operand, &offset);
+        cairo_cff_font_read_fdselect (font, font->data + offset);
 
-    operand = cff_dict_get_operands (font->top_dict, CHARSET_OP, &size);
-    if (!operand)
-      font->charset_offset = 0;
-    else {
-      decode_integer (operand, &offset);
-      font->charset_offset = offset;
+        operand = cff_dict_get_operands (font->top_dict, FDARRAY_OP, &size);
+        decode_integer (operand, &offset);
+        cairo_cff_font_read_cid_fontdict (font, font->data + offset);
+    } else {
+        operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size);
+        operand = decode_integer (operand, &size);
+        decode_integer (operand, &offset);
+        cairo_cff_font_read_private_dict (font,
+                                          font->private_dict,
+                                          &font->local_sub_index,
+                                          font->data + offset,
+                                          size);
     }
 
     /* Use maximum sized encoding to reserve space for later modification. */
     end_buf = encode_integer_max (buf, 0);
     cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf);
-    cff_dict_set_operands (font->top_dict, ENCODING_OP, buf, end_buf - buf);
+    cff_dict_set_operands (font->top_dict, FDSELECT_OP, buf, end_buf - buf);
+    cff_dict_set_operands (font->top_dict, FDARRAY_OP, buf, end_buf - buf);
     cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf);
-    /* Private has two operands - size and offset */
-    end_buf = encode_integer_max (end_buf, 0);
-    cff_dict_set_operands (font->top_dict, PRIVATE_OP, buf, end_buf - buf);
+
+    cff_dict_remove (font->top_dict, ENCODING_OP);
+    cff_dict_remove (font->top_dict, PRIVATE_OP);
 
 fail:
     cff_index_fini (&index);
@@ -744,138 +912,6 @@ cairo_cff_font_read_global_subroutines (
     return cff_index_read (&font->global_sub_index, &font->current_ptr, font->data_end);
 }
 
-static cairo_int_status_t
-cff_charset_read_data (cff_charset_t *charset, const unsigned char *data,
-	const unsigned char *data_end, int num_glyphs)
-{
-    const unsigned char *p = data;
-
-    num_glyphs -= 1; /* do not count .notdef */
-
-    if (p + 1 > data_end)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    switch (*p++) {
-    case 0:
-	if (p + num_glyphs*2 > data_end)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-	charset->is_builtin = FALSE;
-	charset->data = data;
-	charset->length = num_glyphs * 2 + 1;
-	break;
-    case 1:
-	while (num_glyphs > 0) {
-	    if (p + 3 > data_end)
-		return CAIRO_INT_STATUS_UNSUPPORTED;
-	    num_glyphs -= p[2] + 1;
-	    p += 3;
-	}
-	if (num_glyphs < 0)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-	charset->is_builtin = FALSE;
-	charset->data = data;
-	charset->length = p - data;
-	break;
-    case 2:
-	while (num_glyphs > 0) {
-	    if (p + 4 > data_end)
-		return CAIRO_INT_STATUS_UNSUPPORTED;
-	    num_glyphs -= be16_to_cpu(*(uint16_t *)(p + 2)) + 1;
-	    p += 4;
-	}
-	if (num_glyphs < 0)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-	charset->is_builtin = FALSE;
-	charset->data = data;
-	charset->length = p - data;
-	break;
-    default:
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static const uint16_t ISOAdobe_charset[] = {
-    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-    17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
-    31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
-    45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
-    59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
-    73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
-    87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
-    101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
-    112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
-    123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133,
-    134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
-    145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
-    156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
-    167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
-    178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
-    189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
-    200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
-    211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
-    222, 223, 224, 225, 226, 227, 228,
-};
-
-static const uint16_t Expert_charset[] = {
-    1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13,
-    14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247,
-    248, 27, 28, 249, 250, 251, 252, 253, 254, 255, 256, 257,
-    258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110,
-    267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277,
-    278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
-    289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
-    300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310,
-    311, 312, 313, 314, 315, 316, 317, 318, 158, 155, 163,
-    319, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169,
-    327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337,
-    338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348,
-    349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359,
-    360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370,
-    371, 372, 373, 374, 375, 376, 377, 378,
-};
-
-static const uint16_t ExpertSubset_charset[] = {
-    1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240,
-    241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250,
-    251, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
-    263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272,
-    300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321,
-    322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329,
-    330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340,
-    341, 342, 343, 344, 345, 346,
-};
-
-static cairo_int_status_t
-cairo_cff_font_read_charset (cairo_cff_font_t *font)
-{
-    switch (font->charset_offset) {
-    case 0:
-	/* ISOAdobe charset */
-	font->charset.is_builtin = TRUE;
-        font->charset.sids = ISOAdobe_charset;
-        font->charset.length = sizeof (ISOAdobe_charset);
-	return CAIRO_STATUS_SUCCESS;
-    case 1:
-	/* Expert charset */
-	font->charset.is_builtin = TRUE;
-        font->charset.sids = Expert_charset;
-        font->charset.length = sizeof (Expert_charset);
-	return CAIRO_STATUS_SUCCESS;
-    case 2:
-	/* ExpertSubset charset */;
-	font->charset.is_builtin = TRUE;
-        font->charset.sids = ExpertSubset_charset;
-        font->charset.length = sizeof (ExpertSubset_charset);
-	return CAIRO_STATUS_SUCCESS;
-    default:
-	break;
-    }
-    return cff_charset_read_data (&font->charset, font->data + (unsigned)font->charset_offset,
-	    font->data_end, font->num_glyphs);
-}
-
 typedef cairo_int_status_t
 (*font_read_t) (cairo_cff_font_t *font);
 
@@ -885,8 +921,6 @@ static const font_read_t font_read_funcs
     cairo_cff_font_read_top_dict,
     cairo_cff_font_read_strings,
     cairo_cff_font_read_global_subroutines,
-    /* non-contiguous */
-    cairo_cff_font_read_charset,
 };
 
 static cairo_int_status_t
@@ -904,6 +938,34 @@ cairo_cff_font_read_font (cairo_cff_font
     return CAIRO_STATUS_SUCCESS;
 }
 
+static void
+cairo_cff_font_set_ros_strings (cairo_cff_font_t *font)
+{
+    unsigned char buf[30];
+    unsigned char *p;
+    int sid1, sid2;
+    const char *registry = "Adobe";
+    const char *ordering = "Identity";
+
+    sid1 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
+    cff_index_append_copy (&font->strings_subset_index,
+                           (unsigned char *)registry,
+                           strlen(registry));
+
+    sid2 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
+    cff_index_append_copy (&font->strings_subset_index,
+                           (unsigned char *)ordering,
+                           strlen(ordering));
+
+    p = encode_integer (buf, sid1);
+    p = encode_integer (p, sid2);
+    p = encode_integer (p, 0);
+    cff_dict_set_operands (font->top_dict, ROS_OP, buf, p - buf);
+
+    p = encode_integer (buf, font->scaled_font_subset->num_glyphs);
+    cff_dict_set_operands (font->top_dict, CIDCOUNT_OP, buf, p - buf);
+}
+
 static cairo_status_t
 cairo_cff_font_subset_dict_string(cairo_cff_font_t   *font,
                                   cairo_hash_table_t *dict,
@@ -965,29 +1027,12 @@ cairo_cff_font_subset_dict_strings (cair
 }
 
 static cairo_status_t
-cairo_cff_font_subset_strings (cairo_cff_font_t *font)
-{
-    cairo_status_t status;
-
-    status = cairo_cff_font_subset_dict_strings (font, font->top_dict);
-    if (status)
-        return status;
-
-    status = cairo_cff_font_subset_dict_strings (font, font->private_dict);
-
-    return status;
-}
-
-static cairo_status_t
 cairo_cff_font_subset_charstrings (cairo_cff_font_t  *font)
 {
     cff_index_element_t *element;
     unsigned int i;
     cairo_status_t status;
 
-    if (status)
-        return status;
-
     for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
         element = _cairo_array_index (&font->charstrings_index,
                                       font->scaled_font_subset->glyphs[i]);
@@ -1001,78 +1046,105 @@ cairo_cff_font_subset_charstrings (cairo
     return CAIRO_STATUS_SUCCESS;
 }
 
-static uint16_t
-cff_sid_from_gid (const cff_charset_t *charset, int gid)
+static cairo_status_t
+cairo_cff_font_subset_fontdict (cairo_cff_font_t  *font)
 {
-    const uint16_t *sids;
-    const unsigned char *p;
-    int prev_glyph;
-
-    if (charset->is_builtin) {
-        if (gid - 1 < charset->length / 2)
-	    return charset->sids[gid - 1];
-    }
-    else {
-	/* no need to check sizes here, this was done during reading */
-	switch (charset->data[0]) {
-	case 0:
-	    sids = (const uint16_t *)(charset->data + 1);
-	    return be16_to_cpu(sids[gid - 1]);
-	case 1:
-	    prev_glyph = 1;
-	    for (p = charset->data + 1; p < charset->data + charset->length; p += 3) {
-		if (gid <= prev_glyph + p[2]) {
-		    uint16_t sid = be16_to_cpu(*(const uint16_t *)p);
-		    return sid + gid - prev_glyph;
-		}
-		prev_glyph += p[2] + 1;
-	    }
-	    break;
-	case 2:
-	    prev_glyph = 1;
-	    for (p = charset->data + 1; p < charset->data + charset->length; p += 4) {
-		uint16_t nLeft = be16_to_cpu(*(const uint16_t *)(p + 2));
-		if (gid <= prev_glyph + nLeft) {
-		    uint16_t sid = be16_to_cpu(*(const uint16_t *)p);
-		    return sid + gid - prev_glyph;
-		}
-		prev_glyph += nLeft + 1;
-	    }
-	    break;
-	default:
-	    break;
-	}
+    unsigned int i;
+    int fd;
+    int *reverse_map;
+
+    font->fdselect_subset = calloc (font->scaled_font_subset->num_glyphs,
+                                     sizeof (int));
+    if (font->fdselect_subset == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
+
+    font->fd_subset_map = calloc (font->num_fontdicts, sizeof (int));
+    if (font->fd_subset_map == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
+
+    font->private_dict_offset = calloc (font->num_fontdicts, sizeof (int));
+    if (font->private_dict_offset == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
+
+    reverse_map = calloc (font->num_fontdicts, sizeof (int));
+    if (reverse_map == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
+
+    for (i = 0; i < font->num_fontdicts; i++)
+        reverse_map[i] = -1;
+
+    font->num_subset_fontdicts = 0;
+    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+        fd = font->fdselect[font->scaled_font_subset->glyphs[i]];
+        if (reverse_map[fd] < 0) {
+            font->fd_subset_map[font->num_subset_fontdicts] = fd;
+            reverse_map[fd] = font->num_subset_fontdicts++;
+        }
+        font->fdselect_subset[i] = reverse_map[fd];
     }
-    return 0;
+
+    free (reverse_map);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font)
+{
+    unsigned char buf[100];
+    unsigned char *end_buf;
+
+    font->num_fontdicts = 1;
+    font->fd_dict = malloc (sizeof (cairo_hash_table_t *));
+    if (font->fd_dict == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
+
+    cff_dict_init (&font->fd_dict[0]);
+
+    font->fd_subset_map = malloc (sizeof (int));
+    if (font->fd_subset_map == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
+
+    font->private_dict_offset = malloc (sizeof (int));
+    if (font->private_dict_offset == NULL)
+        return CAIRO_STATUS_NO_MEMORY;
+
+    font->fd_subset_map[0] = 0;
+    font->num_subset_fontdicts = 1;
+
+    /* Set integer operand to max value to use max size encoding to reserve
+     * space for any value later */
+    end_buf = encode_integer_max (buf, 0);
+    end_buf = encode_integer_max (end_buf, 0);
+    cff_dict_set_operands (font->fd_dict[0], PRIVATE_OP, buf, end_buf - buf);
+
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-cairo_cff_font_subset_charset (cairo_cff_font_t  *font)
+cairo_cff_font_subset_strings (cairo_cff_font_t *font)
 {
+    cairo_status_t status;
     unsigned int i;
 
-    for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) {
-	int gid = font->scaled_font_subset->glyphs[i];
-	uint16_t original_sid = cff_sid_from_gid(&font->charset, gid);
-	uint16_t new_sid;
-	cff_index_element_t *element;
-	cairo_status_t status;
-
-	if (original_sid >= NUM_STD_STRINGS) {
-	    element = _cairo_array_index (&font->strings_index, original_sid - NUM_STD_STRINGS);
-	    new_sid = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
-	    status = cff_index_append (&font->strings_subset_index, element->data, element->length);
-	    if (status)
-		return status;
-	}
-	else
-	    new_sid = original_sid;
+    status = cairo_cff_font_subset_dict_strings (font, font->top_dict);
+    if (status)
+        return status;
+    if (font->is_cid) {
+        for (i = 0; i < font->num_subset_fontdicts; i++) {
+            status = cairo_cff_font_subset_dict_strings (font, font->fd_dict[font->fd_subset_map[i]]);
+            if (status)
+                return status;
 
-	status = _cairo_array_append(&font->charset_subset, &new_sid);
-	if (status)
-	    return status;
+            status = cairo_cff_font_subset_dict_strings (font, font->fd_private_dict[font->fd_subset_map[i]]);
+            if (status)
+                return status;
+        }
+    } else {
+        status = cairo_cff_font_subset_dict_strings (font, font->private_dict);
     }
-    return CAIRO_STATUS_SUCCESS;
+
+    return status;
 }
 
 static cairo_status_t
@@ -1080,17 +1152,20 @@ cairo_cff_font_subset_font (cairo_cff_fo
 {
     cairo_status_t status;
 
-    /* TODO: subset subroutines */
+    cairo_cff_font_set_ros_strings (font);
 
-    status = cairo_cff_font_subset_strings (font);
+    status = cairo_cff_font_subset_charstrings (font);
     if (status)
         return status;
 
-    status = cairo_cff_font_subset_charstrings (font);
-    if (status)
-	return status;
+    if (font->is_cid)
+        cairo_cff_font_subset_fontdict (font);
+    else
+        cairo_cff_font_create_cid_fontdict (font);
 
-    status = cairo_cff_font_subset_charset (font);
+    status = cairo_cff_font_subset_strings (font);
+    if (status)
+        return status;
 
     return status;
 }
@@ -1205,38 +1280,82 @@ cairo_cff_font_write_global_subrs (cairo
 }
 
 static cairo_status_t
-cairo_cff_font_write_encoding (cairo_cff_font_t  *font)
+cairo_cff_font_write_fdselect (cairo_cff_font_t  *font)
 {
-    unsigned char buf[10];
+    unsigned char data;
+    unsigned int i;
+    cairo_int_status_t status;
+
+    cairo_cff_font_set_topdict_operator_to_cur_pos (font, FDSELECT_OP);
+
+    if (font->is_cid) {
+        data = 0;
+        status = _cairo_array_append (&font->output, &data);
+        if (status)
+            return status;
+
+        for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+            data = font->fdselect_subset[i];
+            status = _cairo_array_append (&font->output, &data);
+            if (status)
+                return status;
+        }
+    } else {
+        unsigned char byte;
+        uint16_t word;
+
+        status = _cairo_array_grow_by (&font->output, 9);
+        if (status)
+            return status;
 
-    cairo_cff_font_set_topdict_operator_to_cur_pos (font, ENCODING_OP);
-    buf[0] = 1; /* Format 1 */
-    buf[1] = 1; /* Number of ranges */
-    buf[2] = 0; /* First code in range */
-    /* Codes left in range excluding first */
-    buf[3] = font->scaled_font_subset->num_glyphs - 1;
+        byte = 3;
+        status = _cairo_array_append (&font->output, &byte);
+        assert (status == CAIRO_STATUS_SUCCESS);
+
+        word = cpu_to_be16 (1);
+        status = _cairo_array_append_multiple (&font->output, &word, 2);
+        assert (status == CAIRO_STATUS_SUCCESS);
+
+        word = cpu_to_be16 (0);
+        status = _cairo_array_append_multiple (&font->output, &word, 2);
+        assert (status == CAIRO_STATUS_SUCCESS);
+
+        byte = 0;
+        status = _cairo_array_append (&font->output, &byte);
+        assert (status == CAIRO_STATUS_SUCCESS);
+
+        word = cpu_to_be16 (font->scaled_font_subset->num_glyphs);
+        status = _cairo_array_append_multiple (&font->output, &word, 2);
+        assert (status == CAIRO_STATUS_SUCCESS);
+    }
 
-    return _cairo_array_append_multiple (&font->output, buf, 4);
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
 cairo_cff_font_write_charset (cairo_cff_font_t  *font)
 {
-    unsigned char format = 0;
-    unsigned int i;
+    unsigned char byte;
+    uint16_t word;
     cairo_status_t status;
 
     cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSET_OP);
-    status = _cairo_array_append (&font->output, &format);
+    status = _cairo_array_grow_by (&font->output, 5);
     if (status)
-	return status;
+        return status;
+
+    byte = 2;
+    status = _cairo_array_append (&font->output, &byte);
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    word = cpu_to_be16 (1);
+    status = _cairo_array_append_multiple (&font->output, &word, 2);
+    assert (status == CAIRO_STATUS_SUCCESS);
+
+    word = cpu_to_be16 (font->scaled_font_subset->num_glyphs - 2);
+    status = _cairo_array_append_multiple (&font->output, &word, 2);
+    assert (status == CAIRO_STATUS_SUCCESS);
 
-    for (i = 0; i < (unsigned)_cairo_array_num_elements(&font->charset_subset); i++) {
-	uint16_t sid = cpu_to_be16(*(uint16_t *)_cairo_array_index(&font->charset_subset, i));
-	status = _cairo_array_append_multiple (&font->output, &sid, sizeof(sid));
-	if (status)
-	    return status;
-    }
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1249,9 +1368,48 @@ cairo_cff_font_write_charstrings (cairo_
 }
 
 static cairo_status_t
-cairo_cff_font_write_private_dict_and_local_sub (cairo_cff_font_t *font)
+cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font)
 {
-    int offset, private_dict_offset;
+    unsigned int i;
+    cairo_int_status_t status;
+    uint32_t *offset_array;
+    int offset_base;
+    uint16_t count;
+    uint8_t offset_size = 4;
+
+    cairo_cff_font_set_topdict_operator_to_cur_pos (font, FDARRAY_OP);
+    count = cpu_to_be16 (font->num_subset_fontdicts);
+    status = _cairo_array_append_multiple (&font->output, &count, sizeof (uint16_t));
+    if (status)
+        return status;
+    status = _cairo_array_append (&font->output, &offset_size);
+    if (status)
+        return status;
+    status = _cairo_array_allocate (&font->output,
+                                    (font->num_subset_fontdicts + 1)*offset_size,
+                                    (void **) &offset_array);
+    if (status)
+        return status;
+    offset_base = _cairo_array_num_elements (&font->output) - 1;
+    *offset_array++ = cpu_to_be32(1);
+    for (i = 0; i < font->num_subset_fontdicts; i++) {
+        status = cff_dict_write (font->fd_dict[font->fd_subset_map[i]],
+                                 &font->output);
+        if (status)
+            return status;
+        *offset_array++ = cpu_to_be32(_cairo_array_num_elements (&font->output) - offset_base);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+cairo_cff_font_write_private_dict (cairo_cff_font_t   *font,
+                                   int                 dict_num,
+                                   cairo_hash_table_t *parent_dict,
+                                   cairo_hash_table_t *private_dict)
+{
+    int offset;
     int size;
     unsigned char buf[10];
     unsigned char *buf_end;
@@ -1259,30 +1417,46 @@ cairo_cff_font_write_private_dict_and_lo
     cairo_status_t status;
 
     /* Write private dict and update offset and size in top dict */
-    private_dict_offset = _cairo_array_num_elements (&font->output);
-    status = cff_dict_write (font->private_dict, &font->output);
+    font->private_dict_offset[dict_num] = _cairo_array_num_elements (&font->output);
+    status = cff_dict_write (private_dict, &font->output);
     if (status)
         return status;
-    size = _cairo_array_num_elements (&font->output) - private_dict_offset;
+    size = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num];
     /* private entry has two operands - size and offset */
     buf_end = encode_integer_max (buf, size);
-    buf_end = encode_integer_max (buf_end, private_dict_offset);
-    offset = cff_dict_get_location (font->top_dict, PRIVATE_OP, &size);
+    buf_end = encode_integer_max (buf_end, font->private_dict_offset[dict_num]);
+    offset = cff_dict_get_location (parent_dict, PRIVATE_OP, &size);
     assert (offset > 0);
     p = _cairo_array_index (&font->output, offset);
     memcpy (p, buf, buf_end - buf);
 
-    if (_cairo_array_num_elements (&font->local_sub_index) > 0) {
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+cairo_cff_font_write_local_sub (cairo_cff_font_t   *font,
+                                int                 dict_num,
+                                cairo_hash_table_t *private_dict,
+                                cairo_array_t      *local_sub_index)
+{
+    int offset;
+    int size;
+    unsigned char buf[10];
+    unsigned char *buf_end;
+    unsigned char *p;
+    cairo_status_t status;
+
+    if (_cairo_array_num_elements (local_sub_index) > 0) {
         /* Write local subroutines and update offset in private
          * dict. Local subroutines offset is relative to start of
          * private dict */
-        offset = _cairo_array_num_elements (&font->output) - private_dict_offset;
+        offset = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num];
         buf_end = encode_integer_max (buf, offset);
-        offset = cff_dict_get_location (font->private_dict, LOCAL_SUB_OP, &size);
+        offset = cff_dict_get_location (private_dict, LOCAL_SUB_OP, &size);
         assert (offset > 0);
         p = _cairo_array_index (&font->output, offset);
         memcpy (p, buf, buf_end - buf);
-        status = cff_index_write (&font->local_sub_index, &font->output);
+        status = cff_index_write (local_sub_index, &font->output);
         if (status)
             return status;
     }
@@ -1290,6 +1464,47 @@ cairo_cff_font_write_private_dict_and_lo
     return CAIRO_STATUS_SUCCESS;
 }
 
+
+static cairo_status_t
+cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t  *font)
+{
+    unsigned int i;
+    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+
+    if (font->is_cid) {
+        for (i = 0; i < font->num_subset_fontdicts; i++) {
+            status = cairo_cff_font_write_private_dict (
+                            font,
+                            i,
+                            font->fd_dict[font->fd_subset_map[i]],
+                            font->fd_private_dict[font->fd_subset_map[i]]);
+            if (status)
+                return status;
+        }
+
+        for (i = 0; i < font->num_subset_fontdicts; i++) {
+            status = cairo_cff_font_write_local_sub (
+                            font,
+                            i,
+                            font->fd_private_dict[font->fd_subset_map[i]],
+                           &font->fd_local_sub_index[font->fd_subset_map[i]]);
+            if (status)
+                return status;
+        }
+    } else {
+        status = cairo_cff_font_write_private_dict (font,
+                                                    0,
+                                                    font->fd_dict[0],
+                                                    font->private_dict);
+        status = cairo_cff_font_write_local_sub (font,
+                                                 0,
+                                                 font->private_dict,
+                                                 &font->local_sub_index);
+    }
+
+    return status;
+}
+
 typedef cairo_status_t
 (*font_write_t) (cairo_cff_font_t *font);
 
@@ -1299,10 +1514,11 @@ static const font_write_t font_write_fun
     cairo_cff_font_write_top_dict,
     cairo_cff_font_write_strings,
     cairo_cff_font_write_global_subrs,
-    cairo_cff_font_write_encoding,
+    cairo_cff_font_write_fdselect,
     cairo_cff_font_write_charset,
     cairo_cff_font_write_charstrings,
-    cairo_cff_font_write_private_dict_and_local_sub,
+    cairo_cff_font_write_cid_fontdict,
+    cairo_cff_font_write_cid_private_dict_and_local_sub,
 };
 
 static cairo_status_t
@@ -1548,7 +1764,13 @@ _cairo_cff_font_create (cairo_scaled_fon
     cff_index_init (&font->local_sub_index);
     cff_index_init (&font->charstrings_subset_index);
     cff_index_init (&font->strings_subset_index);
-    _cairo_array_init (&font->charset_subset, sizeof(uint16_t));
+    font->fdselect = NULL;
+    font->fd_dict = NULL;
+    font->fd_private_dict = NULL;
+    font->fd_local_sub_index = NULL;
+    font->fdselect_subset = NULL;
+    font->fd_subset_map = NULL;
+    font->private_dict_offset = NULL;
 
     free (name);
     *font_return = font;
@@ -1575,6 +1797,8 @@ fail1:
 static void
 cairo_cff_font_destroy (cairo_cff_font_t *font)
 {
+    unsigned int i;
+
     free (font->widths);
     free (font->font_name);
     free (font->subset_font_name);
@@ -1587,7 +1811,43 @@ cairo_cff_font_destroy (cairo_cff_font_t
     cff_index_fini (&font->local_sub_index);
     cff_index_fini (&font->charstrings_subset_index);
     cff_index_fini (&font->strings_subset_index);
-    _cairo_array_fini (&font->charset_subset);
+
+    /* If we bailed out early as a result of an error some of the
+     * following cairo_cff_font_t members may still be NULL */
+    if (font->fd_dict) {
+        for (i = 0; i < font->num_fontdicts; i++) {
+            if (font->fd_dict[i])
+                cff_dict_fini (font->fd_dict[i]);
+        }
+        free (font->fd_dict);
+    }
+    if (font->fd_subset_map)
+        free (font->fd_subset_map);
+    if (font->private_dict_offset)
+        free (font->private_dict_offset);
+
+    if (font->is_cid) {
+        if (font->fdselect)
+            free (font->fdselect);
+        if (font->fdselect_subset)
+            free (font->fdselect_subset);
+        if (font->fd_private_dict) {
+            for (i = 0; i < font->num_fontdicts; i++) {
+                if (font->fd_private_dict[i])
+                    cff_dict_fini (font->fd_private_dict[i]);
+            }
+            free (font->fd_private_dict);
+        }
+        if (font->fd_local_sub_index) {
+            for (i = 0; i < font->num_fontdicts; i++)
+                cff_index_fini (&font->fd_local_sub_index[i]);
+            free (font->fd_local_sub_index);
+        }
+    }
+
+    if (font->data)
+        free (font->data);
+
     free (font);
 }
 
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index d6c1f8f..7a164e0 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -2440,9 +2440,11 @@ _cairo_pdf_surface_emit_unscaled_font_su
     cairo_pdf_surface_t *surface = closure;
     cairo_status_t status;
 
+#if 0
     status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return;
+#endif
 
 #if CAIRO_HAS_FT_FONT
     status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset);
diff-tree 073fce5a85ab90b1bc6915e41d6a420a47e540e6 (from bf957ee0f29ff49970b4791718eccdb92f3d6886)
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Fri Apr 20 22:29:41 2007 +0930

    Add support for creating CID/composite font subsets
    
    cairo-scaled-font-subsets.c now provides three functions for creating subsets:
    
      _cairo_scaled_font_subsets_create_scaled()
        Create a subset for each scaled font with maximum size INT_MAX.
    
      _cairo_scaled_font_subsets_create_simple()
        Create subsets suitable for embedding as simple fonts in PS/PDF.
    
      _cairo_scaled_font_subsets_create_composite()
        Create subsets suitable for embedding as composite fonts in PS/PDF.
    
    The _create_simple() and _create_composite() functions both merge
    scaled fonts with the same face and an outline path available into
    the same subset. _create_composite() has a maximum subset size of
    65536 for outline fonts. Bitmap fonts have a separate subset for
    each scale with a maximum subset size of 256.
    
    The _create_simple() and _create_composite() functions both reserve
    the first glyph in the subset for the .notdef glyph. CID fonts require
    CID 0 to be .notdef.
    
    Update Type1, TrueType and CFF subsetting to expect glyph 0 of each
    subset to be the .notdef.

diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index ab61ae2..b0158fe 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -985,11 +985,6 @@ cairo_cff_font_subset_charstrings (cairo
     unsigned int i;
     cairo_status_t status;
 
-    /* add .notdef */
-    element = _cairo_array_index (&font->charstrings_index, 0);
-    status = cff_index_append (&font->charstrings_subset_index,
-                               element->data,
-                               element->length);
     if (status)
         return status;
 
@@ -1056,7 +1051,7 @@ cairo_cff_font_subset_charset (cairo_cff
 {
     unsigned int i;
 
-    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+    for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) {
 	int gid = font->scaled_font_subset->glyphs[i];
 	uint16_t original_sid = cff_sid_from_gid(&font->charset, gid);
 	uint16_t new_sid;
@@ -1371,7 +1366,7 @@ cairo_cff_font_create_set_widths (cairo_
         return status;
     num_hmetrics = be16_to_cpu (hhea.num_hmetrics);
 
-    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+    for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) {
         glyph_index = font->scaled_font_subset->glyphs[i];
         long_entry_size = 2 * sizeof (int16_t);
         short_entry_size = sizeof (int16_t);
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 2cfad5c..d6c1f8f 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -138,8 +138,6 @@ typedef struct _cairo_pdf_surface {
     cairo_paginated_mode_t paginated_mode;
 } cairo_pdf_surface_t;
 
-#define PDF_SURFACE_MAX_GLYPHS_PER_FONT	256
-
 static cairo_pdf_resource_t
 _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface);
 
@@ -279,8 +277,7 @@ _cairo_pdf_surface_create_for_stream_int
     _cairo_array_init (&surface->streams, sizeof (cairo_pdf_resource_t));
     _cairo_array_init (&surface->alphas, sizeof (double));
 
-    surface->font_subsets = _cairo_scaled_font_subsets_create (PDF_SURFACE_MAX_GLYPHS_PER_FONT,
-                                                               PDF_SURFACE_MAX_GLYPHS_PER_FONT);
+    surface->font_subsets = _cairo_scaled_font_subsets_create_simple();
     if (! surface->font_subsets) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	free (surface);
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index d725c53..520c404 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -84,8 +84,6 @@ typedef struct cairo_ps_surface {
 
 } cairo_ps_surface_t;
 
-#define PS_SURFACE_MAX_GLYPHS_PER_FONT	256
-
 /* A word wrap stream can be used as a filter to do word wrapping on
  * top of an existing output stream. The word wrapping is quite
  * simple, using isspace to determine characters that separate
@@ -486,18 +484,18 @@ _cairo_ps_surface_emit_truetype_font_sub
 
     /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
 
-    for (i = 0; i < font_subset->num_glyphs; i++)
+    for (i = 1; i < font_subset->num_glyphs; i++)
 	_cairo_output_stream_printf (surface->final_stream,
 				     "Encoding %d /g%d put\n", i, i);
 
     _cairo_output_stream_printf (surface->final_stream,
 				 "/CharStrings %d dict dup begin\n"
 				 "/.notdef 0 def\n",
-				 font_subset->num_glyphs + 1);
+				 font_subset->num_glyphs);
 
-    for (i = 0; i < font_subset->num_glyphs; i++)
+    for (i = 1; i < font_subset->num_glyphs; i++)
 	_cairo_output_stream_printf (surface->final_stream,
-				     "/g%d %d def\n", i, i + 1);
+				     "/g%d %d def\n", i, i);
 
     _cairo_output_stream_printf (surface->final_stream,
 				 "end readonly def\n");
@@ -814,8 +812,7 @@ _cairo_ps_surface_create_for_stream_inte
     if (status)
 	goto CLEANUP_TMPFILE;
 
-    surface->font_subsets = _cairo_scaled_font_subsets_create (PS_SURFACE_MAX_GLYPHS_PER_FONT,
-                                                               PS_SURFACE_MAX_GLYPHS_PER_FONT);
+    surface->font_subsets = _cairo_scaled_font_subsets_create_simple ();
     if (! surface->font_subsets)
 	goto CLEANUP_OUTPUT_STREAM;
 
diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h
index db655f7..4c8221e 100644
--- a/src/cairo-scaled-font-subsets-private.h
+++ b/src/cairo-scaled-font-subsets-private.h
@@ -46,20 +46,12 @@ typedef struct _cairo_scaled_font_subset
     unsigned int subset_id;
     unsigned int subset_glyph_index;
     cairo_bool_t is_scaled;
+    cairo_bool_t is_composite;
     double       x_advance;
 } cairo_scaled_font_subsets_glyph_t;
 
 /**
- * _cairo_scaled_font_subsets_create:
- *
- * @max_glyphs_per_unscaled_subset: the maximum number of glyphs that
- * should appear in any unscaled subset. A value of 0 indicates that
- * no unscaled subset will be created. All glyphs will mapped to
- * scaled subsets.
- *
- * @max_glyphs_per_scaled_subset: the maximum number of glyphs that
- * should appear in any scaled subset. A value of 0 indicates that
- * no scaled subset will be created.
+ * _cairo_scaled_font_subsets_create_scaled:
  *
  * Create a new #cairo_scaled_font_subsets_t object which can be used
  * to create subsets of any number of cairo_scaled_font_t
@@ -68,16 +60,57 @@ typedef struct _cairo_scaled_font_subset
  * subsets with glyph indices packed into the range
  * [0 .. max_glyphs_per_subset).
  *
- * @max_glyphs_per_unscaled_subset and @max_glyphs_per_scaled_subset
- * cannot both be 0.
+ * Return value: a pointer to the newly creates font subsets. The
+ * caller owns this object and should call
+ * _cairo_scaled_font_subsets_destroy() when done with it.
+ **/
+cairo_private cairo_scaled_font_subsets_t *
+_cairo_scaled_font_subsets_create_scaled (void);
+
+/**
+ * _cairo_scaled_font_subsets_create_simple:
+ *
+ * Create a new #cairo_scaled_font_subsets_t object which can be used
+ * to create font subsets suitable for embedding as Postscript or PDF
+ * simple fonts.
+ *
+ * Glyphs with an outline path available will be mapped to one font
+ * subset for each font face. Glyphs from bitmap fonts will mapped to
+ * separate font subsets for each cairo_scaled_font_t object.
+ *
+ * The maximum number of glyphs per subset is 256. Each subset
+ * reserves the first glyph for the .notdef glyph.
+ *
+ * Return value: a pointer to the newly creates font subsets. The
+ * caller owns this object and should call
+ * _cairo_scaled_font_subsets_destroy() when done with it.
+ **/
+cairo_private cairo_scaled_font_subsets_t *
+_cairo_scaled_font_subsets_create_simple (void);
+
+/**
+ * _cairo_scaled_font_subsets_create_composite:
+ *
+ * Create a new #cairo_scaled_font_subsets_t object which can be used
+ * to create font subsets suitable for embedding as Postscript or PDF
+ * composite fonts.
+ *
+ * Glyphs with an outline path available will be mapped to one font
+ * subset for each font face. Each unscaled subset has a maximum of
+ * 65536 glyphs.
+ *
+ * Glyphs from bitmap fonts will mapped to separate font subsets for
+ * each cairo_scaled_font_t object. Each unscaled subset has a maximum
+ * of 256 glyphs.
+ *
+ * Each subset reserves the first glyph for the .notdef glyph.
  *
  * Return value: a pointer to the newly creates font subsets. The
  * caller owns this object and should call
  * _cairo_scaled_font_subsets_destroy() when done with it.
  **/
 cairo_private cairo_scaled_font_subsets_t *
-_cairo_scaled_font_subsets_create (int max_glyphs_unscaled_per_subset,
-                                   int max_glyphs_scaled_per_subset);
+_cairo_scaled_font_subsets_create_composite (void);
 
 /**
  * _cairo_scaled_font_subsets_destroy:
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 974aebb..47260c8 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -42,12 +42,21 @@
 #include "cairoint.h"
 #include "cairo-scaled-font-subsets-private.h"
 
+#define MAX_GLYPHS_PER_SIMPLE_FONT 256
+#define MAX_GLYPHS_PER_COMPOSITE_FONT 65536
+
+typedef enum {
+    CAIRO_SUBSETS_SCALED,
+    CAIRO_SUBSETS_SIMPLE,
+    CAIRO_SUBSETS_COMPOSITE
+} cairo_subsets_type_t;
+
 struct _cairo_scaled_font_subsets {
-    int max_glyphs_per_unscaled_subset_limit;
+    cairo_subsets_type_t type;
+
     int max_glyphs_per_unscaled_subset_used;
     cairo_hash_table_t *unscaled_sub_fonts;
 
-    int max_glyphs_per_scaled_subset_limit;
     int max_glyphs_per_scaled_subset_used;
     cairo_hash_table_t *scaled_sub_fonts;
 
@@ -223,6 +232,11 @@ _cairo_sub_font_create (cairo_scaled_fon
 	return NULL;
     }
 
+    if (parent->type != CAIRO_SUBSETS_SCALED) {
+        /* Reserve first glyph in subset for the .notdef glyph */
+        sub_font->num_glyphs_in_current_subset++;
+    }
+
     return sub_font;
 }
 
@@ -289,6 +303,11 @@ _cairo_sub_font_map_glyph (cairo_sub_fon
 	{
 	    sub_font->current_subset++;
 	    sub_font->num_glyphs_in_current_subset = 0;
+
+            if (sub_font->parent->type != CAIRO_SUBSETS_SCALED) {
+                /* Reserve first glyph in subset for the .notdef glyph */
+                sub_font->num_glyphs_in_current_subset++;
+            }
 	}
 
         status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
@@ -340,13 +359,20 @@ _cairo_sub_font_collect (void *entry, vo
     for (i = 0; i <= sub_font->current_subset; i++) {
 	collection->subset_id = i;
 
-	collection->num_glyphs = 0;
-	collection->max_glyph = 0;
+        if (sub_font->parent->type == CAIRO_SUBSETS_SCALED) {
+            collection->num_glyphs = 0;
+            collection->max_glyph = 0;
+        } else {
+            /* Assign .notdef glyph to the first glyph in the subset */
+            collection->glyphs[0] = 0;
+            collection->num_glyphs = 1;
+            collection->max_glyph = 0;
+        }
 
 	_cairo_hash_table_foreach (sub_font->sub_font_glyphs,
 				   _cairo_sub_font_glyph_collect, collection);
 
-	/* Ensure the resulting array has no uninitialized holes */
+        /* Ensure the resulting array has no uninitialized holes */
 	assert (collection->num_glyphs == collection->max_glyph + 1);
 
 	subset.scaled_font = sub_font->scaled_font;
@@ -371,9 +397,8 @@ _cairo_sub_font_collect (void *entry, vo
     }
 }
 
-cairo_scaled_font_subsets_t *
-_cairo_scaled_font_subsets_create (int max_glyphs_per_unscaled_subset,
-                                   int max_glyphs_per_scaled_subset)
+static cairo_scaled_font_subsets_t *
+_cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
 {
     cairo_scaled_font_subsets_t *subsets;
 
@@ -381,12 +406,9 @@ _cairo_scaled_font_subsets_create (int m
     if (subsets == NULL)
 	return NULL;
 
-    subsets->max_glyphs_per_unscaled_subset_limit = max_glyphs_per_unscaled_subset;
+    subsets->type = type;
     subsets->max_glyphs_per_unscaled_subset_used = 0;
-
-    subsets->max_glyphs_per_scaled_subset_limit = max_glyphs_per_scaled_subset;
     subsets->max_glyphs_per_scaled_subset_used = 0;
-
     subsets->num_sub_fonts = 0;
 
     subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
@@ -405,6 +427,24 @@ _cairo_scaled_font_subsets_create (int m
     return subsets;
 }
 
+cairo_scaled_font_subsets_t *
+_cairo_scaled_font_subsets_create_scaled (void)
+{
+    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED);
+}
+
+cairo_scaled_font_subsets_t *
+_cairo_scaled_font_subsets_create_simple (void)
+{
+    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE);
+}
+
+cairo_scaled_font_subsets_t *
+_cairo_scaled_font_subsets_create_composite (void)
+{
+    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE);
+}
+
 void
 _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
 {
@@ -429,9 +469,10 @@ _cairo_scaled_font_subsets_map_glyph (ca
     cairo_font_options_t font_options;
     cairo_scaled_font_t	*unscaled_font;
     cairo_status_t status;
+    int max_glyphs;
 
     /* Lookup glyph in unscaled subsets */
-    if (subsets->max_glyphs_per_unscaled_subset_limit > 0) {
+    if (subsets->type != CAIRO_SUBSETS_SCALED) {
         key.is_scaled = FALSE;
         _cairo_sub_font_init_key (&key, scaled_font);
         if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
@@ -451,22 +492,20 @@ _cairo_scaled_font_subsets_map_glyph (ca
     }
 
     /* Lookup glyph in scaled subsets */
-    if (subsets->max_glyphs_per_scaled_subset_limit > 0) {
-        key.is_scaled = TRUE;
-        _cairo_sub_font_init_key (&key, scaled_font);
-        if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
-                                      (cairo_hash_entry_t **) &sub_font))
-        {
-            status = _cairo_sub_font_lookup_glyph (sub_font,
-                                                   scaled_font_glyph_index,
-                                                   &subset_glyph->subset_id,
-                                                   &subset_glyph->subset_glyph_index,
-                                                   &subset_glyph->x_advance);
-            if (status == CAIRO_STATUS_SUCCESS) {
-                subset_glyph->font_id = sub_font->font_id;
-                subset_glyph->is_scaled = TRUE;
-                return CAIRO_STATUS_SUCCESS;
-            }
+    key.is_scaled = TRUE;
+    _cairo_sub_font_init_key (&key, scaled_font);
+    if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
+                                  (cairo_hash_entry_t **) &sub_font))
+    {
+        status = _cairo_sub_font_lookup_glyph (sub_font,
+                                               scaled_font_glyph_index,
+                                               &subset_glyph->subset_id,
+                                               &subset_glyph->subset_glyph_index,
+                                               &subset_glyph->x_advance);
+        if (status == CAIRO_STATUS_SUCCESS) {
+            subset_glyph->font_id = sub_font->font_id;
+            subset_glyph->is_scaled = TRUE;
+            return CAIRO_STATUS_SUCCESS;
         }
     }
 
@@ -476,7 +515,10 @@ _cairo_scaled_font_subsets_map_glyph (ca
                                          scaled_font_glyph_index,
 					 CAIRO_SCALED_GLYPH_INFO_PATH,
                                          &scaled_glyph);
-    if (status == 0 && subsets->max_glyphs_per_unscaled_subset_limit > 0) {
+    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
+        return status;
+
+    if (status == 0 && subsets->type != CAIRO_SUBSETS_SCALED) {
         /* Path available. Add to unscaled subset. */
         key.is_scaled = FALSE;
         _cairo_sub_font_init_key (&key, scaled_font);
@@ -493,10 +535,15 @@ _cairo_scaled_font_subsets_map_glyph (ca
                                                       &identity,
                                                       &font_options);
 
+            if (subsets->type == CAIRO_SUBSETS_COMPOSITE)
+                max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
+            else
+                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
+
             sub_font = _cairo_sub_font_create (subsets,
                                                unscaled_font,
                                                subsets->num_sub_fonts++,
-                                               subsets->max_glyphs_per_unscaled_subset_limit,
+                                               max_glyphs,
                                                FALSE);
             if (sub_font == NULL)
                 return CAIRO_STATUS_NO_MEMORY;
@@ -507,17 +554,26 @@ _cairo_scaled_font_subsets_map_glyph (ca
                 return status;
         }
         subset_glyph->is_scaled = FALSE;
-    } else if (subsets->max_glyphs_per_scaled_subset_limit > 0) {
+        if (subsets->type == CAIRO_SUBSETS_COMPOSITE)
+            subset_glyph->is_composite = TRUE;
+        else
+            subset_glyph->is_composite = FALSE;
+    } else {
         /* No path available. Add to scaled subset. */
         key.is_scaled = TRUE;
         _cairo_sub_font_init_key (&key, scaled_font);
         if (! _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
                                         (cairo_hash_entry_t **) &sub_font))
         {
+            if (subsets->type == CAIRO_SUBSETS_SCALED)
+                max_glyphs = INT_MAX;
+            else
+                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
+
             sub_font = _cairo_sub_font_create (subsets,
                                                cairo_scaled_font_reference (scaled_font),
                                                subsets->num_sub_fonts++,
-                                               subsets->max_glyphs_per_scaled_subset_limit,
+                                               max_glyphs,
                                                TRUE);
             if (sub_font == NULL)
                 return CAIRO_STATUS_NO_MEMORY;
@@ -528,8 +584,7 @@ _cairo_scaled_font_subsets_map_glyph (ca
                 return status;
         }
         subset_glyph->is_scaled = TRUE;
-    } else {
-        return CAIRO_INT_STATUS_UNSUPPORTED;
+        subset_glyph->is_composite = FALSE;
     }
     subset_glyph->font_id = sub_font->font_id;
 
@@ -583,7 +638,7 @@ _cairo_scaled_font_subsets_foreach_scale
 }
 
 cairo_private cairo_status_t
-_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t		    *font_subsets,
+_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t	    *font_subsets,
                                            cairo_scaled_font_subset_callback_func_t  font_subset_callback,
                                            void					    *closure)
 {
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 3fb6b79..a582de3 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -2092,7 +2092,7 @@ _cairo_svg_document_create (cairo_output
     }
 
     /* The use of defs for font glyphs imposes no per-subset limit. */
-    document->font_subsets = _cairo_scaled_font_subsets_create (0, INT_MAX);
+    document->font_subsets = _cairo_scaled_font_subsets_create_scaled ();
     if (document->font_subsets == NULL) {
 	_cairo_error (CAIRO_STATUS_NO_MEMORY);
 	free (document);
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c
index d791c63..91e618c 100644
--- a/src/cairo-truetype-subset.c
+++ b/src/cairo-truetype-subset.c
@@ -385,12 +385,12 @@ cairo_truetype_font_write_cmap_table (ca
     cairo_truetype_font_write_be16 (font, 4);  /* searchrange */
     cairo_truetype_font_write_be16 (font, 1);  /* entry selector */
     cairo_truetype_font_write_be16 (font, 0);  /* rangeshift */
-    cairo_truetype_font_write_be16 (font, 0xf000 + font->base.num_glyphs - 2); /* end count[0] */
+    cairo_truetype_font_write_be16 (font, 0xf000 + font->base.num_glyphs - 1); /* end count[0] */
     cairo_truetype_font_write_be16 (font, 0xffff);  /* end count[1] */
     cairo_truetype_font_write_be16 (font, 0);       /* reserved */
     cairo_truetype_font_write_be16 (font, 0xf000);  /* startCode[0] */
     cairo_truetype_font_write_be16 (font, 0xffff);  /* startCode[1] */
-    cairo_truetype_font_write_be16 (font, 0x1001);  /* delta[0] */
+    cairo_truetype_font_write_be16 (font, 0x1000);  /* delta[0] */
     cairo_truetype_font_write_be16 (font, 1);       /* delta[1] */
     cairo_truetype_font_write_be16 (font, 0);       /* rangeOffset[0] */
     cairo_truetype_font_write_be16 (font, 0);       /* rangeOffset[1] */
@@ -398,12 +398,12 @@ cairo_truetype_font_write_cmap_table (ca
     /* Output a format 6 encoding table. */
 
     cairo_truetype_font_write_be16 (font, 6);
-    cairo_truetype_font_write_be16 (font, 10 + 2 * (font->base.num_glyphs - 1));
+    cairo_truetype_font_write_be16 (font, 10 + 2 * font->base.num_glyphs);
     cairo_truetype_font_write_be16 (font, 0);
     cairo_truetype_font_write_be16 (font, 0); /* First character */
     cairo_truetype_font_write_be16 (font, font->base.num_glyphs);
     for (i = 0; i < font->base.num_glyphs; i++)
-	cairo_truetype_font_write_be16 (font, i + 1);
+	cairo_truetype_font_write_be16 (font, i);
 
     return font->status;
 }
@@ -928,10 +928,6 @@ _cairo_truetype_subset_init (cairo_truet
     if (status)
 	return status;
 
-    /* Add the notdef glyph. This is required at glyph index 0
-     * in the subsetted font. */
-    cairo_truetype_font_use_glyph (font, 0);
-
     for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
 	parent_glyph = font->scaled_font_subset->glyphs[i];
 	cairo_truetype_font_use_glyph (font, parent_glyph);
@@ -946,16 +942,15 @@ _cairo_truetype_subset_init (cairo_truet
     if (truetype_subset->base_font == NULL)
 	goto fail1;
 
-    /* The widths array returned must contain only widths for
-     * the glyphs in font_subset. The notdef glyph at index 0
-     * and any subglyphs appended after font_subset->num_glyphs
-     * are omitted. */
+    /* The widths array returned must contain only widths for the
+     * glyphs in font_subset. Any subglyphs appended after
+     * font_subset->num_glyphs are omitted. */
     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] = (double)font->base.widths[i + 1]/font->base.units_per_em;
+	truetype_subset->widths[i] = (double)font->base.widths[i]/font->base.units_per_em;
 
     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;
diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c
index a8f88df..dcf55f4 100644
--- a/src/cairo-type1-fallback.c
+++ b/src/cairo-type1-fallback.c
@@ -421,7 +421,7 @@ cairo_type1_font_write_charstrings (cair
                                  "2 index /CharStrings %d dict dup begin\n",
                                  font->scaled_font_subset->num_glyphs + 1);
 
-    for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
+    for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) {
         _cairo_array_truncate (&data, 0);
         /* four "random" bytes required by encryption algorithm */
         status = _cairo_array_append_multiple (&data, zeros, 4);
diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index e4f5015..40c212e 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -1133,9 +1133,6 @@ _cairo_type1_subset_init (cairo_type1_su
 	cairo_type1_font_subset_use_glyph (font, parent_glyph);
     }
 
-    /* Pull in the .notdef glyph */
-    cairo_type1_font_subset_use_glyph (font, 0);
-
     status = cairo_type1_font_subset_generate (font, name);
     if (status)
 	goto fail1;


More information about the cairo-commit mailing list