Add vertical metrics support to OpenType CFF outlines.  Based on a
patch from Mike Moening <MikeM@RetekSolutions.com>

* src/cff/cffgload.c (cff_face_get_vertical_metrics): New function.
(cff_slot_load): Use cff_face_get_vertical_metrics.

* docs/CHANGES: Updated.
diff --git a/ChangeLog b/ChangeLog
index b8186c5..c6ae94e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,17 +1,29 @@
+2005-11-17  Werner Lemberg  <wl@gnu.org>
+
+	Add vertical metrics support to OpenType CFF outlines.  Based on a
+	patch from Mike Moening <MikeM@RetekSolutions.com>
+
+	* src/cff/cffgload.c (cff_face_get_vertical_metrics): New function.
+	(cff_slot_load): Use cff_face_get_vertical_metrics.
+
+	* docs/CHANGES: Updated.
+
 2005-11-17  Chia-I Wu  <b90201047@ntu.edu.tw>
 
 	* src/base/ftcalc.c (FT_MulTo64): Commented out.
 
-	* include/freetype/internal/ftcalc.h (FT_SqrtFixed), src/base/ftcalc.c
-	(FT_SqrtFixed), include/freetype/internal/ftdebug.h
+	* include/freetype/internal/ftcalc.h (FT_SqrtFixed),
+	src/base/ftcalc.c (FT_SqrtFixed),
+	include/freetype/internal/ftdebug.h (FT_Trace_Get_Count,
+	FT_Trace_Get_Name, FT_Message, FT_Panic), src/base/ftdebug.c
 	(FT_Trace_Get_Count, FT_Trace_Get_Name, FT_Message, FT_Panic),
-	src/base/ftdebug.c (FT_Trace_Get_Count, FT_Trace_Get_Name, FT_Message,
-	FT_Panic), include/freetype/internal/ftobjs.h (FT_New_Memory,
-	FT_Done_Memory), include/freetype/internal/ftstream.h
-	(FT_Stream_Open), src/base/ftsystem.c (FT_New_Memory, FT_Done_Memory,
-	FT_Stream_Open): s/FT_EXPORT/FT_BASE/.
+	include/freetype/internal/ftobjs.h (FT_New_Memory, FT_Done_Memory),
+	include/freetype/internal/ftstream.h (FT_Stream_Open),
+	src/base/ftsystem.c (FT_New_Memory, FT_Done_Memory, FT_Stream_Open):
+	s/FT_EXPORT/FT_BASE/.
 
-	* builds/exports.mk: Manually add TT_New_Context to EXPORTS_LIST too.
+	* builds/exports.mk: Manually add TT_New_Context to EXPORTS_LIST
+	too.
 
 2005-11-15  David Turner  <david@freetype.org>
 
diff --git a/docs/CHANGES b/docs/CHANGES
index 0a9f352..6295ec2 100644
--- a/docs/CHANGES
+++ b/docs/CHANGES
@@ -6,6 +6,9 @@
 
     - The FT_HAS_KERNING macro always returned 0.
 
+    - CFF OpenType  fonts didn't return  correct vertical  metrics for
+      glyphs with outlines.
+
   II. IMPORTANT CHANGES
 
     - A  new API  `FT_TrueTypeGX_Validate'  (in FT_GX_VALIDATE_H)  has
diff --git a/src/cff/cffgload.c b/src/cff/cffgload.c
index f4e7753..d4ea07b 100644
--- a/src/cff/cffgload.c
+++ b/src/cff/cffgload.c
@@ -569,6 +569,117 @@
   }
 
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cff_face_get_vertical_metrics                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Return the vertical metrics in font units for a given glyph.  The  */
+  /*    metrics are the top side bearing and advance height.               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    header  :: A pointer to the vertical metrics structure.            */
+  /*                                                                       */
+  /*    idx     :: The glyph index.                                        */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    bearing :: The top side bearing.                                   */
+  /*                                                                       */
+  /*    advance :: The advance height.                                     */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Horizontal metric values are directly computed from the CFF data,  */
+  /*    bypassing the `hmtx' table completely.                             */
+  /*                                                                       */
+#ifdef FT_OPTIMIZE_MEMORY
+
+  static void
+  cff_face_get_vertical_metrics( TT_Face     face,
+                                 FT_UInt     idx,
+                                 FT_Short   *abearing,
+                                 FT_UShort  *aadvance )
+  {
+    TT_VertHeader*  header;
+    FT_Byte*        p;
+    FT_Byte*        limit;
+    FT_UShort       k;
+
+
+    header = &face->vertical;
+    p      = face->vert_metrics;
+    limit  = p + face->vert_metrics_size;
+    
+    k = header->number_Of_VMetrics;
+    
+    if ( k > 0 )
+    {
+      if ( idx < (FT_UInt)k )
+      {
+        p += 4 * idx;
+        if ( p + 4 > limit )
+          goto NoData;
+          
+        *aadvance = FT_NEXT_USHORT( p );
+        *abearing = FT_NEXT_SHORT( p );
+      }
+      else
+      {
+        p += 4 * ( k - 1 );
+        if ( p + 4 > limit )
+          goto NoData;
+          
+        *aadvance = FT_NEXT_USHORT( p );
+        p += 2 + 2 * ( idx - k );
+        if ( p + 2 > limit )
+          *abearing = 0;
+        else
+          *abearing = FT_PEEK_SHORT( p );
+      }
+    }
+    else
+    {
+    NoData:
+      *abearing = 0;
+      *aadvance = 0;
+    }
+  }
+
+#else /* !FT_OPTIMIZE_MEMORY */
+
+  static void
+  cff_face_get_vertical_metrics( TT_Face     face,
+                                 FT_UInt     idx,
+                                 FT_Short   *abearing,
+                                 FT_UShort  *aadvance )
+  {
+    TT_VertHeader*  header = &face->vertical;
+    TT_LongMetrics  longs_m;
+    FT_UShort       k      = header->number_Of_VMetrics;
+
+
+    if ( k == 0 )
+    {
+      *abearing = *aadvance = 0;
+      return;
+    }
+
+    if ( idx < (FT_UInt)k )
+    {
+      longs_m   = (TT_LongMetrics)header->long_metrics + idx;
+      *abearing = longs_m->bearing;
+      *aadvance = longs_m->advance;
+    }
+    else
+    {
+      *abearing = ((TT_ShortMetrics*)header->short_metrics)[idx - k];
+      *aadvance = ((TT_LongMetrics)header->long_metrics)[k - 1].advance;
+    }
+  }
+
+#endif /* !FT_OPTIMIZE_MEMORY */
+
+
   static FT_Error
   cff_get_glyph_data( TT_Face    face,
                       FT_UInt    glyph_index,
@@ -1299,7 +1410,7 @@
               goto Fail;
 
             args = stack;
-            while (args < decoder->top )
+            while ( args < decoder->top )
             {
               if ( phase )
                 x += args[0];
@@ -1425,7 +1536,7 @@
               goto Fail;
 
             args = stack;
-            if (num_args < 4 || ( num_args % 4 ) > 1 )
+            if ( num_args < 4 || ( num_args % 4 ) > 1 )
               goto Stack_Underflow;
 
             if ( check_points( builder, ( num_args / 4 ) * 3 ) )
@@ -1772,7 +1883,8 @@
             /* close hints recording session */
             if ( hinter )
             {
-              if (hinter->close( hinter->hints, builder->current->n_points ) )
+              if ( hinter->close( hinter->hints,
+                                  builder->current->n_points ) )
                 goto Syntax_Error;
 
               /* apply hints to the loaded glyph outline now */
@@ -2048,7 +2160,7 @@
 
         case cff_op_ifelse:
           {
-            FT_Fixed  cond = (args[2] <= args[3]);
+            FT_Fixed  cond = ( args[2] <= args[3] );
 
 
             FT_TRACE4(( " ifelse" ));
@@ -2268,22 +2380,6 @@
 #endif /* 0 */
 
 
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-  /**********                                                      *********/
-  /**********                                                      *********/
-  /**********               UNHINTED GLYPH LOADER                  *********/
-  /**********                                                      *********/
-  /**********    The following code is in charge of loading a      *********/
-  /**********    single outline.  It completely ignores hinting    *********/
-  /**********    and is used when FT_LOAD_NO_HINTING is set.       *********/
-  /**********                                                      *********/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
   FT_LOCAL_DEF( FT_Error )
   cff_slot_load( CFF_GlyphSlot  glyph,
                  CFF_Size       size,
@@ -2515,8 +2611,26 @@
 
         /* make up vertical ones */
         metrics->vertAdvance  = 0;
+        metrics->vertBearingX = 0;
+        metrics->vertBearingY = 0;
+
         glyph->root.linearVertAdvance = 0;
 
+        /* get the vertical metrics from the vtmx table if we have one */
+        if ( face->vertical_info                   &&
+             face->vertical.number_Of_VMetrics > 0 &&
+             face->vertical.long_metrics != 0      )
+        {
+          FT_Short   vertBearingY = 0;
+          FT_UShort  vertAdvance  = 0;
+
+
+          cff_face_get_vertical_metrics( face, glyph_index,
+                                         &vertBearingY, &vertAdvance );
+          metrics->vertBearingY = vertBearingY;
+          metrics->vertAdvance  = vertAdvance;
+        }
+
         glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
 
         glyph->root.outline.flags = 0;
@@ -2536,6 +2650,7 @@
         advance.y = 0;
         FT_Vector_Transform( &advance, &font_matrix );
         metrics->horiAdvance = advance.x + font_offset.x;
+
         advance.x = 0;
         advance.y = metrics->vertAdvance;
         FT_Vector_Transform( &advance, &font_matrix );
@@ -2560,8 +2675,8 @@
             }
 
           /* Then scale the metrics */
-          metrics->horiAdvance  = FT_MulFix( metrics->horiAdvance,  x_scale );
-          metrics->vertAdvance  = FT_MulFix( metrics->vertAdvance,  y_scale );
+          metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+          metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
         }
 
         /* compute the other metrics */
@@ -2573,10 +2688,6 @@
         metrics->horiBearingX = cbox.xMin;
         metrics->horiBearingY = cbox.yMax;
 
-        /* make up vertical ones */
-        metrics->vertBearingX = 0;
-        metrics->vertBearingY = 0;
-
         if ( hinting )
           ft_glyphslot_grid_fit_metrics( &glyph->root );
       }