home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: SysTools
/
SysTools.zip
/
ft-beta.zip
/
freetype
/
lib
/
ttgload.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-06
|
30KB
|
1,095 lines
/*******************************************************************
*
* ttgload.c 1.0
*
* TrueType Glyph Loader.
*
* Copyright 1996, 1997 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 "tterror.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"
/* 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
/* end composite */
static void Get_HMetrics( PFace face,
Int index,
Int* lsb,
Int* aw )
{
Int k;
k = face->horizontalHeader.number_Of_HMetrics;
if ( index < k )
{
*lsb = face->longHMetrics[index].lsb;
*aw = face->longHMetrics[index].advance_Width;
}
else
{
*lsb = face->shortMetrics[index-k];
*aw = face->longHMetrics[k-1].advance_Width;
}
}
static
TT_Error Load_Simple_Glyph( PExecution_Context exec,
TT_Stream input,
Int n_contours,
Int left_contours,
Int left_points,
Int load_flags,
PSubglyph_Record subg )
{
DEFINE_LOAD_LOCALS(input);
Int k, n_points, n_ins;
Byte c, cnt;
PFace face;
PCoordinates xs, ys;
PTouchTable flag;
TT_F26Dot6 x, y, xmin, ymin, xmax, ymax;
PVecRecord pts;
Int leftSideBearing;
Int advanceWidth;
face = exec->owner;
/* simple check */
if ( n_contours > left_contours )
{
DebugTrace(( "ERROR: Glyph index %d has %d contours > left %d\n",
subg->index, n_contours, left_contours ));
return TT_Err_Too_Many_Contours;
}
/* preparing the execution context */
exec->pts.n = 0;
exec->pts.org_x = subg->org_x + subg->n_points;
exec->pts.org_y = subg->org_y + subg->n_points;
exec->pts.cur_x = subg->cur_x + subg->n_points;
exec->pts.cur_y = subg->cur_y + subg->n_points;
exec->pts.touch = subg->flag + subg->n_points;
exec->numContours = 0;
exec->endContours = subg->contours + subg->n_contours;
/* reading the contours endpoints */
if ( ACCESS_Frame( (n_contours+1)*2L ) )
return error;
n_points = 0;
for ( k=0; k < n_contours; k++ )
{
DebugTrace(( "%d ", n_points ));
exec->endContours[k] = n_points = GET_Short();
n_points++;
}
n_ins = GET_Short();
FORGET_Frame();
if ( n_points > left_points )
{
DebugTrace(( "ERROR : Too many points in glyph %d\n", subg->index ));
return TT_Err_Too_Many_Points;
}
/* loading instructions */
DebugTrace(("Instructions size : %d\n", n_ins ));
if ( n_ins > face->maxProfile.maxSizeOfInstructions )
{
DebugTrace(("That's too many !!\n"));
return TT_Err_Too_Many_Ins;
}
if ( FILE_Read( exec->glyphIns, n_ins ) )
return error;
exec->glyphSize = n_ins;
if ( (error = Set_CodeRange( exec,
TT_CodeRange_Glyph,
exec->glyphIns,
exec->glyphSize )) )
return error;
/* read the flags */
if ( CHECK_ACCESS_Frame( n_points * 5L ) )
return error;
k = 0;
flag = exec->pts.touch;
while ( k < n_points )
{
flag[k] = c = GET_Byte();
k++;
if ( c & 8 )
{
cnt = GET_Byte();
while( cnt > 0 )
{
flag[k++] = c;
cnt--;
}
}
}
/* read the X */
x = 0;
xmin = 0;
xmax = 0;
xs = exec->pts.org_x;
for ( k = 0; k < n_points; k++ )
{
if ( flag[k] & 2 )
{
if ( flag[k] & 16 )
x += GET_Byte();
else
x -= GET_Byte();
}
else
{
if ( (flag[k] & 16) == 0 )
x += GET_Short();
}
xs[k] = x;
if ( x < xmin ) xmin = x;
if ( x > xmax ) xmax = x;
}
/* read the Y */
y = 0;
ymin = 0;
ymax = 0;
ys = exec->pts.org_y;
for ( k = 0; k < n_points; k++ )
{
if ( flag[k] & 4 )
{
if ( flag[k] & 32 )
y += GET_Byte();
else
y -= GET_Byte();
}
else
{
if ( (flag[k] & 32) == 0 )
y += GET_Short();
}
ys[k] = y;
if ( y < ymin ) ymin = y;
if ( y > ymax ) ymax = y;
}
FORGET_Frame();
/* Now adds the two shadow points at n and n+1 */
/* We need the left side bearing and advance width */
Get_HMetrics( face, subg->index, &leftSideBearing, &advanceWidth );
subg->leftSideBearing = leftSideBearing;
subg->advanceWidth = advanceWidth;
xs[n_points] = subg->xMin - leftSideBearing;
ys[n_points] = 0;
/* pp1 = xMin - lsb */
xs[n_points+1] = xs[n_points] + advanceWidth;
ys[n_points+1] = 0;
/* pp2 = pp1 + aw */
/* clear the touch flags */
for ( k = 0; k < n_points; k++ )
exec->pts.touch[k] &= 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 = n_points;
exec->numContours = n_contours;
if ( (load_flags & TTLOAD_SCALE_GLYPH) == 0 )
{
/* no scaling, just copy the org arrays into the cur ones */
for ( k = 0; k < n_points; k++ )
{
pts->cur_x[k] = pts->org_x[k];
pts->cur_y[k] = pts->org_y[k];
}
}
else
{
/* first scale the glyph points */
for ( k = 0; k < n_points; k++ )
{
x = MulDiv_Round( pts->org_x[k],
exec->metrics.x_scale1,
exec->metrics.x_scale2 );
y = MulDiv_Round( pts->org_y[k],
exec->metrics.y_scale1,
exec->metrics.y_scale2 );
pts->org_x[k] = x;
pts->org_y[k] = y;
pts->cur_x[k] = x;
pts->cur_y[k] = y;
}
/* scale advance width and left side bearing too */
subg->leftSideBearing = MulDiv_Round( leftSideBearing,
exec->metrics.x_scale1,
exec->metrics.x_scale2 ) & -64;
subg->advanceWidth = ( MulDiv_Round( advanceWidth,
exec->metrics.x_scale1,
exec->metrics.x_scale2 )+32 ) & -64;
/* then round the phantom points. This is critical for correct */
/* hinting at low ppems */
pts->cur_x[n_points-2] = pts->cur_x[n_points-2] & -64;
pts->cur_x[n_points-1] = ( pts->cur_x[n_points-1] + 32 ) & -64;
/* now consider hinting */
if ( subg->is_hinted && n_ins > 0 )
if ( (error = Context_Run( exec, FALSE )) )
return error;
/* adjust advance width to its grid-fitted value */
subg->advanceWidth += pts->cur_x[n_points-1] -
pts->org_x[n_points-1];
}
return TT_Err_Ok;
}
static
TT_Error Load_Composite_Instructions( Int n_points,
Int n_contours,
PExecution_Context exec,
PSubglyph_Record subg )
{
Int k;
PVecRecord pts;
TT_Error error;
/* prepare the execution context */
exec->pts.n = n_points+2;
exec->pts.org_x = subg->org_x;
exec->pts.org_y = subg->org_y;
exec->pts.cur_x = subg->cur_x;
exec->pts.cur_y = subg->cur_y;
exec->pts.touch = subg->flag;
exec->numContours = n_contours;
exec->endContours = subg->contours;
pts = &exec->pts;
/* add phantom points */
pts->cur_x[n_points] = subg->xMin - subg->leftSideBearing;
pts->cur_y[n_points] = 0;
/* pp1 = xMin - lsb */
pts->cur_x[n_points+1] = subg->xMin - subg->leftSideBearing +
subg->advanceWidth;
pts->cur_y[n_points+1] = 0;
/* pp2 = pp1 + aw */
for ( k = 0; k < n_points+2; k++ )
{
pts->org_x[k] = pts->cur_x[k];
pts->org_y[k] = pts->cur_y[k];
pts->touch[k] = pts->touch[k] & TT_Flag_On_Curve;
}
if ( (error = Set_CodeRange( exec,
TT_CodeRange_Glyph,
exec->glyphIns,
exec->glyphSize )) )
return error;
/* now consider hinting */
if ( subg->is_hinted &&
exec->glyphSize > 0 )
return Context_Run( exec, FALSE );
else
return TT_Err_Ok;
}
static
void Init_Glyph_Component( PSubglyph_Record element,
PSubglyph_Record original,
PExecution_Context exec )
{
Int n;
element->index = -1;
element->is_scaled = FALSE;
element->n_contours = 0;
element->n_points = 0;
if (original)
{
element->is_hinted = original->is_hinted;
n = original->n_points;
element->org_x = original->org_x + n;
element->org_y = original->org_y + n;
element->cur_x = original->cur_x + n;
element->cur_y = original->cur_y + n;
element->flag = original->flag + n;
n = original->n_contours;
element->contours = original->contours + n;
}
else
{
element->is_hinted = FALSE;
element->org_x = exec->pts.org_x;
element->org_y = exec->pts.org_y;
element->cur_x = exec->pts.cur_x;
element->cur_y = exec->pts.cur_y;
element->flag = exec->pts.touch;
element->contours = exec->endContours;
}
element->arg1 = 0;
element->arg2 = 0;
element->element_flag = 0;
element->transform.xx = 1 << 16;
element->transform.xy = 0;
element->transform.yx = 0;
element->transform.yy = 1 << 16;
element->transform.ox = 0;
element->transform.oy = 0;
element->leftSideBearing = 0;
element->advanceWidth = 0;
}
TT_Error Load_TrueType_Glyph( PInstance instance,
PGlyph glyph,
Int glyph_index,
Int load_flags )
{
enum _TPhases
{
Load_Exit,
Load_Glyph,
Load_Simple,
Load_Composite,
Load_End
};
typedef enum _TPhases TPhases;
DEFINE_ALL_LOCALS;
PFace face;
Int num_points;
Int num_contours;
Int left_points;
Int left_contours;
Int table, index, load_top, new_flags, k, l;
Long glyph_offset, offset;
TT_F26Dot6 x, y, nx, ny;
TT_F26Dot6 xmin, xmax, ymin, ymax;
Fixed xx, xy, yx, yy;
PExecution_Context exec;
PSubglyph_Record subglyph, subglyph2;
TVecRecord base_pts;
Int base_n_contours;
PUShort base_contours;
TPhases phase;
/* first of all, check arguments */
if ( !instance || !instance->owner )
return TT_Err_Invalid_Face_Handle;
face = instance->owner;
if (glyph_index < 0 || glyph_index >= face->numGlyphs )
return TT_Err_Invalid_Glyph_Index;
table = LookUp_TrueType_Table( face, TTAG_glyf );
if (table < 0)
{
DebugTrace(( "ERROR : there is no glyph table in this font file !!\n" ));
return TT_Err_Table_Missing;
}
glyph_offset = face->dirTables[table].Offset;
/* query new execution context */
if (instance->debug)
exec = instance->context;
else
exec = New_Context(face);
if (!exec)
return TT_Err_Out_Of_Memory;
Context_Load( exec, instance );
if ( instance->GS.instruct_control & 2 )
exec->GS = Default_GraphicsState;
else
exec->GS = instance->GS;
/* load default graphics state */
/* save its critical pointers, as they'll be modified during load */
base_pts = exec->pts;
base_n_contours = exec->numContours;
base_contours = exec->endContours;
/* 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->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;
while ( phase != Load_Exit )
{
subglyph = exec->loadStack + load_top;
switch (phase)
{
/************************************************************/
/* */
/* Load_Glyph state */
/* */
/* reading a glyph's generic header to determine */
/* wether it's simple or composite */
/* */
/* exit states : Load_Simple and Load_Composite */
/* */
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 */
Get_HMetrics( face, index, &k, &l );
if (load_flags & TTLOAD_SCALE_GLYPH)
{
k = MulDiv_Round( k,
exec->metrics.x_scale1,
exec->metrics.x_scale2 );
l = MulDiv_Round( l,
exec->metrics.x_scale1,
exec->metrics.x_scale2 );
}
subglyph->leftSideBearing = k;
subglyph->advanceWidth = l;
/* 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->xMin = 0;
subglyph->xMax = 0;
subglyph->yMin = 0;
subglyph->yMax = 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->xMin = GET_Short();
subglyph->yMin = GET_Short();
subglyph->xMax = GET_Short();
subglyph->yMax = GET_Short();
FORGET_Frame();
DebugTrace(( "Glyph %d\n", index ));
DebugTrace(( " # of contours : %d\n", num_contours ));
DebugTrace(( " xMin : %4d xMax : %4d\n",
subglyph->xMin,
subglyph->xMax ));
DebugTrace(( " yMin : %4d yMax : %4d\n",
subglyph->yMin,
subglyph->yMax ));
DebugTrace(( "-" ));
if ( num_contours > left_contours )
{
DebugTrace(( "ERROR : Too many contours for glyph %d\n", index ));
error = TT_Err_Too_Many_Contours;
goto Fail;
}
/* 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;
if ( !subglyph->is_hinted )
new_flags &= ~TTLOAD_HINT_GLYPH;
/* disable hinting when scaling */
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 - 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 );
/* now read composite header */
if ( ACCESS_Frame(4) )
goto Fail_File;
subglyph->element_flag = new_flags = GET_UShort();
subglyph2->index = GET_UShort();
FORGET_Frame();
k = 2;
if ( new_flags & ARGS_ARE_WORDS )
k += 2;
if ( new_flags & WE_HAVE_A_SCALE )
k += 2;
if ( new_flags & WE_HAVE_AN_XY_SCALE )
k += 4;
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
{
l = GET_UShort();
k = (signed char)(l >> 8);
l = (signed char)(l & 0xFF);
}
subglyph->arg1 = k;
subglyph->arg2 = l;
if ( new_flags & ARGS_ARE_XY_VALUES )
{
subglyph->transform.ox = k;
subglyph->transform.oy = l;
}
xx = 1 << 16;
xy = 0;
yx = 0;
yy = 1 << 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 = MulDiv_Round( xx, yy, 1 << 16 ) -
MulDiv_Round( xy, yx, 1 << 16 );
if ( k < -(1 << 16) || k > (1 << 16) )
subglyph2->is_hinted = FALSE;
/* disable hinting in case of scaling/slanting */
subglyph->file_offset = FILE_Pos();
phase = Load_Glyph;
break;
/************************************************************/
/* */
/* Load_End state */
/* */
/* after loading a glyph, apply transform 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->element_flag & USE_MY_METRICS ||
subglyph->advanceWidth == 0 )
{
subglyph->leftSideBearing = subglyph2->leftSideBearing;
subglyph->advanceWidth = subglyph2->advanceWidth;
}
/* apply scale */
if (subglyph2->is_scaled)
{
for ( k = 0; k < num_points; k++ )
{
x = subglyph2->cur_x[k];
y = subglyph2->cur_y[k];
nx = MulDiv_Round( x, subglyph->transform.xx, 1 << 16 ) +
MulDiv_Round( y, subglyph->transform.yx, 1 << 16 );
ny = MulDiv_Round( x, subglyph->transform.xy, 1 << 16 ) +
MulDiv_Round( y, subglyph->transform.yy, 1 << 16 );
subglyph2->cur_x[k] = nx;
subglyph2->cur_y[k] = ny;
x = subglyph2->org_x[k];
y = subglyph2->org_y[k];
nx = MulDiv_Round( x, subglyph->transform.xx, 1 << 16 ) +
MulDiv_Round( y, subglyph->transform.yx, 1 << 16 );
ny = MulDiv_Round( x, subglyph->transform.xy, 1 << 16 ) +
MulDiv_Round( y, subglyph->transform.yy, 1 << 16 );
subglyph2->org_x[k] = nx;
subglyph2->org_y[k] = ny;
}
}
/* adjust counts */
for ( k = 0; k < num_contours; k++ )
subglyph2->contours[k] += subglyph->n_points;
subglyph->n_points += num_points;
subglyph->n_contours += num_contours;
left_points -= num_points;
left_contours -= num_contours;
/* apply offset */
if ( !(subglyph->element_flag & ARGS_ARE_XY_VALUES) )
{
k = subglyph->arg1;
l = subglyph->arg2;
if ( k < 0 || k >= subglyph->n_points ||
l < 0 || l >= subglyph->n_points )
{
error = TT_Err_Invalid_Composite;
goto Fail;
}
subglyph->transform.ox = subglyph->org_x[l] -
subglyph->org_x[k];
subglyph->transform.oy = subglyph->org_y[l] -
subglyph->org_y[k];
}
x = subglyph->transform.ox;
y = subglyph->transform.oy;
if ( load_flags & TTLOAD_SCALE_GLYPH )
{
x = MulDiv_Round( x,
exec->metrics.x_scale1,
exec->metrics.x_scale2 );
y = MulDiv_Round( y,
exec->metrics.y_scale1,
exec->metrics.y_scale2 );
}
if ( subglyph->element_flag & ARGS_ARE_XY_VALUES &&
subglyph->element_flag & ROUND_XY_TO_GRID )
{
x = ROUND_F26DOT6(x);
y = ROUND_F26DOT6(y);
}
for ( k = 0; k < num_points; k++ )
{
subglyph2->org_x[k] += x;
subglyph2->org_y[k] += y;
subglyph2->cur_x[k] += x;
subglyph2->cur_y[k] += y;
}
num_points = subglyph->n_points;
num_contours = subglyph->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
{
if ( subglyph->is_hinted &&
subglyph->element_flag & WE_HAVE_INSTR )
{
if ( ACCESS_Frame(2) )
goto Fail;
k = GET_UShort();
/* read size of instructions */
FORGET_Frame();
DebugTrace(( "Instructions size = %d\n", k ));
if ( k > face->maxProfile.maxSizeOfInstructions )
{
DebugTrace(( "Too many instructions\n" ));
error = TT_Err_Too_Many_Ins;
goto Fail;
}
if ( FILE_Read( exec->glyphIns, k ) )
goto Fail;
exec->glyphSize = k;
error = Load_Composite_Instructions( num_points,
num_contours,
exec,
subglyph );
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;
exec->numContours = base_n_contours;
exec->endContours = base_contours;
if (num_points > 0)
{
xmin = xmax = exec->pts.cur_x[0];
ymin = ymax = exec->pts.cur_y[0];
for ( k = 1; k < num_points; k++ )
{
x = exec->pts.cur_x[k];
if ( x < xmin ) xmin = x;
if ( x > xmax ) xmax = x;
y = exec->pts.cur_y[k];
if ( y < ymin ) ymin = y;
if ( y > ymax ) ymax = y;
}
subglyph->xMin = xmin;
subglyph->xMax = xmax;
subglyph->yMin = ymin;
subglyph->yMax = ymax;
}
num_points += 2;
for ( k = 0; k < num_points-1; k++ )
{
glyph->x_coord[k] = exec->pts.cur_x[k];
glyph->y_coord[k] = exec->pts.cur_y[k];
glyph->touch [k] = exec->pts.touch[k];
}
for ( k = 0; k < num_contours; k++ )
glyph->endContours[k] = exec->endContours[k];
glyph->num_points = num_points;
glyph->num_contours = num_contours;
glyph->leftSideBearing = subglyph->leftSideBearing;
glyph->advanceWidth = subglyph->advanceWidth;
glyph->scan_type = exec->GS.scan_type;
glyph->high_precision = ( instance->metrics.y_ppem < 24 );
/* We use high precision whenever the render size is below 24 ppems */
glyph->xMin = subglyph->xMin;
glyph->yMin = subglyph->yMin;
glyph->xMax = subglyph->xMax;
glyph->yMax = subglyph->yMax;
error = TT_Err_Ok;
Fail_File:
Fail:
TT_Done_Stream( &stream );
Fin:
/* reset the execution context */
exec->pts = base_pts;
exec->numContours = base_n_contours;
exec->endContours = base_contours;
if ( !instance->debug )
Done_Context(exec);
return error;
}