summaryrefslogtreecommitdiff
path: root/third_party/freetype/src/sfnt/ttsbit.c
diff options
context:
space:
mode:
authorBo Xu <bo_xu@foxitsoftware.com>2014-12-19 14:29:17 -0800
committerBo Xu <bo_xu@foxitsoftware.com>2014-12-19 15:03:12 -0800
commit4c764f391a4cfb82c81117cf9f249a8598be1cc5 (patch)
tree7d0cc6e2db4182a12ecab5f528c9bfccb4b7df6e /third_party/freetype/src/sfnt/ttsbit.c
parentd44e39279b08c0954f07283b4fb3e7f3e292e4de (diff)
downloadpdfium-4c764f391a4cfb82c81117cf9f249a8598be1cc5.tar.xz
XFA: merge patch from CL 815103002
Update freetype to 2.5.4. Put freetype into third_party directory, cleaning up header files. Previously freetype header files are in core/src/fxge/freetype and core/include/thirdparties. There were also multiple fx_freetype.h. This patch removes the additional Foxit wrapper to make further update easier. Notice, for original freetype source code, the following files are modified and need to be updated accordingly in future update: third_party/freetype/include/config/ftmodule.h third_party/freetype/include/config/ftoption.h BUG=407341 R=thestig@chromium.org Review URL: https://codereview.chromium.org/815103002
Diffstat (limited to 'third_party/freetype/src/sfnt/ttsbit.c')
-rw-r--r--third_party/freetype/src/sfnt/ttsbit.c1466
1 files changed, 1466 insertions, 0 deletions
diff --git a/third_party/freetype/src/sfnt/ttsbit.c b/third_party/freetype/src/sfnt/ttsbit.c
new file mode 100644
index 0000000000..c2db96c6d8
--- /dev/null
+++ b/third_party/freetype/src/sfnt/ttsbit.c
@@ -0,0 +1,1466 @@
+/***************************************************************************/
+/* */
+/* ttsbit.c */
+/* */
+/* TrueType and OpenType embedded bitmap support (body). */
+/* */
+/* Copyright 2005-2009, 2013, 2014 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* Copyright 2013 by Google, Inc. */
+/* Google Author(s): Behdad Esfahbod. */
+/* */
+/* 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 FT_BITMAP_H
+#include "ttsbit.h"
+
+#include "sferrors.h"
+
+#include "ttmtx.h"
+#include "pngshim.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_sbit( TT_Face face,
+ FT_Stream stream )
+ {
+ FT_Error error;
+ FT_ULong table_size;
+
+
+ face->sbit_table = NULL;
+ face->sbit_table_size = 0;
+ face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE;
+ face->sbit_num_strikes = 0;
+
+ error = face->goto_table( face, TTAG_CBLC, stream, &table_size );
+ if ( !error )
+ face->sbit_table_type = TT_SBIT_TABLE_TYPE_CBLC;
+ else
+ {
+ error = face->goto_table( face, TTAG_EBLC, stream, &table_size );
+ if ( error )
+ error = face->goto_table( face, TTAG_bloc, stream, &table_size );
+ if ( !error )
+ face->sbit_table_type = TT_SBIT_TABLE_TYPE_EBLC;
+ }
+
+ if ( error )
+ {
+ error = face->goto_table( face, TTAG_sbix, stream, &table_size );
+ if ( !error )
+ face->sbit_table_type = TT_SBIT_TABLE_TYPE_SBIX;
+ }
+ if ( error )
+ goto Exit;
+
+ if ( table_size < 8 )
+ {
+ FT_ERROR(( "tt_face_load_sbit_strikes: table too short\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ switch ( (FT_UInt)face->sbit_table_type )
+ {
+ case TT_SBIT_TABLE_TYPE_EBLC:
+ case TT_SBIT_TABLE_TYPE_CBLC:
+ {
+ FT_Byte* p;
+ FT_Fixed version;
+ FT_ULong num_strikes;
+ FT_UInt count;
+
+
+ if ( FT_FRAME_EXTRACT( table_size, face->sbit_table ) )
+ goto Exit;
+
+ face->sbit_table_size = table_size;
+
+ p = face->sbit_table;
+
+ version = FT_NEXT_ULONG( p );
+ num_strikes = FT_NEXT_ULONG( p );
+
+ if ( ( version & 0xFFFF0000UL ) != 0x00020000UL )
+ {
+ error = FT_THROW( Unknown_File_Format );
+ goto Exit;
+ }
+
+ if ( num_strikes >= 0x10000UL )
+ {
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /*
+ * 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)( ( table_size - 8 ) / 48 );
+
+ face->sbit_num_strikes = count;
+ }
+ break;
+
+ case TT_SBIT_TABLE_TYPE_SBIX:
+ {
+ FT_UShort version;
+ FT_UShort flags;
+ FT_ULong num_strikes;
+ FT_UInt count;
+
+
+ if ( FT_FRAME_ENTER( 8 ) )
+ goto Exit;
+
+ version = FT_GET_USHORT();
+ flags = FT_GET_USHORT();
+ num_strikes = FT_GET_ULONG();
+
+ FT_FRAME_EXIT();
+
+ if ( version < 1 )
+ {
+ error = FT_THROW( Unknown_File_Format );
+ goto Exit;
+ }
+
+ /* Bit 0 must always be `1'. */
+ /* Bit 1 controls the overlay of bitmaps with outlines. */
+ /* All other bits should be zero. */
+ if ( !( flags == 1 || flags == 3 ) ||
+ num_strikes >= 0x10000UL )
+ {
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* we currently don't support bit 1; however, it is better to */
+ /* draw at least something... */
+ if ( flags == 3 )
+ FT_TRACE1(( "tt_face_load_sbit_strikes:"
+ " sbix overlay not supported yet\n"
+ " "
+ " expect bad rendering results\n" ));
+
+ /*
+ * 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 + 4UL * count > table_size )
+ count = (FT_UInt)( ( table_size - 8 ) / 4 );
+
+ if ( FT_STREAM_SEEK( FT_STREAM_POS() - 8 ) )
+ goto Exit;
+
+ face->sbit_table_size = 8 + count * 4;
+ if ( FT_FRAME_EXTRACT( face->sbit_table_size, face->sbit_table ) )
+ goto Exit;
+
+ face->sbit_num_strikes = count;
+ }
+ break;
+
+ default:
+ error = FT_THROW( Unknown_File_Format );
+ break;
+ }
+
+ if ( !error )
+ FT_TRACE3(( "sbit_num_strikes: %u\n", face->sbit_num_strikes ));
+
+ return FT_Err_Ok;
+
+ Exit:
+ if ( error )
+ {
+ if ( face->sbit_table )
+ FT_FRAME_RELEASE( face->sbit_table );
+ face->sbit_table_size = 0;
+ face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE;
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ tt_face_free_sbit( TT_Face face )
+ {
+ FT_Stream stream = face->root.stream;
+
+
+ FT_FRAME_RELEASE( face->sbit_table );
+ face->sbit_table_size = 0;
+ face->sbit_table_type = TT_SBIT_TABLE_TYPE_NONE;
+ 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 )
+ {
+ if ( strike_index >= (FT_ULong)face->sbit_num_strikes )
+ return FT_THROW( Invalid_Argument );
+
+ switch ( (FT_UInt)face->sbit_table_type )
+ {
+ case TT_SBIT_TABLE_TYPE_EBLC:
+ case TT_SBIT_TABLE_TYPE_CBLC:
+ {
+ FT_Byte* strike;
+
+
+ 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;
+
+ /* 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 FT_Err_Ok;
+ }
+
+ case TT_SBIT_TABLE_TYPE_SBIX:
+ {
+ FT_Stream stream = face->root.stream;
+ FT_UInt offset, upem;
+ FT_UShort ppem, resolution;
+ TT_HoriHeader *hori;
+ FT_ULong table_size;
+
+ FT_Error error;
+ FT_Byte* p;
+
+
+ p = face->sbit_table + 8 + 4 * strike_index;
+ offset = FT_NEXT_ULONG( p );
+
+ error = face->goto_table( face, TTAG_sbix, stream, &table_size );
+ if ( error )
+ return error;
+
+ if ( offset + 4 > table_size )
+ return FT_THROW( Invalid_File_Format );
+
+ if ( FT_STREAM_SEEK( FT_STREAM_POS() + offset ) ||
+ FT_FRAME_ENTER( 4 ) )
+ return error;
+
+ ppem = FT_GET_USHORT();
+ resolution = FT_GET_USHORT();
+
+ FT_UNUSED( resolution ); /* What to do with this? */
+
+ FT_FRAME_EXIT();
+
+ upem = face->header.Units_Per_EM;
+ hori = &face->horizontal;
+
+ metrics->x_ppem = ppem;
+ metrics->y_ppem = ppem;
+
+ metrics->ascender = ppem * hori->Ascender * 64 / upem;
+ metrics->descender = ppem * hori->Descender * 64 / upem;
+ metrics->height = ppem * ( hori->Ascender -
+ hori->Descender +
+ hori->Line_Gap ) * 64 / upem;
+ metrics->max_advance = ppem * hori->advance_Width_Max * 64 / upem;
+
+ return error;
+ }
+
+ default:
+ return FT_THROW( Unknown_File_Format );
+ }
+ }
+
+
+ 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_CBDT, stream, &ebdt_size );
+ if ( error )
+ 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 = FT_THROW( 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;
+
+ /* decoder->strike_index_array + */
+ /* 8 * decoder->strike_index_count > face->sbit_table_size ? */
+ if ( decoder->strike_index_array > face->sbit_table_size ||
+ decoder->strike_index_count >
+ ( face->sbit_table_size - decoder->strike_index_array ) / 8 )
+ error = FT_THROW( 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 = FT_Err_Ok;
+ FT_UInt width, height;
+ FT_Bitmap* map = decoder->bitmap;
+ FT_Long size;
+
+
+ if ( !decoder->metrics_loaded )
+ {
+ error = FT_THROW( 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;
+ map->num_grays = 2;
+ break;
+
+ case 2:
+ map->pixel_mode = FT_PIXEL_MODE_GRAY2;
+ map->pitch = ( map->width + 3 ) >> 2;
+ map->num_grays = 4;
+ break;
+
+ case 4:
+ map->pixel_mode = FT_PIXEL_MODE_GRAY4;
+ map->pitch = ( map->width + 1 ) >> 1;
+ map->num_grays = 16;
+ break;
+
+ case 8:
+ map->pixel_mode = FT_PIXEL_MODE_GRAY;
+ map->pitch = map->width;
+ map->num_grays = 256;
+ break;
+
+ case 32:
+ map->pixel_mode = FT_PIXEL_MODE_BGRA;
+ map->pitch = map->width * 4;
+ map->num_grays = 256;
+ break;
+
+ default:
+ error = FT_THROW( 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;
+ }
+ else
+ {
+ /* avoid uninitialized data in case there is no vertical info -- */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+ }
+
+ decoder->metrics_loaded = 1;
+ *pp = p;
+ return FT_Err_Ok;
+
+ Fail:
+ FT_TRACE1(( "tt_sbit_decoder_load_metrics: broken table\n" ));
+ return FT_THROW( 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 = FT_Err_Ok;
+ FT_Byte* line;
+ FT_Int bit_height, bit_width, pitch, width, height, line_bits, h;
+ FT_Bitmap* bitmap;
+
+
+ /* 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;
+
+ line_bits = width * decoder->bit_depth;
+
+ if ( x_pos < 0 || x_pos + width > bit_width ||
+ y_pos < 0 || y_pos + height > bit_height )
+ {
+ FT_TRACE1(( "tt_sbit_decoder_load_byte_aligned:"
+ " invalid bitmap dimensions\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ if ( p + ( ( line_bits + 7 ) >> 3 ) * height > limit )
+ {
+ FT_TRACE1(( "tt_sbit_decoder_load_byte_aligned: broken bitmap\n" ));
+ error = FT_THROW( 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* pwrite = line;
+ FT_Int w;
+
+
+ for ( w = line_bits; w >= 8; w -= 8 )
+ {
+ pwrite[0] = (FT_Byte)( pwrite[0] | *p++ );
+ pwrite += 1;
+ }
+
+ if ( w > 0 )
+ pwrite[0] = (FT_Byte)( pwrite[0] | ( *p++ & ( 0xFF00U >> w ) ) );
+ }
+ }
+ else /* x_pos > 0 */
+ {
+ for ( h = height; h > 0; h--, line += pitch )
+ {
+ FT_Byte* pwrite = line;
+ FT_Int w;
+ FT_UInt wval = 0;
+
+
+ for ( w = line_bits; w >= 8; w -= 8 )
+ {
+ wval = (FT_UInt)( wval | *p++ );
+ pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) );
+ pwrite += 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 */
+
+ pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) );
+
+ if ( x_pos + w > 8 )
+ {
+ pwrite++;
+ wval <<= 8;
+ pwrite[0] = (FT_Byte)( pwrite[0] | ( wval >> x_pos ) );
+ }
+ }
+ }
+
+ Exit:
+ if ( !error )
+ FT_TRACE3(( "tt_sbit_decoder_load_byte_aligned: loaded\n" ));
+ return error;
+ }
+
+
+ /*
+ * Load a bit-aligned bitmap (with pointer `p') into a line-aligned bitmap
+ * (with pointer `pwrite'). In the example below, the width is 3 pixel,
+ * and `x_pos' is 1 pixel.
+ *
+ * p p+1
+ * | | |
+ * | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 |...
+ * | | |
+ * +-------+ +-------+ +-------+ ...
+ * . . .
+ * . . .
+ * v . .
+ * +-------+ . .
+ * | | .
+ * | 7 6 5 4 3 2 1 0 | .
+ * | | .
+ * pwrite . .
+ * . .
+ * v .
+ * +-------+ .
+ * | |
+ * | 7 6 5 4 3 2 1 0 |
+ * | |
+ * pwrite+1 .
+ * .
+ * v
+ * +-------+
+ * | |
+ * | 7 6 5 4 3 2 1 0 |
+ * | |
+ * pwrite+2
+ *
+ */
+
+ 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 = FT_Err_Ok;
+ FT_Byte* line;
+ FT_Int bit_height, bit_width, pitch, width, height, line_bits, h, nbits;
+ FT_Bitmap* bitmap;
+ FT_UShort rval;
+
+
+ /* 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;
+
+ line_bits = width * decoder->bit_depth;
+
+ if ( x_pos < 0 || x_pos + width > bit_width ||
+ y_pos < 0 || y_pos + height > bit_height )
+ {
+ FT_TRACE1(( "tt_sbit_decoder_load_bit_aligned:"
+ " invalid bitmap dimensions\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ if ( p + ( ( line_bits * height + 7 ) >> 3 ) > limit )
+ {
+ FT_TRACE1(( "tt_sbit_decoder_load_bit_aligned: broken bitmap\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ /* now do the blit */
+
+ /* adjust `line' to point to the first byte of the bitmap */
+ 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* pwrite = line;
+ FT_Int w = line_bits;
+
+
+ /* handle initial byte (in target bitmap) specially if necessary */
+ if ( x_pos )
+ {
+ w = ( line_bits < 8 - x_pos ) ? line_bits : 8 - x_pos;
+
+ if ( h == height )
+ {
+ rval = *p++;
+ nbits = x_pos;
+ }
+ else if ( nbits < w )
+ {
+ if ( p < limit )
+ rval |= *p++;
+ nbits += 8 - w;
+ }
+ else
+ {
+ rval >>= 8;
+ nbits -= w;
+ }
+
+ *pwrite++ |= ( ( rval >> nbits ) & 0xFF ) &
+ ( ~( 0xFF << w ) << ( 8 - w - x_pos ) );
+ rval <<= 8;
+
+ w = line_bits - w;
+ }
+
+ /* handle medial bytes */
+ for ( ; w >= 8; w -= 8 )
+ {
+ rval |= *p++;
+ *pwrite++ |= ( rval >> nbits ) & 0xFF;
+
+ rval <<= 8;
+ }
+
+ /* handle final byte if necessary */
+ if ( w > 0 )
+ {
+ if ( nbits < w )
+ {
+ if ( p < limit )
+ rval |= *p++;
+ *pwrite |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w );
+ nbits += 8 - w;
+
+ rval <<= 8;
+ }
+ else
+ {
+ *pwrite |= ( ( rval >> nbits ) & 0xFF ) & ( 0xFF00U >> w );
+ nbits -= w;
+ }
+ }
+ }
+
+ Exit:
+ if ( !error )
+ FT_TRACE3(( "tt_sbit_decoder_load_bit_aligned: loaded\n" ));
+ 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_Err_Ok;
+ FT_UInt num_components, nn;
+
+ FT_Char horiBearingX = (FT_Char)decoder->metrics->horiBearingX;
+ FT_Char horiBearingY = (FT_Char)decoder->metrics->horiBearingY;
+ FT_Byte horiAdvance = (FT_Byte)decoder->metrics->horiAdvance;
+ FT_Char vertBearingX = (FT_Char)decoder->metrics->vertBearingX;
+ FT_Char vertBearingY = (FT_Char)decoder->metrics->vertBearingY;
+ FT_Byte vertAdvance = (FT_Byte)decoder->metrics->vertAdvance;
+
+
+ if ( p + 2 > limit )
+ goto Fail;
+
+ num_components = FT_NEXT_USHORT( p );
+ if ( p + 4 * num_components > limit )
+ {
+ FT_TRACE1(( "tt_sbit_decoder_load_compound: broken table\n" ));
+ goto Fail;
+ }
+
+ FT_TRACE3(( "tt_sbit_decoder_load_compound: loading %d components\n",
+ num_components ));
+
+ 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;
+ }
+
+ FT_TRACE3(( "tt_sbit_decoder_load_compound: done\n" ));
+
+ 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_Byte)decoder->bitmap->width;
+ decoder->metrics->height = (FT_Byte)decoder->bitmap->rows;
+
+ Exit:
+ return error;
+
+ Fail:
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+
+#ifdef FT_CONFIG_OPTION_USE_PNG
+
+ static FT_Error
+ tt_sbit_decoder_load_png( TT_SBitDecoder decoder,
+ FT_Byte* p,
+ FT_Byte* limit,
+ FT_Int x_pos,
+ FT_Int y_pos )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_ULong png_len;
+
+
+ if ( limit - p < 4 )
+ {
+ FT_TRACE1(( "tt_sbit_decoder_load_png: broken bitmap\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ png_len = FT_NEXT_ULONG( p );
+ if ( (FT_ULong)( limit - p ) < png_len )
+ {
+ FT_TRACE1(( "tt_sbit_decoder_load_png: broken bitmap\n" ));
+ error = FT_THROW( Invalid_File_Format );
+ goto Exit;
+ }
+
+ error = Load_SBit_Png( decoder->face->root.glyph,
+ x_pos,
+ y_pos,
+ decoder->bit_depth,
+ decoder->metrics,
+ decoder->stream->memory,
+ p,
+ png_len,
+ FALSE );
+
+ Exit:
+ if ( !error )
+ FT_TRACE3(( "tt_sbit_decoder_load_png: loaded\n" ));
+ return error;
+ }
+
+#endif /* FT_CONFIG_OPTION_USE_PNG */
+
+
+ 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_THROW( 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:
+ case 17:
+ error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 0 );
+ break;
+
+ case 6:
+ case 7:
+ case 9:
+ case 18:
+ error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 );
+ break;
+
+ default:
+ error = FT_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 7:
+ {
+ /* Don't trust `glyph_format'. For example, Apple's main Korean */
+ /* system font, `AppleMyungJo.ttf' (version 7.0d2e6), uses glyph */
+ /* format 7, but the data is format 6. We check whether we have */
+ /* an excessive number of bytes in the image: If it is equal to */
+ /* the value for a byte-aligned glyph, use the other loading */
+ /* routine. */
+ /* */
+ /* Note that for some (width,height) combinations, where the */
+ /* width is not a multiple of 8, the sizes for bit- and */
+ /* byte-aligned data are equal, for example (7,7) or (15,6). We */
+ /* then prefer what `glyph_format' specifies. */
+
+ FT_UInt width = decoder->metrics->width;
+ FT_UInt height = decoder->metrics->height;
+
+ FT_UInt bit_size = ( width * height + 7 ) >> 3;
+ FT_UInt byte_size = height * ( ( width + 7 ) >> 3 );
+
+
+ if ( bit_size < byte_size &&
+ byte_size == (FT_UInt)( p_limit - p ) )
+ loader = tt_sbit_decoder_load_byte_aligned;
+ else
+ loader = tt_sbit_decoder_load_bit_aligned;
+ }
+ break;
+
+ case 5:
+ 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;
+
+ case 17: /* small metrics, PNG image data */
+ case 18: /* big metrics, PNG image data */
+ case 19: /* metrics in EBLC, PNG image data */
+#ifdef FT_CONFIG_OPTION_USE_PNG
+ loader = tt_sbit_decoder_load_png;
+ break;
+#else
+ error = FT_THROW( Unimplemented_Feature );
+ goto Fail;
+#endif /* FT_CONFIG_OPTION_USE_PNG */
+
+ default:
+ error = FT_THROW( Invalid_Table );
+ goto Fail;
+ }
+
+ if ( !decoder->bitmap_allocated )
+ {
+ error = tt_sbit_decoder_alloc_bitmap( decoder );
+ if ( error )
+ 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 */
+ p = decoder->eblc_base + decoder->strike_index_array;
+ if ( image_offset > (FT_ULong)( p_limit - p ) )
+ goto Failure;
+
+ p += 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 for p + ( num_glyphs + 1 ) * 4 */
+ if ( p + 4 > p_limit ||
+ num_glyphs > (FT_ULong)( ( ( p_limit - p ) >> 2 ) - 1 ) )
+ 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 */
+ case 19:
+ {
+ 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 for p + 2 * num_glyphs */
+ if ( num_glyphs > (FT_ULong)( ( p_limit - p ) >> 1 ) )
+ 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;
+
+ FT_TRACE3(( "tt_sbit_decoder_load_image:"
+ " found sbit (format %d) for glyph index %d\n",
+ image_format, glyph_index ));
+
+ return tt_sbit_decoder_load_bitmap( decoder,
+ image_format,
+ image_start,
+ image_end,
+ x_pos,
+ y_pos );
+
+ Failure:
+ return FT_THROW( Invalid_Table );
+
+ NoBitmap:
+ FT_TRACE4(( "tt_sbit_decoder_load_image:"
+ " no sbit found for glyph index %d\n", glyph_index ));
+
+ return FT_THROW( Invalid_Argument );
+ }
+
+
+ static FT_Error
+ tt_face_load_sbix_image( TT_Face face,
+ FT_ULong strike_index,
+ FT_UInt glyph_index,
+ FT_Stream stream,
+ FT_Bitmap *map,
+ TT_SBit_MetricsRec *metrics )
+ {
+ FT_UInt sbix_pos, strike_offset, glyph_start, glyph_end;
+ FT_ULong table_size;
+ FT_Int originOffsetX, originOffsetY;
+ FT_Tag graphicType;
+ FT_Int recurse_depth = 0;
+
+ FT_Error error;
+ FT_Byte* p;
+
+ FT_UNUSED( map );
+
+
+ metrics->width = 0;
+ metrics->height = 0;
+
+ p = face->sbit_table + 8 + 4 * strike_index;
+ strike_offset = FT_NEXT_ULONG( p );
+
+ error = face->goto_table( face, TTAG_sbix, stream, &table_size );
+ if ( error )
+ return error;
+ sbix_pos = FT_STREAM_POS();
+
+ retry:
+ if ( glyph_index > (FT_UInt)face->root.num_glyphs )
+ return FT_THROW( Invalid_Argument );
+
+ if ( strike_offset >= table_size ||
+ table_size - strike_offset < 4 + glyph_index * 4 + 8 )
+ return FT_THROW( Invalid_File_Format );
+
+ if ( FT_STREAM_SEEK( sbix_pos + strike_offset + 4 + glyph_index * 4 ) ||
+ FT_FRAME_ENTER( 8 ) )
+ return error;
+
+ glyph_start = FT_GET_ULONG();
+ glyph_end = FT_GET_ULONG();
+
+ FT_FRAME_EXIT();
+
+ if ( glyph_start == glyph_end )
+ return FT_THROW( Invalid_Argument );
+ if ( glyph_start > glyph_end ||
+ glyph_end - glyph_start < 8 ||
+ table_size - strike_offset < glyph_end )
+ return FT_THROW( Invalid_File_Format );
+
+ if ( FT_STREAM_SEEK( sbix_pos + strike_offset + glyph_start ) ||
+ FT_FRAME_ENTER( glyph_end - glyph_start ) )
+ return error;
+
+ originOffsetX = FT_GET_SHORT();
+ originOffsetY = FT_GET_SHORT();
+
+ graphicType = FT_GET_TAG4();
+
+ switch ( graphicType )
+ {
+ case FT_MAKE_TAG( 'd', 'u', 'p', 'e' ):
+ if ( recurse_depth < 4 )
+ {
+ glyph_index = FT_GET_USHORT();
+ FT_FRAME_EXIT();
+ recurse_depth++;
+ goto retry;
+ }
+ error = FT_THROW( Invalid_File_Format );
+ break;
+
+ case FT_MAKE_TAG( 'p', 'n', 'g', ' ' ):
+#ifdef FT_CONFIG_OPTION_USE_PNG
+ error = Load_SBit_Png( face->root.glyph,
+ 0,
+ 0,
+ 32,
+ metrics,
+ stream->memory,
+ stream->cursor,
+ glyph_end - glyph_start - 8,
+ TRUE );
+#else
+ error = FT_THROW( Unimplemented_Feature );
+#endif
+ break;
+
+ case FT_MAKE_TAG( 'j', 'p', 'g', ' ' ):
+ case FT_MAKE_TAG( 't', 'i', 'f', 'f' ):
+ case FT_MAKE_TAG( 'r', 'g', 'b', 'l' ): /* used on iOS 7.1 */
+ error = FT_THROW( Unknown_File_Format );
+ break;
+
+ default:
+ error = FT_THROW( Unimplemented_Feature );
+ break;
+ }
+
+ FT_FRAME_EXIT();
+
+ if ( !error )
+ {
+ FT_Short abearing;
+ FT_UShort aadvance;
+
+
+ tt_face_get_metrics( face, FALSE, glyph_index, &abearing, &aadvance );
+
+ metrics->horiBearingX = (FT_Short)originOffsetX;
+ metrics->horiBearingY = (FT_Short)( -originOffsetY + metrics->height );
+ metrics->horiAdvance = (FT_Short)( aadvance *
+ face->root.size->metrics.x_ppem /
+ face->header.Units_Per_EM );
+ }
+
+ return error;
+ }
+
+ 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 )
+ {
+ FT_Error error = FT_Err_Ok;
+
+
+ switch ( (FT_UInt)face->sbit_table_type )
+ {
+ case TT_SBIT_TABLE_TYPE_EBLC:
+ case TT_SBIT_TABLE_TYPE_CBLC:
+ {
+ TT_SBitDecoderRec decoder[1];
+
+
+ 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 );
+ }
+ }
+ break;
+
+ case TT_SBIT_TABLE_TYPE_SBIX:
+ error = tt_face_load_sbix_image( face,
+ strike_index,
+ glyph_index,
+ stream,
+ map,
+ metrics );
+ break;
+
+ default:
+ error = FT_THROW( Unknown_File_Format );
+ break;
+ }
+
+ /* Flatten color bitmaps if color was not requested. */
+ if ( !error &&
+ !( load_flags & FT_LOAD_COLOR ) &&
+ map->pixel_mode == FT_PIXEL_MODE_BGRA )
+ {
+ FT_Bitmap new_map;
+ FT_Library library = face->root.glyph->library;
+
+
+ FT_Bitmap_New( &new_map );
+
+ /* Convert to 8bit grayscale. */
+ error = FT_Bitmap_Convert( library, map, &new_map, 1 );
+ if ( error )
+ FT_Bitmap_Done( library, &new_map );
+ else
+ {
+ map->pixel_mode = new_map.pixel_mode;
+ map->pitch = new_map.pitch;
+ map->num_grays = new_map.num_grays;
+
+ ft_glyphslot_set_bitmap( face->root.glyph, new_map.buffer );
+ face->root.glyph->internal->flags |= FT_GLYPH_OWN_BITMAP;
+ }
+ }
+
+ return error;
+ }
+
+
+/* EOF */