[CMAKE]
[reactos.git] / lib / 3rdparty / freetype / src / cff / cffobjs.c
index c02cf33..1cd35c9 100644 (file)
@@ -4,7 +4,8 @@
 /*                                                                         */
 /*    OpenType objects manager (body).                                     */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by             */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,   */
+/*            2010 by                                                      */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
 #include FT_TRUETYPE_IDS_H
 #include FT_TRUETYPE_TAGS_H
 #include FT_INTERNAL_SFNT_H
-#include FT_SERVICE_POSTSCRIPT_CMAPS_H
-#include FT_INTERNAL_POSTSCRIPT_HINTS_H
 #include "cffobjs.h"
 #include "cffload.h"
 #include "cffcmap.h"
 #include "cfferrs.h"
+#include "cffpic.h"
 
 
   /*************************************************************************/
@@ -56,8 +56,8 @@
   cff_size_get_globals_funcs( CFF_Size  size )
   {
     CFF_Face          face     = (CFF_Face)size->root.face;
-    CFF_Font          font     = (CFF_FontRec *)face->extra.data;
-    PSHinter_Service  pshinter = (PSHinter_Service)font->pshinter;
+    CFF_Font          font     = (CFF_Font)face->extra.data;
+    PSHinter_Service  pshinter = font->pshinter;
     FT_Module         module;
 
 
   FT_LOCAL_DEF( void )
   cff_size_done( FT_Size  cffsize )        /* CFF_Size */
   {
-    CFF_Size  size = (CFF_Size)cffsize;
+    CFF_Size      size     = (CFF_Size)cffsize;
+    CFF_Face      face     = (CFF_Face)size->root.face;
+    CFF_Font      font     = (CFF_Font)face->extra.data;
+    CFF_Internal  internal = (CFF_Internal)cffsize->internal;
 
 
-    if ( cffsize->internal )
+    if ( internal )
     {
       PSH_Globals_Funcs  funcs;
 
 
       funcs = cff_size_get_globals_funcs( size );
       if ( funcs )
-        funcs->destroy( (PSH_Globals)cffsize->internal );
+      {
+        FT_UInt  i;
+
+
+        funcs->destroy( internal->topfont );
 
-      cffsize->internal = 0;
+        for ( i = font->num_subfonts; i > 0; i-- )
+          funcs->destroy( internal->subfonts[i - 1] );
+      }
+
+      /* `internal' is freed by destroy_size (in ftobjs.c) */
     }
   }
 
 
+  /* CFF and Type 1 private dictionaries have slightly different      */
+  /* structures; we need to synthesize a Type 1 dictionary on the fly */
+
+  static void
+  cff_make_private_dict( CFF_SubFont  subfont,
+                         PS_Private   priv )
+  {
+    CFF_Private  cpriv = &subfont->private_dict;
+    FT_UInt      n, count;
+
+
+    FT_MEM_ZERO( priv, sizeof ( *priv ) );
+
+    count = priv->num_blue_values = cpriv->num_blue_values;
+    for ( n = 0; n < count; n++ )
+      priv->blue_values[n] = (FT_Short)cpriv->blue_values[n];
+
+    count = priv->num_other_blues = cpriv->num_other_blues;
+    for ( n = 0; n < count; n++ )
+      priv->other_blues[n] = (FT_Short)cpriv->other_blues[n];
+
+    count = priv->num_family_blues = cpriv->num_family_blues;
+    for ( n = 0; n < count; n++ )
+      priv->family_blues[n] = (FT_Short)cpriv->family_blues[n];
+
+    count = priv->num_family_other_blues = cpriv->num_family_other_blues;
+    for ( n = 0; n < count; n++ )
+      priv->family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n];
+
+    priv->blue_scale = cpriv->blue_scale;
+    priv->blue_shift = (FT_Int)cpriv->blue_shift;
+    priv->blue_fuzz  = (FT_Int)cpriv->blue_fuzz;
+
+    priv->standard_width[0]  = (FT_UShort)cpriv->standard_width;
+    priv->standard_height[0] = (FT_UShort)cpriv->standard_height;
+
+    count = priv->num_snap_widths = cpriv->num_snap_widths;
+    for ( n = 0; n < count; n++ )
+      priv->snap_widths[n] = (FT_Short)cpriv->snap_widths[n];
+
+    count = priv->num_snap_heights = cpriv->num_snap_heights;
+    for ( n = 0; n < count; n++ )
+      priv->snap_heights[n] = (FT_Short)cpriv->snap_heights[n];
+
+    priv->force_bold     = cpriv->force_bold;
+    priv->language_group = cpriv->language_group;
+    priv->lenIV          = cpriv->lenIV;
+  }
+
+
   FT_LOCAL_DEF( FT_Error )
   cff_size_init( FT_Size  cffsize )         /* CFF_Size */
   {
 
     if ( funcs )
     {
-      PSH_Globals    globals;
-      CFF_Face       face    = (CFF_Face)cffsize->face;
-      CFF_Font       font    = (CFF_FontRec *)face->extra.data;
-      CFF_SubFont    subfont = &font->top_font;
+      CFF_Face      face     = (CFF_Face)cffsize->face;
+      CFF_Font      font     = (CFF_Font)face->extra.data;
+      CFF_Internal  internal;
 
-      CFF_Private    cpriv   = &subfont->private_dict;
       PS_PrivateRec  priv;
+      FT_Memory      memory = cffsize->face->memory;
 
+      FT_UInt  i;
 
-      /* IMPORTANT: The CFF and Type1 private dictionaries have    */
-      /*            slightly different structures; we need to      */
-      /*            synthetize a type1 dictionary on the fly here. */
-
-      {
-        FT_UInt  n, count;
-
-
-        FT_MEM_ZERO( &priv, sizeof ( priv ) );
-
-        count = priv.num_blue_values = cpriv->num_blue_values;
-        for ( n = 0; n < count; n++ )
-          priv.blue_values[n] = (FT_Short)cpriv->blue_values[n];
-
-        count = priv.num_other_blues = cpriv->num_other_blues;
-        for ( n = 0; n < count; n++ )
-          priv.other_blues[n] = (FT_Short)cpriv->other_blues[n];
-
-        count = priv.num_family_blues = cpriv->num_family_blues;
-        for ( n = 0; n < count; n++ )
-          priv.family_blues[n] = (FT_Short)cpriv->family_blues[n];
 
-        count = priv.num_family_other_blues = cpriv->num_family_other_blues;
-        for ( n = 0; n < count; n++ )
-          priv.family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n];
-
-        priv.blue_scale = cpriv->blue_scale;
-        priv.blue_shift = (FT_Int)cpriv->blue_shift;
-        priv.blue_fuzz  = (FT_Int)cpriv->blue_fuzz;
+      if ( FT_NEW( internal ) )
+        goto Exit;
 
-        priv.standard_width[0]  = (FT_UShort)cpriv->standard_width;
-        priv.standard_height[0] = (FT_UShort)cpriv->standard_height;
+      cff_make_private_dict( &font->top_font, &priv );
+      error = funcs->create( cffsize->face->memory, &priv,
+                             &internal->topfont );
+      if ( error )
+        goto Exit;
 
-        count = priv.num_snap_widths = cpriv->num_snap_widths;
-        for ( n = 0; n < count; n++ )
-          priv.snap_widths[n] = (FT_Short)cpriv->snap_widths[n];
+      for ( i = font->num_subfonts; i > 0; i-- )
+      {
+        CFF_SubFont  sub = font->subfonts[i - 1];
 
-        count = priv.num_snap_heights = cpriv->num_snap_heights;
-        for ( n = 0; n < count; n++ )
-          priv.snap_heights[n] = (FT_Short)cpriv->snap_heights[n];
 
-        priv.force_bold     = cpriv->force_bold;
-        priv.language_group = cpriv->language_group;
-        priv.lenIV          = cpriv->lenIV;
+        cff_make_private_dict( sub, &priv );
+        error = funcs->create( cffsize->face->memory, &priv,
+                               &internal->subfonts[i - 1] );
+        if ( error )
+          goto Exit;
       }
 
-      error = funcs->create( cffsize->face->memory, &priv, &globals );
-      if ( !error )
-        cffsize->internal = (FT_Size_Internal)(void*)globals;
+      cffsize->internal = (FT_Size_Internal)(void*)internal;
     }
 
     size->strike_index = 0xFFFFFFFFUL;
 
+  Exit:
     return error;
   }
 
     funcs = cff_size_get_globals_funcs( cffsize );
 
     if ( funcs )
-      funcs->set_scale( (PSH_Globals)size->internal,
-                        size->metrics.x_scale,
-                        size->metrics.y_scale,
+    {
+      CFF_Face      face     = (CFF_Face)size->face;
+      CFF_Font      font     = (CFF_Font)face->extra.data;
+      CFF_Internal  internal = (CFF_Internal)size->internal;
+
+      FT_ULong  top_upm  = font->top_font.font_dict.units_per_em;
+      FT_UInt   i;
+
+
+      funcs->set_scale( internal->topfont,
+                        size->metrics.x_scale, size->metrics.y_scale,
                         0, 0 );
 
+      for ( i = font->num_subfonts; i > 0; i-- )
+      {
+        CFF_SubFont  sub     = font->subfonts[i - 1];
+        FT_ULong     sub_upm = sub->font_dict.units_per_em;
+        FT_Pos       x_scale, y_scale;
+
+
+        if ( top_upm != sub_upm )
+        {
+          x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm );
+          y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm );
+        }
+        else
+        {
+          x_scale = size->metrics.x_scale;
+          y_scale = size->metrics.y_scale;
+        }
+
+        funcs->set_scale( internal->subfonts[i - 1],
+                          x_scale, y_scale, 0, 0 );
+      }
+    }
+
     return CFF_Err_Ok;
   }
 
     funcs = cff_size_get_globals_funcs( cffsize );
 
     if ( funcs )
-      funcs->set_scale( (PSH_Globals)size->internal,
-                        size->metrics.x_scale,
-                        size->metrics.y_scale,
+    {
+      CFF_Face      cffface  = (CFF_Face)size->face;
+      CFF_Font      font     = (CFF_Font)cffface->extra.data;
+      CFF_Internal  internal = (CFF_Internal)size->internal;
+
+      FT_ULong  top_upm  = font->top_font.font_dict.units_per_em;
+      FT_UInt   i;
+
+
+      funcs->set_scale( internal->topfont,
+                        size->metrics.x_scale, size->metrics.y_scale,
                         0, 0 );
 
+      for ( i = font->num_subfonts; i > 0; i-- )
+      {
+        CFF_SubFont  sub     = font->subfonts[i - 1];
+        FT_ULong     sub_upm = sub->font_dict.units_per_em;
+        FT_Pos       x_scale, y_scale;
+
+
+        if ( top_upm != sub_upm )
+        {
+          x_scale = FT_MulDiv( size->metrics.x_scale, top_upm, sub_upm );
+          y_scale = FT_MulDiv( size->metrics.y_scale, top_upm, sub_upm );
+        }
+        else
+        {
+          x_scale = size->metrics.x_scale;
+          y_scale = size->metrics.y_scale;
+        }
+
+        funcs->set_scale( internal->subfonts[i - 1],
+                          x_scale, y_scale, 0, 0 );
+      }
+    }
+
     return CFF_Err_Ok;
   }
 
   cff_slot_init( FT_GlyphSlot  slot )
   {
     CFF_Face          face     = (CFF_Face)slot->face;
-    CFF_Font          font     = (CFF_FontRec *)face->extra.data;
-    PSHinter_Service  pshinter = (PSHinter_Service)font->pshinter;
+    CFF_Font          font     = (CFF_Font)face->extra.data;
+    PSHinter_Service  pshinter = font->pshinter;
 
 
     if ( pshinter )
       }
     }
 
-    return 0;
+    return CFF_Err_Ok;
   }
 
 
     FT_String*  result;
 
 
-    result = ft_mem_strdup( memory, source, &error );
+    (void)FT_STRDUP( result, source );
+
+    FT_UNUSED( error );
 
     return result;
   }
 
 
+  /* Strip all subset prefixes of the form `ABCDEF+'.  Usually, there */
+  /* is only one, but font names like `APCOOG+JFABTD+FuturaBQ-Bold'   */
+  /* have been seen in the wild.                                      */
+
+  static void
+  remove_subset_prefix( FT_String*  name )
+  {
+    FT_Int32  idx             = 0;
+    FT_Int32  length          = strlen( name ) + 1;
+    FT_Bool   continue_search = 1;
+
+    while ( continue_search )
+    {
+      if ( length >= 7 && name[6] == '+' )
+      {
+        for ( idx = 0; idx < 6; idx++ )
+        {
+          /* ASCII uppercase letters */
+          if ( !( 'A' <= name[idx] && name[idx] <= 'Z' ) )
+            continue_search = 0;
+        }
+
+        if ( continue_search )
+        {
+          for ( idx = 7; idx < length; idx++ )
+            name[idx - 7] = name[idx];
+        }
+      }
+      else
+        continue_search = 0;
+    }
+  }
+
+
   FT_LOCAL_DEF( FT_Error )
   cff_face_init( FT_Stream      stream,
                  FT_Face        cffface,        /* CFF_Face */
     PSHinter_Service    pshinter;
     FT_Bool             pure_cff    = 1;
     FT_Bool             sfnt_format = 0;
+    FT_Library library = cffface->driver->root.library;
 
 
-#if 0
-    FT_FACE_FIND_GLOBAL_SERVICE( face, sfnt,     SFNT );
-    FT_FACE_FIND_GLOBAL_SERVICE( face, psnames,  POSTSCRIPT_NAMES );
-    FT_FACE_FIND_GLOBAL_SERVICE( face, pshinter, POSTSCRIPT_HINTER );
-
-    if ( !sfnt )
-      goto Bad_Format;
-#else
     sfnt = (SFNT_Service)FT_Get_Module_Interface(
-             cffface->driver->root.library, "sfnt" );
+             library, "sfnt" );
     if ( !sfnt )
       goto Bad_Format;
 
     FT_FACE_FIND_GLOBAL_SERVICE( face, psnames, POSTSCRIPT_CMAPS );
 
     pshinter = (PSHinter_Service)FT_Get_Module_Interface(
-                 cffface->driver->root.library, "pshinter" );
-#endif
+                 library, "pshinter" );
 
     /* create input stream from resource */
     if ( FT_STREAM_SEEK( 0 ) )
     error = sfnt->init_face( stream, face, face_index, num_params, params );
     if ( !error )
     {
-      if ( face->format_tag != 0x4F54544FL )  /* `OTTO'; OpenType/CFF font */
+      if ( face->format_tag != TTAG_OTTO )  /* `OTTO'; OpenType/CFF font */
       {
         FT_TRACE2(( "[not a valid OpenType/CFF font]\n" ));
         goto Bad_Format;
         pure_cff = 0;
 
         /* load font directory */
-        error = sfnt->load_face( stream, face,
-                                 face_index, num_params, params );
+        error = sfnt->load_face( stream, face, 0, num_params, params );
         if ( error )
           goto Exit;
       }
         goto Exit;
 
       face->extra.data = cff;
-      error = cff_font_load( stream, face_index, cff );
+      error = cff_font_load( library, stream, face_index, cff, pure_cff );
       if ( error )
         goto Exit;
 
       cff->pshinter = pshinter;
-      cff->psnames  = (void*)psnames;
+      cff->psnames  = psnames;
+
+      cffface->face_index = face_index;
 
       /* Complement the root flags with some interesting information. */
       /* Note that this is only necessary for pure CFF and CEF fonts; */
       /* which aren't CID-keyed                               */
       if ( dict->cid_registry == 0xFFFFU && !psnames )
       {
-        FT_ERROR(( "cff_face_init:" ));
-        FT_ERROR(( " cannot open CFF & CEF fonts\n" ));
-        FT_ERROR(( "              " ));
-        FT_ERROR(( " without the `PSNames' module\n" ));
+        FT_ERROR(( "cff_face_init:"
+                   " cannot open CFF & CEF fonts\n"
+                   "              "
+                   " without the `PSNames' module\n" ));
         goto Bad_Format;
       }
 
+      if ( !dict->units_per_em )
+        dict->units_per_em = pure_cff ? 1000 : face->root.units_per_EM;
+
+      /* Normalize the font matrix so that `matrix->xx' is 1; the */
+      /* scaling is done with `units_per_em' then (at this point, */
+      /* it already contains the scaling factor, but without      */
+      /* normalization of the matrix).                            */
+      /*                                                          */
+      /* Note that the offsets must be expressed in integer font  */
+      /* units.                                                   */
+
+      {
+        FT_Matrix*  matrix = &dict->font_matrix;
+        FT_Vector*  offset = &dict->font_offset;
+        FT_ULong*   upm    = &dict->units_per_em;
+        FT_Fixed    temp   = FT_ABS( matrix->yy );
+
+
+        if ( temp != 0x10000L )
+        {
+          *upm = FT_DivFix( *upm, temp );
+
+          matrix->xx = FT_DivFix( matrix->xx, temp );
+          matrix->yx = FT_DivFix( matrix->yx, temp );
+          matrix->xy = FT_DivFix( matrix->xy, temp );
+          matrix->yy = FT_DivFix( matrix->yy, temp );
+          offset->x  = FT_DivFix( offset->x,  temp );
+          offset->y  = FT_DivFix( offset->y,  temp );
+        }
+
+        offset->x >>= 16;
+        offset->y >>= 16;
+      }
+
+      for ( i = cff->num_subfonts; i > 0; i-- )
+      {
+        CFF_FontRecDict  sub = &cff->subfonts[i - 1]->font_dict;
+        CFF_FontRecDict  top = &cff->top_font.font_dict;
+
+        FT_Matrix*  matrix;
+        FT_Vector*  offset;
+        FT_ULong*   upm;
+        FT_Fixed    temp;
+
+
+        if ( sub->units_per_em )
+        {
+          FT_Long  scaling;
+
+
+          if ( top->units_per_em > 1 && sub->units_per_em > 1 )
+            scaling = FT_MIN( top->units_per_em, sub->units_per_em );
+          else
+            scaling = 1;
+
+          FT_Matrix_Multiply_Scaled( &top->font_matrix,
+                                     &sub->font_matrix,
+                                     scaling );
+          FT_Vector_Transform_Scaled( &sub->font_offset,
+                                      &top->font_matrix,
+                                      scaling );
+
+          sub->units_per_em = FT_MulDiv( sub->units_per_em,
+                                         top->units_per_em,
+                                         scaling );
+        }
+        else
+        {
+          sub->font_matrix = top->font_matrix;
+          sub->font_offset = top->font_offset;
+
+          sub->units_per_em = top->units_per_em;
+        }
+
+        matrix = &sub->font_matrix;
+        offset = &sub->font_offset;
+        upm    = &sub->units_per_em;
+        temp   = FT_ABS( matrix->yy );
+
+        if ( temp != 0x10000L )
+        {
+          *upm = FT_DivFix( *upm, temp );
+
+          /* if *upm is larger than 100*1000 we divide by 1000 --     */
+          /* this can happen if e.g. there is no top-font FontMatrix  */
+          /* and the subfont FontMatrix already contains the complete */
+          /* scaling for the subfont (see section 5.11 of the PLRM)   */
+
+          /* 100 is a heuristic value */
+
+          if ( *upm > 100L * 1000L )
+            *upm = ( *upm + 500 ) / 1000;
+
+          matrix->xx = FT_DivFix( matrix->xx, temp );
+          matrix->yx = FT_DivFix( matrix->yx, temp );
+          matrix->xy = FT_DivFix( matrix->xy, temp );
+          matrix->yy = FT_DivFix( matrix->yy, temp );
+          offset->x  = FT_DivFix( offset->x,  temp );
+          offset->y  = FT_DivFix( offset->y,  temp );
+        }
+
+        offset->x >>= 16;
+        offset->y >>= 16;
+      }
+
       if ( pure_cff )
       {
         char*  style_name = NULL;
 
         /* compute number of glyphs */
         if ( dict->cid_registry != 0xFFFFU )
-          cffface->num_glyphs = dict->cid_count;
+          cffface->num_glyphs = cff->charset.max_cid + 1;
         else
           cffface->num_glyphs = cff->charstrings_index.count;
 
         /* set global bbox, as well as EM size */
-        cffface->bbox.xMin =   dict->font_bbox.xMin             >> 16;
-        cffface->bbox.yMin =   dict->font_bbox.yMin             >> 16;
-        cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFFU ) >> 16;
-        cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFFU ) >> 16;
+        cffface->bbox.xMin =   dict->font_bbox.xMin            >> 16;
+        cffface->bbox.yMin =   dict->font_bbox.yMin            >> 16;
+        /* no `U' suffix here to 0xFFFF! */
+        cffface->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFF ) >> 16;
+        cffface->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFF ) >> 16;
 
-        if ( !dict->units_per_em )
-          dict->units_per_em = 1000;
-
-        cffface->units_per_EM = dict->units_per_em;
+        cffface->units_per_EM = (FT_UShort)( dict->units_per_em );
 
         cffface->ascender  = (FT_Short)( cffface->bbox.yMax );
         cffface->descender = (FT_Short)( cffface->bbox.yMin );
           (FT_Short)( dict->underline_thickness >> 16 );
 
         /* retrieve font family & style name */
-        cffface->family_name = cff_index_get_name( &cff->name_index,
-                                                   face_index );
-
+        cffface->family_name = cff_index_get_name( cff, face_index );
         if ( cffface->family_name )
         {
-          char*  full   = cff_index_get_sid_string( &cff->string_index,
-                                                    dict->full_name,
-                                                    psnames );
+          char*  full   = cff_index_get_sid_string( cff,
+                                                    dict->full_name );
           char*  fullp  = full;
           char*  family = cffface->family_name;
-          char*  family_name = 0;
+          char*  family_name = NULL;
+
 
+          remove_subset_prefix( cffface->family_name ); 
 
           if ( dict->family_name )
           {
-            family_name = cff_index_get_sid_string( &cff->string_index,
-                                                    dict->family_name,
-                                                    psnames);
+            family_name = cff_index_get_sid_string( cff,
+                                                    dict->family_name );
             if ( family_name )
               family = family_name;
           }
               }
               break;
             }
-
-            if ( family_name )
-              FT_FREE( family_name );
-            FT_FREE( full );
           }
         }
         else
         {
           char  *cid_font_name =
-                   cff_index_get_sid_string( &cff->string_index,
-                                             dict->cid_font_name,
-                                             psnames );
+                   cff_index_get_sid_string( cff,
+                                             dict->cid_font_name );
 
 
           /* do we have a `/FontName' for a CID-keyed font? */
           if ( cid_font_name )
-            cffface->family_name = cid_font_name;
+            cffface->family_name = cff_strcpy( memory, cid_font_name );
         }
 
         if ( style_name )
         /*                                                                 */
         /* Compute face flags.                                             */
         /*                                                                 */
-        flags = FT_FACE_FLAG_SCALABLE   |       /* scalable outlines */
-                FT_FACE_FLAG_HORIZONTAL |       /* horizontal data   */
-                FT_FACE_FLAG_HINTER;            /* has native hinter */
+        flags = (FT_UInt32)( FT_FACE_FLAG_SCALABLE   | /* scalable outlines */
+                             FT_FACE_FLAG_HORIZONTAL | /* horizontal data   */
+                             FT_FACE_FLAG_HINTER );    /* has native hinter */
 
         if ( sfnt_format )
-          flags |= FT_FACE_FLAG_SFNT;
+          flags |= (FT_UInt32)FT_FACE_FLAG_SFNT;
 
         /* fixed width font? */
         if ( dict->is_fixed_pitch )
-          flags |= FT_FACE_FLAG_FIXED_WIDTH;
+          flags |= (FT_UInt32)FT_FACE_FLAG_FIXED_WIDTH;
 
   /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */
 #if 0
         /* kerning available? */
         if ( face->kern_pairs )
-          flags |= FT_FACE_FLAG_KERNING;
+          flags |= (FT_UInt32)FT_FACE_FLAG_KERNING;
 #endif
 
         cffface->face_flags = flags;
           flags |= FT_STYLE_FLAG_ITALIC;
 
         {
-          char  *weight = cff_index_get_sid_string( &cff->string_index,
-                                                    dict->weight,
-                                                    psnames );
+          char  *weight = cff_index_get_sid_string( cff,
+                                                    dict->weight );
 
 
           if ( weight )
             if ( !ft_strcmp( weight, "Bold"  ) ||
                  !ft_strcmp( weight, "Black" ) )
               flags |= FT_STYLE_FLAG_BOLD;
-          FT_FREE( weight );
         }
 
         /* double check */
 
         cffface->style_flags = flags;
       }
-      else
-      {
-        if ( !dict->units_per_em )
-          dict->units_per_em = face->root.units_per_EM;
-      }
-
-      /* handle font matrix settings in subfonts (if any) */
-      for ( i = cff->num_subfonts; i > 0; i-- )
-      {
-        CFF_FontRecDict  sub = &cff->subfonts[i - 1]->font_dict;
-        CFF_FontRecDict  top = &cff->top_font.font_dict;
 
 
-        if ( sub->units_per_em )
-        {
-          FT_Matrix  scale;
-
-
-          scale.xx = scale.yy = (FT_Fixed)FT_DivFix( top->units_per_em,
-                                                     sub->units_per_em );
-          scale.xy = scale.yx = 0;
-
-          FT_Matrix_Multiply( &scale, &sub->font_matrix );
-          FT_Vector_Transform( &sub->font_offset, &scale );
-        }
-        else
-        {
-          sub->font_matrix = top->font_matrix;
-          sub->font_offset = top->font_offset;
-        }
-      }
-
 #ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
       /* CID-keyed CFF fonts don't have glyph names -- the SFNT loader */
-      /* has unset this flag because of the 3.0 `post' table           */
+      /* has unset this flag because of the 3.0 `post' table.          */
       if ( dict->cid_registry == 0xFFFFU )
         cffface->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
 #endif
 
+      if ( dict->cid_registry != 0xFFFFU && pure_cff )
+        cffface->face_flags |= FT_FACE_FLAG_CID_KEYED;
+
+
       /*******************************************************************/
       /*                                                                 */
       /* Compute char maps.                                              */
       /*                                                                 */
 
-      /* Try to synthetize a Unicode charmap if there is none available */
+      /* Try to synthesize a Unicode charmap if there is none available */
       /* already.  If an OpenType font contains a Unicode "cmap", we    */
       /* will use it, whatever be in the CFF part of the file.          */
       {
         {
           cmap = cffface->charmaps[nn];
 
-          /* Windows Unicode (3,1)? */
-          if ( cmap->platform_id == 3 && cmap->encoding_id == 1 )
+          /* Windows Unicode? */
+          if ( cmap->platform_id == TT_PLATFORM_MICROSOFT &&
+               cmap->encoding_id == TT_MS_ID_UNICODE_CS   )
             goto Skip_Unicode;
 
-          /* Deprecated Unicode platform id? */
-          if ( cmap->platform_id == 0 )
-            goto Skip_Unicode; /* Standard Unicode (deprecated) */
+          /* Apple Unicode platform id? */
+          if ( cmap->platform_id == TT_PLATFORM_APPLE_UNICODE )
+            goto Skip_Unicode; /* Apple Unicode */
         }
 
         /* since CID-keyed fonts don't contain glyph names, we can't */
         if ( pure_cff && cff->top_font.font_dict.cid_registry != 0xFFFFU )
           goto Exit;
 
-        /* we didn't find a Unicode charmap -- synthetize one */
+#ifdef FT_MAX_CHARMAP_CACHEABLE
+        if ( nn + 1 > FT_MAX_CHARMAP_CACHEABLE )
+        {
+          FT_ERROR(( "cff_face_init: no Unicode cmap is found, "
+                     "and too many subtables (%d) to add synthesized cmap\n",
+                     nn ));
+          goto Exit;
+        }
+#endif
+
+        /* we didn't find a Unicode charmap -- synthesize one */
         cmaprec.face        = cffface;
-        cmaprec.platform_id = 3;
-        cmaprec.encoding_id = 1;
+        cmaprec.platform_id = TT_PLATFORM_MICROSOFT;
+        cmaprec.encoding_id = TT_MS_ID_UNICODE_CS;
         cmaprec.encoding    = FT_ENCODING_UNICODE;
 
         nn = (FT_UInt)cffface->num_charmaps;
 
-        FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, &cmaprec, NULL );
+        error = FT_CMap_New( &FT_CFF_CMAP_UNICODE_CLASS_REC_GET, NULL,
+                             &cmaprec, NULL );
+        if ( error && FT_Err_No_Unicode_Glyph_Name != error )
+          goto Exit;
+        error = FT_Err_Ok;
 
         /* if no Unicode charmap was previously selected, select this one */
         if ( cffface->charmap == NULL && nn != (FT_UInt)cffface->num_charmaps )
           cffface->charmap = cffface->charmaps[nn];
 
       Skip_Unicode:
+#ifdef FT_MAX_CHARMAP_CACHEABLE
+        if ( nn > FT_MAX_CHARMAP_CACHEABLE )
+        {
+          FT_ERROR(( "cff_face_init: Unicode cmap is found, "
+                     "but too many preceding subtables (%d) to access\n",
+                     nn - 1 ));
+          goto Exit;
+        }
+#endif
         if ( encoding->count > 0 )
         {
           FT_CMap_Class  clazz;
 
 
           cmaprec.face        = cffface;
-          cmaprec.platform_id = 7;  /* Adobe platform id */
+          cmaprec.platform_id = TT_PLATFORM_ADOBE;  /* Adobe platform id */
 
           if ( encoding->offset == 0 )
           {
             cmaprec.encoding_id = TT_ADOBE_ID_STANDARD;
             cmaprec.encoding    = FT_ENCODING_ADOBE_STANDARD;
-            clazz               = &cff_cmap_encoding_class_rec;
+            clazz               = &FT_CFF_CMAP_ENCODING_CLASS_REC_GET;
           }
           else if ( encoding->offset == 1 )
           {
             cmaprec.encoding_id = TT_ADOBE_ID_EXPERT;
             cmaprec.encoding    = FT_ENCODING_ADOBE_EXPERT;
-            clazz               = &cff_cmap_encoding_class_rec;
+            clazz               = &FT_CFF_CMAP_ENCODING_CLASS_REC_GET;
           }
           else
           {
             cmaprec.encoding_id = TT_ADOBE_ID_CUSTOM;
             cmaprec.encoding    = FT_ENCODING_ADOBE_CUSTOM;
-            clazz               = &cff_cmap_encoding_class_rec;
+            clazz               = &FT_CFF_CMAP_ENCODING_CLASS_REC_GET;
           }
 
-          FT_CMap_New( clazz, NULL, &cmaprec, NULL );
+          error = FT_CMap_New( clazz, NULL, &cmaprec, NULL );
         }
       }
     }
   FT_LOCAL_DEF( void )
   cff_face_done( FT_Face  cffface )         /* CFF_Face */
   {
-    CFF_Face      face   = (CFF_Face)cffface;
-    FT_Memory     memory = cffface->memory;
-    SFNT_Service  sfnt   = (SFNT_Service)face->sfnt;
+    CFF_Face      face = (CFF_Face)cffface;
+    FT_Memory     memory;
+    SFNT_Service  sfnt;
+
+
+    if ( !face )
+      return;
 
+    memory = cffface->memory;
+    sfnt   = (SFNT_Service)face->sfnt;
 
     if ( sfnt )
       sfnt->done_face( face );