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.
--- 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
{