summaryrefslogtreecommitdiff
path: root/Build/source/libs/libttf/extend/ftxsbit.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/libttf/extend/ftxsbit.c')
-rw-r--r--Build/source/libs/libttf/extend/ftxsbit.c1391
1 files changed, 1391 insertions, 0 deletions
diff --git a/Build/source/libs/libttf/extend/ftxsbit.c b/Build/source/libs/libttf/extend/ftxsbit.c
new file mode 100644
index 00000000000..02162bd2e3f
--- /dev/null
+++ b/Build/source/libs/libttf/extend/ftxsbit.c
@@ -0,0 +1,1391 @@
+/*******************************************************************
+ *
+ * ftxsbit.c
+ *
+ * Embedded bitmap API extension
+ *
+ * Copyright 1996-1999 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 extension is used to load the embedded bitmaps present
+ * in certain TrueType files.
+ *
+ ******************************************************************/
+
+#include "ftxsbit.h"
+#include "ttobjs.h"
+#include "ttfile.h"
+#include "ttload.h"
+#include "ttmemory.h"
+#include "tttags.h"
+#include "ttextend.h"
+#include "ttdebug.h"
+
+
+#define SBIT_ID Build_Extension_ID( 's', 'b', 'i', 't' )
+
+
+/* Required by the tracing mode */
+#undef TT_COMPONENT
+#define TT_COMPONENT trace_bitmap
+
+/* In all functions, the stream is taken from the 'face' object */
+#define DEFINE_LOCALS DEFINE_LOAD_LOCALS( face->stream )
+#define DEFINE_LOCALS_WO_FRAME DEFINE_LOAD_LOCALS_WO_FRAME( face->stream )
+
+
+/***************************
+ *
+ * miscellaneous functions
+ *
+ ***************************/
+
+/*******************************************************************
+ *
+ * Function: Load_BitmapData
+ *
+ * Bit-aligned bitmap data -> Byte-aligned bitmap data when pad is 0
+ *
+ ******************************************************************/
+
+ static
+ TT_Error Load_BitmapData( TT_SBit_Image* image,
+ Int image_size,
+ Byte x_offset,
+ Byte y_offset,
+ UShort source_width,
+ UShort source_height,
+ Bool byte_padded )
+ {
+ DEFINE_LOCALS;
+
+ Int count; /* number of bits left in rows */
+ Int loaded; /* number of bits loaded in the accumulator */
+ UShort buff; /* accumulator */
+
+ PByte line; /* target write cursor */
+ PByte limit;
+
+
+ if ( ( y_offset + source_height > image->map.rows ) ||
+ ( x_offset + source_width > image->map.width ) )
+ return TT_Err_Invalid_Argument;
+
+ if ( ACCESS_Frame( image_size ) )
+ return error;
+
+ buff = 0;
+ loaded = 0;
+ line = (PByte)image->map.bitmap +
+ y_offset * image->map.cols;
+ limit = (PByte)image->map.bitmap +
+ ( y_offset + source_height ) * image->map.cols;
+
+ for ( ; line < limit; line += image->map.cols )
+ {
+ PByte ptr;
+
+
+ ptr = line + x_offset / 8;
+ count = source_width;
+
+ /* We may assume that `loaded' is less than 8 */
+ buff >>= x_offset % 8;
+ loaded += x_offset % 8;
+
+ /* first of all, read all consecutive bytes */
+ while ( count >= 8 )
+ {
+ if ( loaded < 8 )
+ {
+ buff |= ((UShort)GET_Byte()) << (8 - loaded);
+ loaded += 8;
+ }
+
+ *ptr++ |= (Byte)(buff >> 8);
+ buff <<= 8;
+ loaded -= 8;
+ count -= 8;
+ }
+
+ /* now write remaining bits (i.e. end of line with count < 8) */
+ if ( count > 0 )
+ {
+ if ( loaded < count )
+ {
+ buff |= ((UShort)GET_Byte()) << (8 - loaded);
+ loaded += 8;
+ }
+
+ *ptr |= ((Byte)(buff >> 8)) & ~(0xFF >> count);
+ buff <<= count;
+ loaded -= count;
+ }
+
+ if ( byte_padded )
+ {
+ buff = 0;
+ loaded = 0;
+ }
+ }
+
+ FORGET_Frame();
+ return TT_Err_Ok;
+ }
+
+
+/*******************************************************************
+ *
+ * Function: Crop_Bitmap
+ *
+ ******************************************************************/
+
+ static
+ void Crop_Bitmap( TT_SBit_Image* image )
+ {
+ /*******************************************************/
+ /* In the following situation, some bounding boxes of */
+ /* embedded bitmaps are too large. We need to crop it */
+ /* to a reasonable size. */
+ /* */
+ /* --------- */
+ /* | | ----- */
+ /* | *** | |***| */
+ /* | * | -----> | * | */
+ /* | * | | * | */
+ /* | * | | * | */
+ /* | * | | * | */
+ /* | *** | |***| */
+ /* --------- ----- */
+ /* */
+ /*******************************************************/
+
+ Int rows, count;
+ Long line_len;
+ PByte line;
+
+
+ /********************************************************************/
+ /* */
+ /* first of all, check the top-most lines of the bitmap and remove */
+ /* them if they're empty. */
+ /* */
+ {
+ line = (PByte)image->map.bitmap;
+ rows = image->map.rows;
+ line_len = image->map.cols;
+
+ for ( count = 0; count < rows; count++ )
+ {
+ PByte cur = line;
+ PByte limit = line + line_len;
+
+
+ for ( ; cur < limit; cur++ )
+ if ( cur[0] )
+ goto Found_Top;
+
+ /* the current line was empty -- skip to next one */
+ line = limit;
+ }
+
+ Found_Top:
+ /* check that we have at least one filled line */
+ if ( count >= rows )
+ goto Empty_Bitmap;
+
+ /* now, crop the empty upper lines */
+ if ( count > 0 )
+ {
+ line = (PByte)image->map.bitmap;
+
+ MEM_Move( line, line + count*line_len, (rows-count) * line_len );
+
+ image->metrics.bbox.yMax -= count;
+ image->metrics.vertBearingY -= count;
+ image->metrics.horiBearingY -= count;
+ image->map.rows -= count;
+ rows -= count;
+ }
+ }
+
+ /*******************************************************************/
+ /* */
+ /* second, crop the lower lines */
+ /* */
+ {
+ line = (PByte)image->map.bitmap + (rows-1) * line_len;
+
+ for ( count = 0; count < rows; count++ )
+ {
+ PByte cur = line;
+ PByte limit = line + line_len;
+
+
+ for ( ; cur < limit; cur++ )
+ if ( cur[0] )
+ goto Found_Bottom;
+
+ /* the current line was empty -- skip to previous one */
+ line -= line_len;
+ }
+
+ Found_Bottom:
+ if ( count > 0 )
+ {
+ image->metrics.bbox.yMin += count;
+ image->map.rows -= count;
+ rows -= count;
+ }
+ }
+
+ /*******************************************************************/
+ /* */
+ /* third, get rid of the space on the left side of the glyph */
+ /* */
+ do
+ {
+ PByte limit;
+
+
+ line = (PByte)image->map.bitmap;
+ limit = line + rows * line_len;
+
+ for ( ; line < limit; line += line_len )
+ if ( line[0] & 0x80 )
+ goto Found_Left;
+
+ /* shift the whole glyph one pixel to the left */
+ line = (PByte)image->map.bitmap;
+ limit = line + rows * line_len;
+
+ for ( ; line < limit; line += line_len )
+ {
+ Int n, width = image->map.width;
+ Byte old;
+ PByte cur = line;
+
+
+ old = cur[0] << 1;
+
+ for ( n = 8; n < width; n += 8 )
+ {
+ Byte val;
+
+
+ val = cur[1];
+ cur[0] = old | (val >> 7);
+ old = val << 1;
+ cur++;
+ }
+ cur[0] = old;
+ }
+
+ image->map.width--;
+ image->metrics.horiBearingX++;
+ image->metrics.vertBearingX++;
+ image->metrics.bbox.xMin++;
+
+ } while ( image->map.width > 0 );
+
+ Found_Left:
+
+ /*********************************************************************/
+ /* */
+ /* finally, crop the bitmap width to get rid of the space on the */
+ /* right side of the glyph. */
+ /* */
+ do
+ {
+ Int right = image->map.width-1;
+ PByte limit;
+ Byte mask;
+
+
+ line = (PByte)image->map.bitmap + (right >> 3);
+ limit = line + rows*line_len;
+ mask = 0x80 >> (right & 7);
+
+ for ( ; line < limit; line += line_len )
+ if ( line[0] & mask )
+ goto Found_Right;
+
+ /* crop the whole glyph on the right */
+ image->map.width--;
+ image->metrics.bbox.xMax--;
+
+ } while ( image->map.width > 0 );
+
+ Found_Right:
+ /* all right, the bitmap was cropped */
+ return;
+
+ Empty_Bitmap:
+ image->map.width = 0;
+ image->map.rows = 0;
+ image->map.cols = 0;
+ image->map.size = 0;
+ }
+
+/*************
+ *
+ * Main body
+ *
+ *************/
+
+
+ static
+ TT_Error Load_Range_Codes( TT_SBit_Range* range,
+ PFace face,
+ Bool load_offsets )
+ {
+ DEFINE_LOCALS;
+
+ ULong count, n, size;
+
+
+ (void)face;
+
+ /* read glyph count */
+ if ( ACCESS_Frame( 4L ) )
+ goto Exit;
+ count = GET_ULong();
+ FORGET_Frame();
+
+ range->num_glyphs = count;
+
+ /* Allocate glyph offsets table if needed */
+ if ( load_offsets )
+ {
+ if ( ALLOC_ARRAY( range->glyph_offsets, count, ULong ) )
+ goto Exit;
+
+ size = count * 4L;
+ }
+ else
+ size = count * 2L;
+
+ /* Allocate glyph codes table and access frame */
+ if ( ALLOC_ARRAY ( range->glyph_codes, count, UShort ) ||
+ ACCESS_Frame( size ) )
+ goto Exit;
+
+ for ( n = 0; n < count; n++ )
+ {
+ range->glyph_codes[n] = GET_UShort();
+
+ if ( load_offsets )
+ range->glyph_offsets[n] = (ULong)range->image_offset + GET_UShort();
+ }
+
+ FORGET_Frame();
+
+ Exit:
+ return error;
+ }
+
+
+ static
+ TT_Error Load_SBit_Range( TT_SBit_Strike* strike,
+ TT_SBit_Range* range,
+ PFace face )
+ {
+ DEFINE_LOCALS;
+
+ UShort format;
+
+
+ (void)face;
+ (void)strike;
+
+ format = range->index_format;
+ PTRACE6(( "Index Format: %d\n", format ));
+
+ switch( format )
+ {
+ case 1: /* variable metrics with 4-byte offsets */
+ case 3: /* variable metrics with 2-byte offsets */
+ {
+ UShort num_glyphs, size_elem;
+ Bool large = (format == 1);
+ ULong* cur;
+
+ num_glyphs = range->last_glyph - range->first_glyph + 1;
+ PTRACE5(( " num glyphs: %hu\n", num_glyphs ));
+
+ range->num_glyphs = num_glyphs;
+
+ num_glyphs++; /* BEWARE */
+
+ size_elem = large ? 4 : 2;
+
+ if ( ALLOC_ARRAY( range->glyph_offsets, num_glyphs, ULong ) ||
+ ACCESS_Frame( num_glyphs * size_elem ) )
+ return error;
+
+ cur = range->glyph_offsets;
+
+ while ( num_glyphs > 0 )
+ {
+ cur[0] = (TT_ULong)( range->image_offset +
+ (large ? GET_ULong() : GET_UShort()) );
+ PTRACE7(( " offset: %d\n", cur[0] ));
+ cur++;
+ num_glyphs--;
+ }
+
+ FORGET_Frame();
+ }
+ break;
+
+ case 2: /* all glyphs have identical metrics */
+ case 4:
+ case 5:
+ {
+ error = 0;
+
+ if ( format != 4 ) /* read constant metrics, formats 2 and 5 */
+ {
+ TT_SBit_Metrics* metrics;
+
+
+ if ( ACCESS_Frame( 12L ) )
+ return error;
+
+ range->image_size = GET_ULong();
+ metrics = &range->metrics;
+
+ metrics->height = GET_Byte();
+ metrics->width = GET_Byte();
+
+ metrics->horiBearingX = GET_Char();
+ metrics->horiBearingY = GET_Char();
+ metrics->horiAdvance = GET_Byte();
+
+ metrics->vertBearingX = GET_Char();
+ metrics->vertBearingY = GET_Char();
+ metrics->vertAdvance = GET_Byte();
+
+ FORGET_Frame();
+ }
+
+ if ( format != 2 ) /* load range codes, formats 4 and 5 */
+ error = Load_Range_Codes( range, face, (format == 4) );
+ }
+ break;
+
+ default:
+ error = TT_Err_Invalid_File_Format;
+ }
+
+ PTRACE3(( "Embedded Bitmap Location Tables loaded.\n" ));
+
+ return error;
+ }
+
+
+/*******************************************************************
+ *
+ * Function : Load_TrueType_Eblc
+ *
+ * Description : Loads the Eblc table directory into face table.
+ *
+ * Input : face face record to look for
+ *
+ * Output : Error code.
+ *
+ ******************************************************************/
+
+ static
+ TT_Error Load_TrueType_Eblc( PFace face,
+ TT_EBLC* eblc )
+ {
+ DEFINE_LOCALS;
+
+ ULong eblc_offset;
+ UShort i;
+ Long table;
+
+ TT_SBit_Strike* strike;
+
+
+ PTRACE2(( "Load_EBLC_Table( %08lx )\n", (long)face ));
+
+ eblc->version = 0;
+
+ /* Try to find the `EBLC' or `bloc' table in the font files. */
+ /* Both tags describe the same table; `EBLC' is for OpenType */
+ /* fonts while `bloc' is for TrueType GX fonts. Many fonts */
+ /* contain both tags pointing to the same table. */
+
+ table = TT_LookUp_Table( face, TTAG_EBLC );
+ if ( table < 0 )
+ table = TT_LookUp_Table( face, TTAG_bloc );
+
+ if ( table < 0 )
+ /* This table is optional */
+ return TT_Err_Ok;
+
+ eblc_offset = face->dirTables[table].Offset;
+
+ if ( FILE_Seek( eblc_offset ) ||
+ ACCESS_Frame( 8L ) )
+ return error;
+
+ eblc->version = GET_ULong();
+ eblc->num_strikes = GET_ULong();
+
+ FORGET_Frame();
+
+ PTRACE2(( "-- Tables count: %12u\n", eblc->num_strikes ));
+ PTRACE2(( "-- Format version: %08lx\n", eblc->version ));
+
+ if ( eblc->version != 0x00020000 )
+ {
+ PERROR(( "Invalid file format!\n" ));
+ return TT_Err_Invalid_File_Format;
+ }
+
+ if ( ALLOC_ARRAY( eblc->strikes, eblc->num_strikes, TT_SBit_Strike ) ||
+ ACCESS_Frame( 48L * eblc->num_strikes ) )
+ return error;
+
+ strike = eblc->strikes;
+
+ for ( i = 0; i < eblc->num_strikes; i++, strike++ )
+ { /* loop through the tables and get all entries */
+ ULong indexTablesSize;
+ TT_SBit_Line_Metrics* metrics;
+ Int count;
+
+
+ strike->ranges_offset = GET_ULong();
+ indexTablesSize = GET_ULong(); /* dont' save */
+
+ strike->num_ranges = GET_ULong();
+ strike->color_ref = GET_ULong();
+
+ /* load horizontal and vertical metrics */
+ metrics = &strike->hori;
+ for ( count = 2; count > 0; count-- )
+ {
+ metrics->ascender = GET_Char();
+ metrics->descender = GET_Char();
+ metrics->max_width = GET_Byte();
+
+ metrics->caret_slope_numerator = GET_Char();
+ metrics->caret_slope_denominator = GET_Char();
+ metrics->caret_offset = GET_Char();
+
+ metrics->min_origin_SB = GET_Char();
+ metrics->min_advance_SB = GET_Char();
+ metrics->max_before_BL = GET_Char();
+ metrics->min_after_BL = GET_Char();
+ metrics->pads[0] = GET_Char();
+ metrics->pads[1] = GET_Char();
+
+ metrics = &strike->vert;
+ }
+
+ strike->start_glyph = GET_UShort();
+ strike->end_glyph = GET_UShort();
+ strike->x_ppem = GET_Byte();
+ strike->y_ppem = GET_Byte();
+ strike->bit_depth = GET_Byte();
+ strike->flags = GET_Char();
+
+ PTRACE4(( " start - end - ppemX - ppemY\n" ));
+ PTRACE4(( " %04d - %04d - %3u - %3u\n",
+ strike->start_glyph,
+ strike->end_glyph,
+ strike->x_ppem,
+ strike->y_ppem ));
+ }
+
+ FORGET_Frame();
+
+ /* Load EBLC index ranges */
+ strike = eblc->strikes;
+
+ for ( i = 0; i < eblc->num_strikes; i++, strike++ )
+ {
+ TT_SBit_Range* range;
+ UShort count = strike->num_ranges;
+
+
+ /* loop through the tables and get all entries */
+ if ( ALLOC_ARRAY( strike->sbit_ranges,
+ strike->num_ranges,
+ TT_SBit_Range ) ||
+ FILE_Seek( eblc_offset + strike->ranges_offset ) ||
+ ACCESS_Frame( strike->num_ranges * 8L ) )
+ return error;
+
+ for ( range = strike->sbit_ranges; count > 0; count--, range++ )
+ {
+ range->first_glyph = GET_UShort();
+ range->last_glyph = GET_UShort();
+ range->table_offset = eblc_offset + strike->ranges_offset +
+ GET_ULong();
+ }
+ FORGET_Frame();
+
+ /* Now, read each index table */
+ range = strike->sbit_ranges;
+ for ( count = strike->num_ranges; count > 0; count--, range++ )
+ {
+ /* Read the header */
+ if ( FILE_Seek( range->table_offset ) ||
+ ACCESS_Frame( 8L ) )
+ return error;;
+
+ range->index_format = GET_UShort();
+ range->image_format = GET_UShort();
+ range->image_offset = GET_ULong();
+
+ FORGET_Frame();
+
+ error = Load_SBit_Range( strike, range, face );
+ if (error) return error;
+ }
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ static
+ void Free_TrueType_Eblc( TT_EBLC* eblc )
+ {
+ if ( eblc )
+ {
+ ULong i;
+ TT_SBit_Strike* strike = eblc->strikes;
+
+
+ strike = eblc->strikes;
+
+ for ( i = eblc->num_strikes; i > 0; i--, strike++ )
+ {
+ /* for each strike, release all glyph ranges */
+ TT_SBit_Range* range = strike->sbit_ranges;
+ Int n;
+
+
+ for ( n = strike->num_ranges; n > 0; n--, range++ )
+ {
+ /* release a range */
+ FREE( range->glyph_offsets );
+ FREE( range->glyph_codes );
+ }
+ FREE( strike->sbit_ranges );
+ strike->num_ranges = 0;
+ }
+ FREE( eblc->strikes );
+ eblc->num_strikes = 0;
+ eblc->version = 0;
+ }
+ }
+
+
+ static
+ TT_Error Load_SBit_Metrics( TT_Big_Glyph_Metrics* metrics,
+ TT_SBit_Range* range,
+ ULong ebdt_offset )
+ {
+ TT_Error error;
+ Byte height, width;
+
+
+ /* copy bitmap metrics for formats 2 and 5 */
+ if ( ( ( range->index_format == 2 ) || ( range->index_format == 5 ) ) &&
+ ( range->image_format == 5 ) )
+ /* metrics are taken from current image bitmap */
+ /* i.e. from `image.metrics' */
+ {
+ TT_SBit_Metrics* rmetrics = &range->metrics;
+
+
+ metrics->bbox.xMin = rmetrics->horiBearingX;
+ metrics->bbox.xMax = metrics->bbox.xMin + rmetrics->width;
+
+ metrics->bbox.yMax = rmetrics->horiBearingY;
+ metrics->bbox.yMin = metrics->bbox.yMax - rmetrics->height;
+
+ metrics->horiBearingX = rmetrics->horiBearingX;
+ metrics->horiBearingY = metrics->bbox.yMax;
+ metrics->horiAdvance = rmetrics->horiAdvance;
+
+ metrics->vertBearingX = rmetrics->vertBearingX;
+ metrics->vertBearingY = rmetrics->vertBearingY;
+ metrics->vertAdvance = rmetrics->vertAdvance;
+
+ return TT_Err_Ok;
+ }
+
+ switch ( range->image_format )
+ {
+ case 1:
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ {
+ Long length = 5L;
+
+
+ if ( range->image_format == 8 )
+ length++;
+
+ /* read the small metrics */
+ if ( ACCESS_Frame( length ) )
+ return error;
+
+ height = GET_Byte();
+ width = GET_Byte();
+
+ metrics->horiBearingX = GET_Char();
+ metrics->horiBearingY = GET_Char();
+ metrics->horiAdvance = GET_Byte();
+
+ FORGET_Frame();
+
+ metrics->bbox.xMin = metrics->horiBearingX;
+ metrics->bbox.yMax = metrics->horiBearingY;
+ metrics->bbox.xMax = metrics->bbox.xMin + width;
+ metrics->bbox.yMin = metrics->bbox.yMax - height;
+
+ /* read the rest of the big metrics for the formats */
+ /* that support it. */
+ if ( ( range->image_format >= 6 ) && ( range->image_format != 8 ) )
+ {
+ if ( ACCESS_Frame( 3L ) )
+ return error;
+
+ metrics->vertBearingX = (Int)GET_Char();
+ metrics->vertBearingY = (Int)GET_Char();
+ metrics->vertAdvance = (Int)GET_Char();
+
+ FORGET_Frame();
+ }
+ else
+ {
+ /* XXX: How can we fill these when the information isn't */
+ /* available? */
+ metrics->vertBearingX = 0;
+ metrics->vertBearingY = 0;
+ metrics->vertAdvance = 0;
+ }
+ }
+ break;
+
+ case 5: /* metrics are taken from current image bitmap */
+ /* i.e. from 'image.metrics' */
+ break;
+
+ default:
+ PERROR(( "Unsupported embedded bitmap format!\n" ));
+ return TT_Err_Invalid_File_Format;
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+ static
+ TT_Error Load_SBit_Image( TT_SBit_Strike strike,
+ UShort glyph_index,
+ Byte x_offset,
+ Byte y_offset,
+ ULong ebdt_offset,
+ TT_SBit_Image* image,
+ UShort component_depth )
+ {
+ TT_Error error;
+ Byte height, width;
+
+ ULong bitmap_offset;
+
+ TT_SBit_Range* range = 0;
+
+ TT_Big_Glyph_Metrics metrics;
+
+ /********************************************************************/
+ /* */
+ /* Scan the strike's range for the position/metrics of the source */
+ /* glyph. */
+ {
+ UShort count = strike.num_ranges;
+ TT_SBit_Range* cur = strike.sbit_ranges;
+
+ for ( ; count > 0; count--, cur++ )
+ {
+ /* look for the glyph in the current range */
+ switch ( cur->index_format )
+ {
+ case 1:
+ case 2:
+ case 3:
+ if ( glyph_index >= cur->first_glyph &&
+ glyph_index <= cur->last_glyph )
+ {
+ UShort delta = glyph_index - cur->first_glyph;
+
+
+ range = cur;
+ bitmap_offset = cur->index_format == 2
+ ? cur->image_offset + cur->image_size * delta
+ : cur->glyph_offsets[delta];
+ goto Found;
+ }
+ break;
+
+ case 4:
+ case 5:
+ {
+ UShort n;
+
+
+ for ( n = 0; n < cur->num_glyphs; n++ )
+ if ( cur->glyph_codes[n] == glyph_index )
+ {
+ range = cur;
+ bitmap_offset = cur->index_format == 4
+ ? cur->glyph_offsets[n]
+ : cur->image_offset + cur->image_size * n;
+ goto Found;
+ }
+ }
+ break;
+
+ default:
+ return TT_Err_Invalid_Glyph_Index;
+ }
+ }
+ /* Not found */
+ return TT_Err_Invalid_Glyph_Index;
+ }
+
+ Found:
+ if ( FILE_Seek( ebdt_offset + bitmap_offset ) )
+ return error;
+
+ /* First of all, load the metrics if needed */
+ error = Load_SBit_Metrics( &metrics, range, ebdt_offset );
+ if ( error )
+ return error;
+
+ width = metrics.bbox.xMax - metrics.bbox.xMin;
+ height = metrics.bbox.yMax - metrics.bbox.yMin;
+
+ if ( !component_depth )
+ {
+ image->metrics = metrics;
+
+ image->map.width = width;
+ image->map.rows = height;
+
+ image->map.cols = (width + 7) >> 3;
+ image->map.size = height * image->map.cols;
+
+ if ( REALLOC( image->map.bitmap, image->map.size ) )
+ return error;
+
+ MEM_Set( image->map.bitmap, 0, image->map.size );
+ }
+
+ /* Now, load the data as needed */
+ switch ( range->image_format )
+ {
+ case 1:
+ case 6: /* byte-aligned data */
+ error = Load_BitmapData( image,
+ height * (( width + 7 ) >> 3),
+ x_offset, y_offset,
+ width, height,
+ 1 );
+ if ( error )
+ return error;
+ break;
+
+ case 2:
+ case 5:
+ case 7:
+ error = Load_BitmapData( image,
+ (width * height + 7) >> 3,
+ x_offset, y_offset,
+ width, height, 0 );
+ if ( error )
+ return error;
+ break;
+
+ case 8:
+ case 9:
+ {
+ /* Now, load composite sbit glyphs */
+ /* This code is not sophisticated */
+
+ TT_SBit_Component* component_array;
+ UShort num_components;
+
+ Int i = 0;
+
+
+ if ( ACCESS_Frame( 2L ) )
+ return error;
+ num_components = GET_UShort();
+ FORGET_Frame();
+
+ MEM_Alloc( component_array,
+ sizeof ( TT_SBit_Component ) * num_components );
+
+ if ( ACCESS_Frame( 4L * num_components ) )
+ return error;
+
+ for ( i = 0; i < num_components; i++ )
+ {
+ component_array[i].glyph_code = GET_UShort();
+ component_array[i].x_offset = GET_Char();
+ component_array[i].y_offset = GET_Char();
+ }
+
+ FORGET_Frame();
+
+ component_depth++;
+
+ for ( i = 0; i < num_components; i++ )
+ {
+ error = Load_SBit_Image( strike, component_array[i].glyph_code,
+ component_array[i].x_offset,
+ component_array[i].y_offset,
+ ebdt_offset,
+ image,
+ component_depth );
+ if ( error )
+ return error;
+ }
+ FREE( component_array );
+ break;
+
+ default:
+ return TT_Err_Invalid_File_Format;
+ }
+ }
+
+ return TT_Err_Ok;
+ }
+
+
+/*******************************************************************
+ *
+ * Function: Load_TrueType_Ebdt
+ *
+ ******************************************************************/
+
+ static
+ TT_Error Load_TrueType_Ebdt( PFace face,
+ TT_SBit_Strike strike,
+ ULong glyph_index,
+ TT_SBit_Image* image )
+ {
+ DEFINE_LOCALS;
+
+ ULong ebdt_offset;
+ ULong version;
+ Long i;
+
+
+ /* Try to find the `EBDT' or `bdat' table in the font files. */
+ /* Both tags describe the same table, `EBDT' is for OpenType */
+ /* fonts, while `bdat' is for TrueType GX fonts. Many fonts */
+ /* contain both tags pointing to the same table */
+
+ i = TT_LookUp_Table( face, TTAG_EBDT );
+ if ( i < 0 )
+ i = TT_LookUp_Table( face, TTAG_bdat );
+
+ if ( i < 0 )
+ return TT_Err_Table_Missing;
+
+ ebdt_offset = face->dirTables[i].Offset;
+
+ if ( FILE_Seek( ebdt_offset ) ||
+ ACCESS_Frame( 4L ) ) /* read into frame */
+ return error;
+
+ version = GET_ULong();
+ FORGET_Frame();
+
+ PTRACE2(( "-- Format version : %08lx\n", version ));
+ if ( version != 0x00020000 )
+ {
+ PERROR(( "Invalid file format!\n" ));
+ return TT_Err_Invalid_File_Format;
+ }
+
+ /* This doesn't compile, I simply commented it out ?? - David */
+ /* PTRACE4(( "-- Format: %d\n", range->image_format )); */
+
+ error = Load_SBit_Image( strike,
+ glyph_index,
+ 0, 0,
+ ebdt_offset,
+ image,
+ 0 );
+ if ( error )
+ return error;
+
+ return TT_Err_Ok;
+ }
+
+
+ static TT_Error EBLC_Create( void* ext,
+ PFace face )
+ {
+ TT_EBLC* eblc = (TT_EBLC*)ext;
+
+
+ /* by convention */
+ if ( !eblc )
+ return TT_Err_Ok;
+
+ return Load_TrueType_Eblc( face, eblc );
+ }
+
+
+ static TT_Error EBLC_Destroy( void* ext,
+ PFace face )
+ {
+ TT_EBLC* eblc = (TT_EBLC*)ext;
+
+
+ (void)face;
+
+ if ( eblc )
+ Free_TrueType_Eblc( eblc );
+
+ return TT_Err_Ok;
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Init_SBit_Extension */
+ /* */
+ /* <Description> */
+ /* Initialize the embedded bitmaps extension for the */
+ /* FreeType engine. */
+ /* */
+ /* <Input> */
+ /* engine :: handle to current FreeType library instance */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ EXPORT_FUNC
+ TT_Error TT_Init_SBit_Extension( TT_Engine engine )
+ {
+ PEngine_Instance _engine = HANDLE_Engine( engine );
+
+ TT_Error error;
+
+
+ if ( !_engine )
+ return TT_Err_Invalid_Engine;
+
+ error = TT_Register_Extension( _engine,
+ SBIT_ID,
+ sizeof ( TT_EBLC ),
+ EBLC_Create,
+ EBLC_Destroy );
+
+ return error;
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Get_Face_Bitmaps */
+ /* */
+ /* <Description> */
+ /* Loads the `EBLC' table from a font file, if any. */
+ /* */
+ /* <Input> */
+ /* face :: handle to the source TrueType font/face */
+ /* */
+ /* <Output> */
+ /* eblc_table :: a descriptor for the EBLC table */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function returns TT_Err_Table_Missing if the */
+ /* font contains no embedded bitmaps. All fields in */
+ /* `eblc_table' will then be set to 0. */
+ /* */
+ EXPORT_FUNC
+ TT_Error TT_Get_Face_Bitmaps( TT_Face face,
+ TT_EBLC* eblc_table )
+ {
+ PFace faze = HANDLE_Face( face );
+ TT_EBLC* eblc;
+ TT_Error error;
+
+
+ error = TT_Extension_Get( faze, SBIT_ID, (void**)&eblc );
+ if ( !error )
+ {
+ if ( eblc->version )
+ {
+ *eblc_table = *eblc;
+ return TT_Err_Ok;
+ }
+ error = TT_Err_Table_Missing;
+ }
+
+ eblc_table->version = 0;
+ eblc_table->num_strikes = 0;
+ eblc_table->strikes = 0;
+
+ return error;
+ }
+
+
+/*******************************************************************
+ *
+ * <Function> TT_Get_SBit_Strike
+ *
+ * <Description>
+ * Loads suitable strike (bitmap sizetable) for given instance.
+ * This strike includes sbitLineMetrics.
+ *
+ * <Input>
+ * face :: the source face
+ * instance :: the current size instance
+ *
+ * <Output>
+ * strike :: the bitmap strike descriptor
+ *
+ * <Return>
+ * TrueType error code. 0 means success.
+ *
+ ******************************************************************/
+
+ EXPORT_FUNC
+ TT_Error TT_Get_SBit_Strike( TT_Face face,
+ TT_Instance instance,
+ TT_SBit_Strike* strike )
+ {
+ TT_Error error;
+ PFace faze = HANDLE_Face( face );
+ PInstance ins = HANDLE_Instance( instance );
+
+ TT_EBLC* eblc;
+ TT_Int x_ppem, y_ppem;
+
+
+ if ( !strike || !ins || ins->owner != faze )
+ return TT_Err_Invalid_Argument;
+
+ error = TT_Extension_Get( faze, SBIT_ID, (void**)&eblc );
+ if ( error )
+ goto Exit;
+
+ /********************************************************************/
+ /* */
+ /* Look for an sbit strike that matches the current x and y ppms */
+ /* */
+ {
+ UShort count = eblc->num_strikes;
+ TT_SBit_Strike* cur = eblc->strikes;
+
+
+ x_ppem = ins->metrics.x_ppem;
+ y_ppem = ins->metrics.y_ppem;
+
+ MEM_Set( strike, 0, sizeof ( TT_SBit_Strike ) );
+
+ for ( ; count > 0; count--, cur++ )
+ if ( cur->x_ppem == x_ppem &&
+ cur->y_ppem == y_ppem )
+ {
+ *strike = *cur;
+ break;
+ }
+
+ /* return immediately if we didn't find an appropriate strike */
+ if ( !strike->num_ranges )
+ error = TT_Err_Invalid_PPem;
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Load_Glyph_Bitmap */
+ /* */
+ /* <Description> */
+ /* Loads a given glyph embedded bitmap. */
+ /* */
+ /* <Input> */
+ /* face :: handle to the source TrueType font/face */
+ /* instance :: current size/transform instance */
+ /* glyph_index :: index of source glyph */
+ /* bitmap :: target embedded bitmap descriptor */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ /* <Note> */
+ /* This function returns an error if there is no */
+ /* embedded bitmap for the glyph at the given */
+ /* instance. */
+ /* */
+ EXPORT_FUNC
+ TT_Error TT_Load_Glyph_Bitmap( TT_Face face,
+ TT_Instance instance,
+ TT_UShort glyph_index,
+ TT_SBit_Image* image )
+ {
+ TT_Stream stream;
+ TT_Error error;
+
+ PFace faze = HANDLE_Face( face );
+ PInstance ins = HANDLE_Instance( instance );
+
+ TT_SBit_Strike strike;
+
+
+ if ( ins->owner != faze )
+ {
+ error = TT_Err_Invalid_Argument;
+ goto Fail;
+ }
+
+ /********************************************************************/
+ /* */
+ /* Look for an sbit strike that matches the current x and y ppms */
+ /* */
+ error = TT_Get_SBit_Strike( face, instance, &strike );
+ if ( error )
+ goto Fail;
+
+ /* return immediately if the glyph index isn't in the strike extent */
+ if ( glyph_index < strike.start_glyph ||
+ glyph_index > strike.end_glyph )
+ {
+ error = TT_Err_Invalid_Glyph_Index;
+ goto Fail;
+ }
+
+ {
+ image->bit_depth = 1;
+
+ if ( !USE_Stream( faze->stream, stream ) )
+ {
+ error = Load_TrueType_Ebdt( faze, strike, glyph_index, image );
+
+ DONE_Stream( stream );
+
+ /* exit successfully if we can */
+ if ( !error )
+ {
+ image->map.flow = TT_Flow_Down;
+
+ Crop_Bitmap( image );
+
+ /* correct sbit metrics */
+ {
+ TT_Big_Glyph_Metrics* metrics = &image->metrics;
+
+
+ metrics->bbox.xMin *= 64;
+ metrics->bbox.xMax *= 64;
+
+ metrics->bbox.yMax *= 64;
+ metrics->bbox.yMin *= 64;
+
+ metrics->horiBearingX *= 64;
+ metrics->horiBearingY *= 64;
+ metrics->horiAdvance *= 64;
+
+ metrics->vertBearingX *= 64;
+ metrics->vertBearingY *= 64;
+ metrics->vertAdvance *= 64;
+ }
+
+ goto Exit;
+ }
+ }
+ }
+
+ Fail:
+ image->map.width = 0;
+ image->map.rows = 0;
+ image->map.cols = 0;
+ image->map.size = 0;
+ image->map.bitmap = 0;
+ image->map.flow = 0;
+ image->bit_depth = 0;
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_New_SBit_Image */
+ /* */
+ /* <Description> */
+ /* Allocates a new embedded bitmap container. */
+ /* */
+ /* <Output> */
+ /* image :: sbit image */
+ /* */
+ /* <Return> */
+ /* Error code. 0 means success. */
+ /* */
+ EXPORT_FUNC
+ TT_Error TT_New_SBit_Image( TT_SBit_Image** image )
+ {
+ return MEM_Alloc( *image, sizeof ( **image ) );
+ }
+
+
+ /*************************************************************/
+ /* */
+ /* <Function> */
+ /* TT_Done_SBit_Image */
+ /* */
+ /* <Description> */
+ /* Releases an embedded bitmap container. */
+ /* */
+ /* <Input> */
+ /* image :: sbit image */
+ /* */
+ EXPORT_FUNC
+ void TT_Done_SBit_Image( TT_SBit_Image* image )
+ {
+ FREE( image->map.bitmap );
+ FREE( image );
+ }
+
+
+/* END */