summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/freetype/src/sfnt/ttsbit0.c
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/3rdparty/freetype/src/sfnt/ttsbit0.c
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/3rdparty/freetype/src/sfnt/ttsbit0.c')
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttsbit0.c969
1 files changed, 969 insertions, 0 deletions
diff --git a/src/3rdparty/freetype/src/sfnt/ttsbit0.c b/src/3rdparty/freetype/src/sfnt/ttsbit0.c
new file mode 100644
index 0000000000..3ebcbbd740
--- /dev/null
+++ b/src/3rdparty/freetype/src/sfnt/ttsbit0.c
@@ -0,0 +1,969 @@
+/***************************************************************************/
+/* */
+/* ttsbit0.c */
+/* */
+/* TrueType and OpenType embedded bitmap support (body). */
+/* This is a heap-optimized version. */
+/* */
+/* Copyright 2005, 2006, 2007, 2008, 2009 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. */
+/* */
+/***************************************************************************/
+
+
+/* This file is included by ttsbit.c */
+
+
+#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
+
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_eblc( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error = SFNT_Err_Ok;
+ FT_Fixed version;
+ FT_ULong num_strikes, table_size;
+ FT_Byte* p;
+ FT_Byte* p_limit;
+ FT_UInt 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(( "tt_face_load_sbit_strikes: table too short!\n" ));
+ 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 != 0x00020000UL || num_strikes >= 0x10000UL )
+ {
+ FT_ERROR(( "tt_face_load_sbit_strikes: invalid table version!\n" ));
+ error = SFNT_Err_Invalid_File_Format;
+ goto Fail;
+ }
+
+ /*
+ * Count the number of strikes available in the table. We are 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;
+
+ FT_TRACE3(( "sbit_num_strikes: %u\n", 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_eblc( 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_Size_Request req,
+ FT_ULong* astrike_index )
+ {
+ return FT_Match_Size( (FT_Face)face, req, 0, astrike_index );
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ tt_face_load_strike_metrics( TT_Face face,
+ FT_ULong strike_index,
+ FT_Size_Metrics* metrics )
+ {
+ FT_Byte* strike;
+
+
+ if ( strike_index >= (FT_ULong)face->sbit_num_strikes )
+ return SFNT_Err_Invalid_Argument;
+
+ strike = face->sbit_table + 8 + strike_index * 48;
+
+ metrics->x_ppem = (FT_UShort)strike[44];
+ metrics->y_ppem = (FT_UShort)strike[45];
+
+ metrics->ascender = (FT_Char)strike[16] << 6; /* hori.ascender */
+ metrics->descender = (FT_Char)strike[17] << 6; /* hori.descender */
+ metrics->height = metrics->ascender - metrics->descender;
+
+ /* XXX: Is this correct? */
+ metrics->max_advance = ( (FT_Char)strike[22] + /* min_origin_SB */
+ strike[18] + /* max_width */
+ (FT_Char)strike[23] /* min_advance_SB */
+ ) << 6;
+
+ return SFNT_Err_Ok;
+ }
+
+
+ typedef struct TT_SBitDecoderRec_
+ {
+ 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;
+
+
+ if ( 8 + 48 * strike_index + 3 * 4 + 34 + 1 > face->sbit_table_size )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ 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;
+
+ if ( decoder->strike_index_array > face->sbit_table_size ||
+ decoder->strike_index_array + 8 * decoder->strike_index_count >
+ face->sbit_table_size )
+ error = SFNT_Err_Invalid_File_Format;
+ }
+
+ 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 = SFNT_Err_Ok;
+ FT_UInt width, height;
+ FT_Bitmap* map = decoder->bitmap;
+ FT_Long size;
+
+
+ if ( !decoder->metrics_loaded )
+ {
+ error = SFNT_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;
+
+ 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;
+
+ 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 SFNT_Err_Ok;
+
+ Fail:
+ return SFNT_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 = SFNT_Err_Ok;
+ FT_Byte* line;
+ FT_Int bit_height, bit_width, pitch, width, height, h;
+ FT_Bitmap* bitmap;
+
+
+ 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;
+ line = bitmap->buffer;
+
+ 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 = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ if ( p + ( ( width + 7 ) >> 3 ) * height > limit )
+ {
+ error = SFNT_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++ & ( 0xFF00U >> 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++ & ( 0xFF00U >> w ) ) );
+
+ /* all bits read and there are `x_pos + w' bits to be written */
+
+ write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) );
+
+ if ( x_pos + w > 8 )
+ {
+ write++;
+ wval <<= 8;
+ 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 = SFNT_Err_Ok;
+ FT_Byte* line;
+ FT_Int bit_height, bit_width, pitch, width, height, h, nbits;
+ FT_Bitmap* bitmap;
+ FT_UShort 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;
+ line = bitmap->buffer;
+
+ 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 = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ if ( p + ( ( width * height + 7 ) >> 3 ) > limit )
+ {
+ error = SFNT_Err_Invalid_File_Format;
+ goto Exit;
+ }
+
+ /* now do the blit */
+ line += y_pos * pitch + ( x_pos >> 3 );
+ x_pos &= 7;
+
+ /* the higher byte of `rval' is used as a buffer */
+ rval = 0;
+ nbits = 0;
+
+ for ( h = height; h > 0; h--, line += pitch )
+ {
+ FT_Byte* write = line;
+ FT_Int w = width;
+
+
+ if ( x_pos )
+ {
+ w = ( width < 8 - x_pos ) ? width : 8 - x_pos;
+
+ if ( h == height )
+ {
+ rval |= *p++;
+ nbits += x_pos;
+ }
+ else if ( nbits < w )
+ {
+ rval |= *p++;
+ nbits += 8 - w;
+ }
+ else
+ {
+ rval >>= 8;
+ nbits -= w;
+ }
+
+ *write++ |= ( ( rval >> nbits ) & 0xFF ) &
+ ( ~( 0xFF << w ) << ( 8 - w - x_pos ) );
+ rval <<= 8;
+
+ w = width - w;
+ }
+
+ for ( ; w >= 8; w -= 8 )
+ {
+ rval |= *p++;
+ *write++ |= ( rval >> nbits ) & 0xFF;
+
+ rval <<= 8;
+ }
+
+ if ( w > 0 )
+ {
+ if ( nbits < w )
+ {
+ rval |= *p++;
+ *write |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w );
+ nbits += 8 - w;
+
+ rval <<= 8;
+ }
+ else
+ {
+ *write |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w );
+ nbits -= w;
+ }
+ }
+ }
+
+ 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 = SFNT_Err_Ok;
+ FT_UInt num_components, nn;
+
+ FT_Char horiBearingX = decoder->metrics->horiBearingX;
+ FT_Char horiBearingY = decoder->metrics->horiBearingY;
+ FT_Byte horiAdvance = decoder->metrics->horiAdvance;
+ FT_Char vertBearingX = decoder->metrics->vertBearingX;
+ FT_Char vertBearingY = decoder->metrics->vertBearingY;
+ FT_Byte vertAdvance = decoder->metrics->vertAdvance;
+
+
+ if ( p + 2 > limit )
+ goto Fail;
+
+ num_components = FT_NEXT_USHORT( p );
+ if ( p + 4 * num_components > limit )
+ goto Fail;
+
+ if ( !decoder->bitmap_allocated )
+ {
+ error = tt_sbit_decoder_alloc_bitmap( decoder );
+ if ( error )
+ goto Exit;
+ }
+
+ 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;
+ }
+
+ decoder->metrics->horiBearingX = horiBearingX;
+ decoder->metrics->horiBearingY = horiBearingY;
+ decoder->metrics->horiAdvance = horiAdvance;
+ decoder->metrics->vertBearingX = vertBearingX;
+ decoder->metrics->vertBearingY = vertBearingY;
+ decoder->metrics->vertAdvance = vertAdvance;
+ decoder->metrics->width = (FT_UInt)decoder->bitmap->width;
+ decoder->metrics->height = (FT_UInt)decoder->bitmap->rows;
+
+ Exit:
+ return error;
+
+ Fail:
+ error = SFNT_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 = SFNT_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 = SFNT_Err_Ok;
+ }
+
+ 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, index_format, image_format;
+ FT_ULong image_start = 0, image_end = 0, image_offset;
+
+
+ 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:
+ image_offset = FT_NEXT_ULONG( p );
+
+ /* overflow check */
+ if ( decoder->eblc_base + decoder->strike_index_array + image_offset <
+ decoder->eblc_base )
+ goto Failure;
+
+ p = decoder->eblc_base + decoder->strike_index_array + image_offset;
+ if ( p + 8 > p_limit )
+ goto NoBitmap;
+
+ /* now 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_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 );
+
+ /* overflow check */
+ if ( p + ( num_glyphs + 1 ) * 4 < p )
+ goto Failure;
+
+ 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 );
+
+ /* overflow check */
+ if ( p + 2 * num_glyphs < p )
+ goto Failure;
+
+ 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_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_start,
+ image_end,
+ x_pos,
+ y_pos );
+
+ Failure:
+ return SFNT_Err_Invalid_Table;
+
+ NoBitmap:
+ return SFNT_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;
+
+ FT_UNUSED( load_flags );
+ FT_UNUSED( stream );
+ FT_UNUSED( map );
+
+
+ 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;
+ }
+
+/* EOF */