diff options
Diffstat (limited to 'Build/source/libs/libttf/ttgload.c')
-rw-r--r-- | Build/source/libs/libttf/ttgload.c | 1351 |
1 files changed, 1351 insertions, 0 deletions
diff --git a/Build/source/libs/libttf/ttgload.c b/Build/source/libs/libttf/ttgload.c new file mode 100644 index 00000000000..a7ca3179aeb --- /dev/null +++ b/Build/source/libs/libttf/ttgload.c @@ -0,0 +1,1351 @@ +/******************************************************************* + * + * ttgload.c 1.0 + * + * TrueType Glyph Loader. + * + * 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. + * + ******************************************************************/ + +#include "tttypes.h" +#include "ttdebug.h" +#include "ttcalc.h" +#include "ttfile.h" + +#include "tttables.h" +#include "ttobjs.h" +#include "ttgload.h" + +#include "ttmemory.h" +#include "tttags.h" +#include "ttload.h" + +/* required by the tracing mode */ +#undef TT_COMPONENT +#define TT_COMPONENT trace_gload + + +/* composite font flags */ + +#define ARGS_ARE_WORDS 0x001 +#define ARGS_ARE_XY_VALUES 0x002 +#define ROUND_XY_TO_GRID 0x004 +#define WE_HAVE_A_SCALE 0x008 +/* reserved 0x010 */ +#define MORE_COMPONENTS 0x020 +#define WE_HAVE_AN_XY_SCALE 0x040 +#define WE_HAVE_A_2X2 0x080 +#define WE_HAVE_INSTR 0x100 +#define USE_MY_METRICS 0x200 + + +/********************************************************/ +/* Return 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). */ +/* */ +/* This function will much probably move to another */ +/* component in the short future, but I haven't decided */ +/* which yet... */ + + LOCAL_FUNC + void TT_Get_Metrics( TT_Horizontal_Header* header, + UShort index, + Short* bearing, + UShort* advance ) + { + PLongMetrics longs_m; + + UShort k = header->number_Of_HMetrics; + + + if ( index < k ) + { + longs_m = (PLongMetrics)header->long_metrics + index; + *bearing = longs_m->bearing; + *advance = longs_m->advance; + } + else + { + *bearing = ((PShortMetrics)header->short_metrics)[index - k]; + *advance = ((PLongMetrics)header->long_metrics)[k - 1].advance; + } + } + + +/********************************************************/ +/* Return horizontal metrics in font units for a given */ +/* glyph. If `check' is true, take care of mono-spaced */ +/* fonts by returning the advance width max. */ + + static void Get_HMetrics( PFace face, + UShort index, + Bool check, + Short* lsb, + UShort* aw ) + { + TT_Get_Metrics( &face->horizontalHeader, index, lsb, aw ); + + if ( check && face->postscript.isFixedPitch ) + *aw = face->horizontalHeader.advance_Width_Max; + } + + +/********************************************************/ +/* Return advance width table for a given pixel size */ +/* if it is found in the font's `hdmx' table (if any). */ + + static PByte Get_Advance_Widths( PFace face, + UShort ppem ) + { + UShort n; + + + for ( n = 0; n < face->hdmx.num_records; n++ ) + if ( face->hdmx.records[n].ppem == ppem ) + return face->hdmx.records[n].widths; + + return NULL; + } + + +/********************************************************/ +/* Copy current glyph into original one. */ + +#define cur_to_org( n, zone ) \ + MEM_Copy( (zone)->org, (zone)->cur, (n) * sizeof ( TT_Vector ) ) + +/********************************************************/ +/* copy original glyph into current one */ + +#define org_to_cur( n, zone ) \ + MEM_Copy( (zone)->cur, (zone)->org, (n) * sizeof ( TT_Vector ) ) + +/********************************************************/ +/* translate an array of coordinates */ + + static void translate_array( UShort n, + TT_Vector* coords, + TT_Pos delta_x, + TT_Pos delta_y ) + { + UShort k; + + + if ( delta_x ) + for ( k = 0; k < n; k++ ) + coords[k].x += delta_x; + + if ( delta_y ) + for ( k = 0; k < n; k++ ) + coords[k].y += delta_y; + } + + +/********************************************************/ +/* mount one zone on top of another */ + + static void mount_zone( PGlyph_Zone source, + PGlyph_Zone target ) + { + UShort np; + Short nc; + + np = source->n_points; + nc = source->n_contours; + + target->org = source->org + np; + target->cur = source->cur + np; + target->touch = source->touch + np; + + target->contours = source->contours + nc; + + target->n_points = 0; + target->n_contours = 0; + } + + +/******************************************************************* + * + * Function: Load_Simple_Glyph + * + ******************************************************************/ + + static TT_Error Load_Simple_Glyph( PExecution_Context exec, + TT_Stream input, + Short n_contours, + Short left_contours, + UShort left_points, + UShort load_flags, + PSubglyph_Record subg ) + { + DEFINE_LOAD_LOCALS( input ); + + PGlyph_Zone pts; + Short k; + UShort j; + UShort n_points, n_ins; + PFace face; + Byte* flag; + TT_Vector* vec; + TT_F26Dot6 x, y; + + + face = exec->face; + + /* simple check */ + if ( n_contours > left_contours ) + { + PTRACE0(( "ERROR: Glyph index %ld has %d contours > left %d\n", + subg->index, n_contours, left_contours )); + return TT_Err_Too_Many_Contours; + } + + + /* preparing the execution context */ + mount_zone( &subg->zone, &exec->pts ); + + /* reading the contours endpoints */ + if ( ACCESS_Frame( (n_contours + 1) * 2L ) ) + return error; + + PTRACE4(( " Contour endpoints:" )); + + for ( k = 0; k < n_contours; k++ ) + { + exec->pts.contours[k] = GET_UShort(); + PTRACE4(( " %d", exec->pts.contours[k] )); + } + PTRACE4(( "\n" )); + + if ( n_contours > 0 ) + n_points = exec->pts.contours[n_contours - 1] + 1; + else + n_points = 0; + + n_ins = GET_UShort(); + + FORGET_Frame(); + + if ( n_points > left_points ) + { + PTRACE0(( "ERROR: Too many points in glyph %ld\n", subg->index )); + return TT_Err_Too_Many_Points; + } + + /* loading instructions */ + + PTRACE4(( " Instructions size: %d\n", n_ins )); + + if ( n_ins > face->maxProfile.maxSizeOfInstructions ) + { + PTRACE0(( "ERROR: Too many instructions!\n" )); + return TT_Err_Too_Many_Ins; + } + + if ( FILE_Read( exec->glyphIns, n_ins ) ) + return error; + + if ( (error = Set_CodeRange( exec, + TT_CodeRange_Glyph, + exec->glyphIns, + n_ins )) != TT_Err_Ok ) + return error; + + + /* read the flags */ + + if ( CHECK_ACCESS_Frame( n_points * 5L ) ) + return error; + + j = 0; + flag = exec->pts.touch; + + while ( j < n_points ) + { + Byte c, cnt; + + flag[j] = c = GET_Byte(); + j++; + + if ( c & 8 ) + { + cnt = GET_Byte(); + while( cnt > 0 ) + { + flag[j++] = c; + cnt--; + } + } + } + + /* read the X */ + + x = 0; + vec = exec->pts.org; + + for ( j = 0; j < n_points; j++ ) + { + if ( flag[j] & 2 ) + { + if ( flag[j] & 16 ) + x += GET_Byte(); + else + x -= GET_Byte(); + } + else + { + if ( (flag[j] & 16) == 0 ) + x += GET_Short(); + } + + vec[j].x = x; + } + + + /* read the Y */ + + y = 0; + + for ( j = 0; j < n_points; j++ ) + { + if ( flag[j] & 4 ) + { + if ( flag[j] & 32 ) + y += GET_Byte(); + else + y -= GET_Byte(); + } + else + { + if ( (flag[j] & 32) == 0 ) + y += GET_Short(); + } + + vec[j].y = y; + } + + FORGET_Frame(); + + /* Now add the two shadow points at n and n + 1. */ + /* We need the left side bearing and advance width. */ + + /* pp1 = xMin - lsb */ + vec[n_points].x = subg->metrics.bbox.xMin - subg->metrics.horiBearingX; + vec[n_points].y = 0; + + /* pp2 = pp1 + aw */ + vec[n_points+1].x = vec[n_points].x + subg->metrics.horiAdvance; + vec[n_points+1].y = 0; + + /* clear the touch flags */ + + for ( j = 0; j < n_points; j++ ) + exec->pts.touch[j] &= TT_Flag_On_Curve; + + exec->pts.touch[n_points ] = 0; + exec->pts.touch[n_points + 1] = 0; + + /* Note that we return two more points that are not */ + /* part of the glyph outline. */ + + 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 & TTLOAD_SCALE_GLYPH) == 0 ) + { + /* no scaling, just copy the orig arrays into the cur ones */ + org_to_cur( n_points, pts ); + } + else + { + /* first scale the glyph points */ + + for ( j = 0; j < n_points; j++ ) + { + pts->org[j].x = Scale_X( &exec->metrics, pts->org[j].x ); + pts->org[j].y = Scale_Y( &exec->metrics, pts->org[j].y ); + } + + /* if hinting, round pp1, and shift the glyph accordingly */ + if ( subg->is_hinted ) + { + x = pts->org[n_points - 2].x; + x = ((x+32) & -64) - x; + translate_array( n_points, pts->org, x, 0 ); + + org_to_cur( n_points, pts ); + + pts->cur[n_points - 1].x = (pts->cur[n_points - 1].x + 32) & -64; + + /* now consider hinting */ + if ( n_ins > 0 ) + { + exec->is_composite = FALSE; + exec->pedantic_hinting = load_flags & TTLOAD_PEDANTIC; + + error = Context_Run( exec, FALSE ); + if (error && exec->pedantic_hinting) + return error; + } + } + else + org_to_cur( n_points, pts ); + } + + /* save glyph phantom points */ + if (!subg->preserve_pps) + { + subg->pp1 = pts->cur[n_points - 2]; + subg->pp2 = pts->cur[n_points - 1]; + } + + return TT_Err_Ok; + } + + +/******************************************************************* + * + * Function : Load_Composite_End + * + ******************************************************************/ + + static + TT_Error Load_Composite_End( UShort n_points, + Short n_contours, + PExecution_Context exec, + PSubglyph_Record subg, + UShort load_flags, + TT_Stream input ) + { + DEFINE_LOAD_LOCALS( input ); + + UShort k, n_ins; + PGlyph_Zone pts; + + + if ( subg->is_hinted && + subg->element_flag & WE_HAVE_INSTR ) + { + if ( ACCESS_Frame( 2L ) ) + return error; + + n_ins = GET_UShort(); /* read size of instructions */ + FORGET_Frame(); + + PTRACE4(( " Instructions size: %d\n", n_ins )); + + if ( n_ins > exec->face->maxProfile.maxSizeOfInstructions ) + { + PTRACE0(( "ERROR: 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 = 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] &= TT_Flag_On_Curve; + + 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 & TTLOAD_PEDANTIC; + + error = Context_Run( exec, FALSE ); + 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; + } + + +/******************************************************************* + * + * Function : Init_Glyph_Component + * + ******************************************************************/ + + static + void Init_Glyph_Component( PSubglyph_Record element, + PSubglyph_Record original, + PExecution_Context 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 = 1L << 16; + element->transform.xy = 0; + element->transform.yx = 0; + element->transform.yy = 1L << 16; + + element->transform.ox = 0; + element->transform.oy = 0; + + element->metrics.horiBearingX = 0; + element->metrics.horiAdvance = 0; + } + + + + LOCAL_FUNC + TT_Error Load_TrueType_Glyph( PInstance instance, + PGlyph glyph, + UShort glyph_index, + UShort load_flags ) + { + enum TPhases_ + { + Load_Exit, + Load_Glyph, + Load_Header, + Load_Simple, + Load_Composite, + Load_End + }; + + typedef enum TPhases_ TPhases; + + DEFINE_ALL_LOCALS; + + PFace face; + + UShort num_points; + Short num_contours; + UShort left_points; + Short left_contours; + UShort num_elem_points; + + Long table; + UShort load_top; + Long k, l; + UShort new_flags; + Long index; + UShort u, v; + + Long glyph_offset, offset; + + TT_F26Dot6 x, y, nx, ny; + + Fixed xx, xy, yx, yy; + + PExecution_Context exec; + + PSubglyph_Record subglyph, subglyph2; + + TGlyph_Zone base_pts; + + TPhases phase; + PByte widths; + +/* TT_Glyph_Loader_Callback cacheCb; */ +/* TT_Outline cached_outline; */ + + + /* first of all, check arguments */ + if ( !glyph ) + return TT_Err_Invalid_Glyph_Handle; + + face = glyph->face; + if ( !face ) + return TT_Err_Invalid_Glyph_Handle; + + if ( glyph_index >= face->numGlyphs ) + return TT_Err_Invalid_Glyph_Index; + + if ( instance && (load_flags & TTLOAD_SCALE_GLYPH) == 0 ) + { + instance = 0; + load_flags &= ~( TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH ); + } + + table = TT_LookUp_Table( face, TTAG_glyf ); + if ( table < 0 ) + { + PTRACE0(( "ERROR: There is no glyph table in this font file!\n" )); + return TT_Err_Glyf_Table_Missing; + } + + glyph_offset = face->dirTables[table].Offset; + + /* query new execution context */ + + if ( instance && instance->debug ) + exec = instance->context; + else + exec = New_Context( face ); + + if ( !exec ) + return TT_Err_Could_Not_Find_Context; + + Context_Load( exec, face, instance ); + + if ( instance ) + { + if ( instance->GS.instruct_control & 2 ) + exec->GS = Default_GraphicsState; + else + exec->GS = instance->GS; + /* load default graphics state */ + + glyph->outline.high_precision = ( instance->metrics.y_ppem < 24 ); + } + + /* save its critical pointers, as they'll be modified during load */ + base_pts = exec->pts; + + /* init variables */ + left_points = face->maxPoints; + left_contours = face->maxContours; + + 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 & TTLOAD_HINT_GLYPH; + + /* when the cvt program has disabled hinting, the argument */ + /* is ignored. */ + if ( instance && instance->GS.instruct_control & 1 ) + subglyph->is_hinted = FALSE; + + + /* now access stream */ + + if ( USE_Stream( face->stream, stream ) ) + goto Fin; + + /* Main loading loop */ + + phase = Load_Glyph; + index = 0; + + while ( phase != Load_Exit ) + { + subglyph = exec->loadStack + load_top; + + switch ( phase ) + { + /************************************************************/ + /* */ + /* Load_Glyph state */ + /* */ + /* reading a glyph's generic header to determine */ + /* whether it's simple or composite */ + /* */ + /* exit states: Load_Header and Load_End */ + + case Load_Glyph: + /* check glyph index and table */ + + index = subglyph->index; + if ( index < 0 || index >= face->numGlyphs ) + { + error = TT_Err_Invalid_Glyph_Index; + goto Fail; + } + + /* get horizontal metrics */ + + { + Short left_bearing; + UShort advance_width; + + + Get_HMetrics( face, (UShort)index, + !(load_flags & TTLOAD_IGNORE_GLOBAL_ADVANCE_WIDTH), + &left_bearing, + &advance_width ); + + subglyph->metrics.horiBearingX = left_bearing; + subglyph->metrics.horiAdvance = advance_width; + } + + phase = Load_Header; + + + /* The cache callback isn't part of the FreeType release yet */ + /* It is discarded for the moment.. */ + /* */ +#if 0 + if ( instance ) + { + /* is the glyph in an outline cache ? */ + cacheCb = instance->owner->engine->glCallback; + if ( cacheCb && 0 ) /* disabled */ + { + /* we have a callback */ + error = cacheCb( instance->generic, + index, &cached_outline, &x, &y ); + if ( !error ) + { + /* no error, then append the outline to the current subglyph */ + /* error = Append_Outline( subglyph, + &left_points, + &left_contours, + &cached_outline ); */ + phase = Load_End; + } + } + } +#endif + break; + + + /************************************************************/ + /* */ + /* Load_Header state */ + /* */ + /* reading a glyph's generic header to determine */ + /* wether it's simple or composite */ + /* */ + /* exit states: Load_Simple and Load_Composite */ + /* */ + + case Load_Header: /* load glyph */ + + if ( index + 1 < face->numLocations && + face->glyphLocations[index] == face->glyphLocations[index + 1] ) + { + /* as described by Frederic Loyer, these are spaces, and */ + /* not the unknown glyph. */ + + num_contours = 0; + num_points = 0; + + subglyph->metrics.bbox.xMin = 0; + subglyph->metrics.bbox.xMax = 0; + subglyph->metrics.bbox.yMin = 0; + subglyph->metrics.bbox.yMax = 0; + + subglyph->pp1.x = 0; + subglyph->pp2.x = subglyph->metrics.horiAdvance; + if (load_flags & TTLOAD_SCALE_GLYPH) + subglyph->pp2.x = Scale_X( &exec->metrics, subglyph->pp2.x ); + + exec->glyphSize = 0; + phase = Load_End; + break; + } + + offset = glyph_offset + face->glyphLocations[index]; + + /* read first glyph header */ + if ( FILE_Seek( offset ) || + ACCESS_Frame( 10L ) ) + goto Fail_File; + + num_contours = GET_Short(); + + subglyph->metrics.bbox.xMin = GET_Short(); + subglyph->metrics.bbox.yMin = GET_Short(); + subglyph->metrics.bbox.xMax = GET_Short(); + subglyph->metrics.bbox.yMax = GET_Short(); + + FORGET_Frame(); + + PTRACE6(( "Glyph %ld:\n", index )); + PTRACE6(( " # of contours: %d\n", num_contours )); + PTRACE6(( " xMin: %4d xMax: %4d\n", + subglyph->metrics.bbox.xMin, + subglyph->metrics.bbox.xMax )); + PTRACE6(( " yMin: %4d yMax: %4d\n", + subglyph->metrics.bbox.yMin, + subglyph->metrics.bbox.yMax )); + + if ( num_contours > left_contours ) + { + PTRACE0(( "ERROR: Too many contours for glyph %ld\n", index )); + error = TT_Err_Too_Many_Contours; + goto Fail; + } + + subglyph->pp1.x = subglyph->metrics.bbox.xMin - + subglyph->metrics.horiBearingX; + subglyph->pp1.y = 0; + subglyph->pp2.x = subglyph->pp1.x + subglyph->metrics.horiAdvance; + if (load_flags & TTLOAD_SCALE_GLYPH) + { + subglyph->pp1.x = Scale_X( &exec->metrics, subglyph->pp1.x ); + subglyph->pp2.x = Scale_X( &exec->metrics, subglyph->pp2.x ); + } + + /* is it a simple glyph ? */ + if ( num_contours > 0 ) + phase = Load_Simple; + else + phase = Load_Composite; + + break; + + + /************************************************************/ + /* */ + /* Load_Simple state */ + /* */ + /* reading a simple glyph (num_contours must be set to */ + /* the glyph's number of contours.) */ + /* */ + /* exit states : Load_End */ + /* */ + + case Load_Simple: + new_flags = load_flags; + + /* disable hinting when scaling */ + if ( !subglyph->is_hinted ) + new_flags &= ~TTLOAD_HINT_GLYPH; + + error = Load_Simple_Glyph( exec, + stream, + num_contours, + left_contours, + left_points, + new_flags, + subglyph ); + 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 a pushing a new */ + /* load element on the stack. */ + /* */ + /* exit states: Load_Glyph */ + /* */ + + case Load_Composite: + + /* create a new element on the stack */ + load_top++; + + if ( load_top > face->maxComponents ) + { + 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(); + } + else + { + k = GET_Char(); + l = GET_Char(); + } + + subglyph->arg1 = k; + subglyph->arg2 = l; + + if ( new_flags & ARGS_ARE_XY_VALUES ) + { + subglyph->transform.ox = k; + subglyph->transform.oy = l; + } + + xx = 1L << 16; + xy = 0; + yx = 0; + yy = 1L << 16; + + if ( new_flags & WE_HAVE_A_SCALE ) + { + xx = (Fixed)GET_Short() << 2; + yy = xx; + subglyph2->is_scaled = TRUE; + } + else if ( new_flags & WE_HAVE_AN_XY_SCALE ) + { + xx = (Fixed)GET_Short() << 2; + yy = (Fixed)GET_Short() << 2; + subglyph2->is_scaled = TRUE; + } + else if ( new_flags & WE_HAVE_A_2X2 ) + { + xx = (Fixed)GET_Short() << 2; + xy = (Fixed)GET_Short() << 2; + yx = (Fixed)GET_Short() << 2; + yy = (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; + + k = TT_MulFix( xx, yy ) - TT_MulFix( xy, yx ); + + /* disable hinting in case of scaling/slanting */ + if ( ABS( k ) != (1L << 16) ) + 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, pops element and continue or */ + /* stop process. */ + /* */ + /* exit states : Load_Composite and Load_Exit */ + /* */ + + case Load_End: + if ( load_top > 0 ) + { + subglyph2 = subglyph; + + load_top--; + subglyph = exec->loadStack + load_top; + + /* check advance width and left side bearing */ + + if ( !subglyph->preserve_pps && + subglyph->element_flag & USE_MY_METRICS ) + { + subglyph->metrics.horiBearingX = subglyph2->metrics.horiBearingX; + subglyph->metrics.horiAdvance = subglyph2->metrics.horiAdvance; + + subglyph->pp1 = subglyph2->pp1; + subglyph->pp2 = subglyph2->pp2; + + subglyph->preserve_pps = TRUE; + } + + /* apply scale */ + + if ( subglyph2->is_scaled ) + { + TT_Vector* cur = subglyph2->zone.cur; + TT_Vector* org = subglyph2->zone.org; + + for ( u = 0; u < num_points; u++ ) + { + nx = TT_MulFix( cur->x, subglyph->transform.xx ) + + TT_MulFix( cur->y, subglyph->transform.yx ); + + ny = TT_MulFix( cur->x, subglyph->transform.xy ) + + TT_MulFix( cur->y, subglyph->transform.yy ); + + cur->x = nx; + cur->y = ny; + + nx = TT_MulFix( org->x, subglyph->transform.xx ) + + TT_MulFix( org->y, subglyph->transform.yx ); + + ny = TT_MulFix( org->x, subglyph->transform.xy ) + + TT_MulFix( org->y, subglyph->transform.yy ); + + 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; + + if ( !(subglyph->element_flag & ARGS_ARE_XY_VALUES) ) + { + /* move second glyph according to control points */ + /* the attach points are relative to the specific component */ + + u = (UShort)subglyph->arg1; + v = (UShort)subglyph->arg2; + + if ( u >= num_elem_points || + v >= num_points ) + { + error = TT_Err_Invalid_Composite; + goto Fail; + } + + /* adjust count */ + v += num_elem_points; + + x = subglyph->zone.cur[u].x - subglyph->zone.cur[v].x; + y = subglyph->zone.cur[u].y - subglyph->zone.cur[v].y; + } + else + { + /* apply offset */ + + x = subglyph->transform.ox; + y = subglyph->transform.oy; + + if ( load_flags & TTLOAD_SCALE_GLYPH ) + { + x = Scale_X( &exec->metrics, x ); + y = Scale_Y( &exec->metrics, y ); + + if ( subglyph->element_flag & ROUND_XY_TO_GRID ) + { + x = (x+32) & -64; + y = (y+32) & -64; + } + } + } + + 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, + load_flags, + stream ); + if ( error ) + goto Fail; + + phase = Load_End; + } + } + else + phase = Load_Exit; + + break; + + + case Load_Exit: + break; + } + } + + /* finally, copy the points arrays to the glyph object */ + + exec->pts = base_pts; + + for ( u = 0; u < num_points + 2; u++ ) + { + glyph->outline.points[u] = exec->pts.cur[u]; + glyph->outline.flags [u] = exec->pts.touch[u]; + } + + for ( k = 0; k < num_contours; k++ ) + glyph->outline.contours[k] = exec->pts.contours[k]; + + glyph->outline.n_points = num_points; + glyph->outline.n_contours = num_contours; + glyph->outline.second_pass = TRUE; + + /* translate array so that (0,0) is the glyph's origin */ + translate_array( num_points + 2, + glyph->outline.points, + -subglyph->pp1.x, + 0 ); + + TT_Get_Outline_BBox( &glyph->outline, &glyph->metrics.bbox ); + + if ( subglyph->is_hinted ) + { + /* grid-fit the bounding box */ + glyph->metrics.bbox.xMin &= -64; + glyph->metrics.bbox.yMin &= -64; + glyph->metrics.bbox.xMax = (glyph->metrics.bbox.xMax+63) & -64; + glyph->metrics.bbox.yMax = (glyph->metrics.bbox.yMax+63) & -64; + } + + /* get the device-independent scaled horizontal metrics */ + /* take care of fixed-pitch fonts... */ + { + TT_Pos left_bearing; + TT_Pos advance; + + + left_bearing = subglyph->metrics.horiBearingX; + advance = subglyph->metrics.horiAdvance; + + if ( face->postscript.isFixedPitch ) + advance = face->horizontalHeader.advance_Width_Max; + + if ( load_flags & TTLOAD_SCALE_GLYPH ) + { + left_bearing = Scale_X( &exec->metrics, left_bearing ); + advance = Scale_X( &exec->metrics, advance ); + } + + glyph->metrics.linearHoriBearingX = left_bearing; + glyph->metrics.linearHoriAdvance = advance; + } + + glyph->metrics.horiBearingX = glyph->metrics.bbox.xMin; + glyph->metrics.horiBearingY = glyph->metrics.bbox.yMax; + glyph->metrics.horiAdvance = subglyph->pp2.x - subglyph->pp1.x; + + /* Now take care of vertical metrics. In the case where there is */ + /* no vertical information within the font (relatively common), make */ + /* up some metrics `by hand' ... */ + + { + Short top_bearing; /* vertical top side bearing (EM units) */ + UShort advance_height; /* vertical advance height (EM units) */ + + TT_Pos left; /* scaled vertical left side bearing */ + TT_Pos Top; /* scaled original vertical top side bearing */ + TT_Pos top; /* scaled vertical top side bearing */ + TT_Pos advance; /* scaled vertical advance height */ + + + /* Get the unscaled `tsb' and `ah' values */ + if ( face->verticalInfo && + face->verticalHeader.number_Of_VMetrics > 0 ) + { + /* Don't assume that both the vertical header and vertical */ + /* metrics are present in the same font :-) */ + + TT_Get_Metrics( (TT_Horizontal_Header*)&face->verticalHeader, + glyph_index, + &top_bearing, + &advance_height ); + } + else + { + /* Make up the distances from the horizontal header.. */ + + /* NOTE: The OS/2 values are the only `portable' ones, */ + /* which is why we use them... */ + /* */ + /* NOTE2: The sTypoDescender is negative, which is why */ + /* we compute the baseline-to-baseline distance */ + /* here with : */ + /* ascender - descender + linegap */ + /* */ + top_bearing = (Short) (face->os2.sTypoLineGap / 2); + advance_height = (UShort)(face->os2.sTypoAscender - + face->os2.sTypoDescender + + face->os2.sTypoLineGap); + } + + /* We must adjust the top_bearing value from the bounding box given + in the glyph header to te bounding box calculated with + TT_Get_Outline_BBox() */ + + /* scale the metrics */ + if ( load_flags & TTLOAD_SCALE_GLYPH ) + { + Top = Scale_Y( &exec->metrics, top_bearing ); + top = Scale_Y( &exec->metrics, + top_bearing + subglyph->metrics.bbox.yMax ) - + glyph->metrics.bbox.yMax; + advance = Scale_Y( &exec->metrics, advance_height ); + } + else + { + Top = top_bearing; + top = top_bearing + subglyph->metrics.bbox.yMax - + glyph->metrics.bbox.yMax; + advance = advance_height; + } + + glyph->metrics.linearVertBearingY = Top; + glyph->metrics.linearVertAdvance = advance; + + /* XXX : for now, we have no better algo for the lsb, but it should */ + /* work ok.. */ + /* */ + left = ( glyph->metrics.bbox.xMin - glyph->metrics.bbox.xMax ) / 2; + + /* grid-fit them if necessary */ + if ( subglyph->is_hinted ) + { + left &= -64; + top = (top + 63) & -64; + advance = (advance + 32) & -64; + } + + glyph->metrics.vertBearingX = left; + glyph->metrics.vertBearingY = top; + glyph->metrics.vertAdvance = advance; + } + + /* Adjust advance width to the value contained in the hdmx table. */ + if ( !exec->face->postscript.isFixedPitch && instance && + subglyph->is_hinted ) + { + widths = Get_Advance_Widths( exec->face, + exec->instance->metrics.x_ppem ); + if ( widths ) + glyph->metrics.horiAdvance = widths[glyph_index] << 6; + } + + glyph->outline.dropout_mode = (Char)exec->GS.scan_type; + + error = TT_Err_Ok; + + Fail_File: + Fail: + DONE_Stream( stream ); + + Fin: + + /* reset the execution context */ + exec->pts = base_pts; + + if ( !instance || !instance->debug ) + Done_Context( exec ); + + return error; + } + + +/* END */ |