From 8f43c714a5a74c63c2a6242392790510ac487f80 Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 2 Feb 2000 12:16:19 +0000 Subject: [PATCH] A major refresh of the TrueType driver : - some #ifdefs were included in order to _not_ compile support for the bytecode interpreter when FT_CONFIG_OPTION_BYTECODE_INTERPRETER is not defined in "ttconfig.h" - the glyph loader has been seriously re-designed. It is now smaller, simpler and should load composites a bit faster - works with the TrueType debugger --- src/truetype/truetype.c | 4 +- src/truetype/ttconfig.h | 17 +- src/truetype/ttdriver.c | 2 +- src/truetype/ttdriver.h | 107 +-- src/truetype/ttgload.c | 1617 +++++++++++++++++---------------------- src/truetype/ttgload.h | 39 +- src/truetype/ttobjs.c | 164 ++-- src/truetype/ttobjs.h | 3 + 8 files changed, 857 insertions(+), 1096 deletions(-) diff --git a/src/truetype/truetype.c b/src/truetype/truetype.c index e5fe88400..c160aeeb2 100644 --- a/src/truetype/truetype.c +++ b/src/truetype/truetype.c @@ -44,7 +44,9 @@ #include /* driver interface */ #include /* tables loader */ #include /* glyph loader */ -#include /* bytecode interpreter */ #include /* object manager */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include /* bytecode interpreter */ +#endif /* END */ diff --git a/src/truetype/ttconfig.h b/src/truetype/ttconfig.h index cdb4f6e57..eba0de310 100644 --- a/src/truetype/ttconfig.h +++ b/src/truetype/ttconfig.h @@ -28,6 +28,17 @@ #define TTCONFIG_H + /*************************************************************************/ + /* */ + /* Define TT_CONFIG_OPTION_BYTECODE_INTERPRETER if you want to compile */ + /* a bytecode interpreter in the TrueType driver. Note that there are */ + /* important patent issues related to the use of the interpreter. */ + /* */ + /* By undefining this, you'll only compile the code necessary to load */ + /* TrueType glyphs without hinting.. */ + /* */ +#undef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + /*************************************************************************/ /* */ /* Define TT_CONFIG_OPTION_INTERPRETER_SWITCH to compile the TrueType */ @@ -46,7 +57,7 @@ /* Define TT_CONFIG_OPTION_EMBEDDED_BITMAPS if you want to support */ /* embedded bitmaps in the TrueType/OpenType driver. */ /* */ -#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS +#undef TT_CONFIG_OPTION_EMBEDDED_BITMAPS /*************************************************************************/ @@ -55,8 +66,10 @@ /* load and enumerate the glyph Postscript names in a TrueType or */ /* OpenType file. */ /* */ -#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES +#undef TT_CONFIG_OPTION_POSTSCRIPT_NAMES + /* The maximum number of sub-glyphs in a TrueType composite glyph */ +#define TT_MAX_SUBGLYPHS 32 #define TT_USE_FIXED diff --git a/src/truetype/ttdriver.c b/src/truetype/ttdriver.c index fdf9dff25..d61d8e3c4 100644 --- a/src/truetype/ttdriver.c +++ b/src/truetype/ttdriver.c @@ -683,7 +683,7 @@ EXPORT_FUNC FT_DriverInterface* getDriverInterface( void ) { - return &truetype_driver_interface; + return &tt_driver_interface; } #endif /* CONFIG_OPTION_DYNAMIC_DRIVERS */ diff --git a/src/truetype/ttdriver.h b/src/truetype/ttdriver.h index 16e20c3e8..199934fd2 100644 --- a/src/truetype/ttdriver.h +++ b/src/truetype/ttdriver.h @@ -26,115 +26,10 @@ #include - /*************************************************************************/ - /* */ - /* */ - /* TTDriver_getFontData */ - /* */ - /* */ - /* Returns either a single font table or the whole font file into */ - /* caller's memory. This function mimics the GetFontData() API */ - /* function found in Windows. */ - /* */ - /* */ - /* face :: A handle to the source TrueType face object. */ - /* */ - /* tag :: A 32-bit integer used to name the table you want to */ - /* read. Use the macro MAKE_TT_TAG (defined in freetype.h) */ - /* to create one. Use the value 0 if you want to access */ - /* the whole file instead. */ - /* */ - /* offset :: The offset from the start of the table or file from */ - /* which you want to read bytes. */ - /* */ - /* buffer :: The address of the target/read buffer where data will be */ - /* copied. */ - /* */ - /* */ - /* length :: The length in bytes of the data to read. If it is set */ - /* to 0 when this function is called, it will return */ - /* immediately, setting the value of `length' to the */ - /* requested table's size (or the whole font file if the */ - /* tag is 0). It is thus possible to allocate and read an */ - /* arbitrary table in two successive calls. */ - /* */ - /* TrueType error code. 0 means success. */ - /* */ - typedef TT_Error (*TTDriver_getFontData)( TT_Face face, - TT_ULong tag, - TT_ULong offset, - void* buffer, - TT_Long* length ); - - - /*************************************************************************/ - /* */ - /* */ - /* TTDriver_getFaceWidths */ - /* */ - /* */ - /* Returns the widths and/or heights of a given range of glyph from */ - /* a face. */ - /* */ - /* */ - /* face :: A handle to the source FreeType face object. */ - /* */ - /* first_glyph :: The first glyph in the range. */ - /* */ - /* last_glyph :: The last glyph in the range. */ - /* */ - /* */ - /* widths :: The address of the table receiving the widths */ - /* expressed in font units (UShorts). Set this */ - /* parameter to NULL if you're not interested in these */ - /* values. */ - /* */ - /* heights :: The address of the table receiving the heights */ - /* expressed in font units (UShorts). Set this */ - /* parameter to NULL if you're not interested in these */ - /* values. */ - /* */ - /* */ - /* Error code. 0 means success. */ - /* */ - typedef TT_Error (*TTDriver_getFaceWidths)( TT_Face face, - TT_UShort first_glyph, - TT_UShort last_glyph, - TT_UShort* widths, - TT_UShort* heights ); - - - - /*************************************************************************/ - /* */ - /* */ - /* TT_DriverInterface */ - /* */ - /* */ - /* The TrueType-specific interface of this driver. Note that some of */ - /* the methods defined here are optional, as they're only used for */ - /* for specific tasks of the driver. */ - /* */ - /* */ - /* get_font_data :: See the declaration of TTDriver_getFontData(). */ - /* get_face_widths :: See the declaration of */ - /* TTDriver_getFaceWidths(). */ - /* */ - typedef struct TT_DriverInterface_ - { - TTDriver_getFontData get_font_data; - TTDriver_getFaceWidths get_face_widths; - - } TT_DriverInterface; - - EXPORT_DEF - const FT_DriverInterface tt_driver_interface; + const FT_DriverInterface ttz_driver_interface; - EXPORT_DEF - const TT_DriverInterface tt_format_interface; - #endif /* TTDRIVER_H */ diff --git a/src/truetype/ttgload.c b/src/truetype/ttgload.c index bf24b4d85..f62d579a2 100644 --- a/src/truetype/ttgload.c +++ b/src/truetype/ttgload.c @@ -25,8 +25,10 @@ #include #include -#include +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include +#endif /* required for the tracing mode */ #undef FT_COMPONENT @@ -49,41 +51,15 @@ #define USE_MY_METRICS 0x200 -#undef SCALE_X -#define SCALE_X( distance ) FT_MulFix( distance, exec->metrics.x_scale ) - -#undef SCALE_Y -#define SCALE_Y( distance ) FT_MulFix( distance, exec->metrics.y_scale ) - /*************************************************************************/ - /* */ - /* */ - /* TT_Get_Metrics */ - /* */ - /* */ /* Returns the horizontal or vertical metrics in font units for a */ /* given glyph. The metrics are the left side bearing (resp. top */ /* side bearing) and advance width (resp. advance height). */ /* */ - /* */ - /* header :: A pointer to either the horizontal or vertical metrics */ - /* structure. */ - /* */ - /* index :: The glyph index. */ - /* */ - /* */ - /* bearing :: The bearing, either left side or top side. */ - /* */ - /* advance :: The advance width resp. advance height. */ - /* */ - /* */ - /* This function will much probably move to another component in the */ - /* near future, but I haven't decided which yet. */ - /* */ LOCAL_FUNC void TT_Get_Metrics( TT_HoriHeader* header, - TT_UShort index, + TT_UInt index, TT_Short* bearing, TT_UShort* advance ) { @@ -106,30 +82,13 @@ /*************************************************************************/ - /* */ - /* */ - /* Get_HMetrics */ - /* */ - /* */ /* Returns the horizontal metrics in font units for a given glyph. */ /* If `check' is true, take care of monospaced fonts by returning the */ /* advance width maximum. */ /* */ - /* */ - /* face :: A handle to the target source face. */ - /* */ - /* index :: The glyph index. */ - /* */ - /* check :: If set, handle monospaced fonts. */ - /* */ - /* */ - /* lsb :: The left side bearing. */ - /* */ - /* aw :: The advance width. */ - /* */ static void Get_HMetrics( TT_Face face, - TT_UShort index, + TT_UInt index, TT_Bool check, TT_Short* lsb, TT_UShort* aw ) @@ -142,22 +101,9 @@ /*************************************************************************/ - /* */ - /* */ - /* Get_Advance_Widths */ - /* */ - /* */ /* Returns the advance width table for a given pixel size if it is */ /* found in the font's `hdmx' table (if any). */ /* */ - /* */ - /* face :: A handle to the target source face. */ - /* */ - /* ppem :: The pixel size. */ - /* */ - /* */ - /* A pointer to the advance with table. NULL if it doesn't exist. */ - /* */ static TT_Byte* Get_Advance_Widths( TT_Face face, TT_UShort ppem ) @@ -181,31 +127,15 @@ /*************************************************************************/ - /* */ - /* */ - /* translate_array */ - /* */ - /* */ /* Translates an array of coordinates. */ /* */ - /* */ - /* n :: The number of points to translate. */ - /* */ - /* delta_x :: The horizontal coordinate of the shift vector. */ - /* */ - /* delta_y :: The vertical coordinate of the shift vector. */ - /* */ - /* */ - /* coords :: The vector array to translate. */ - /* */ static - void translate_array( TT_UShort n, + void translate_array( TT_UInt n, TT_Vector* coords, TT_Pos delta_x, TT_Pos delta_y ) { - TT_UShort k; - + TT_UInt k; if ( delta_x ) for ( k = 0; k < n; k++ ) @@ -217,28 +147,17 @@ } + /*************************************************************************/ - /* */ - /* */ - /* mount_zone */ - /* */ - /* */ /* Mounts one glyph zone on top of another. This is needed to */ /* assemble composite glyphs. */ /* */ - /* */ - /* source :: The source glyph zone. */ - /* */ - /* */ - /* target :: The target glyph zone. */ - /* */ static void mount_zone( TT_GlyphZone* source, TT_GlyphZone* target ) { - TT_UShort np; - TT_Short nc; - + TT_UInt np; + TT_Int nc; np = source->n_points; nc = source->n_contours; @@ -254,6 +173,9 @@ } +#undef IS_HINTED +#define IS_HINTED(flags) ((flags & FT_LOAD_NO_HINTING) == 0) + /*************************************************************************/ /* */ /* */ @@ -265,35 +187,23 @@ /* glyphs elements will be loaded with routine. */ /* */ static - TT_Error Load_Simple_Glyph( TT_ExecContext exec, - FT_Stream stream, - TT_ULong byte_count, - TT_Short n_contours, - TT_Short left_contours, - TT_UShort left_points, - TT_UInt load_flags, - TT_SubGlyphRec* subg, - TT_Bool debug ) + TT_Error Load_Simple( TT_Loader* load, + TT_UInt byte_count, + TT_Int n_contours, + TT_Bool debug ) { TT_Error error; - TT_GlyphZone* pts; - TT_Short k; - TT_UShort j; - TT_UShort n_points, n_ins; - TT_Face face; - TT_Byte* flag; - TT_Vector* vec; - TT_F26Dot6 x, y; + FT_Stream stream = load->stream; + TT_GlyphZone* zone = &load->zone; + TT_Face face = load->face; - TT_Vector *pp1, *pp2; + TT_UShort n_ins; + TT_Int n, n_points; - - face = exec->face; - /*********************************************************************/ /* simple check */ - if ( n_contours > left_contours ) + if ( n_contours > load->left_contours ) { FT_TRACE0(( "ERROR: Glyph index %ld has %d contours > left %d\n", subg->index, @@ -303,8 +213,7 @@ } /* preparing the execution context */ - mount_zone( &subg->zone, &exec->pts ); - + mount_zone( &load->base, zone ); /*********************************************************************/ /* reading the contours endpoints */ @@ -312,12 +221,12 @@ if ( ACCESS_Frame( byte_count ) ) return error; - for ( k = 0; k < n_contours; k++ ) - exec->pts.contours[k] = GET_UShort(); + for ( n = 0; n < n_contours; n++ ) + zone->contours[n] = GET_UShort(); n_points = 0; if ( n_contours > 0 ) - n_points = exec->pts.contours[n_contours - 1] + 1; + n_points = zone->contours[n_contours - 1] + 1; /*********************************************************************/ @@ -325,7 +234,7 @@ n_ins = GET_UShort(); - if ( n_points > left_points ) + if ( n_points > load->left_points ) { FT_TRACE0(( "ERROR: Too many points in glyph %ld\n", subg->index )); error = TT_Err_Too_Many_Points; @@ -347,34 +256,32 @@ error = TT_Err_Too_Many_Ins; goto Fail; } - MEM_Copy( exec->glyphIns, stream->cursor, n_ins ); - stream->cursor += n_ins; - error = TT_Set_CodeRange( exec, tt_coderange_glyph, - exec->glyphIns, n_ins ); +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + MEM_Copy( load->exec->glyphIns, stream->cursor, n_ins ); + + error = TT_Set_CodeRange( load->exec, tt_coderange_glyph, + load->exec->glyphIns, n_ins ); if (error) goto Fail; +#endif + stream->cursor += n_ins; /*********************************************************************/ /* reading the point flags */ - - j = 0; - flag = exec->pts.touch; - while ( j < n_points ) - { - TT_Byte c, cnt; - - flag[j] = c = GET_Byte(); - j++; - - if ( c & 8 ) + { + TT_Byte* flag = load->zone.touch; + TT_Byte* limit = flag + n_points; + TT_Byte c, count; + + for (; flag < limit; flag++) { - cnt = GET_Byte(); - while( cnt > 0 ) + *flag = c = GET_Byte(); + if ( c & 8 ) { - flag[j++] = c; - cnt--; + for ( count = GET_Byte(); count > 0; count-- ) + *++flag = c; } } } @@ -382,49 +289,53 @@ /*********************************************************************/ /* reading the X coordinates */ - x = 0; - vec = exec->pts.org; - - for ( j = 0; j < n_points; j++ ) { - if ( flag[j] & 2 ) + TT_Vector* vec = zone->org; + TT_Vector* limit = vec + n_points; + TT_Byte* flag = zone->touch; + TT_Pos x = 0; + + for ( ; vec < limit; vec++, flag++ ) { - if ( flag[j] & 16 ) - x += GET_Byte(); - else - x -= GET_Byte(); + TT_Pos y = 0; + + if ( *flag & 2 ) + { + y = GET_Byte(); + if ((*flag & 16) == 0) y = -y; + } + else if ((*flag & 16) == 0) + y = GET_Short(); + + x += y; + vec->x = x; } - else - { - if ( (flag[j] & 16) == 0 ) - x += GET_Short(); - } - - vec[j].x = x; } - /*********************************************************************/ /* reading the YX coordinates */ - - y = 0; - for ( j = 0; j < n_points; j++ ) { - if ( flag[j] & 4 ) + TT_Vector* vec = zone->org; + TT_Vector* limit = vec + n_points; + TT_Byte* flag = zone->touch; + TT_Pos x = 0; + + for ( ; vec < limit; vec++, flag++ ) { - if ( flag[j] & 32 ) - y += GET_Byte(); - else - y -= GET_Byte(); + TT_Pos y = 0; + + if ( *flag & 4 ) + { + y = GET_Byte(); + if ((*flag & 32) == 0) y = -y; + } + else if ((*flag & 32) == 0) + y = GET_Short(); + + x += y; + vec->y = x; } - else - { - if ( (flag[j] & 32) == 0 ) - y += GET_Short(); - } - - vec[j].y = y; } FORGET_Frame(); @@ -435,79 +346,93 @@ /* Now add the two shadow points at n and n + 1. */ /* We need the left side bearing and advance width. */ - /* pp1 = xMin - lsb */ - pp1 = vec + n_points; - pp1->x = subg->bbox.xMin - subg->left_bearing; - pp1->y = 0; - - /* pp2 = pp1 + aw */ - pp2 = pp1 + 1; - pp2->x = pp1->x + subg->advance; - pp2->y = 0; + { + TT_Vector* pp1; + TT_Vector* pp2; + + /* pp1 = xMin - lsb */ + pp1 = zone->org + n_points; + pp1->x = load->bbox.xMin - load->left_bearing; + pp1->y = 0; + + /* pp2 = pp1 + aw */ + pp2 = pp1 + 1; + pp2->x = pp1->x + load->advance; + pp2->y = 0; - /* clear the touch flags */ - for ( j = 0; j < n_points; j++ ) - exec->pts.touch[j] &= FT_Curve_Tag_On; - - exec->pts.touch[n_points ] = 0; - exec->pts.touch[n_points + 1] = 0; + /* clear the touch flags */ + for ( n = 0; n < n_points; n++ ) + zone->touch[n] &= FT_Curve_Tag_On; + zone->touch[n_points ] = 0; + zone->touch[n_points + 1] = 0; + } /* Note that we return two more points that are not */ /* part of the glyph outline. */ - n_points += 2; + zone->n_points = n_points; + zone->n_contours = n_contours; + n_points += 2; + /*******************************************/ /* now eventually scale and hint the glyph */ - pts = &exec->pts; - pts->n_points = n_points; - pts->n_contours = n_contours; - - if (load_flags & FT_LOAD_NO_SCALE) + if (load->load_flags & FT_LOAD_NO_SCALE) { /* no scaling, just copy the orig arrays into the cur ones */ - org_to_cur( n_points, pts ); + org_to_cur( n_points, zone ); } else { + TT_Vector* vec = zone->org; + TT_Vector* limit = vec + n_points; + TT_Fixed x_scale = load->size->root.metrics.x_scale; + TT_Fixed y_scale = load->size->root.metrics.y_scale; + /* first scale the glyph points */ - for ( j = 0; j < n_points; j++ ) + for (; vec < limit; vec++) { - pts->org[j].x = SCALE_X( pts->org[j].x ); - pts->org[j].y = SCALE_Y( pts->org[j].y ); + vec->x = FT_MulFix( vec->x, x_scale ); + vec->y = FT_MulFix( vec->y, y_scale ); } /* if hinting, round pp1, and shift the glyph accordingly */ - if ( subg->is_hinted ) + if ( !IS_HINTED(load->load_flags) ) { - x = pts->org[n_points - 2].x; + org_to_cur( n_points, zone ); + } + else + { + TT_Pos x = zone->org[n_points-2].x; x = ((x + 32) & -64) - x; - translate_array( n_points, pts->org, x, 0 ); + translate_array( n_points, zone->org, x, 0 ); - org_to_cur( n_points, pts ); + org_to_cur( n_points, zone ); - pts->cur[n_points - 1].x = (pts->cur[n_points - 1].x + 32) & -64; + zone->cur[n_points-1].x = (zone->cur[n_points-1].x + 32) & -64; +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER /* now consider hinting */ if ( n_ins > 0 ) { - exec->is_composite = FALSE; - exec->pedantic_hinting = load_flags & FT_LOAD_PEDANTIC; + load->exec->is_composite = FALSE; + load->exec->pedantic_hinting = (TT_Bool)(load->load_flags & FT_LOAD_PEDANTIC); + load->exec->pts = *zone; + load->exec->pts.n_points += 2; - error = TT_Run_Context( exec, debug ); - if ( error && exec->pedantic_hinting ) + error = TT_Run_Context( load->exec, debug ); + if ( error && load->exec->pedantic_hinting ) return error; } +#endif } - else - org_to_cur( n_points, pts ); } /* save glyph phantom points */ - if ( !subg->preserve_pps ) + if ( !load->preserve_pps ) { - subg->pp1 = pts->cur[n_points - 2]; - subg->pp2 = pts->cur[n_points - 1]; + load->pp1 = zone->cur[n_points - 2]; + load->pp2 = zone->cur[n_points - 1]; } return TT_Err_Ok; @@ -518,683 +443,304 @@ } + + + + /*************************************************************************/ /* */ /* */ - /* Load_Composite_End */ + /* load_truetype_glyph */ /* */ /* */ - /* Finalizes the loading process of a composite glyph element. This */ - /* function is used for the `Load_End' state of TT_Load_Glyph(). */ + /* Loads a given truetype glyph. Handles composites and uses a */ + /* TT_Loader object.. */ /* */ static - TT_Error Load_Composite_End( TT_UShort n_points, - TT_Short n_contours, - TT_ExecContext exec, - TT_SubGlyphRec* subg, - FT_Stream stream, - TT_UInt load_flags, - TT_Bool debug ) + TT_Error load_truetype_glyph( TT_Loader* loader, + TT_UInt glyph_index ) { - TT_Error error; - - TT_UShort k, n_ins; - TT_GlyphZone* pts; - - if ( subg->is_hinted && - subg->element_flag & WE_HAVE_INSTR ) - { - if ( READ_UShort( n_ins ) ) /* read size of instructions */ - return error; - - FT_TRACE4(( "Instructions size = %d\n", n_ins )); - - if ( n_ins > exec->face->max_profile.maxSizeOfInstructions ) - { - FT_TRACE0(( "Too many instructions in composite glyph %ld\n", - subg->index )); - return TT_Err_Too_Many_Ins; - } - - if ( FILE_Read( exec->glyphIns, n_ins ) ) - return error; - - error = TT_Set_CodeRange( exec, - tt_coderange_glyph, - exec->glyphIns, - n_ins ); - if ( error ) - return error; - } - else - n_ins = 0; - - - /* prepare the execution context */ - n_points += 2; - exec->pts = subg->zone; - pts = &exec->pts; - - pts->n_points = n_points; - pts->n_contours = n_contours; - - /* add phantom points */ - pts->cur[n_points - 2] = subg->pp1; - pts->cur[n_points - 1] = subg->pp2; - - pts->touch[n_points - 1] = 0; - pts->touch[n_points - 2] = 0; - - /* if hinting, round the phantom points */ - if ( subg->is_hinted ) - { - pts->cur[n_points - 2].x = ((subg->pp1.x + 32) & -64); - pts->cur[n_points - 1].x = ((subg->pp2.x + 32) & -64); - } - - for ( k = 0; k < n_points; k++ ) - pts->touch[k] &= FT_Curve_Tag_On; - - cur_to_org( n_points, pts ); - - /* now consider hinting */ - if ( subg->is_hinted && n_ins > 0 ) - { - exec->is_composite = TRUE; - exec->pedantic_hinting = load_flags & FT_LOAD_PEDANTIC; - - error = TT_Run_Context( exec, debug ); - if ( error && exec->pedantic_hinting ) - return error; - } - - /* save glyph origin and advance points */ - subg->pp1 = pts->cur[n_points - 2]; - subg->pp2 = pts->cur[n_points - 1]; - - return TT_Err_Ok; - } - - - /*************************************************************************/ - /* */ - /* */ - /* Init_Glyph_Component */ - /* */ - /* */ - /* Initializes a glyph component for further processing. */ - /* */ - static - void Init_Glyph_Component( TT_SubGlyphRec* element, - TT_SubGlyphRec* original, - TT_ExecContext exec ) - { - element->index = -1; - element->is_scaled = FALSE; - element->is_hinted = FALSE; - - if ( original ) - mount_zone( &original->zone, &element->zone ); - else - element->zone = exec->pts; - - element->zone.n_contours = 0; - element->zone.n_points = 0; - - element->arg1 = 0; - element->arg2 = 0; - - element->element_flag = 0; - element->preserve_pps = FALSE; - - element->transform.xx = 0x10000; - element->transform.xy = 0; - element->transform.yx = 0; - element->transform.yy = 0x10000; - - element->transform.ox = 0; - element->transform.oy = 0; - - element->left_bearing = 0; - element->advance = 0; - } - - - /*************************************************************************/ - /* */ - /* */ - /* TT_Load_Glyph */ - /* */ - /* */ - /* A function used to load a single glyph within a given glyph slot, */ - /* for a given size. */ - /* */ - /* */ - /* glyph :: A handle to a target slot object where the glyph */ - /* will be loaded. */ - /* */ - /* size :: A handle to the source face size at which the glyph */ - /* must be scaled/loaded. */ - /* */ - /* glyph_index :: The index of the glyph in the font file. */ - /* */ - /* load_flags :: A flag indicating what to load for this glyph. The */ - /* FT_LOAD_XXX constants can be used to control the */ - /* glyph loading process (e.g., whether the outline */ - /* should be scaled, whether to load bitmaps or not, */ - /* whether to hint the outline, etc). */ - /* */ - /* result :: A set of bit flags indicating the type of data that */ - /* was loaded in the glyph slot (outline or bitmap, */ - /* etc). */ - /* */ - /* You can set this field to 0 if you don't want this */ - /* information. */ - /* */ - /* */ - /* FreeType error code. 0 means success. */ - /* */ - LOCAL_FUNC - TT_Error TT_Load_Glyph( TT_Size size, - TT_GlyphSlot glyph, - TT_UShort glyph_index, - TT_UInt load_flags ) - { - typedef enum TPhases_ - { - Load_Exit, - Load_Glyph, - Load_Header, - Load_Simple, - Load_Composite, - Load_End - - } TPhases; - - TT_Error error = 0; - FT_Stream stream; - - TT_Face face; - - TT_UShort num_points; - TT_Short num_contours; - TT_UShort left_points; - TT_Short left_contours; - - TT_ULong load_top; - TT_Long k, l; - TT_Int new_flags; - TT_UShort index; - TT_UShort u; - TT_Long count; - - TT_Long glyph_offset, offset; - - TT_F26Dot6 x, y, nx, ny; - - TT_Fixed xx, xy, yx, yy; - TT_BBox bbox; - - TT_ExecContext exec; - - TT_SubGlyphRec *subglyph, *subglyph2; - - TT_GlyphZone base_pts; - - TPhases phase; - TT_Byte* widths; - TT_Int num_elem_points; - - SFNT_Interface* sfnt; + FT_Stream stream = loader->stream; + TT_Error error; + TT_Face face = loader->face; + TT_ULong offset; + FT_SubGlyph subglyphs[ TT_MAX_SUBGLYPHS ]; + TT_Int num_subglyphs = 0, contours_count; + TT_UInt index, num_points, num_contours, count; + TT_Fixed x_scale, y_scale; + TT_ULong ins_offset; - /* first of all, check arguments */ - if ( !glyph ) - return TT_Err_Invalid_Glyph_Handle; - - face = (TT_Face)glyph->face; - if ( !face ) - return TT_Err_Invalid_Glyph_Handle; - - sfnt = (SFNT_Interface*)face->sfnt; - stream = face->root.stream; - count = 0; - - if ( glyph_index >= face->root.num_glyphs ) - return TT_Err_Invalid_Glyph_Index; - - if ( !size || (load_flags & FT_LOAD_NO_SCALE) ) + /* check glyph index */ + index = (TT_UInt)glyph_index; + if ( index >= (TT_UInt)face->root.num_glyphs ) { - size = NULL; - load_flags |= FT_LOAD_NO_SCALE | - FT_LOAD_NO_HINTING | - FT_LOAD_NO_BITMAP; + error = TT_Err_Invalid_Glyph_Index; + goto Fail; } - /* Try to load embedded bitmap if any */ - if ( size && (load_flags & FT_LOAD_NO_BITMAP) == 0 && sfnt->load_sbits ) - { - TT_SBit_Metrics metrics; - - error = sfnt->load_sbit_image( face, - size->root.metrics.x_ppem, - size->root.metrics.y_ppem, - glyph_index, - stream, - &glyph->bitmap, - &metrics ); - if ( !error ) - { - glyph->outline.n_points = 0; - glyph->outline.n_contours = 0; - - glyph->metrics.width = (TT_Pos)metrics.width << 6; - glyph->metrics.height = (TT_Pos)metrics.height << 6; - - glyph->metrics.horiBearingX = (TT_Pos)metrics.horiBearingX << 6; - glyph->metrics.horiBearingY = (TT_Pos)metrics.horiBearingY << 6; - glyph->metrics.horiAdvance = (TT_Pos)metrics.horiAdvance << 6; - - glyph->metrics.vertBearingX = (TT_Pos)metrics.vertBearingX << 6; - glyph->metrics.vertBearingY = (TT_Pos)metrics.vertBearingY << 6; - glyph->metrics.vertAdvance = (TT_Pos)metrics.vertAdvance << 6; - - glyph->format = ft_glyph_format_bitmap; - return error; - } - } - - if ( load_flags & FT_LOAD_NO_OUTLINE ) - return ( error ? error : TT_Err_Unavailable_Bitmap ); - - error = face->goto_table( face, TTAG_glyf, stream, 0 ); - if (error) - { - FT_ERROR(( "TT.GLoad: could not access glyph table\n" )); - return error; - } - - glyph_offset = FILE_Pos(); - - /* query new execution context */ - - if ( size && size->debug ) - exec = size->context; - else - exec = TT_New_Context( face ); - - if ( !exec ) - return TT_Err_Could_Not_Find_Context; - - TT_Load_Context( exec, face, size ); - - if ( size ) - { - /* load default graphics state - if needed */ - if ( size->GS.instruct_control & 2 ) - exec->GS = tt_default_graphics_state; - - glyph->outline.high_precision = ( size->root.metrics.y_ppem < 24 ); - } - - /* save its critical pointers, as they'll be modified during load */ - base_pts = exec->pts; - - /* init variables */ - left_points = face->root.max_points; /* remove phantom points */ - left_contours = face->root.max_contours; - - num_points = 0; num_contours = 0; - - load_top = 0; - subglyph = exec->loadStack; - - Init_Glyph_Component( subglyph, NULL, exec ); - - subglyph->index = glyph_index; - subglyph->is_hinted = !(load_flags & FT_LOAD_NO_HINTING); - - /* when the cvt program has disabled hinting, the argument */ - /* is ignored. */ - if ( size && (size->GS.instruct_control & 1) ) - subglyph->is_hinted = FALSE; - - /* Main loading loop */ - - phase = Load_Glyph; - index = 0; - - while ( phase != Load_Exit ) + num_points = 0; + ins_offset = 0; + + x_scale = 0x10000; + y_scale = 0x10000; { - subglyph = exec->loadStack + load_top; + x_scale = loader->size->root.metrics.x_scale; + y_scale = loader->size->root.metrics.y_scale; + } - switch ( phase ) - { + /* get horizontal metrics */ + { + TT_Short left_bearing; + TT_UShort advance_width; - /************************************************************/ - /* */ - /* Load_Glyph state */ - /* */ - /* reading a glyph's generic data, checking whether the */ - /* glyph is cached already (not implemented yet) */ - /* */ - /* exit states: Load_Header and Load_End */ - /* */ - case Load_Glyph: - /* check glyph index and table */ + Get_HMetrics( face, index, TRUE, + &left_bearing, + &advance_width ); - index = (TT_UInt)subglyph->index; - if ( index >= face->root.num_glyphs ) - { - error = TT_Err_Invalid_Glyph_Index; - goto Fail; - } + loader->left_bearing = left_bearing; + loader->advance = advance_width; + } - /* get horizontal metrics */ - { - TT_Short left_bearing; - TT_UShort advance_width; - - Get_HMetrics( face, index, TRUE, - &left_bearing, - &advance_width ); - - subglyph->left_bearing = left_bearing; - subglyph->advance = advance_width; - } - - phase = Load_Header; - - /************************************************************/ - /* */ - /* Load_Header state */ - /* */ - /* reading a glyph's generic header to determine whether */ - /* it is a simple or composite glyph */ - /* */ - /* exit states: Load_Simple and Load_Composite */ - /* */ - case Load_Header: - /* load glyph */ - - offset = face->glyph_locations[index]; - count = 0; - if (index < face->num_locations-1) - count = face->glyph_locations[index+1] - offset; + /* load glyph header */ + offset = face->glyph_locations[index]; + count = 0; + if (index < (TT_UInt)face->num_locations-1) + count = face->glyph_locations[index+1] - offset; - if (count == 0) - { - /* as described by Frederic Loyer, these are spaces, and */ - /* not the unknown glyph. */ - num_contours = 0; - num_points = 0; + if (count == 0) + { + /* as described by Frederic Loyer, these are spaces, and */ + /* not the unknown glyph. */ + loader->bbox.xMin = 0; + loader->bbox.xMax = 0; + loader->bbox.yMin = 0; + loader->bbox.yMax = 0; - subglyph->bbox.xMin = 0; - subglyph->bbox.xMax = 0; - subglyph->bbox.yMin = 0; - subglyph->bbox.yMax = 0; + loader->pp1.x = 0; + loader->pp2.x = loader->advance; - subglyph->pp1.x = 0; - subglyph->pp2.x = subglyph->advance; + if ( (loader->load_flags & FT_LOAD_NO_SCALE)==0 ) + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); - if ( !(load_flags & FT_LOAD_NO_SCALE) ) - subglyph->pp2.x = SCALE_X( subglyph->pp2.x ); +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + loader->exec->glyphSize = 0; +#endif + goto Load_End; + } - exec->glyphSize = 0; - phase = Load_End; - break; - } + offset = loader->glyf_offset + offset; - offset = glyph_offset + offset; + /* read first glyph header */ + if ( FILE_Seek( offset ) || ACCESS_Frame( 10L ) ) + goto Fail; - /* read first glyph header */ - if ( FILE_Seek( offset ) || - ACCESS_Frame( 10L ) ) - goto Fail_File; + contours_count = GET_Short(); - num_contours = GET_Short(); + loader->bbox.xMin = GET_Short(); + loader->bbox.yMin = GET_Short(); + loader->bbox.xMax = GET_Short(); + loader->bbox.yMax = GET_Short(); - subglyph->bbox.xMin = GET_Short(); - subglyph->bbox.yMin = GET_Short(); - subglyph->bbox.xMax = GET_Short(); - subglyph->bbox.yMax = GET_Short(); + FORGET_Frame(); - FORGET_Frame(); + FT_TRACE6(( "Glyph %ld\n", index )); + FT_TRACE6(( " # of contours : %d\n", num_contours )); + FT_TRACE6(( " xMin: %4d xMax: %4d\n", loader->bbox.xMin, + loader->bbox.xMax )); + FT_TRACE6(( " yMin: %4d yMax: %4d\n", loader->bbox.yMin, + loader->bbox.yMax )); + FT_TRACE6(( "-" )); - FT_TRACE6(( "Glyph %ld\n", index )); - FT_TRACE6(( " # of contours : %d\n", num_contours )); - FT_TRACE6(( " xMin: %4d xMax: %4d\n", - subglyph->bbox.xMin, - subglyph->bbox.xMax )); - FT_TRACE6(( " yMin: %4d yMax: %4d\n", - subglyph->bbox.yMin, - subglyph->bbox.yMax )); - FT_TRACE6(( "-" )); + count -= 10; - count -= 10; + if ( contours_count > loader->left_contours ) + { + FT_TRACE0(( "ERROR: Too many contours for glyph %ld\n", index )); + error = TT_Err_Too_Many_Contours; + goto Fail; + } - if ( num_contours > left_contours ) - { - FT_TRACE0(( "ERROR: Too many contours for glyph %ld\n", index )); - error = TT_Err_Too_Many_Contours; - goto Fail; - } + loader->pp1.x = loader->bbox.xMin - loader->left_bearing; + loader->pp1.y = 0; + loader->pp2.x = loader->pp1.x + loader->advance; + loader->pp2.y = 0; + + if ((loader->load_flags & FT_LOAD_NO_SCALE)==0) + { + loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale ); + loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale ); + } - subglyph->pp1.x = subglyph->bbox.xMin - subglyph->left_bearing; - subglyph->pp1.y = 0; - subglyph->pp2.x = subglyph->pp1.x + subglyph->advance; - if (!(load_flags & FT_LOAD_NO_SCALE)) - { - subglyph->pp1.x = SCALE_X( subglyph->pp1.x ); - subglyph->pp2.x = SCALE_X( subglyph->pp2.x ); - } + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ - /* is it a simple glyph ? */ - if ( num_contours < 0 ) - { - phase = Load_Composite; - break; - } + /**********************************************************************/ + /* if it is a simple glyph, load it */ + if (contours_count >= 0) + { + TT_UInt num_base_points; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + error = Load_Simple( loader, + count, + contours_count, + (TT_Bool)( loader->size && + loader->size->debug ) ); +#else + error = Load_Simple( loader, count, contours_count, 0 ); +#endif + if ( error ) + goto Fail; - phase = Load_Simple; + /* Note: We could have put the simple loader source there */ + /* but the code is fat enough already :-) */ + num_points = loader->zone.n_points; + num_contours = loader->zone.n_contours; + + num_base_points = loader->base.n_points; + { + TT_UInt k; + for ( k = 0; k < num_contours; k++ ) + loader->zone.contours[k] += num_base_points; + } + + loader->base.n_points += num_points; + loader->base.n_contours += num_contours; + + loader->zone.n_points = 0; + loader->zone.n_contours = 0; + + loader->left_points -= num_points; + loader->left_contours -= num_contours; + } + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /************************************************************************/ + else /* otherwise, load a composite !! */ + { + /* for each subglyph, read composite header */ + FT_SubGlyph* subglyph = subglyphs; + + if (ACCESS_Frame(count)) goto Fail; + + num_subglyphs = 0; + do + { + TT_Fixed xx, xy, yy, yx; - /************************************************************/ - /* */ - /* Load_Simple state */ - /* */ - /* reading a simple glyph (num_contours must be set to */ - /* the glyph's number of contours.) */ - /* */ - /* exit state: Load_End */ - /* */ - case Load_Simple: - new_flags = load_flags; + subglyph->arg1 = subglyph->arg2 = 0; + + subglyph->flags = GET_UShort(); + subglyph->index = GET_UShort(); - /* disable hinting when scaling */ - if ( !subglyph->is_hinted ) - new_flags |= FT_LOAD_NO_HINTING; - - error = Load_Simple_Glyph( exec, - stream, - count, - num_contours, - left_contours, - left_points, - new_flags, - subglyph, - (TT_Bool)(size && size->debug && - load_top == 0) ); - if ( error ) - goto Fail; - - /* Note: We could have put the simple loader source there */ - /* but the code is fat enough already :-) */ - - num_points = exec->pts.n_points - 2; - - phase = Load_End; - break; - - /************************************************************/ - /* */ - /* Load_Composite state */ - /* */ - /* reading a composite glyph header and pushing a new */ - /* load element on the stack. */ - /* */ - /* exit state: Load_Glyph */ - /* */ - case Load_Composite: - - /* create a new element on the stack */ - load_top++; - - if ( load_top > face->max_components ) + /* read arguments */ + if (subglyph->flags & ARGS_ARE_WORDS) { - error = TT_Err_Invalid_Composite; - goto Fail; - } - - subglyph2 = exec->loadStack + load_top; - - Init_Glyph_Component( subglyph2, subglyph, NULL ); - subglyph2->is_hinted = subglyph->is_hinted; - - /* now read composite header */ - - if ( ACCESS_Frame( 4L ) ) - goto Fail_File; - - subglyph->element_flag = new_flags = GET_UShort(); - - subglyph2->index = GET_UShort(); - - FORGET_Frame(); - - k = 1+1; - - if ( new_flags & ARGS_ARE_WORDS ) - k *= 2; - - if ( new_flags & WE_HAVE_A_SCALE ) - k += 2; - - else if ( new_flags & WE_HAVE_AN_XY_SCALE ) - k += 4; - - else if ( new_flags & WE_HAVE_A_2X2 ) - k += 8; - - if ( ACCESS_Frame( k ) ) - goto Fail_File; - - if ( new_flags & ARGS_ARE_WORDS ) - { - k = GET_Short(); - l = GET_Short(); + subglyph->arg1 = GET_Short(); + subglyph->arg2 = GET_Short(); } else { - k = GET_Char(); - l = GET_Char(); + subglyph->arg1 = GET_Char(); + subglyph->arg2 = GET_Char(); } - - subglyph->arg1 = k; - subglyph->arg2 = l; - - if ( new_flags & ARGS_ARE_XY_VALUES ) - { - subglyph->transform.ox = k; - subglyph->transform.oy = l; - } - - xx = 0x10000; - xy = 0; - yx = 0; - yy = 0x10000; - - if ( new_flags & WE_HAVE_A_SCALE ) + + /* read transform */ + xx = yy = 0x10000; + xy = yx = 0; + + if (subglyph->flags & WE_HAVE_A_SCALE) { xx = (TT_Fixed)GET_Short() << 2; yy = xx; - subglyph2->is_scaled = TRUE; } - else if ( new_flags & WE_HAVE_AN_XY_SCALE ) + else if (subglyph->flags & WE_HAVE_AN_XY_SCALE) { xx = (TT_Fixed)GET_Short() << 2; yy = (TT_Fixed)GET_Short() << 2; - subglyph2->is_scaled = TRUE; } - else if ( new_flags & WE_HAVE_A_2X2 ) + else if (subglyph->flags & WE_HAVE_A_2X2) { xx = (TT_Fixed)GET_Short() << 2; xy = (TT_Fixed)GET_Short() << 2; yx = (TT_Fixed)GET_Short() << 2; yy = (TT_Fixed)GET_Short() << 2; - subglyph2->is_scaled = TRUE; } - - FORGET_Frame(); - + subglyph->transform.xx = xx; subglyph->transform.xy = xy; subglyph->transform.yx = yx; subglyph->transform.yy = yy; + + subglyph++; + num_subglyphs++; + if (num_subglyphs >= TT_MAX_SUBGLYPHS) + break; + } + while (subglyph[-1].flags & MORE_COMPONENTS); - k = FT_MulFix( xx, yy ) - FT_MulFix( xy, yx ); +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + { + /* we must undo the ACCESS_Frame in order to point to the */ + /* composite instructions, if we find some .. */ + /* we will process them later.. */ + ins_offset = FILE_Pos() + stream->cursor - stream->limit; + FORGET_Frame(); + } +#endif - /* disable hinting in case of scaling/slanting */ - if ( ABS( k ) != 0x10000 ) - subglyph2->is_hinted = FALSE; + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ - subglyph->file_offset = FILE_Pos(); - - phase = Load_Glyph; - break; - - /************************************************************/ - /* */ - /* Load_End state */ - /* */ - /* after loading a glyph, apply transformation and offset */ - /* where necessary, pop element and continue or stop */ - /* process. */ - /* */ - /* exit states: Load_Composite and Load_Exit */ - /* */ - case Load_End: - if ( load_top > 0 ) + /*********************************************************************/ + /* Now, read each subglyph independently.. */ + { + TT_Int n, num_base_points, num_new_points; + + subglyph = subglyphs; + for ( n = 0; n < num_subglyphs; n++, subglyph++ ) { - subglyph2 = subglyph; + TT_Vector pp1, pp2; + TT_Pos x, y; + + pp1 = loader->pp1; + pp2 = loader->pp2; - load_top--; - subglyph = exec->loadStack + load_top; - - /* check advance width and left side bearing */ - - if ( !subglyph->preserve_pps && - subglyph->element_flag & USE_MY_METRICS ) + num_base_points = loader->base.n_points; + + error = load_truetype_glyph( loader, subglyph->index ); + if ((subglyph->flags & USE_MY_METRICS) == 0) { - subglyph->left_bearing = subglyph2->left_bearing; - subglyph->advance = subglyph2->advance; - - subglyph->pp1 = subglyph2->pp1; - subglyph->pp2 = subglyph2->pp2; - - subglyph->preserve_pps = TRUE; + loader->pp1 = pp1; + loader->pp2 = pp2; } - - /* apply scale */ - - if ( subglyph2->is_scaled ) + + num_points = loader->base.n_points; + num_contours = loader->base.n_contours; + + num_new_points = num_points - num_base_points; + + /********************************************************/ + /* now perform the transform required for this subglyph */ + + if ( subglyph->flags & ( WE_HAVE_A_SCALE | + WE_HAVE_AN_XY_SCALE | + WE_HAVE_A_2X2 ) ) { - TT_Vector* cur = subglyph2->zone.cur; - TT_Vector* org = subglyph2->zone.org; + TT_Vector* cur = loader->zone.cur; + TT_Vector* org = loader->zone.org; + TT_Vector* limit = cur + num_new_points; - - for ( u = 0; u < num_points; u++ ) + for ( ; cur < limit; cur++, org++ ) { + TT_Pos nx, ny; + nx = FT_MulFix( cur->x, subglyph->transform.xx ) + FT_MulFix( cur->y, subglyph->transform.yx ); @@ -1212,55 +758,39 @@ org->x = nx; org->y = ny; - - cur++; - org++; } } - /* adjust counts */ - - num_elem_points = subglyph->zone.n_points; - - for ( k = 0; k < num_contours; k++ ) - subglyph2->zone.contours[k] += num_elem_points; - - subglyph->zone.n_points += num_points; - subglyph->zone.n_contours += num_contours; - - left_points -= num_points; - left_contours -= num_contours; - /* apply offset */ - if ( !(subglyph->element_flag & ARGS_ARE_XY_VALUES) ) + if ( !(subglyph->flags & ARGS_ARE_XY_VALUES) ) { - k = subglyph->arg1; - l = subglyph->arg2; + TT_Int k = subglyph->arg1; + TT_UInt l = subglyph->arg2; - if ( k >= num_elem_points || - l >= num_points ) + if ( k >= num_base_points || + l >= (TT_UInt)num_new_points ) { error = TT_Err_Invalid_Composite; goto Fail; } - l += num_elem_points; + l += num_base_points; - x = subglyph->zone.cur[k].x - subglyph->zone.cur[l].x; - y = subglyph->zone.cur[k].y - subglyph->zone.cur[l].y; + x = loader->base.cur[k].x - loader->base.cur[l].x; + y = loader->base.cur[k].y - loader->base.cur[l].y; } else { - x = subglyph->transform.ox; - y = subglyph->transform.oy; + x = subglyph->arg1; + y = subglyph->arg2; - if (!(load_flags & FT_LOAD_NO_SCALE)) + if (!(loader->load_flags & FT_LOAD_NO_SCALE)) { - x = SCALE_X( x ); - y = SCALE_Y( y ); + x = FT_MulFix( x, x_scale ); + y = FT_MulFix( y, y_scale ); - if ( subglyph->element_flag & ROUND_XY_TO_GRID ) + if ( subglyph->flags & ROUND_XY_TO_GRID ) { x = (x + 32) & -64; y = (y + 32) & -64; @@ -1268,58 +798,157 @@ } } - translate_array( num_points, subglyph2->zone.cur, x, y ); - - cur_to_org( num_points, &subglyph2->zone ); - - num_points = subglyph->zone.n_points; - num_contours = subglyph->zone.n_contours; - - /* check for last component */ - - if ( FILE_Seek( subglyph->file_offset ) ) - goto Fail_File; - - if ( subglyph->element_flag & MORE_COMPONENTS ) - phase = Load_Composite; - else - { - error = Load_Composite_End( num_points, - num_contours, - exec, - subglyph, - stream, - load_flags, - (TT_Bool)(size && size->debug && - load_top == 0) ); - if ( error ) - goto Fail; - - phase = Load_End; - } + translate_array( num_new_points, loader->zone.cur, x, y ); + cur_to_org( num_new_points, &loader->zone ); } - else - phase = Load_Exit; + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ - break; + /* we have finished loading all sub-glyphs, now, look for */ + /* instructions for this composite !! */ - case Load_Exit: - break; +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + subglyph--; + if (num_subglyphs > 0 && subglyph->flags & WE_HAVE_INSTR) + { + TT_UShort n_ins; + TT_ExecContext exec = loader->exec; + TT_UInt n_points = loader->base.n_points; + TT_GlyphZone* pts; + TT_Vector* pp1; + + /* read size of instructions */ + if ( FILE_Seek( ins_offset ) || + READ_UShort(n_ins) ) goto Fail; + FT_TRACE4(( "Instructions size = %d\n", n_ins )); + + /* check it */ + if ( n_ins > face->max_profile.maxSizeOfInstructions ) + { + FT_TRACE0(( "Too many instructions in composite glyph %ld\n", + subglyph->index )); + return TT_Err_Too_Many_Ins; + } + + /* read the instructions */ + if ( FILE_Read( exec->glyphIns, n_ins ) ) + goto Fail; + + error = TT_Set_CodeRange( exec, + tt_coderange_glyph, + exec->glyphIns, + n_ins ); + if ( error ) goto Fail; + + /* prepare the execution context */ + exec->pts = loader->base; + pts = &exec->pts; + + pts->n_points = num_points + 2; + pts->n_contours = num_contours; + + /* add phantom points */ + pp1 = pts->cur + num_points; + pp1[0] = loader->pp1; + pp1[1] = loader->pp2; + + pts->touch[num_points - 1] = 0; + pts->touch[num_points - 2] = 0; + + /* if hinting, round the phantom points */ + if ( IS_HINTED(loader->load_flags) ) + { + pp1[0].x = ((loader->pp1.x + 32) & -64); + pp1[1].x = ((loader->pp2.x + 32) & -64); + } + + { + TT_UInt k; + for ( k = 0; k < n_points; k++ ) + pts->touch[k] &= FT_Curve_Tag_On; + } + + cur_to_org( n_points, pts ); + + /* now consider hinting */ + if ( IS_HINTED(loader->load_flags) && n_ins > 0 ) + { + exec->is_composite = TRUE; + exec->pedantic_hinting = + (TT_Bool)(loader->load_flags & FT_LOAD_PEDANTIC); + + error = TT_Run_Context( exec, loader->size->debug ); + if ( error && exec->pedantic_hinting ) + goto Fail; + } + + /* save glyph origin and advance points */ + loader->pp1 = pp1[0]; + loader->pp2 = pp1[1]; + } +#endif + } } - /* finally, copy the points arrays to the glyph object */ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ - exec->pts = base_pts; + Load_End: + error = TT_Err_Ok; - for ( u = 0; u < num_points + 2; u++ ) + Fail: + return error; + } + + + + + + static + void compute_glyph_metrics( TT_Loader* loader, + TT_UInt glyph_index ) + { + TT_UInt num_points = loader->base.n_points; + TT_UInt num_contours = loader->base.n_contours; + TT_BBox bbox; + TT_Face face = loader->face; + TT_Fixed x_scale, y_scale; + TT_GlyphSlot glyph = loader->glyph; + TT_Size size = loader->size; + + /* when a simple glyph was loaded, the value of */ + /* "base.n_points" and "base.n_contours" is 0, we must */ + /* take those in the "zone" instead.. */ + if ( num_points == 0 && num_contours == 0 ) { - glyph->outline.points[u] = exec->pts.cur[u]; - glyph->outline.flags [u] = exec->pts.touch[u]; + num_points = loader->zone.n_points; + num_contours = loader->zone.n_contours; } + + x_scale = 0x10000; + y_scale = 0x10000; + if ( (loader->load_flags & FT_LOAD_NO_SCALE) == 0) + { + x_scale = size->root.metrics.x_scale; + y_scale = size->root.metrics.y_scale; + } + + { + TT_UInt u; + for ( u = 0; u < num_points + 2; u++ ) + { + glyph->outline.points[u] = loader->base.cur[u]; + glyph->outline.flags [u] = loader->base.touch[u]; + } - for ( k = 0; k < num_contours; k++ ) - glyph->outline.contours[k] = exec->pts.contours[k]; + for ( u = 0; u < num_contours; u++ ) + glyph->outline.contours[u] = loader->base.contours[u]; + } glyph->outline.n_points = num_points; glyph->outline.n_contours = num_contours; @@ -1328,12 +957,12 @@ /* translate array so that (0,0) is the glyph's origin */ translate_array( (TT_UShort)(num_points + 2), glyph->outline.points, - -subglyph->pp1.x, + -loader->pp1.x, 0 ); FT_Get_Outline_CBox( &glyph->outline, &bbox ); - if ( subglyph->is_hinted ) + if ( IS_HINTED(loader->load_flags) ) { /* grid-fit the bounding box */ bbox.xMin &= -64; @@ -1348,17 +977,16 @@ TT_Pos left_bearing; TT_Pos advance; - - left_bearing = subglyph->left_bearing; - advance = subglyph->advance; + left_bearing = loader->left_bearing; + advance = loader->advance; if ( face->postscript.isFixedPitch ) advance = face->horizontal.advance_Width_Max; - if ( !(load_flags & FT_LOAD_NO_SCALE) ) + if ( !(loader->load_flags & FT_LOAD_NO_SCALE) ) { - left_bearing = SCALE_X( left_bearing ); - advance = SCALE_X( advance ); + left_bearing = FT_MulFix( left_bearing, x_scale ); + advance = FT_MulFix( advance, x_scale ); } glyph->metrics2.horiBearingX = left_bearing; @@ -1367,7 +995,7 @@ glyph->metrics.horiBearingX = bbox.xMin; glyph->metrics.horiBearingY = bbox.yMax; - glyph->metrics.horiAdvance = subglyph->pp2.x - subglyph->pp1.x; + glyph->metrics.horiAdvance = loader->pp2.x - loader->pp1.x; /* Now take care of vertical metrics. In the case where there is */ /* no vertical information within the font (relatively common), make */ @@ -1430,16 +1058,17 @@ TT_Get_Outline_BBox() */ /* scale the metrics */ - if ( !(load_flags & FT_LOAD_NO_SCALE) ) + if ( !(loader->load_flags & FT_LOAD_NO_SCALE) ) { - Top = SCALE_Y( top_bearing ); - top = SCALE_Y( top_bearing + subglyph->bbox.yMax ) - bbox.yMax; - advance = SCALE_Y( advance_height ); + Top = FT_MulFix( top_bearing, y_scale ); + top = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale ) + - bbox.yMax; + advance = FT_MulFix( advance_height, y_scale ); } else { Top = top_bearing; - top = top_bearing + subglyph->bbox.yMax - bbox.yMax; + top = top_bearing + loader->bbox.yMax - bbox.yMax; advance = advance_height; } @@ -1452,7 +1081,7 @@ left = ( bbox.xMin - bbox.xMax ) / 2; /* grid-fit them if necessary */ - if ( subglyph->is_hinted ) + if ( IS_HINTED(loader->load_flags) ) { left &= -64; top = (top + 63) & -64; @@ -1465,36 +1094,198 @@ } /* Adjust advance width to the value contained in the hdmx table. */ - if ( !exec->face->postscript.isFixedPitch && size && - subglyph->is_hinted ) + if ( !face->postscript.isFixedPitch && size && + IS_HINTED(loader->load_flags) ) { - widths = Get_Advance_Widths( exec->face, - exec->size->root.metrics.x_ppem ); + TT_Byte* widths = Get_Advance_Widths( face, + size->root.metrics.x_ppem ); if ( widths ) glyph->metrics.horiAdvance = widths[glyph_index] << 6; } - glyph->outline.dropout_mode = (TT_Char)exec->GS.scan_type; +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + glyph->outline.dropout_mode = (TT_Char)loader->exec->GS.scan_type; +#else + glyph->outline.dropout_mode = 2; +#endif /* set glyph dimensions */ glyph->metrics.width = bbox.xMax - bbox.xMin; glyph->metrics.height = bbox.yMax - bbox.yMin; glyph->format = ft_glyph_format_outline; + } - error = TT_Err_Ok; - Fail_File: - Fail: - /* reset the execution context */ - exec->pts = base_pts; + + + + + + + + + LOCAL_FUNC + TT_Error TT_Load_Glyph( TT_Size size, + TT_GlyphSlot glyph, + TT_UShort glyph_index, + TT_UInt load_flags ) + { + SFNT_Interface* sfnt; + TT_Face face; + FT_Stream stream; + FT_Memory memory; + TT_Error error; + TT_Loader loader; + + face = (TT_Face)glyph->face; + sfnt = (SFNT_Interface*)face->sfnt; + stream = face->root.stream; + memory = face->root.memory; + error = 0; + + if ( !size || (load_flags & FT_LOAD_NO_SCALE) ) + { + size = NULL; + load_flags |= FT_LOAD_NO_SCALE | + FT_LOAD_NO_HINTING | + FT_LOAD_NO_BITMAP; + } + +#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS + /*********************************************************************/ + /* Try to load embedded bitmap if any */ + if ( size && (load_flags & FT_LOAD_NO_BITMAP) == 0 && sfnt->load_sbits ) + { + TT_SBit_Metrics metrics; + + error = sfnt->load_sbit_image( face, + size->root.metrics.x_ppem, + size->root.metrics.y_ppem, + glyph_index, + stream, + &glyph->bitmap, + &metrics ); + if ( !error ) + { + glyph->outline.n_points = 0; + glyph->outline.n_contours = 0; + + glyph->metrics.width = (TT_Pos)metrics.width << 6; + glyph->metrics.height = (TT_Pos)metrics.height << 6; + + glyph->metrics.horiBearingX = (TT_Pos)metrics.horiBearingX << 6; + glyph->metrics.horiBearingY = (TT_Pos)metrics.horiBearingY << 6; + glyph->metrics.horiAdvance = (TT_Pos)metrics.horiAdvance << 6; + + glyph->metrics.vertBearingX = (TT_Pos)metrics.vertBearingX << 6; + glyph->metrics.vertBearingY = (TT_Pos)metrics.vertBearingY << 6; + glyph->metrics.vertAdvance = (TT_Pos)metrics.vertAdvance << 6; + + glyph->format = ft_glyph_format_bitmap; + return error; + } + } +#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */ + + if ( load_flags & FT_LOAD_NO_OUTLINE ) + return ( error ? error : TT_Err_Unavailable_Bitmap ); + + /* seek to the beginning of the glyph table. For Type 43 fonts */ + /* the table might be accessed from a Postscript stream or something */ + /* else... */ + error = face->goto_table( face, TTAG_glyf, stream, 0 ); + if (error) + { + FT_ERROR(( "TT.GLoad: could not access glyph table\n" )); + return error; + } + + MEM_Set( &loader, 0, sizeof(loader) ); + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + if ( size ) + { + /* query new execution context */ + loader.exec = size->debug ? size->context : TT_New_Context(face); + if ( !loader.exec ) + return TT_Err_Could_Not_Find_Context; + + TT_Load_Context( loader.exec, face, size ); + + /* load default graphics state - if needed */ + if ( size->GS.instruct_control & 2 ) + loader.exec->GS = tt_default_graphics_state; + } +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + + if (size) + glyph->outline.high_precision = ( size->root.metrics.y_ppem < 24 ); + + /************************************************************************/ + /* let's initialise our loader now */ + error = TT_New_GlyphZone( memory, &loader.base, + face->root.max_points, face->root.max_contours ); + if (error) return error; + + loader.left_points = face->root.max_points; + loader.left_contours = face->root.max_contours; + loader.load_flags = load_flags; + + loader.face = face; + loader.size = size; + loader.glyph = glyph; + loader.stream = stream; + + loader.glyf_offset = FILE_Pos(); + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + /* when the cvt program has disabled hinting, the argument */ + /* is ignored. */ + if ( size && (size->GS.instruct_control & 1) ) + loader.load_flags |= FT_LOAD_NO_HINTING; +#endif + + /* Main loading loop */ + error = load_truetype_glyph( &loader, glyph_index ); + if (!error) + compute_glyph_metrics( &loader, glyph_index ); + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER if ( !size || !size->debug ) - TT_Done_Context( exec ); + TT_Done_Context( loader.exec ); +#endif + TT_Done_GlyphZone( memory, &loader.base ); return error; } + + + + + + + + + + + + + + + + + + + + + + + + + /* END */ diff --git a/src/truetype/ttgload.h b/src/truetype/ttgload.h index d544cee85..3dcdabff6 100644 --- a/src/truetype/ttgload.h +++ b/src/truetype/ttgload.h @@ -21,10 +21,47 @@ #include +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include +#endif + #ifdef __cplusplus extern "C" { #endif + typedef struct TT_Loader_ + { + TT_Face face; + TT_Size size; + TT_GlyphSlot glyph; + + TT_ULong load_flags; + + FT_Stream stream; + TT_Int byte_len; + TT_Int left_points; + TT_Int left_contours; + + TT_BBox bbox; + TT_Int left_bearing; + TT_Int advance; + TT_Bool preserve_pps; + TT_Vector pp1; + TT_Vector pp2; + + TT_ULong glyf_offset; + + /* the zone where we load our glyphs */ + TT_GlyphZone base; + TT_GlyphZone zone; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + TT_ExecContext exec; + TT_Byte* instructions; +#endif + + } TT_Loader; + /*************************************************************************/ /* */ @@ -53,7 +90,7 @@ /* */ LOCAL_DEF void TT_Get_Metrics( TT_HoriHeader* header, - TT_UShort index, + TT_UInt index, TT_Short* bearing, TT_UShort* advance ); diff --git a/src/truetype/ttobjs.c b/src/truetype/ttobjs.c index 262f3e1b2..aa7b03b35 100644 --- a/src/truetype/ttobjs.c +++ b/src/truetype/ttobjs.c @@ -21,13 +21,18 @@ #include #include #include +#include #include +#include #include -#include #include +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#include +#endif + /* required by tracing mode */ #undef FT_COMPONENT #define FT_COMPONENT trace_ttobjs @@ -442,14 +447,16 @@ LOCAL_DEF TT_Error TT_Init_Size( TT_Size size ) { + TT_Error error = 0; + +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER TT_Face face = (TT_Face)size->root.face; FT_Memory memory = face->root.memory; - TT_Error error; TT_Int i; - TT_UShort n_twilight; - TT_MaxProfile* maxp = &face->max_profile; TT_ExecContext exec; + TT_UShort n_twilight; + TT_MaxProfile* maxp = &face->max_profile; size->ttmetrics.valid = FALSE; @@ -587,14 +594,19 @@ if ( !size->debug ) TT_Done_Context( exec ); +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + size->ttmetrics.valid = FALSE; return error; +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER Fail_Exec: if ( !size->debug ) TT_Done_Context( exec ); Fail_Memory: +#endif + TT_Done_Size( size ); return error; } @@ -614,9 +626,9 @@ LOCAL_FUNC void TT_Done_Size( TT_Size size ) { +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER FT_Memory memory = size->root.face->memory; - if ( size->debug ) { /* the debug context must be deleted by the debugger itself */ @@ -643,6 +655,7 @@ size->max_func = 0; size->max_ins = 0; +#endif size->ttmetrics.valid = FALSE; } @@ -663,10 +676,8 @@ LOCAL_DEF TT_Error TT_Reset_Size( TT_Size size ) { - TT_ExecContext exec; - TT_Error error; - TT_UShort i, j; - TT_Face face; + TT_Face face; + TT_Error error = TT_Err_Ok; FT_Size_Metrics* metrics; @@ -713,72 +724,79 @@ metrics->max_advance = ( FT_MulFix( face->root.max_advance_width, metrics->x_scale ) + 32 ) & -64; - /* Scale the cvt values to the new ppem. */ - /* We use by default the y ppem to scale the CVT. */ - - for ( i = 0; i < size->cvt_size; i++ ) - size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); - - /* All twilight points are originally zero */ - for ( j = 0; j < size->twilight.n_points; j++ ) +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER { - size->twilight.org[j].x = 0; - size->twilight.org[j].y = 0; - size->twilight.cur[j].x = 0; - size->twilight.cur[j].y = 0; - } - - /* clear storage area */ - for ( i = 0; i < size->storage_size; i++ ) - size->storage[i] = 0; - - size->GS = tt_default_graphics_state; - - /* get execution context and run prep program */ - if ( size->debug ) - exec = size->context; - else - exec = TT_New_Context( face ); - /* debugging instances have their own context */ - - if ( !exec ) - return TT_Err_Could_Not_Find_Context; - - TT_Load_Context( exec, face, size ); - - TT_Set_CodeRange( exec, - tt_coderange_cvt, - face->cvt_program, - face->cvt_program_size ); - - TT_Clear_CodeRange( exec, tt_coderange_glyph ); - - exec->instruction_trap = FALSE; - - exec->top = 0; - exec->callTop = 0; - - if ( face->cvt_program_size > 0 ) - { - error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); - if ( error ) - goto Fin; - + TT_ExecContext exec; + TT_UInt i, j; + + /* Scale the cvt values to the new ppem. */ + /* We use by default the y ppem to scale the CVT. */ + + for ( i = 0; i < size->cvt_size; i++ ) + size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale ); + + /* All twilight points are originally zero */ + for ( j = 0; j < size->twilight.n_points; j++ ) + { + size->twilight.org[j].x = 0; + size->twilight.org[j].y = 0; + size->twilight.cur[j].x = 0; + size->twilight.cur[j].y = 0; + } + + /* clear storage area */ + for ( i = 0; i < size->storage_size; i++ ) + size->storage[i] = 0; + + size->GS = tt_default_graphics_state; + + /* get execution context and run prep program */ + if ( size->debug ) + exec = size->context; + else + exec = TT_New_Context( face ); + /* debugging instances have their own context */ + + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + + TT_Load_Context( exec, face, size ); + + TT_Set_CodeRange( exec, + tt_coderange_cvt, + face->cvt_program, + face->cvt_program_size ); + + TT_Clear_CodeRange( exec, tt_coderange_glyph ); + + exec->instruction_trap = FALSE; + + exec->top = 0; + exec->callTop = 0; + + if ( face->cvt_program_size > 0 ) + { + error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 ); + if ( error ) + goto Fin; + + if ( !size->debug ) + error = face->interpreter( exec ); + } + else + error = TT_Err_Ok; + + size->GS = exec->GS; + /* save default graphics state */ + + Fin: + TT_Save_Context( exec, size ); + if ( !size->debug ) - error = face->interpreter( exec ); + TT_Done_Context( exec ); + /* debugging instances keep their context */ } - else - error = TT_Err_Ok; - - size->GS = exec->GS; - /* save default graphics state */ - - Fin: - TT_Save_Context( exec, size ); - - if ( !size->debug ) - TT_Done_Context( exec ); - /* debugging instances keep their context */ +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ if ( !error ) size->ttmetrics.valid = TRUE; @@ -888,12 +906,14 @@ TT_Done_Extensions( driver ); #endif +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER /* destroy the execution context */ if ( driver->context ) { TT_Destroy_Context( driver->context, driver->root.memory ); driver->context = NULL; } +#endif } diff --git a/src/truetype/ttobjs.h b/src/truetype/ttobjs.h index e4befb576..257a3b646 100644 --- a/src/truetype/ttobjs.h +++ b/src/truetype/ttobjs.h @@ -330,6 +330,7 @@ TT_Size_Metrics ttmetrics; +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER TT_UInt num_function_defs; /* number of function definitions */ TT_UInt max_function_defs; TT_DefArray function_defs; /* table of function definitions */ @@ -362,6 +363,8 @@ TT_Bool debug; TT_ExecContext context; +#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */ + } TT_SizeRec;