shithub: freetype+ttf2subf

Download patch

ref: 6a487b59bef559f614b02fb7031985643b6226b6
parent: 150c0dc616b18922f8524d4902f408dcd8c54dda
author: David Turner <[email protected]>
date: Mon Feb 28 17:09:07 EST 2005

* src/base/ftdbgmem.c (FT_DumpMemory): added sorting of memory sources
  according to decreasing maximum cumulative allocations.

  * include/freetype/internal/tttypes.h, src/sfnt/ttsbit.c, src/sfnt/ttsbit0.c,
  src/truetype/ttobjs.c, src/cff/cffobjs.c, src/sfnt/sfobjs.c: implementing new
  heap-optimized embedded bitmap loader. This one also fixes bug #12107

  * src/sfnt/sfobjs.c: fixed bug that prevented loading SFNT fonts without
  a 'kern' table.

git/fs: mount .git/fs: mount/attach disallowed
--- a/include/freetype/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -1263,8 +1263,14 @@
     TT_PCLT               pclt;
 
     /* embedded bitmaps support */
+#ifdef FT_OPTIMIZE_MEMORY
+    FT_Byte*              sbit_table;
+    FT_ULong              sbit_table_size;
+    FT_UInt               sbit_num_strikes;
+#else
     FT_ULong              num_sbit_strikes;
     TT_SBit_Strike        sbit_strikes;
+#endif
 
     FT_ULong              num_sbit_scales;
     TT_SBit_Scale         sbit_scales;
--- a/src/autofit/afhints.h
+++ b/src/autofit/afhints.h
@@ -86,12 +86,12 @@
   {
     AF_Flags      flags;    /* point flags used by hinter */
     FT_Pos        ox, oy;   /* original, scaled position  */
-    FT_Pos        fx, fy;   /* original, unscaled position (font units) */
+    FT_Short      fx, fy;   /* original, unscaled position (font units) */
     FT_Pos        x,  y;    /* current position */
     FT_Pos        u,  v;    /* current (x,y) or (y,x) depending on context */
 
-    AF_Direction  in_dir;   /* direction of inwards vector  */
-    AF_Direction  out_dir;  /* direction of outwards vector */
+    FT_Char       in_dir;   /* direction of inwards vector  */
+    FT_Char       out_dir;  /* direction of outwards vector */
 
     AF_Point      next;     /* next point in contour     */
     AF_Point      prev;     /* previous point in contour */
@@ -102,10 +102,10 @@
   typedef struct  AF_SegmentRec_
   {
     AF_Edge_Flags  flags;       /* edge/segment flags for this segment */
-    AF_Direction   dir;         /* segment direction                   */
-    FT_Pos         pos;         /* position of segment                 */
-    FT_Pos         min_coord;   /* minimum coordinate of segment       */
-    FT_Pos         max_coord;   /* maximum coordinate of segment       */
+    FT_Char        dir;         /* segment direction                   */
+    FT_Short       pos;         /* position of segment                 */
+    FT_Short       min_coord;   /* minimum coordinate of segment       */
+    FT_Short       max_coord;   /* maximum coordinate of segment       */
 
     AF_Edge        edge;        /* the segment's parent edge */
     AF_Segment     edge_next;   /* link to next segment in parent edge */
@@ -124,18 +124,18 @@
 
   typedef struct  AF_EdgeRec_
   {
-    FT_Pos         fpos;       /* original, unscaled position (font units) */
+    FT_Short       fpos;       /* original, unscaled position (font units) */
     FT_Pos         opos;       /* original, scaled position                */
     FT_Pos         pos;        /* current position                         */
 
-    AF_Edge_Flags  flags;      /* edge flags */
-    AF_Direction   dir;        /* edge direction */
+    FT_Byte        flags;      /* edge flags */
+    FT_Char        dir;        /* edge direction */
     FT_Fixed       scale;      /* used to speed up interpolation between edges */
     AF_Width       blue_edge;  /* non-NULL if this is a blue edge              */
 
     AF_Edge        link;
     AF_Edge        serif;
-    FT_Int         num_linked;
+    FT_Short       num_linked;
 
     FT_Int         score;
 
@@ -179,7 +179,7 @@
     AF_Point*     contours;
 
     AF_AxisHintsRec  axis[ AF_DIMENSION_MAX ];
-    
+
     FT_UInt32         scaler_flags;  /* copy of scaler flags */
     FT_UInt32         other_flags;   /* free for script-specific implementations */
     AF_ScriptMetrics  metrics;
--- a/src/autofit/afloader.c
+++ b/src/autofit/afloader.c
@@ -54,6 +54,8 @@
   FT_LOCAL_DEF( void )
   af_loader_done( AF_Loader   loader )
   {
+    af_glyph_hints_done( &loader->hints );
+
     loader->face    = NULL;
     loader->globals = NULL;
 
--- a/src/base/ftdbgmem.c
+++ b/src/base/ftdbgmem.c
@@ -921,6 +921,22 @@
   }
 
 
+  static int
+  ft_mem_source_compare( const void*  p1,
+                         const void*  p2 )
+  {
+    FT_MemSource  s1 = *(FT_MemSource*)p1;
+    FT_MemSource  s2 = *(FT_MemSource*)p2;
+
+    if ( s2->max_size > s1->max_size )
+      return 1;
+    else if ( s2->max_size < s1->max_size )
+      return -1;
+    else
+      return 0;
+  }
+
+
   extern void
   FT_DumpMemory( FT_Memory  memory )
   {
@@ -931,8 +947,32 @@
     {
       FT_MemSource* bucket = table->sources;
       FT_MemSource* limit  = bucket + FT_MEM_SOURCE_BUCKETS;
+      FT_MemSource* sources;
+      FT_UInt       nn, count;
       const char*   fmt;
 
+      count = 0;
+      for ( ; bucket < limit; bucket++ )
+      {
+        FT_MemSource  source = *bucket;
+
+        for ( ; source; source = source->link )
+          count++;
+      }
+
+      sources = ft_mem_table_alloc( table, sizeof(*sources) * count );
+
+      count = 0;
+      for ( bucket = table->sources; bucket < limit; bucket++ )
+      {
+        FT_MemSource  source = *bucket;
+
+        for ( ; source; source = source->link )
+          sources[count++] = source;
+      }
+
+      ft_qsort( sources, count, sizeof(*sources), ft_mem_source_compare );
+
       printf( "FreeType Memory Dump: current=%ld max=%ld total=%ld count=%ld\n",
               table->alloc_current, table->alloc_max, table->alloc_total, table->alloc_count );
       printf( " block  block    sizes    sizes    sizes   source\n" );
@@ -940,20 +980,19 @@
       printf( "-------------------------------------------------\n" );
       fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n";
 
-      for ( ; bucket < limit; bucket++ )
+      for ( nn = 0; nn < count; nn++ )
       {
-        FT_MemSource  source = *bucket;
+        FT_MemSource  source = sources[nn];
 
-        for ( ; source; source = source->link )
-        {
-          printf( fmt,
-                  source->cur_blocks, source->max_blocks,
-                  source->cur_size,   source->max_size, source->cur_max,
-                  FT_FILENAME( source->file_name ),
-                  source->line_no );
-        }
+        printf( fmt,
+                source->cur_blocks, source->max_blocks,
+                source->cur_size,   source->max_size, source->cur_max,
+                FT_FILENAME( source->file_name ),
+                source->line_no );
       }
       printf( "------------------------------------------------\n" );
+
+      ft_mem_table_free( table, sources );
     }
   }
 
--- a/src/cff/cffobjs.c
+++ b/src/cff/cffobjs.c
@@ -74,30 +74,45 @@
     sbit_metrics = &size->strike_metrics;
 
     error = sfnt->set_sbit_strike( face,
-                                   metrics->x_ppem, metrics->y_ppem,
+                                   metrics->x_ppem,
+                                   metrics->y_ppem,
                                    &strike_index );
 
     if ( !error )
     {
-      TT_SBit_Strike  strike = face->sbit_strikes + strike_index;
+      /* XXX: TODO: move this code to the SFNT module where it belongs */
+#ifdef FT_OPTIMIZE_MEMORY
+      FT_Byte*    strike = face->sbit_table + 8 + strike_index*48;
 
+      sbit_metrics->ascender  = (FT_Char)strike[16] << 6;  /* hori.ascender */
+      sbit_metrics->descender = (FT_Char)strike[17] << 6;  /* hori.descender */
 
-      sbit_metrics->x_ppem = metrics->x_ppem;
-      sbit_metrics->y_ppem = metrics->y_ppem;
+      /* XXX: Is this correct? */
+      sbit_metrics->max_advance = ( (FT_Char)strike[22] + /* min_origin_SB */
+                                             strike[18] + /* max_width */
+                                    (FT_Char)strike[23]   /* min_advance_SB */
+                                                        ) << 6;
 
+#else /* !OPTIMIZE_MEMORY */
+      TT_SBit_Strike  strike = face->sbit_strikes + strike_index;
+
+
       sbit_metrics->ascender  = strike->hori.ascender << 6;
       sbit_metrics->descender = strike->hori.descender << 6;
 
       /* XXX: Is this correct? */
-      sbit_metrics->height = sbit_metrics->ascender -
-                             sbit_metrics->descender;
-
-      /* XXX: Is this correct? */
       sbit_metrics->max_advance = ( strike->hori.min_origin_SB  +
                                     strike->hori.max_width      +
                                     strike->hori.min_advance_SB ) << 6;
+#endif /* !OPTIMIZE_MEMORY */
 
-      size->strike_index = (FT_UInt)strike_index;
+      /* XXX: Is this correct? */
+      sbit_metrics->height = sbit_metrics->ascender -
+                             sbit_metrics->descender;
+
+      sbit_metrics->x_ppem = metrics->x_ppem;
+      sbit_metrics->y_ppem = metrics->y_ppem;
+      size->strike_index   = (FT_UInt)strike_index;
     }
     else
     {
--- a/src/sfnt/sfdriver.c
+++ b/src/sfnt/sfdriver.c
@@ -366,8 +366,8 @@
     /* see `ttsbit.h' and `sfnt.h' */
     tt_face_set_sbit_strike,
     tt_face_load_sbit_strikes,
-    tt_find_sbit_image,
-    tt_load_sbit_metrics,
+    NULL /* tt_find_sbit_image */,
+    NULL /* tt_load_sbit_metrics */,
     tt_face_load_sbit_image,
     tt_face_free_sbit_strikes,
 
@@ -376,8 +376,8 @@
     0,
     0,
     0,
-    0, 
-    0, 
+    0,
+    0,
     0,
     0,
 
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -511,6 +511,8 @@
     (void)LOAD_( gasp );
     (void)LOAD_( kerning );
 
+    error = 0;
+
     face->root.family_name = tt_face_get_name( face,
                                                TT_NAME_ID_PREFERRED_FAMILY );
     if ( !face->root.family_name )
@@ -526,7 +528,7 @@
     /* now set up root fields */
     {
       FT_Face    root = &face->root;
-      FT_Int32   flags = 0;
+      FT_Int32   flags = root->face_flags;
       FT_Memory  memory;
 
 
@@ -537,7 +539,7 @@
       /* Compute face flags.                                               */
       /*                                                                   */
       if ( has_outline == TRUE )
-        flags = FT_FACE_FLAG_SCALABLE;    /* scalable outlines */
+        flags |= FT_FACE_FLAG_SCALABLE;    /* scalable outlines */
 
       flags |= FT_FACE_FLAG_SFNT      |   /* SFNT file format  */
                FT_FACE_FLAG_HORIZONTAL;   /* horizontal data   */
@@ -635,59 +637,6 @@
       }
 
 
-#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
-
-      if ( face->num_sbit_strikes )
-      {
-        FT_ULong  n;
-
-
-        root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
-
-#if 0
-        /* XXX: I don't know criteria whether layout is horizontal */
-        /*      or vertical.                                       */
-        if ( has_outline.... )
-        {
-          ...
-          root->face_flags |= FT_FACE_FLAG_VERTICAL;
-        }
-#endif
-        root->num_fixed_sizes = (FT_Int)face->num_sbit_strikes;
-
-        if ( FT_NEW_ARRAY( root->available_sizes, face->num_sbit_strikes ) )
-          goto Exit;
-
-        for ( n = 0 ; n < face->num_sbit_strikes ; n++ )
-        {
-          FT_Bitmap_Size*  bsize  = root->available_sizes + n;
-          TT_SBit_Strike   strike = face->sbit_strikes + n;
-          FT_UShort        fupem  = face->header.Units_Per_EM;
-          FT_Short         height = (FT_Short)( face->horizontal.Ascender -
-                                                face->horizontal.Descender +
-                                                face->horizontal.Line_Gap );
-          FT_Short         avg    = face->os2.xAvgCharWidth;
-
-
-          /* assume 72dpi */
-          bsize->height =
-            (FT_Short)( ( height * strike->y_ppem + fupem/2 ) / fupem );
-          bsize->width  =
-            (FT_Short)( ( avg * strike->y_ppem + fupem/2 ) / fupem );
-          bsize->size   = strike->y_ppem << 6;
-          bsize->x_ppem = strike->x_ppem << 6;
-          bsize->y_ppem = strike->y_ppem << 6;
-        }
-      }
-      else
-
-#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
-
-      {
-        root->num_fixed_sizes = 0;
-        root->available_sizes = 0;
-      }
-
       /*********************************************************************/
       /*                                                                   */
       /*  Set up metrics.                                                  */
@@ -830,7 +779,7 @@
 #ifdef FT_OPTIMIZE_MEMORY
     {
       FT_Stream  stream = FT_FACE_STREAM( face );
-      
+
       FT_FRAME_RELEASE( face->horz_metrics );
       FT_FRAME_RELEASE( face->vert_metrics );
       face->horz_metrics_size = 0;
--- a/src/sfnt/ttsbit.c
+++ b/src/sfnt/ttsbit.c
@@ -15,7 +15,15 @@
 /*                                                                         */
 /***************************************************************************/
 
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
 
+#ifdef FT_OPTIMIZE_MEMORY
+#include "ttsbit0.c"
+#else /* !OPTIMIZE_MEMORY */
+
 #include <ft2build.h>
 #include FT_INTERNAL_DEBUG_H
 #include FT_INTERNAL_STREAM_H
@@ -407,7 +415,7 @@
     FT_ULong   num_strikes;
     FT_ULong   table_base;
 
-    const FT_Frame_Field  sbit_line_metrics_fields[] =
+    static const FT_Frame_Field  sbit_line_metrics_fields[] =
     {
 #undef  FT_STRUCTURE
 #define FT_STRUCTURE  TT_SBit_LineMetricsRec
@@ -430,7 +438,7 @@
       FT_FRAME_END
     };
 
-    const FT_Frame_Field  strike_start_fields[] =
+    static const FT_Frame_Field  strike_start_fields[] =
     {
 #undef  FT_STRUCTURE
 #define FT_STRUCTURE  TT_SBit_StrikeRec
@@ -443,7 +451,7 @@
       FT_FRAME_END
     };
 
-    const FT_Frame_Field  strike_end_fields[] =
+    static const FT_Frame_Field  strike_end_fields[] =
     {
       /* no FT_FRAME_START */
         FT_FRAME_USHORT( start_glyph ),
@@ -576,6 +584,42 @@
       }
     }
 
+   /* now set up the root fields to indicate the strikes
+    */
+    if ( face->num_sbit_strikes )
+    {
+      FT_ULong  n;
+      FT_Face   root = FT_FACE(face);
+
+
+      if ( FT_NEW_ARRAY( root->available_sizes, face->num_sbit_strikes ) )
+        goto Exit;
+
+      for ( n = 0 ; n < face->num_sbit_strikes ; n++ )
+      {
+        FT_Bitmap_Size*  bsize  = root->available_sizes + n;
+        TT_SBit_Strike   strike = face->sbit_strikes + n;
+        FT_UShort        fupem  = face->header.Units_Per_EM;
+        FT_Short         height = (FT_Short)( face->horizontal.Ascender -
+                                              face->horizontal.Descender +
+                                              face->horizontal.Line_Gap );
+        FT_Short         avg    = face->os2.xAvgCharWidth;
+
+
+        /* assume 72dpi */
+        bsize->height =
+          (FT_Short)( ( height * strike->y_ppem + fupem/2 ) / fupem );
+        bsize->width  =
+          (FT_Short)( ( avg * strike->y_ppem + fupem/2 ) / fupem );
+        bsize->size   = strike->y_ppem << 6;
+        bsize->x_ppem = strike->x_ppem << 6;
+        bsize->y_ppem = strike->y_ppem << 6;
+      }
+
+      root->face_flags     |= FT_FACE_FLAG_FIXED_SIZES;
+      root->num_fixed_sizes = (FT_Int)face->num_sbit_strikes;
+    }
+
   Exit:
     return error;
   }
@@ -1472,3 +1516,4 @@
 
 
 /* END */
+#endif /* !OPTIMIZE_MEMORY */
--- /dev/null
+++ b/src/sfnt/ttsbit0.c
@@ -1,0 +1,943 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttsbit.c                                                               */
+/*                                                                         */
+/*    TrueType and OpenType embedded bitmap support (body).                */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002, 2003, 2004 by                               */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttsbit.h"
+
+#include "sferrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttsbit
+
+
+    static const FT_Frame_Field  tt_sbit_line_metrics_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_SBit_LineMetricsRec
+
+      /* no FT_FRAME_START */
+        FT_FRAME_CHAR( ascender ),
+        FT_FRAME_CHAR( descender ),
+        FT_FRAME_BYTE( max_width ),
+
+        FT_FRAME_CHAR( caret_slope_numerator ),
+        FT_FRAME_CHAR( caret_slope_denominator ),
+        FT_FRAME_CHAR( caret_offset ),
+
+        FT_FRAME_CHAR( min_origin_SB ),
+        FT_FRAME_CHAR( min_advance_SB ),
+        FT_FRAME_CHAR( max_before_BL ),
+        FT_FRAME_CHAR( min_after_BL ),
+        FT_FRAME_CHAR( pads[0] ),
+        FT_FRAME_CHAR( pads[1] ),
+      FT_FRAME_END
+    };
+
+    static const FT_Frame_Field  tt_strike_start_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_SBit_StrikeRec
+
+      /* no FT_FRAME_START */
+        FT_FRAME_ULONG( ranges_offset ),
+        FT_FRAME_SKIP_LONG,
+        FT_FRAME_ULONG( num_ranges ),
+        FT_FRAME_ULONG( color_ref ),
+      FT_FRAME_END
+    };
+
+    static const FT_Frame_Field  tt_strike_end_fields[] =
+    {
+      /* no FT_FRAME_START */
+        FT_FRAME_USHORT( start_glyph ),
+        FT_FRAME_USHORT( end_glyph ),
+        FT_FRAME_BYTE  ( x_ppem ),
+        FT_FRAME_BYTE  ( y_ppem ),
+        FT_FRAME_BYTE  ( bit_depth ),
+        FT_FRAME_CHAR  ( flags ),
+      FT_FRAME_END
+    };
+
+
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_sbit_strikes( TT_Face    face,
+                             FT_Stream  stream )
+  {
+    FT_Error   error  = 0;
+    FT_Memory  memory = stream->memory;
+    FT_Fixed   version;
+    FT_ULong   num_strikes, table_size;
+    FT_ULong   table_base;
+    FT_Byte*   p;
+    FT_Byte*   p_limit;
+    FT_UInt    nn, count;
+
+    face->sbit_num_strikes = 0;
+
+    /* this table is optional */
+    error = face->goto_table( face, TTAG_EBLC, stream, &table_size );
+    if ( error )
+      error = face->goto_table( face, TTAG_bloc, stream, &table_size );
+    if ( error )
+      goto Exit;
+
+    if ( table_size < 8 )
+    {
+      FT_ERROR(( "%s: table too short !\n", "tt_face_load_sbit_strikes" ));
+      error = SFNT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    if ( FT_FRAME_EXTRACT( table_size, face->sbit_table ) )
+      goto Exit;
+
+    face->sbit_table_size = table_size;
+
+    p       = face->sbit_table;
+    p_limit = p + table_size;
+
+    version     = FT_NEXT_ULONG(p);
+    num_strikes = FT_NEXT_ULONG(p);
+
+    if ( version != 0x00020000 || num_strikes >= 0x10000UL )
+    {
+      FT_ERROR(( "%s: invalid table version !\n", "tt_face_load_sbit_strikes" ));
+      error = SFNT_Err_Invalid_File_Format;
+      goto Fail;
+    }
+
+   /* count the number of strikes available in the table. we're a bit
+    * paranoid there and don't trust the data.
+    */
+    count = (FT_UInt)num_strikes;
+    if ( 8+48UL*count > table_size )
+      count = (FT_UInt)( (p_limit - p)/48 );
+
+    face->sbit_num_strikes = count;
+
+   /* now allocate the root array of F_Bitmap_Size records,
+    * populate them, and that's all there is to it. Unfortunately,
+    * it's not possible to indicate bit depths in the FT_Bitmap_Size
+    * record. What were we thinking ?
+    */
+    {
+      FT_Memory  memory  = face->root.stream->memory;
+      FT_UInt    em_size = (FT_UInt) face->header.Units_Per_EM;
+      FT_Short   height  = (FT_Short)( face->horizontal.Ascender -
+                                       face->horizontal.Descender +
+                                       face->horizontal.Line_Gap );
+
+      FT_Short   avgwidth = face->os2.xAvgCharWidth;
+
+      if ( FT_NEW_ARRAY( face->root.available_sizes, count ) )
+        goto Fail;
+
+      for ( nn = 0; nn < count; nn++ )
+      {
+        FT_Bitmap_Size*  bsize = face->root.available_sizes + nn;
+        FT_UInt          x_ppem, y_ppem;
+
+        x_ppem = p[44];
+        y_ppem = p[45];
+
+        bsize->x_ppem = (FT_Pos)(x_ppem << 6);
+        bsize->y_ppem = (FT_Pos)(y_ppem << 6);
+
+        bsize->height = (FT_Short)( height*y_ppem   + em_size/2 ) / em_size;
+        bsize->width  = (FT_Short)( avgwidth*y_ppem + em_size/2 ) / em_size;
+        bsize->size   = bsize->y_ppem;
+
+        p += 48;
+      }
+
+      face->root.face_flags     |= FT_FACE_FLAG_FIXED_SIZES;
+      face->root.num_fixed_sizes = count;
+
+    }
+
+  Exit:
+    return error;
+
+  Fail:
+    FT_FRAME_RELEASE( face->sbit_table );
+    face->sbit_table_size = 0;
+    goto Exit;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  tt_face_free_sbit_strikes( TT_Face  face )
+  {
+    FT_Stream  stream = face->root.stream;
+
+    FT_FRAME_RELEASE( face->sbit_table );
+    face->sbit_table_size  = 0;
+    face->sbit_num_strikes = 0;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_set_sbit_strike( TT_Face    face,
+                           FT_UInt    x_ppem,
+                           FT_UInt    y_ppem,
+                           FT_ULong  *astrike_index )
+  {
+    FT_UInt   nn, count;
+    FT_Byte*  p;
+    FT_Byte*  p_limit;
+
+    if ( x_ppem > 255 ||
+         y_ppem < 1 || y_ppem > 255 )
+      return SFNT_Err_Invalid_PPem;
+
+    p       = face->sbit_table + 8;
+    p_limit = p + face->sbit_table_size;
+    count   = face->sbit_num_strikes;
+    for ( nn = 0; nn < count; nn++ )
+    {
+      if ( x_ppem == (FT_UInt)p[44] && y_ppem == (FT_UInt)p[45] )
+      {
+        *astrike_index = (FT_ULong)nn;
+        return SFNT_Err_Ok;
+      }
+      p += 48;
+    }
+
+    return SFNT_Err_Invalid_PPem;
+  }
+
+
+
+  typedef struct
+  {
+    TT_Face          face;
+    FT_Stream        stream;
+    FT_Bitmap*       bitmap;
+    TT_SBit_Metrics  metrics;
+    FT_Bool          metrics_loaded;
+    FT_Bool          bitmap_allocated;
+    FT_Byte          bit_depth;
+
+    FT_ULong         ebdt_start;
+    FT_ULong         ebdt_size;
+
+    FT_ULong         strike_index_array;
+    FT_ULong         strike_index_count;
+    FT_Byte*         eblc_base;
+    FT_Byte*         eblc_limit;
+
+  } TT_SBitDecoderRec, *TT_SBitDecoder;
+
+
+  static FT_Error
+  tt_sbit_decoder_init( TT_SBitDecoder       decoder,
+                        TT_Face              face,
+                        FT_ULong             strike_index,
+                        TT_SBit_MetricsRec*  metrics )
+  {
+    FT_Error   error;
+    FT_Stream  stream     = face->root.stream;
+    FT_ULong   ebdt_size;
+
+    error = face->goto_table( face, TTAG_EBDT, stream, &ebdt_size );
+    if ( error )
+      error = face->goto_table( face, TTAG_bdat, stream, &ebdt_size );
+    if (error)
+      goto Exit;
+
+    decoder->face       = face;
+    decoder->stream     = stream;
+    decoder->bitmap     = &face->root.glyph->bitmap;
+    decoder->metrics    = metrics;
+
+    decoder->metrics_loaded   = 0;
+    decoder->bitmap_allocated = 0;
+
+    decoder->ebdt_start = FT_STREAM_POS();
+    decoder->ebdt_size  = ebdt_size;
+
+    decoder->eblc_base  = face->sbit_table;
+    decoder->eblc_limit = face->sbit_table + face->sbit_table_size;
+
+   /* now find the strike corresponding to the index
+    */
+    {
+      FT_Byte*  p = decoder->eblc_base + 8 + 48*strike_index;
+
+      decoder->strike_index_array = FT_NEXT_ULONG(p);
+      p                          += 4;
+      decoder->strike_index_count = FT_NEXT_ULONG(p);
+      p                          += 34;
+      decoder->bit_depth          = *p;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  tt_sbit_decoder_done( TT_SBitDecoder  decoder )
+  {
+    FT_UNUSED(decoder);
+  }
+
+
+
+  static FT_Error
+  tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder  decoder )
+  {
+    FT_Error    error = 0;
+    FT_UInt     width, height;
+    FT_Bitmap*  map = decoder->bitmap;
+    FT_Long     size;
+
+    if ( !decoder->metrics_loaded )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    width  = decoder->metrics->width;
+    height = decoder->metrics->height;
+
+    map->width = (int) width;
+    map->rows  = (int) height;
+
+    switch ( decoder->bit_depth )
+    {
+    case 1:
+        map->pixel_mode = FT_PIXEL_MODE_MONO;
+        map->pitch      = ( map->width + 7 ) >> 3;
+        break;
+
+    case 2:
+        map->pixel_mode = FT_PIXEL_MODE_GRAY2;
+        map->pitch      = ( map->width + 3 ) >> 2;
+        break;
+
+    case 4:
+        map->pixel_mode = FT_PIXEL_MODE_GRAY4;
+        map->pitch      = ( map->width + 1 ) >> 1;
+        break;
+
+    case 8:
+        map->pixel_mode = FT_PIXEL_MODE_GRAY;
+        map->pitch      = map->width;
+        break;
+
+    default:
+      error = SFNT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    size = map->rows * map->pitch;
+
+    /* check that there is no empty image */
+    if ( size == 0 )
+      goto Exit;     /* exit successfully! */
+
+    error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size );
+    if (error)
+      goto Exit;
+
+    decoder->bitmap_allocated = 1;
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  tt_sbit_decoder_load_metrics( TT_SBitDecoder  decoder,
+                                FT_Byte*       *pp,
+                                FT_Byte*        limit,
+                                FT_Bool         big )
+  {
+    FT_Byte*         p       = *pp;
+    TT_SBit_Metrics  metrics = decoder->metrics;
+
+    if ( p+5 > limit )
+      goto Fail;
+
+    if ( !decoder->metrics_loaded )
+    {
+      metrics->height       = p[0];
+      metrics->width        = p[1];
+      metrics->horiBearingX = (FT_Char) p[2];
+      metrics->horiBearingY = (FT_Char) p[3];
+      metrics->horiAdvance  = p[4];
+    }
+
+    p += 5;
+    if ( big )
+    {
+      if ( p+3 > limit )
+        goto Fail;
+
+      if ( !decoder->metrics_loaded )
+      {
+        metrics->vertBearingX = (FT_Char) p[0];
+        metrics->vertBearingY = (FT_Char) p[1];
+        metrics->vertAdvance  = p[2];
+      }
+
+      p += 3;
+    }
+
+    decoder->metrics_loaded = 1;
+    *pp = p;
+    return 0;
+
+  Fail:
+    return FT_Err_Invalid_Argument;
+  }
+
+
+
+
+
+ /* forward declaration */
+  static FT_Error
+  tt_sbit_decoder_load_image( TT_SBitDecoder  decoder,
+                              FT_UInt         glyph_index,
+                              FT_Int          x_pos,
+                              FT_Int          y_pos );
+
+  typedef FT_Error  (*TT_SBitDecoder_LoadFunc)( TT_SBitDecoder  decoder,
+                                                FT_Byte*        p,
+                                                FT_Byte*        plimit,
+                                                FT_Int          x_pos,
+                                                FT_Int          y_pos );
+
+
+
+
+  static FT_Error
+  tt_sbit_decoder_load_byte_aligned( TT_SBitDecoder  decoder,
+                                     FT_Byte*        p,
+                                     FT_Byte*        limit,
+                                     FT_Int          x_pos,
+                                     FT_Int          y_pos )
+  {
+    FT_Error    error = 0;
+    FT_Byte*    line;
+    FT_Int      bit_height, bit_width, pitch, width, height, h;
+    FT_Bitmap*  bitmap;
+    FT_UInt     rval;
+
+    if ( !decoder->bitmap_allocated )
+    {
+      error = tt_sbit_decoder_alloc_bitmap( decoder );
+      if (error)
+        goto Exit;
+    }
+
+   /* check that we can write the glyph into the bitmap
+    */
+    bitmap     = decoder->bitmap;
+    bit_width  = bitmap->width;
+    bit_height = bitmap->rows;
+    pitch      = bitmap->pitch;
+
+    width  = decoder->metrics->width;
+    height = decoder->metrics->height;
+
+    if ( x_pos < 0 || x_pos+width > bit_width   ||
+         y_pos < 0 || y_pos+height > bit_height )
+    {
+      error = FT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    if ( p+((width+7)>>3)*height > limit )
+    {
+      error = FT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+   /* now do the blit
+    */
+    line  += y_pos*pitch + (x_pos >> 3);
+    x_pos &= 7;
+
+    if ( x_pos == 0 )  /* the easy one */
+    {
+      for ( h = height; h > 0; h--, line += pitch )
+      {
+        FT_Byte*  write = line;
+        FT_Int    w;
+
+        for ( w = width; w >= 8; w -= 8 )
+        {
+          write[0] = (FT_Byte)(write[0] | *p++);
+          write   += 1;
+        }
+
+        if ( w > 0 )
+          write[0] = (FT_Byte)(write[0] | (*p++ & (0xFF00 >> w)));
+      }
+    }
+    else  /* x_pos > 0 */
+    {
+      for ( h = height; h > 0; h--, line += pitch )
+      {
+        FT_Byte*  write = line;
+        FT_Int    w;
+        FT_UInt   wval = 0;
+
+        for ( w = width; w >= 8; w -= 8 )
+        {
+          wval      = (FT_UInt)(wval | *p++);
+          write[0]  = (FT_Byte)(write[0] | (wval >> x_pos));
+          write    += 1;
+          wval    <<= 8;
+        }
+
+        if ( w > 0 )
+          wval = (FT_UInt)(wval | (*p++ & (0xFF00 >> w)));
+
+        write[0] = (FT_Byte)(write[0] | (wval >> x_pos));
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  tt_sbit_decoder_load_bit_aligned ( TT_SBitDecoder  decoder,
+                                     FT_Byte*        p,
+                                     FT_Byte*        limit,
+                                     FT_Int          x_pos,
+                                     FT_Int          y_pos )
+  {
+    FT_Error    error = 0;
+    FT_Byte*    line;
+    FT_Int      bit_height, bit_width, pitch, width, height, h;
+    FT_Bitmap*  bitmap;
+    FT_UInt32   rval;
+
+    if ( !decoder->bitmap_allocated )
+    {
+      error = tt_sbit_decoder_alloc_bitmap( decoder );
+      if (error)
+        goto Exit;
+    }
+
+   /* check that we can write the glyph into the bitmap
+    */
+    bitmap     = decoder->bitmap;
+    bit_width  = bitmap->width;
+    bit_height = bitmap->rows;
+    pitch      = bitmap->pitch;
+
+    width  = decoder->metrics->width;
+    height = decoder->metrics->height;
+
+    if ( x_pos < 0 || x_pos+width  > bit_width  ||
+         y_pos < 0 || y_pos+height > bit_height )
+    {
+      error = FT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    if ( p+((width+7)>>3)*height > limit )
+    {
+      error = FT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+   /* now do the blit
+    */
+    line  += y_pos*pitch + (x_pos >> 3);
+    x_pos &= 7;
+    rval   = 0x10000;
+
+    for ( h = height; h > 0; h--, line += pitch )
+    {
+      FT_Byte*   write = line;
+      FT_UInt32  wval  = 0x100 << x_pos;
+      FT_Int     w;
+
+      for ( w = width; w >= 8; w -= 8 )
+      {
+        if ( rval & 0x10000 )
+          rval = 0x100 | *p++;
+
+        wval |= (rval & 0x80);
+
+        wval <<= 1;
+        rval <<= 1;
+
+        if ( wval & 0x10000 )
+        {
+          write[0] = (FT_Byte)(write[0] | (wval >> 8));
+          write   += 1;
+          wval     = 0x100;
+        }
+      }
+
+      if ( wval != 0x100 )
+      {
+        while ( wval > 0x1FF )
+          wval >>= 1;
+
+        write[0] = (FT_Byte)(write[0] | wval);
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  tt_sbit_decoder_load_compound( TT_SBitDecoder  decoder,
+                                 FT_Byte*        p,
+                                 FT_Byte*        limit,
+                                 FT_Int          x_pos,
+                                 FT_Int          y_pos )
+  {
+    FT_Error  error;
+    FT_UInt   num_components, nn;
+
+
+    if ( p+2 > limit )
+      goto Fail;
+
+    num_components = FT_NEXT_USHORT(p);
+    if ( p+4*num_components > limit )
+      goto Fail;
+
+    for ( nn = 0; nn < num_components; nn++ )
+    {
+      FT_UInt   gindex = FT_NEXT_USHORT(p);
+      FT_Byte   dx     = FT_NEXT_BYTE(p);
+      FT_Byte   dy     = FT_NEXT_BYTE(p);
+
+      /* NB: a recursive call */
+      error = tt_sbit_decoder_load_image( decoder, gindex, x_pos+dx, y_pos+dy );
+      if ( error )
+        break;
+    }
+
+  Exit:
+    return error;
+
+  Fail:
+    error = FT_Err_Invalid_File_Format;
+    goto Exit;
+  }
+
+
+  static FT_Error
+  tt_sbit_decoder_load_bitmap( TT_SBitDecoder  decoder,
+                               FT_UInt         glyph_format,
+                               FT_ULong        glyph_start,
+                               FT_ULong        glyph_size,
+                               FT_Int          x_pos,
+                               FT_Int          y_pos )
+  {
+    FT_Error   error;
+    FT_Stream  stream = decoder->stream;
+    FT_Byte*   p;
+    FT_Byte*   p_limit;
+    FT_Byte*   data;
+
+   /* seek into the EBDT table now
+    */
+    if ( glyph_start + glyph_size > decoder->ebdt_size )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    if ( FT_STREAM_SEEK( decoder->ebdt_start + glyph_start ) ||
+         FT_FRAME_EXTRACT( glyph_size, data )                 )
+      goto Exit;
+
+    p       = data;
+    p_limit = p + glyph_size;
+
+   /* read the data, depending on the glyph format
+    */
+    switch ( glyph_format )
+    {
+    case 1: case 2: case 8:
+      error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 0 );
+      break;
+
+    case 6: case 7: case 9:
+      error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 );
+      break;
+
+    default:
+      error = 0;
+    }
+
+    if ( error )
+      goto Fail;
+
+    {
+      TT_SBitDecoder_LoadFunc  loader;
+
+      switch ( glyph_format )
+      {
+      case 1: case 6:
+          loader = tt_sbit_decoder_load_byte_aligned;
+          break;
+
+      case 2: case 5: case 7:
+          loader = tt_sbit_decoder_load_bit_aligned;
+          break;
+
+      case 8:
+          if ( p+1 > p_limit )
+            goto Fail;
+
+          p += 1;  /* skip padding */
+          /* fall-through */
+
+      case 9:
+          loader = tt_sbit_decoder_load_compound;
+          break;
+
+      default:
+          goto Fail;
+      }
+
+      error = loader( decoder, p, p_limit, x_pos, y_pos );
+    }
+
+  Fail:
+    FT_FRAME_RELEASE( data );
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  tt_sbit_decoder_load_image( TT_SBitDecoder  decoder,
+                              FT_UInt         glyph_index,
+                              FT_Int          x_pos,
+                              FT_Int          y_pos )
+  {
+   /* first, we find the correct strike range that applies to this
+    * glyph index.
+    */
+    FT_Byte*  p          = decoder->eblc_base + decoder->strike_index_array;
+    FT_Byte*  p_limit    = decoder->eblc_limit;
+    FT_ULong  num_ranges = decoder->strike_index_count;
+    FT_UInt   start, end, offset, index_format, image_format;
+    FT_ULong  image_start, image_end, image_offset;
+
+    if ( p+8*num_ranges > p_limit )
+      goto NoBitmap;
+
+    for ( ; num_ranges > 0; num_ranges-- )
+    {
+      start = FT_NEXT_USHORT(p);
+      end   = FT_NEXT_USHORT(p);
+
+      if ( glyph_index >= start && glyph_index <= end )
+        goto FoundRange;
+
+      p += 4;  /* ignore index offset */
+    }
+    goto NoBitmap;
+
+  FoundRange:
+    p = decoder->eblc_base + decoder->strike_index_array + FT_NEXT_ULONG(p);
+    if ( p+8 > p_limit )
+      goto NoBitmap;
+
+   /* now, we're going to find the glyph's location and extend within
+    * the ebdt table
+    */
+    index_format = FT_NEXT_USHORT(p);
+    image_format = FT_NEXT_USHORT(p);
+    image_offset = FT_NEXT_ULONG(p);
+
+    switch ( index_format )
+    {
+    case 1: /* 4-byte offsets relative to 'image_offset' */
+        {
+          p += 4*(glyph_index-start);
+          if ( p+8 > p_limit )
+            goto NoBitmap;
+
+          image_start = FT_NEXT_ULONG(p);
+          image_end   = FT_NEXT_ULONG(p);
+
+          if ( image_start == image_end )  /* missing glyph */
+            goto NoBitmap;
+        }
+        break;
+
+    case 2: /* big metrics, constant image size */
+        {
+          FT_ULong  image_size;
+
+          if ( p+12 > p_limit )
+            goto NoBitmap;
+
+          image_size = FT_NEXT_ULONG(p);
+
+          if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) )
+            goto NoBitmap;
+
+          image_start = image_offset + image_size*(glyph_index-start);
+          image_end   = image_start  + image_size;
+        }
+        break;
+
+    case 3: /* 2-byte offsets relative to 'image_offset' */
+        {
+          p += 2*(glyph_index-start);
+          if ( p+4 > p_limit )
+            goto NoBitmap;
+
+          image_start = FT_NEXT_USHORT(p);
+          image_end   = FT_NEXT_USHORT(p);
+
+          if ( image_start == image_end )  /* missing glyph */
+            goto NoBitmap;
+        }
+        break;
+
+    case 4: /* sparse glyph array with (glyph,offset) pairs */
+        {
+          FT_ULong  mm, num_glyphs;
+
+          if ( p+4 > p_limit )
+            goto NoBitmap;
+
+          num_glyphs = FT_NEXT_ULONG(p);
+          if ( p+(num_glyphs+1)*4 > p_limit )
+            goto NoBitmap;
+
+          for ( mm = 0; mm < num_glyphs; mm++ )
+          {
+            FT_UInt  gindex = FT_NEXT_USHORT(p);
+
+            if ( gindex == glyph_index )
+            {
+              image_start = FT_NEXT_USHORT(p);
+              p          += 2;
+              image_end   = FT_PEEK_USHORT(p);
+              break;
+            }
+            p += 2;
+          }
+
+          if ( mm >= num_glyphs )
+            goto NoBitmap;
+        }
+        break;
+
+    case 5: /* constant metrics with sparse glyph codes */
+        {
+          FT_ULong  image_size, mm, num_glyphs;
+
+          if ( p+16 > p_limit )
+            goto NoBitmap;
+
+          image_size = FT_NEXT_ULONG(p);
+
+          if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) )
+            goto NoBitmap;
+
+          num_glyphs = FT_NEXT_ULONG(p);
+          if ( p + 2*num_glyphs > p_limit )
+            goto NoBitmap;
+
+          for ( mm = 0; mm < num_glyphs; mm++ )
+          {
+            FT_UInt  gindex = FT_NEXT_USHORT(p);
+
+            if ( gindex == glyph_index )
+              break;
+          }
+
+          if ( mm >= num_glyphs )
+            goto NoBitmap;
+
+          image_start = image_offset + image_size*mm;
+          image_end   = image_start + image_size;
+        }
+        break;
+
+    default:
+        goto NoBitmap;
+    }
+
+    if ( image_start > image_end )
+      goto NoBitmap;
+
+    image_end  -= image_start;
+    image_start = image_offset + image_start;
+
+
+    return tt_sbit_decoder_load_bitmap( decoder,
+                                        image_format,
+                                        image_offset + image_start,
+                                        image_end,
+                                        x_pos,
+                                        y_pos );
+  NoBitmap:
+    return FT_Err_Invalid_Argument;
+  }
+
+
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_sbit_image( TT_Face              face,
+                           FT_ULong             strike_index,
+                           FT_UInt              glyph_index,
+                           FT_UInt              load_flags,
+                           FT_Stream            stream,
+                           FT_Bitmap           *map,
+                           TT_SBit_MetricsRec  *metrics )
+  {
+    TT_SBitDecoderRec  decoder[1];
+    FT_Error           error;
+
+    error = tt_sbit_decoder_init( decoder, face, strike_index, metrics );
+    if ( !error )
+    {
+      error = tt_sbit_decoder_load_image( decoder, glyph_index, 0, 0 );
+      tt_sbit_decoder_done( decoder );
+    }
+
+    return error;
+  }
--- a/src/truetype/ttobjs.c
+++ b/src/truetype/ttobjs.c
@@ -749,33 +749,39 @@
 
     if ( !error )
     {
-      TT_SBit_Strike  strike = face->sbit_strikes + strike_index;
+      /* XXX: TODO: move this code to the SFNT module where it belongs */
+#ifdef FT_OPTIMIZE_MEMORY
+      FT_Byte*    strike = face->sbit_table + 8 + strike_index*48;
 
+      sbit_metrics->ascender  = (FT_Char)strike[16] << 6;  /* hori.ascender */
+      sbit_metrics->descender = (FT_Char)strike[17] << 6;  /* hori.descender */
 
-      sbit_metrics->x_ppem = metrics->x_ppem;
-      sbit_metrics->y_ppem = metrics->y_ppem;
-#if 0
-      /*
-       * sbit_metrics->?_scale
-       * are not used now.
-       */
-      sbit_metrics->x_scale = 1 << 16;
-      sbit_metrics->y_scale = 1 << 16;
-#endif
+      /* XXX: Is this correct? */
+      sbit_metrics->max_advance = ( (FT_Char)strike[22] + /* min_origin_SB */
+                                             strike[18] + /* max_width */
+                                    (FT_Char)strike[23]   /* min_advance_SB */
+                                                        ) << 6;
 
+#else /* !OPTIMIZE_MEMORY */
+      TT_SBit_Strike  strike = face->sbit_strikes + strike_index;
+
+
       sbit_metrics->ascender  = strike->hori.ascender << 6;
       sbit_metrics->descender = strike->hori.descender << 6;
 
       /* XXX: Is this correct? */
-      sbit_metrics->height = sbit_metrics->ascender -
-                             sbit_metrics->descender;
-
-      /* XXX: Is this correct? */
       sbit_metrics->max_advance = ( strike->hori.min_origin_SB  +
                                     strike->hori.max_width      +
                                     strike->hori.min_advance_SB ) << 6;
+#endif /* !OPTIMIZE_MEMORY */
 
-      size->strike_index = (FT_UInt)strike_index;
+      /* XXX: Is this correct? */
+      sbit_metrics->height = sbit_metrics->ascender -
+                             sbit_metrics->descender;
+
+      sbit_metrics->x_ppem = metrics->x_ppem;
+      sbit_metrics->y_ppem = metrics->y_ppem;
+      size->strike_index   = (FT_UInt)strike_index;
     }
     else
     {