mac-rom/Toolbox/FontMgr/FSglue.c

1707 lines
51 KiB
C
Raw Normal View History

/*
File: FSglue.c
Contains: xxx put contents here (or delete the whole line) xxx
Written by: xxx put name of writer here (or delete the whole line) xxx
Copyright: <EFBFBD> 1988-1991 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<13> 10/22/91 RB Update to Kirin Sources, Finish obsoleting AA and SANGW
<12> 9/25/91 jlf Rolled in mr's SOFTRELEASESFNTFRAG changes.
<11> 12/20/90 RB Change runPreProgram so that the SetDefaults is always called at
beginning. [mr]
<10> 12/11/90 MR Add use-my-metrics support for devMetrics in component glyphs,
initialize key->tInfo in RunPreProgram. [rb]
<9> 12/5/90 MR Use (possible pretransformed) oox to set phantom points. [rb]
<8> 12/5/90 RB Take out point number reversal calls so we are consistent with
change to non-zero winding number fill. [mr]
<7> 11/27/90 MR Need two scalars: one for (possibly rounded) outlines and cvt,
and one (always fractional) metrics. [rb]
<6> 11/16/90 MR Add SnapShotOutline to make instructions after components work
[rb]
<5> 11/9/90 MR Unrename fsg_ReleaseProgramPtrs to RELEASESFNTFRAG. [rb]
<4> 11/5/90 MR Change globalGS.ppemDot6 to globalGS.fpem, change all instrPtr
and curve flags to uint8. [rb]
<3> 10/31/90 MR Add bit-field option for integer or fractional scaling [rb]
<2> 10/20/90 MR Change matrix[2][2] back to a fract (in response to change in
skia). However, ReduceMatrix converts it to a fixed after it has
been used to "regularize" the matrix. Changed scaling routines
for outline and CVT to use integer pixelsPerEm. Removed
scaleFunc from the splineKey. Change some routines that were
calling FracDiv and FixDiv to use LongMulDiv and ShortMulDiv for
greater speed and precision. Removed fsg_InitScaling. [rb]
<20> 8/22/90 MR Only call fixmul when needed in finalComponentPass loop
<19> 8/1/90 MR Add line to set non90DegreeTransformation
<18> 7/26/90 MR remove references to metricInfo junk, don<EFBFBD>t include ToolUtils.h
<17> 7/18/90 MR Change error return type to int, split WorkSpace routine into
two calls, added SWAPW macros
<16> 7/14/90 MR Fixed reference to const SQRT2 to FIXEDSQRT2
<15> 7/13/90 MR Ansi-C stuff, tried to use correct sizes for variables to avoid
coercion (sp?)
<12> 6/21/90 MR Add calls to ReleaseSfntFrag
<11> 6/4/90 MR Remove MVT, change matrix to have bottom right element be a
fixed.
<10> 6/1/90 MR Thou shalt not pay no more attention to the MVT!
<8+> 5/29/90 MR look for problem in Max45Trick
<8> 5/21/90 RB bugfix in fsg_InitInterpreterTrans setting key->imageState
<7> 5/9/90 MR Fix bug in MoreThanXYStretch
<6> 5/4/90 RB support for new scan converter and decryption mrr - add
fsg_ReverseContours and key->reverseContour to account
for glyphs that are flipped. This keeps the
winding-number correct for the scan converter. Mike
fixed fsg_Identity
<5> 5/3/90 RB support for new scan converter and decryption mrr - add
fsg_ReverseContours and key->reverseContour to account for
glyphs that are flipped. This keeps the winding-number correct
for the scan converter.
<4> 4/10/90 CL Fixed infinite loop counter - changed uint16 to int16 (Mikey).
<3> 3/20/90 CL Added HasPerspective for finding fast case
Removed #ifdef SLOW, OLD
Changed NormalizeTransformation to use fpem (16.16) and to use max instead of length
and to loop instead of recurse.
Removed compensation for int ppem in fsg_InitInterpreterTrans (not needed with fpem)
Greased loops in PreTransformGlyph, PostTransformGlyph, LocalPostTransformGlyph,
ShiftChar, ZeroOutTwilightZone, InitLocalT
Changed GetPreMultipliers to special case unit vector * 2x2 matrix
Added support for ppemDot6 and pointSizeDot6
Changed fsg_MxMul to treat the perspective elements as Fracts
arrays to pointers in ScaleChar
Fixed bugs in loops in posttransformglyph, convert loops to --numPts >= 0
<2> 2/27/90 CL It reconfigures itself during runtime ! New lsb and rsb
calculation. Shift bug in instructed components: New error
code for missing but needed table. (0x1409 ) Optimization which
has to do with shifting and copying ox/x and oy/y. Fixed new
format bug. Changed transformed width calculation. Fixed
device metrics for transformed uninstructed sidebearing
characters. Dropoutcontrol scanconverter and SCANCTRL[]
instruction. Fixed transformed component bug.
<3.3> 11/14/89 CEL Left Side Bearing should work right for any transformation. The
phantom points are in, even for components in a composite glyph.
They should also work for transformations. Device metric are
passed out in the output data structure. This should also work
with transformations. Another leftsidebearing along the advance
width vector is also passed out. whatever the metrics are for
the component at it's level. Instructions are legal in
components. The old perspective bug has been fixed. The
transformation is internally automatically normalized. This
should also solve the overflow problem we had. Changed
sidebearing point calculations to use 16.16 precision. For zero
or negative numbers in my tricky/fast square root computation it
would go instable and loop forever. It was not able to handle
large transformations correctly. This has been fixed and the
normalization may call it self recursively to gain extra
precision! It used to normalize an identity transformation
unecessarily.
<3.2> 10/6/89 CEL Phantom points were removed causing a rounding of last 2 points
bug. Characters would become distorted.
<3.1> 9/27/89 CEL Fixed transformation anchor point bug.
<3.0> 8/28/89 sjk Cleanup and one transformation bugfix
<2.2> 8/14/89 sjk 1 point contours now OK
<2.1> 8/8/89 sjk Improved encryption handling
<2.0> 8/2/89 sjk Just fixed EASE comment
<1.5> 8/1/89 sjk Added composites and encryption. Plus some
enhanclocalpostements<EFBFBD>
<1.4> 6/13/89 SJK Comment
<1.3> 6/2/89 CEL 16.16 scaling of metrics, minimum recommended ppem, point size 0
bug, correct transformed integralized ppem behavior, pretty much
so
<1.2> 5/26/89 CEL EASE messed up on <EFBFBD>c<EFBFBD> comments
<<EFBFBD>1.1> 5/26/89 CEL Integrated the new Font Scaler 1.0 into Spline Fonts
<1.0> 5/25/89 CEL Integrated 1.0 Font scaler into Bass code for the first time<EFBFBD>
To Do:
*/
/* rwb r/24/90 - Add support for scanControlIn and scanControlOut variables in global graphiscs
* state
*/
#include "setjmp.h"
/** FontScaler<65>s Includes **/
#include "FSError.h"
#include "FSCdefs.h"
#include "FontMath.h"
#include "sfnt.h"
#include "sc.h"
#include "fnt.h"
#include "FontScaler.h"
#include "FSglue.h"
#include "privateSFNT.h"
/*********** macros ************/
#define WORD_ALIGN( n ) n++, n &= ~1;
#define LONG_WORD_ALIGN( n ) n += 3, n &= ~3;
#define ALMOSTZERO 33
#define NORMALIZELIMIT (135L << 16)
#define FIXEDTODOT6(n) ((n) + (1L << 9) >> 10)
#define FRACT2FIX(n) ((n) + (1 << 13) >> 14)
#define CLOSETOONE(x) ((x) >= ONEFIX-ALMOSTZERO && (x) <= ONEFIX+ALMOSTZERO)
#define MAKEABS(x) if (x < 0) x = -x
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define NUMBEROFPOINTS(elementPtr) (elementPtr->ep[elementPtr->nc - 1] + 1 + PHANTOMCOUNT)
#define GLOBALGSTATE(key) (fnt_GlobalGraphicStateType*)(key->memoryBases[PRIVATE_FONT_SPACE_BASE] + key->offset_globalGS)
#define LOOPDOWN(n) for (--n; n >= 0; --n)
#define ULOOPDOWN(n) while (n--)
#define fsg_MxCopy(a, b) (*b = *a)
#ifdef SEGMENT_LINK
#pragma segment FSGLUE_C
#endif
/**********************************************************************************/
/* PRIVATE PROTOTYPES <4> */
static void fsg_CopyElementBackwards(fnt_ElementType *elementPtr);
static int8 fsg_HasPerspective( transMatrix* matrix );
static void fsg_GetMatrixStretch(fsg_SplineKey* key, Fixed* xStretch, Fixed* yStretch, transMatrix* trans); /*<8>*/
static int8 fsg_Identity( transMatrix *matrix );
static int16 fsg_MoreThanXYStretch( transMatrix *matrix );
static Fixed fsg_FastScale16( fsg_SplineKey *key, int16 value );
static Fixed fsg_MediumScale16( fsg_SplineKey *key, int16 value );
static Fixed fsg_SlowScale16( fsg_SplineKey *key, int16 value );
static int fsg_GetShift( uint32 n );
static void fsg_ScaleCVT( fsg_SplineKey *key, int32 numCVT, F26Dot6 *cvt, int16 *srcCVT );
static void fsg_PreTransformGlyph( fsg_SplineKey* key );
static void fsg_CallStyleFunc( fsg_SplineKey* key, fnt_ElementType* elementPtr );
static void fsg_PostTransformGlyph(fsg_SplineKey *key, transMatrix *trans);
static void fsg_LocalPostTransformGlyph(fsg_SplineKey *key, transMatrix *trans);
static void fsg_ShiftChar(fsg_SplineKey *key, int32 xShift, int32 yShift, int32 lastPoint);
static void fsg_ScaleChar( fsg_SplineKey *key );
static void fsg_ZeroOutTwilightZone(fsg_SplineKey *key);
static void fsg_SetUpProgramPtrs(fsg_SplineKey* key, fnt_GlobalGraphicStateType* globalGS);
#ifdef RELEASE_MEM_FRAG
static void fsg_ReleaseProgramPtrs(fsg_SplineKey* key, fnt_GlobalGraphicStateType* globalGS);
#endif
static void fsg_SetUpTablePtrs(fsg_SplineKey* key);
static int fsg_RunPreProgram(fsg_SplineKey *key, voidFunc traceFunc);
static void fsg_InitLocalT( fsg_SplineKey* key );
static int8 fsg_Max45Trick(Fixed x, Fixed y, Fixed* stretch);
static F26Dot6 fnt_FRound(register fnt_GlobalGraphicStateType *globalGS, register F26Dot6 value);
static F26Dot6 fnt_SRound(register fnt_GlobalGraphicStateType *globalGS, register F26Dot6 value);
static F26Dot6 fnt_FixRound(fnt_GlobalGraphicStateType *globalGS, F26Dot6 value);
/*
* fsg_KeySize
*/
unsigned fsg_KeySize( )
{
return( sizeof( fsg_SplineKey ) );
}
/*
* fsg_InterPreterDataSize <3>
*/
unsigned fsg_InterPreterDataSize( )
{
return MAXBYTE_INSTRUCTIONS * sizeof(voidFunc); /* remove angleInfo constants <13> */
}
/*
* fsg_ScanDataSize
*/
unsigned fsg_ScanDataSize( )
{
return( sizeof(sc_GlobalData) );
}
/*
* fsg_PrivateFontSpaceSize : This data should remain intact for the life of the sfnt
* because function and instruction defs may be defined in the font program
* and/or the preprogram.
*/
unsigned fsg_PrivateFontSpaceSize(register fsg_SplineKey *key)
{
int32 offsetT;
register unsigned size;
unsigned lengthT;
key->offset_storage = size = 0;
size += sizeof(F26Dot6) * key->maxProfile.maxStorage;
/* LONG_WORD_ALIGN( size ); Not needed <4> */
key->offset_functions = size;
size += sizeof(fnt_funcDef) * key->maxProfile.maxFunctionDefs;
/* LONG_WORD_ALIGN( size ); Not needed if struct is long aligned <4> */
key->offset_instrDefs = size;
size += sizeof(fnt_instrDef) * key->maxProfile.maxInstructionDefs; /* <4> */
/* LONG_WORD_ALIGN( size ); Not needed if struct is long aligned <4> */
key->offset_controlValues = size;
sfnt_GetOffsetAndLength( key, &offsetT, &lengthT, sfnt_controlValue );
#ifdef DEBUG
key->cvtCount = lengthT/ sizeof(sfnt_ControlValue);
#endif
size += sizeof(F26Dot6) * (lengthT/ sizeof(sfnt_ControlValue));
/* LONG_WORD_ALIGN( size ); Not needed <4> */
key->offset_globalGS = size;
size += sizeof(fnt_GlobalGraphicStateType);
LONG_WORD_ALIGN( size );
return( size );
}
static unsigned fsg_SetOffestPtr(fsg_OffsetInfo *offsetPtr, unsigned workSpacePos, unsigned maxPoints, unsigned maxContours)
{
register unsigned ArraySize;
offsetPtr->interpreterFlagsOffset = workSpacePos;
workSpacePos += maxPoints * sizeof (int8);
LONG_WORD_ALIGN (workSpacePos);
offsetPtr->startPointOffset = workSpacePos;
workSpacePos += (ArraySize = maxContours * sizeof (int16));
offsetPtr->endPointOffset = workSpacePos;
workSpacePos += ArraySize;
offsetPtr->oldXOffset = workSpacePos;
workSpacePos += (ArraySize = maxPoints * sizeof (F26Dot6));
offsetPtr->oldYOffset = workSpacePos;
workSpacePos += ArraySize;
offsetPtr->scaledXOffset = workSpacePos;
workSpacePos += ArraySize;
offsetPtr->scaledYOffset = workSpacePos;
workSpacePos += ArraySize;
offsetPtr->newXOffset = workSpacePos;
workSpacePos += ArraySize;
offsetPtr->newYOffset = workSpacePos;
workSpacePos += ArraySize;
offsetPtr->onCurveOffset = workSpacePos;
workSpacePos += maxPoints * sizeof (int8);
WORD_ALIGN (workSpacePos);
return workSpacePos;
}
/*
* fsg_WorkSpaceSetOffsets : This stuff changes with each glyph
*
* Computes the workspace size and sets the offsets into it.
*
*/
unsigned fsg_WorkSpaceSetOffsets(fsg_SplineKey *key)
{
register unsigned workSpacePos, maxPoints, maxContours;
register sfnt_maxProfileTable *maxProfilePtr = &key->maxProfile;
key->elementInfoRec.stackBaseOffset = workSpacePos = 0;
workSpacePos += maxProfilePtr->maxStackElements * sizeof (F26Dot6);
/* ELEMENT 0 */
workSpacePos = fsg_SetOffestPtr(&(key->elementInfoRec.offsets[TWILIGHTZONE]),
workSpacePos,
maxProfilePtr->maxTwilightPoints,
MAX_TWILIGHT_CONTOURS);
/* ELEMENT 1 */
maxPoints = (unsigned)maxProfilePtr->maxPoints;
if ( maxPoints < (unsigned)maxProfilePtr->maxCompositePoints )
maxPoints = (unsigned)maxProfilePtr->maxCompositePoints;
maxPoints += PHANTOMCOUNT;
maxContours = (unsigned)maxProfilePtr->maxContours;
if ( maxContours < (unsigned)maxProfilePtr->maxCompositeContours )
maxContours = (unsigned)maxProfilePtr->maxCompositeContours;
return fsg_SetOffestPtr(&(key->elementInfoRec.offsets[GLYPHELEMENT]),
workSpacePos,
maxPoints,
maxContours);
}
/*
* fsg_CopyElementBackwards
*/
static void fsg_CopyElementBackwards(fnt_ElementType *elementPtr)
{
register F26Dot6 *srcZero, *destZero;
register F26Dot6 *srcOne, *destOne;
register uint8 *flagPtr;
register LoopCount i;
register uint8 zero = 0;
srcZero = elementPtr->x;
srcOne = elementPtr->y;
destZero = elementPtr->ox;
destOne = elementPtr->oy;
flagPtr = elementPtr->f;
/* Update the point arrays. */
i = NUMBEROFPOINTS(elementPtr);
LOOPDOWN(i)
{
*destZero++ = *srcZero++;
*destOne++ = *srcOne++;
*flagPtr++ = zero;
}
}
/*
* Inverse scale the hinted, scaled points back into the upem domain.
*/
static void fsg_SnapShotOutline( fsg_SplineKey* key, fnt_ElementType* elem, register LoopCount numPts )
{
int32 bigUpem = (int32)key->emResolution << 10;
Fixed scalar = key->interpScalar;
{
F26Dot6* oox = elem->oox;
F26Dot6* x = elem->x;
LoopCount count = --numPts;
for (; count >= 0; --count)
*oox++ = LongMulDiv( *x++, bigUpem, scalar );
}
{
F26Dot6* ooy = elem->ooy;
F26Dot6* y = elem->y;
for (; numPts >= 0; --numPts)
*ooy++ = LongMulDiv( *y++, bigUpem, scalar );
}
}
/* <3> */
static int8 fsg_HasPerspective( transMatrix* matrix )
{
return (int8)(matrix->transform[0][2] || matrix->transform[1][2] || matrix->transform[2][2] != ONEFIX);
}
/*
* Good for transforming scaled coordinates. Assumes NO translate <4>
*/
void fsg_Dot6XYMul( F26Dot6* x, F26Dot6* y, transMatrix* matrix )
{
register F26Dot6 xTemp, yTemp;
register Fixed *m0, *m1;
m0 = (Fixed *)&matrix->transform[0][0];
m1 = (Fixed *)&matrix->transform[1][0];
xTemp = *x;
yTemp = *y;
*x = FixMul(*m0++, xTemp) + FixMul(*m1++, yTemp);
*y = FixMul(*m0++, xTemp) + FixMul(*m1++, yTemp);
if (*m0 || *m1 || matrix->transform[2][2] != ONEFIX) /* these two are Fracts */
{
Fixed tmp = FracMul(*m0, xTemp) + FracMul(*m1, yTemp);
tmp <<= 10; /* F26Dot6 -> Fixed */
tmp += matrix->transform[2][2];
if (tmp && tmp != ONEFIX)
{
*x = FixDiv(*x, tmp);
*y = FixDiv(*y, tmp);
}
}
}
/*
* Good for transforming fixed point values. Assumes NO translate <4>
*/
void fsg_FixXYMul( Fixed* x, Fixed* y, transMatrix* matrix )
{
register Fixed xTemp, yTemp;
register Fixed *m0, *m1;
m0 = (Fixed*)&matrix->transform[0][0];
m1 = (Fixed*)&matrix->transform[1][0];
xTemp = *x;
yTemp = *y;
*x = FixMul(*m0++, xTemp) + FixMul(*m1++, yTemp);
*y = FixMul(*m0++, xTemp) + FixMul(*m1++, yTemp);
if (*m0 || *m1 || matrix->transform[2][2] != ONEFIX) /* these two are Fracts */
{
Fixed tmp = FracMul(*m0, xTemp) + FracMul(*m1, yTemp);
tmp += matrix->transform[2][2];
if (tmp && tmp != ONEFIX)
{
*x = FixDiv(*x, tmp);
*y = FixDiv(*y, tmp);
}
}
}
/*
* This could be faster <4>
*/
void fsg_FixVectorMul( vectorType* v, transMatrix* matrix )
{
fsg_FixXYMul( &v->x, &v->y, matrix );
}
/*
* B = A * B; <4>
*
* | a b 0 |
* B = | c d 0 | * B;
* | 0 0 1 |
*/
void fsg_MxConcat2x2(register transMatrix* A, register transMatrix* B)
{
Fixed storage[6];
Fixed* s = storage;
*s++ = FixMul(A->transform[0][0], B->transform[0][0]) + FixMul(A->transform[0][1], B->transform[1][0]);
*s++ = FixMul(A->transform[0][0], B->transform[0][1]) + FixMul(A->transform[0][1], B->transform[1][1]);
*s++ = FixMul(A->transform[0][0], B->transform[0][2]) + FixMul(A->transform[0][1], B->transform[1][2]);
*s++ = FixMul(A->transform[1][0], B->transform[0][0]) + FixMul(A->transform[1][1], B->transform[1][0]);
*s++ = FixMul(A->transform[1][0], B->transform[0][1]) + FixMul(A->transform[1][1], B->transform[1][1]);
*s++ = FixMul(A->transform[1][0], B->transform[0][2]) + FixMul(A->transform[1][1], B->transform[1][2]);
{
register Fixed* dst = &B->transform[2][0];
register Fixed* src = s;
register int16 i;
for (i = 5; i >= 0; --i)
*--dst = *--src;
}
}
/*
* scales a matrix by sx and sy.
*
*
* | sx 0 0 |
* matrix = | 0 sy 0 | * matrix;
* | 0 0 1 |
*
*/
void fsg_MxScaleAB(Fixed sx, Fixed sy, transMatrix *matrixB)
{
register Fixed *m;
m = (Fixed *)&matrixB->transform[0][0];
*m = FixMul(sx, *m); m++;
*m = FixMul(sx, *m); m++;
*m = FixMul(sx, *m); m++;
*m = FixMul(sy, *m); m++;
*m = FixMul(sy, *m); m++;
*m = FixMul(sy, *m);
}
static Fixed fsg_MaxAbs(register Fixed a, register Fixed b)
{
MAKEABS(a);
MAKEABS(b);
return a > b ? a : b;
}
/*
* Call this guy before you use the matrix. He does two things:
* He folds any perspective-translation back into perspective,
* and then changes the [2][2] element from a Fract to a fixed.
* He then Finds the largest scaling value in the matrix and
* removes it from then and folds it into metricScalar.
*/
void fsg_ReduceMatrix(fsg_SplineKey* key)
{
Fixed a;
Fixed* matrix = &key->currentTMatrix.transform[0][0];
Fract bottom = matrix[8];
/*
* First, fold translation into perspective, if any.
*/
if (a = matrix[2])
{
matrix[0] -= LongMulDiv(a, matrix[6], bottom);
matrix[1] -= LongMulDiv(a, matrix[7], bottom);
}
if (a = matrix[5])
{
matrix[3] -= LongMulDiv(a, matrix[6], bottom);
matrix[4] -= LongMulDiv(a, matrix[7], bottom);
}
matrix[6] = matrix[7] = 0;
matrix[8] = FRACT2FIX(bottom); /* make this guy a fixed for XYMul routines */
/*
* Now suck out the biggest scaling factor.
* Should be folded into GetMatrixStretch, when I understand xformed-components <4>
*/
a = fsg_MaxAbs( *matrix++, *matrix++ ); matrix++;
a = fsg_MaxAbs( a, *matrix++ );
a = fsg_MaxAbs( a, *matrix );
if (a != ONEFIX)
{
*matrix = FixDiv(*matrix, a); --matrix;
*matrix = FixDiv(*matrix, a);
matrix -= 2;
*matrix = FixDiv(*matrix, a); --matrix;
*matrix = FixDiv(*matrix, a);
key->metricScalar = FixMul( key->metricScalar, a );
}
/* Now the matrix is smaller and metricScalar is bigger */
}
/*
* Return 45 degreeness
*/
static int8 fsg_Max45Trick(register Fixed x, register Fixed y, Fixed* stretch)
{
MAKEABS(x);
MAKEABS(y);
if (x < y) /* make sure x > y */
{
Fixed z = x;
x = y;
y = z;
}
if (x - y <= ALMOSTZERO)
{
*stretch = x << 1;
return true;
} else
{
*stretch = x;
return false;
}
}
/*
* Sets key->phaseShift to true if X or Y are at 45 degrees, flaging the outline
* to be moved in the low bit just before scan-conversion.
* Sets [xy]Stretch factors to be applied before hinting.
* <8> don't return need for point reversal
*/
static void fsg_GetMatrixStretch(fsg_SplineKey* key, Fixed* xStretch, Fixed* yStretch, transMatrix* trans)
{
register Fixed* matrix = &trans->transform[0][0];
register Fixed x, y;
x = *matrix++;
y = *matrix++;
key->phaseShift = fsg_Max45Trick(x, y, xStretch);
matrix++;
x = *matrix++;
y = *matrix;
key->phaseShift |= fsg_Max45Trick(x, y, yStretch);
}
/*
* Returns true if we have the identity matrix.
*/
static int8 fsg_Identity( register transMatrix *matrix )
{
{
register Fixed onefix = ONEFIX;
register Fixed* m = &matrix->transform[0][0];
if (*m++ != onefix) goto TRY_AGAIN;
if (*m++ != 0) goto TRY_AGAIN;
if (*m++ != 0) goto TRY_AGAIN;
if (*m++ != 0) goto TRY_AGAIN;
if (*m++ != onefix) goto TRY_AGAIN;
if (*m != 0) goto TRY_AGAIN;
goto EXIT_TRUE;
}
TRY_AGAIN:
{
register Fixed zero = ALMOSTZERO;
register Fixed negzero = -ALMOSTZERO;
register Fixed oneminuszero = ONEFIX-ALMOSTZERO;
register Fixed onepluszero = ONEFIX+ALMOSTZERO;
register Fixed* m = &matrix->transform[0][0];
if (*m < oneminuszero) goto EXIT_FALSE;
if (*m++ > onepluszero) goto EXIT_FALSE;
if (*m < negzero) goto EXIT_FALSE;
if (*m++ < zero) goto EXIT_FALSE;
if (*m < negzero) goto EXIT_FALSE;
if (*m++ < zero) goto EXIT_FALSE;
if (*m < negzero) goto EXIT_FALSE;
if (*m++ < zero) goto EXIT_FALSE;
if (*m < oneminuszero) goto EXIT_FALSE;
if (*m++ > onepluszero) goto EXIT_FALSE;
if (*m < negzero) goto EXIT_FALSE;
if (*m < zero) goto EXIT_FALSE;
goto EXIT_TRUE;
}
EXIT_FALSE:
return false;
EXIT_TRUE:
return true;
}
/*
* Neg xy stretch considered true
*/
static int16 fsg_MoreThanXYStretch( transMatrix *matrix )
{
register Fixed* m = &matrix->transform[0][0];
if (*m++ < 0) goto EXIT_TRUE;
if (*m++) goto EXIT_TRUE;
if (*m++) goto EXIT_TRUE;
if (*m++) goto EXIT_TRUE;
if (*m++ < 0) goto EXIT_TRUE;
if (*m) goto EXIT_TRUE;
return false;
EXIT_TRUE:
return true;
}
static boolean fsg_Non90Degrees( register transMatrix *matrix )
{
return ( (matrix->transform[0][0] || matrix->transform[1][1]) &&
(matrix->transform[1][0] || matrix->transform[0][1]) );
}
/******************** These three scale 26.6 to 26.6 ********************/
/*
* Fast Rounding (scaling )
*/
static F26Dot6 fnt_FRound(register fnt_GlobalGraphicStateType *globalGS, register F26Dot6 value)
{
register int32 N, D;
N = globalGS->nScale;
D = globalGS->dScale; D >>= 1;
FROUND( value, N, D, globalGS->shift );
return( value );
}
/*
* Slow Rounding (scaling )
*/
static F26Dot6 fnt_SRound(register fnt_GlobalGraphicStateType *globalGS, register F26Dot6 value)
{
register int32 N, D, dOver2;
N = globalGS->nScale;
D = globalGS->dScale;
dOver2 = D >> 1;
SROUND( value, N, D, dOver2 );
return( value );
}
/*
* Fixed Rounding (scaling ), really slow
*/
static F26Dot6 fnt_FixRound(fnt_GlobalGraphicStateType *globalGS, F26Dot6 value)
{
return( FixMul( value, globalGS->fixedScale ));
}
/********************************* End scaling utilities ************************/
/*
* counts number of low bits that are zero
* -- or --
* returns bit number of first ON bit
*/
static int fsg_CountLowZeros( register uint32 n )
{
int shift = 0;
uint32 one = 1;
for (shift = 0; !( n & one ); shift++)
n >>= 1;
return shift;
}
#define ISNOTPOWEROF2(n) ((n) & ((n)-1))
#define FITSINAWORD(n) ((n) < 32768)
/*
* fsg_GetShift
* return 2log of n if n is a power of 2 otherwise -1;
*/
static int fsg_GetShift( register uint32 n )
{
if (ISNOTPOWEROF2(n) || !n)
return -1;
else
return fsg_CountLowZeros( n );
}
/*
* fsg_InitInterpreterTrans <3>
*
* Computes [xy]TransMultiplier in global graphic state from matrix
* It leaves the actual matrix alone
* It then sets these key flags appropriately
* identityTransformation true == no need to run points through matrix
* imageState pixelsPerEm
* imageState Rotate flag if glyph is rotated
* imageState Stretch flag if glyph is stretched
* And these global GS flags
* identityTransformation true == no need to stretch in GetCVT, etc.
*/
void fsg_InitInterpreterTrans( register fsg_SplineKey *key )
{
#define STRETCH 2
register fnt_GlobalGraphicStateType *globalGS = GLOBALGSTATE(key);
transMatrix *trans = &key->currentTMatrix;
int32 pixelsPerEm = FIXROUND( key->interpScalar );
key->phaseShift = false;
key->imageState = pixelsPerEm > 0xFF ? 0xFF : pixelsPerEm;
if ( !(key->identityTransformation = fsg_Identity( trans )) )
{
fsg_GetMatrixStretch( key, &globalGS->xStretch, &globalGS->yStretch, trans); /*<8>*/
if( fsg_Non90Degrees( trans ) ) key->imageState |= ROTATED;
}
else
{
globalGS->xStretch = ONEFIX;
globalGS->yStretch = ONEFIX;
}
if( globalGS->xStretch != ONEFIX || globalGS->yStretch != ONEFIX )
key->imageState |= STRETCHED;
globalGS->identityTransformation = key->identityTransformation;
globalGS->non90DegreeTransformation = fsg_Non90Degrees( trans );
/* Use bit 1 of non90degreeTransformation to signify stretching. stretch = 2 */
if( trans->transform[0][0] == trans->transform[1][1] || trans->transform[0][0] == -trans->transform[1][1] )
globalGS->non90DegreeTransformation &= ~STRETCH;
else globalGS->non90DegreeTransformation |= STRETCH;
}
#define CANTAKESHIFT 0x02000000
/*
* fsg_ScaleCVT
*/
static void fsg_ScaleCVT( register fsg_SplineKey *key, int32 numCVT, register F26Dot6 *cvt, register int16 *srcCVT )
{
/* N is the Nummerator, and D is the Denominator */
/* V is used as a temporary Value */
register int32 N, D, V;
register F26Dot6 *endCvt = cvt + numCVT;
register fnt_GlobalGraphicStateType *globalGS = GLOBALGSTATE(key);
transMatrix *trans = &key->currentTMatrix;
N = key->interpScalar;
D = (int32)key->emResolution << 16;
/* We would like D to be perfectly dividable by 2 */
{
int shift = fsg_CountLowZeros( N | D ) - 1;
if (shift > 0)
{
N >>= shift;
D >>= shift;
}
}
if ( N < CANTAKESHIFT )
N <<= fnt_pixelShift;
else
D >>= fnt_pixelShift;
if ( FITSINAWORD( N ) )
{
register int16 shift = fsg_GetShift( D );
globalGS->nScale = N;
globalGS->dScale = D;
if ( shift >= 0 ) { /* FAST SCALE */
globalGS->ScaleFunc = fnt_FRound;
globalGS->shift = shift;
D >>= 1;
for (; cvt < endCvt; cvt++ ) {
V = *srcCVT++; FROUND( V, N, D, shift ); *cvt = V;
}
} else { /* MEDIUM SCALE */
register int32 dOver2 = D >> 1;
globalGS->ScaleFunc = fnt_SRound;
for (; cvt < endCvt; cvt++ ) {
V = *srcCVT++; SROUND( V, N, D, dOver2 ); *cvt = V;
}
}
} else { /* SLOW SCALE */
globalGS->ScaleFunc = fnt_FixRound;
globalGS->fixedScale = FixDiv( N, D );
{
int16 count = numCVT;
Fixed scaler = globalGS->fixedScale;
for (--count; count >= 0; --count)
*cvt++ = FixMul( *srcCVT++, scaler );
}
}
}
/*
* fsg_PreTransformGlyph <3>
*/
static void fsg_PreTransformGlyph( register fsg_SplineKey* key )
{
fnt_ElementType *elementPtr = &(key->elementInfoRec.interpreterElements[key->elementNumber]);
register int16 numPts = NUMBEROFPOINTS(elementPtr);
register Fixed scale;
scale = key->tInfo.xScale;
if ( scale != ONEFIX )
{
register int32* oox = elementPtr->oox;
register int16 count = numPts;
for ( --count; count >= 0; --count, oox++ )
*oox = FixMul( scale, *oox );
}
scale = key->tInfo.yScale;
if ( scale != ONEFIX )
{
register int32* ooy = elementPtr->ooy;
register int16 count = numPts;
for ( --count; count >= 0; --count, ooy++ )
*ooy = FixMul( scale, *ooy );
}
}
/*
* Styles for Cary
*/
static void fsg_CallStyleFunc( register fsg_SplineKey* key, register fnt_ElementType* elementPtr )
{
register fs_GlyphInfoType* outputPtr = key->outputPtr;
outputPtr->outlinesExist = key->glyphLength != 0;
outputPtr->xPtr = elementPtr->x;
outputPtr->yPtr = elementPtr->y;
outputPtr->startPtr = elementPtr->sp;
outputPtr->endPtr = elementPtr->ep;
outputPtr->onCurve = elementPtr->onCurve;
outputPtr->numberOfContours = elementPtr->nc;
key->styleFunc( key->outputPtr );
}
/*
* fsg_PostTransformGlyph <3>
*/
static void fsg_PostTransformGlyph(register fsg_SplineKey *key, transMatrix *trans)
{
register int16 numPts;
fnt_ElementType *elementPtr = &(key->elementInfoRec.interpreterElements[key->elementNumber]);
register Fixed xStretch, yStretch;
register F26Dot6* x;
register F26Dot6* y;
if ( key->identityTransformation ) return;
numPts = NUMBEROFPOINTS(elementPtr);
xStretch = key->tInfo.xScale;
yStretch = key->tInfo.yScale;
x = elementPtr->x;
y = elementPtr->y;
if ( xStretch == 0L || yStretch == 0L )
{
register F26Dot6 zero = 0;
LOOPDOWN(numPts)
*y++ = *x++ = zero;
}
else if ( !key->styleFunc )
{
if (fsg_HasPerspective( trans )) /* undo stretch, then apply matrix */
{
LOOPDOWN(numPts)
{
*x = FixDiv( *x, xStretch );
*y = FixDiv( *y, yStretch );;
fsg_Dot6XYMul( x++, y++, trans );
}
}
else /* unroll the common case. Fold stretch-undo and matrix together <4> */
{
Fixed m00 = FixDiv(trans->transform[0][0], xStretch);
Fixed m01 = FixDiv(trans->transform[0][1], xStretch);
Fixed m10 = FixDiv(trans->transform[1][0], yStretch);
Fixed m11 = FixDiv(trans->transform[1][1], yStretch);
LOOPDOWN(numPts)
{
register Fixed origx = *x;
register Fixed origy = *y;
*x++ = FixMul(m00, origx) + FixMul(m10, origy);
*y++ = FixMul(m01, origx) + FixMul(m11, origy);
}
}
}
else /* undo stretch, call stylefunc, then apply matrix */
{
register int16 count = numPts;
LOOPDOWN(count)
{
*x = FixDiv( *x, xStretch );
++x;
*y = FixDiv( *y, yStretch );
++y;
}
fsg_CallStyleFunc( key, elementPtr ); /* does this still work??? */
x = elementPtr->x;
y = elementPtr->y;
LOOPDOWN(numPts)
fsg_Dot6XYMul( x++, y++, trans );
}
/*<8> take out contour reversal */
}
/*
* fsg_LocalPostTransformGlyph <3>
*
* (1) Inverts the stretch from the CTM
* (2) Applies the local transformation passed in in the trans parameter
* (3) Applies the global stretch from the root CTM
* (4) Restores oox, ooy, oy, ox, and f.
*/
static void fsg_LocalPostTransformGlyph(register fsg_SplineKey *key, transMatrix *trans)
{
register int16 numPts, count;
register Fixed xScale, yScale;
register F26Dot6* x;
register F26Dot6* y;
fnt_ElementType* elementPtr = &(key->elementInfoRec.interpreterElements[key->elementNumber]);
if ( !fsg_MoreThanXYStretch( trans ) ) return;
numPts = count = NUMBEROFPOINTS(elementPtr);
xScale = key->tInfo.xScale;
yScale = key->tInfo.yScale;
x = elementPtr->x;
y = elementPtr->y;
if ( xScale == 0L || yScale == 0L )
{
register F26Dot6 zero = 0;
LOOPDOWN(numPts)
*x++ = *y++ = zero;
}
else
{
LOOPDOWN(numPts)
{
*x = FixDiv( *x, xScale );
*y = FixDiv( *y, yScale );
fsg_Dot6XYMul( x++, y++, trans );
}
}
xScale = key->globalTInfo.xScale;
yScale = key->globalTInfo.yScale;
if ( xScale != ONEFIX )
{
x = elementPtr->x;
numPts = count;
LOOPDOWN(numPts)
{
*x = FixMul( xScale, *x );
x++;
}
}
if ( yScale != ONEFIX )
{
y = elementPtr->y;
numPts = count;
LOOPDOWN(numPts)
{
*y = FixMul( yScale, *y );
y++;
}
}
fsg_CopyElementBackwards( &(key->elementInfoRec.interpreterElements[GLYPHELEMENT]) );
x = elementPtr->oox;
y = elementPtr->ooy;
LOOPDOWN(count)
fsg_Dot6XYMul( x++, y++, trans );
}
/*
* fsg_ShiftChar
*
* Shifts a character <3>
*/
static void fsg_ShiftChar(register fsg_SplineKey *key, register F26Dot6 xShift, register F26Dot6 yShift, int32 lastPoint)
{
fnt_ElementType *elementPtr = &(key->elementInfoRec.interpreterElements[key->elementNumber]);
if ( xShift )
{
register F26Dot6* x = elementPtr->x;
register LoopCount loop;
for (loop = lastPoint; loop >= 0; --loop)
*x++ += xShift;
}
if ( yShift )
{
register F26Dot6* y = elementPtr->y;
register F26Dot6* lasty = y + lastPoint;
while (y <= lasty)
*y++ += yShift;
}
}
/*
* fsg_ScaleChar <3>
*
* Scales a character and the advancewidth + leftsidebearing.
*/
static void fsg_ScaleChar( register fsg_SplineKey *key )
{
fnt_ElementType *elementPtr = &(key->elementInfoRec.interpreterElements[key->elementNumber]);
fnt_GlobalGraphicStateType *globalGS = GLOBALGSTATE(key);
int16 numPts = NUMBEROFPOINTS(elementPtr);
if ( globalGS->ScaleFunc == fnt_FRound )
{
register int32* oop = elementPtr->oox;
register F26Dot6* p = elementPtr->x;
register int16 shift = globalGS->shift;
register int32 N = globalGS->nScale;
register int32 D = globalGS->dScale >> 1;
register int32 V;
register int16 count = numPts; /* do I get this many registers? */
LOOPDOWN(count)
{
V = *oop++; FROUND( V, N, D, shift ); *p++ = V;
}
p = elementPtr->y;
oop = elementPtr->ooy;
count = numPts;
LOOPDOWN(count)
{
V = *oop++; FROUND( V, N, D, shift ); *p++ = V;
}
}
else if ( globalGS->ScaleFunc == fnt_SRound )
{
register int32* oop = elementPtr->oox;
register F26Dot6* p = elementPtr->x;
register int32 N = globalGS->nScale;
register int32 D = globalGS->dScale;
register int32 V;
register int32 dOver2 = D >> 1;
register int16 count = numPts;
LOOPDOWN(count)
{
V = *oop++; SROUND( V, N, D, dOver2 ); *p++ = V;
}
p = elementPtr->y;
oop = elementPtr->ooy;
count = numPts;
LOOPDOWN(count)
{
V = *oop++; SROUND( V, N, D, dOver2 ); *p++ = V;
}
}
else
{
register int32* oop = elementPtr->oox;
register F26Dot6* p = elementPtr->x;
register int32 N = globalGS->fixedScale;
register int16 count = numPts;
LOOPDOWN(count)
*p++ = FixMul( *oop++, N );
p = elementPtr->y;
oop = elementPtr->ooy;
count = numPts;
LOOPDOWN(count)
*p++ = FixMul( *oop++, N );
}
}
/*
* fsg_SetUpElement
*/
void fsg_SetUpElement(fsg_SplineKey *key, int32 n)
{
register int8 *workSpacePtr = key->memoryBases[WORK_SPACE_BASE];
register fnt_ElementType *elementPtr;
register fsg_OffsetInfo *offsetPtr;
offsetPtr = &(key->elementInfoRec.offsets[n]);
elementPtr = &(key->elementInfoRec.interpreterElements[n]);
elementPtr->x = (int32 *)(workSpacePtr + offsetPtr->newXOffset);
elementPtr->y = (int32 *)(workSpacePtr + offsetPtr->newYOffset);
elementPtr->ox = (int32 *)(workSpacePtr + offsetPtr->scaledXOffset);
elementPtr->oy = (int32 *)(workSpacePtr + offsetPtr->scaledYOffset);
elementPtr->oox = (int32 *)(workSpacePtr + offsetPtr->oldXOffset);
elementPtr->ooy = (int32 *)(workSpacePtr + offsetPtr->oldYOffset);
elementPtr->sp = (int16 *)(workSpacePtr + offsetPtr->startPointOffset);
elementPtr->ep = (int16 *)(workSpacePtr + offsetPtr->endPointOffset);
elementPtr->onCurve = (uint8 *)(workSpacePtr + offsetPtr->onCurveOffset);
elementPtr->f = (uint8 *)(workSpacePtr + offsetPtr->interpreterFlagsOffset);
if ( n == TWILIGHTZONE ) {
/* register int i, j; */
elementPtr->sp[0] = 0;
elementPtr->ep[0] = key->maxProfile.maxTwilightPoints-1;
elementPtr->nc = MAX_TWILIGHT_CONTOURS;
}
}
/*
* fsg_IncrementElement
*/
void fsg_IncrementElement(fsg_SplineKey *key, int32 n, int32 numPoints, int32 numContours)
{
register fnt_ElementType *elementPtr;
elementPtr = &(key->elementInfoRec.interpreterElements[n]);
elementPtr->x += numPoints;
elementPtr->y += numPoints;
elementPtr->ox += numPoints;
elementPtr->oy += numPoints;
elementPtr->oox += numPoints;
elementPtr->ooy += numPoints;
elementPtr->sp += numContours;
elementPtr->ep += numContours;
elementPtr->onCurve += numPoints;
elementPtr->f += numPoints;
}
/*
* fsg_ZeroOutTwilightZone <3>
*/
static void fsg_ZeroOutTwilightZone(fsg_SplineKey *key)
{
register int16 origCount = key->maxProfile.maxTwilightPoints;
register F26Dot6 zero = 0;
fnt_ElementType* elementPtr = &(key->elementInfoRec.interpreterElements[TWILIGHTZONE]);
{
register F26Dot6* x = elementPtr->x;
register F26Dot6* y = elementPtr->y;
register int16 count = origCount;
LOOPDOWN(count)
{
*x++ = zero;
*y++ = zero;
}
}
{
register F26Dot6* ox = elementPtr->ox;
register F26Dot6* oy = elementPtr->oy;
LOOPDOWN(origCount)
{
*ox++ = zero;
*oy++ = zero;
}
}
}
/*
* Assign pgmList[] for each pre program
*/
static void fsg_SetUpProgramPtrs(fsg_SplineKey* key, fnt_GlobalGraphicStateType* globalGS)
{
switch (globalGS->pgmIndex) {
case PREPROGRAM:
globalGS->pgmList[PREPROGRAM] = (uint8*)sfnt_GetTablePtr(key, sfnt_preProgram, false);
case FONTPROGRAM:
globalGS->pgmList[FONTPROGRAM] = (uint8*)sfnt_GetTablePtr(key, sfnt_fontProgram, false);
}
#ifdef DEBUG
globalGS->maxp = &key->maxProfile;
globalGS->cvtCount = key->cvtCount;
#endif
}
/*
* Release pgmList[] for each pre program.
* Important that the order be reversed from SetUpProgramPtrs
* so that memory fragments are allocated and release in stack order
*/
#ifdef RELEASE_MEM_FRAG
static void fsg_ReleaseProgramPtrs(fsg_SplineKey* key, fnt_GlobalGraphicStateType* globalGS)
{
switch (globalGS->pgmIndex) {
case FONTPROGRAM:
SOFTRELEASESFNTFRAG(key, globalGS->pgmList[FONTPROGRAM]); /* <12-jlf> */
break;
case PREPROGRAM:
SOFTRELEASESFNTFRAG(key, globalGS->pgmList[FONTPROGRAM]); /* <12-jlf> */
SOFTRELEASESFNTFRAG(key, globalGS->pgmList[PREPROGRAM]); /* <12-jlf> */
}
}
#endif
static void fsg_SetUpTablePtrs(fsg_SplineKey* key)
{
char** memoryBases = key->memoryBases;
char* private_FontSpacePtr = memoryBases[PRIVATE_FONT_SPACE_BASE];
fnt_GlobalGraphicStateType* globalGS = GLOBALGSTATE(key);
switch (globalGS->pgmIndex) {
case PREPROGRAM:
globalGS->controlValueTable = (F26Dot6*)(private_FontSpacePtr + key->offset_controlValues);
case FONTPROGRAM:
globalGS->store = (F26Dot6*)(private_FontSpacePtr + key->offset_storage);
globalGS->funcDef = (fnt_funcDef*)(private_FontSpacePtr + key->offset_functions);
globalGS->instrDef = (fnt_instrDef*)(private_FontSpacePtr + key->offset_instrDefs);
globalGS->stackBase = (F26Dot6*)(memoryBases[WORK_SPACE_BASE] + key->elementInfoRec.stackBaseOffset);
globalGS->function = (FntFunc*)(memoryBases[VOID_FUNC_PTR_BASE]);
}
}
/*
* fsg_RunPreProgram
*
* Runs the pre-program and scales the control value table
*
*/
static int fsg_RunPreProgram(register fsg_SplineKey *key, voidFunc traceFunc)
{
int32 offsetT;
unsigned lengthT;
int result;
uint8* private_FontSpacePtr = (uint8*)key->memoryBases[PRIVATE_FONT_SPACE_BASE];
F26Dot6* cvt = (F26Dot6*)(private_FontSpacePtr + key->offset_controlValues);
fnt_GlobalGraphicStateType *globalGS = GLOBALGSTATE(key);
int32 numCvt;
sfnt_ControlValue* cvtSrc = (sfnt_ControlValue*)sfnt_GetTablePtr( key, sfnt_controlValue, false );
sfnt_GetOffsetAndLength( key, &offsetT, &lengthT, sfnt_controlValue );
numCvt = lengthT / sizeof(sfnt_ControlValue);
/* Set up the engine compensation array for the interpreter */
/* This will be indexed into by the booleans in some instructions */
globalGS->engine[0] = globalGS->engine[3] = 0; /* Grey and ? distance */
globalGS->engine[1] = FIXEDTODOT6(FIXEDSQRT2 - key->pixelDiameter); /* Black distance */
globalGS->engine[2] = -globalGS->engine[1]; /* White distance */
globalGS->init = true;
globalGS->pixelsPerEm = FIXROUND( key->interpScalar );
globalGS->pointSize = FIXROUND( key->fixedPointSize );
globalGS->fpem = key->interpScalar;
if( result = fsg_SetDefaults( key )) return result; /* Set graphic state to default values */
globalGS->localParBlock = globalGS->defaultParBlock; /* copy gState parameters */
key->globalTInfo.xScale = key->tInfo.xScale = globalGS->xStretch;
key->globalTInfo.yScale = key->tInfo.yScale = globalGS->yStretch;
fsg_ScaleCVT( key, numCvt, cvt, cvtSrc );
SOFTRELEASESFNTFRAG(key, cvtSrc); /* <12-jlf> */
globalGS->pgmIndex = PREPROGRAM;
fsg_SetUpProgramPtrs(key, globalGS);
sfnt_GetOffsetAndLength( key, &offsetT, &lengthT, sfnt_preProgram );
/** TWILIGHT ZONE ELEMENT **/
fsg_SetUpElement( key, TWILIGHTZONE );
fsg_ZeroOutTwilightZone( key );
fsg_SetUpTablePtrs(key);
#ifdef DEBUG
globalGS->glyphProgram = false;
#endif
result = fnt_Execute( key->elementInfoRec.interpreterElements, globalGS->pgmList[PREPROGRAM],
globalGS->pgmList[PREPROGRAM] + lengthT, globalGS, traceFunc );
if( !(globalGS->localParBlock.instructControl & DEFAULTFLAG) )
globalGS->defaultParBlock = globalGS->localParBlock; /* change default parameters */
#ifdef RELEASE_MEM_FRAG
fsg_ReleaseProgramPtrs(key, globalGS);
#endif
return result;
}
/*
* All this guy does is record FDEFs and IDEFs, anything else is ILLEGAL
*/
int fsg_RunFontProgram( fsg_SplineKey* key, voidFunc traceFunc )
{
int32 offsetT;
unsigned lengthT;
int result;
fnt_GlobalGraphicStateType *globalGS = GLOBALGSTATE(key);
globalGS->instrDefCount = 0; /* none allocated yet, always do this, even if there's no fontProgram */
sfnt_GetOffsetAndLength( key, &offsetT, &lengthT, sfnt_fontProgram );
if (lengthT)
{
globalGS->pgmIndex = FONTPROGRAM;
fsg_SetUpProgramPtrs(key, globalGS);
fsg_SetUpTablePtrs(key);
#ifdef DEBUG
globalGS->glyphProgram = false;
#endif
result = fnt_Execute( key->elementInfoRec.interpreterElements, globalGS->pgmList[FONTPROGRAM],
globalGS->pgmList[FONTPROGRAM] + lengthT, globalGS, traceFunc );
#ifdef RELEASE_MEM_FRAG
fsg_ReleaseProgramPtrs(key, globalGS);
#endif
return result;
}
return NO_ERR;
}
/* Set default values for all variables in globalGraphicsState DefaultParameterBlock
* Eventually, we should provide for a Default preprogram that could optionally be
* run at this time to provide a different set of default values.
*/
int fsg_SetDefaults( fsg_SplineKey* key )
{
register fnt_GlobalGraphicStateType *globalGS = GLOBALGSTATE(key);
register fnt_ParameterBlock *par = &globalGS->defaultParBlock;
par->RoundValue = fnt_RoundToGrid;
par->minimumDistance = fnt_pixelSize;
par->wTCI = fnt_pixelSize * 17 / 16;
par->sWCI = 0;
par->sW = 0;
par->autoFlip = true;
par->deltaBase = 9;
par->deltaShift = 3;
par->scanControl = 0;
par->instructControl = 0;
return 0;
}
/*
* Runs the pre program and scales the control value table
*/
int fsg_NewTransformation(register fsg_SplineKey *key, voidFunc traceFunc)
{
/* Run the pre program and scale the control value table */
key->executePrePgm = false;
return fsg_RunPreProgram( key, traceFunc );
}
/*
* fsg_InnerGridFit
*/
int fsg_InnerGridFit(register fsg_SplineKey *key, int16 useHints, voidFunc traceFunc,
sfnt_BBox *bbox, int32 sizeOfInstructions, uint8 *instructionPtr, int finalCompositePass)
{
fnt_GlobalGraphicStateType* globalGS = GLOBALGSTATE(key);
register fnt_ElementType *elementPtr;
/* this is so we can allow recursion */
int32 *save_x, *save_y, *save_ox, *save_oy, *save_oox, *save_ooy;
int16 *save_sp, *save_ep;
uint8 *save_onCurve, *save_f;
int16 save_nc, numPts;
elementPtr = &(key->elementInfoRec.interpreterElements[GLYPHELEMENT]);
if ( finalCompositePass ) {
/* save stuff we are going to muck up below, so we can recurse */
save_x = elementPtr->x;
save_y = elementPtr->y;
save_ox = elementPtr->ox;
save_oy = elementPtr->oy;
save_oox = elementPtr->oox;
save_ooy = elementPtr->ooy;
save_sp = elementPtr->sp;
save_ep = elementPtr->ep;
save_onCurve = elementPtr->onCurve;
save_f = elementPtr->f;
save_nc = elementPtr->nc;
elementPtr->nc = key->totalContours;
fsg_SetUpElement( key, GLYPHELEMENT ); /* Set it up again so we can process as one glyph */
}
key->elementNumber = GLYPHELEMENT;
numPts = NUMBEROFPOINTS(elementPtr);
{
F26Dot6 xMinMinusLSB = bbox->xMin - key->nonScaledLSB;
/* left side bearing point */
elementPtr->oox[numPts-PHANTOMCOUNT+LEFTSIDEBEARING] = xMinMinusLSB;
elementPtr->ooy[numPts-PHANTOMCOUNT+LEFTSIDEBEARING] = 0;
/* origin left side bearing point */
elementPtr->oox[numPts-PHANTOMCOUNT+ORIGINPOINT] = xMinMinusLSB;
elementPtr->ooy[numPts-PHANTOMCOUNT+ORIGINPOINT] = 0;
/* left edge point */
elementPtr->oox[numPts-PHANTOMCOUNT+LEFTEDGEPOINT] = bbox->xMin;
elementPtr->ooy[numPts-PHANTOMCOUNT+LEFTEDGEPOINT] = 0;
/* right side bearing point */
elementPtr->oox[numPts-PHANTOMCOUNT+RIGHTSIDEBEARING] = xMinMinusLSB + key->nonScaledAW;
elementPtr->ooy[numPts-PHANTOMCOUNT+RIGHTSIDEBEARING] = 0;
}
key->tInfo.xScale = globalGS->xStretch;
key->tInfo.yScale = globalGS->yStretch;
/* Pretransform, scale, and copy */
if ( finalCompositePass)
{
register GlobalGSScaleFunc ScaleFunc = globalGS->ScaleFunc;
register int32 j;
register Fixed scale = key->tInfo.xScale;
for ( j = numPts - PHANTOMCOUNT; j < numPts; j++ )
{
if (scale != ONEFIX)
elementPtr->oox[j] = FixMul( scale, elementPtr->oox[j] );
elementPtr->ox[j] = ScaleFunc( globalGS, elementPtr->oox[j] );
elementPtr->x[j] = elementPtr->ox[j];
}
scale = key->tInfo.yScale;
for ( j = numPts - PHANTOMCOUNT; j < numPts; j++ )
{
if (scale != ONEFIX)
elementPtr->ooy[j] = FixMul( scale, elementPtr->ooy[j] );
elementPtr->oy[j] = ScaleFunc( globalGS, elementPtr->ooy[j] );
elementPtr->y[j] = elementPtr->oy[j];
}
}
else
{
fsg_PreTransformGlyph( key );
fsg_ScaleChar( key );
}
if ( useHints ) { /* AutoRound */
int32 oldLeftOrigin, newLeftOrigin, xShift;
newLeftOrigin = oldLeftOrigin = elementPtr->x[numPts-PHANTOMCOUNT+LEFTSIDEBEARING];
newLeftOrigin += fnt_pixelSize/2; /* round to a pixel boundary */
newLeftOrigin &= ~(fnt_pixelSize-1);
xShift = newLeftOrigin - oldLeftOrigin;
if ( !finalCompositePass ) {
/* We can't shift if it is the final composite pass */
fsg_ShiftChar( key, xShift, 0L, NUMBEROFPOINTS(elementPtr) - 1 );
/* Now the distance from the left origin point to the character is exactly lsb */
}
fsg_CopyElementBackwards( elementPtr );
/* Fill in after fsg_ShiftChar(), since this point should not be shifted. */
elementPtr->x[numPts-PHANTOMCOUNT+LEFTSIDEBEARING] = newLeftOrigin;
elementPtr->ox[numPts-PHANTOMCOUNT+LEFTSIDEBEARING] = newLeftOrigin;
{
F26Dot6 width = ShortMulDiv( key->interpScalar,
elementPtr->oox[numPts-PHANTOMCOUNT+RIGHTSIDEBEARING]
- elementPtr->oox[numPts-PHANTOMCOUNT+LEFTSIDEBEARING],
key->emResolution ) + (1L << 9) >> 10;
elementPtr->x[numPts-PHANTOMCOUNT+RIGHTSIDEBEARING] =
elementPtr->x[numPts-PHANTOMCOUNT+LEFTSIDEBEARING] + (width + (1 << 5)) & ~63;
}
}
globalGS->init = false;
globalGS->pixelsPerEm = FIXROUND( key->interpScalar );
globalGS->pointSize = FIXROUND( key->fixedPointSize );
globalGS->fpem = key->interpScalar;
globalGS->localParBlock = globalGS->defaultParBlock; /* default parameters for glyphs */
if ( useHints && sizeOfInstructions > 0 )
{
int32 result;
if ( finalCompositePass )
fsg_SnapShotOutline( key, elementPtr, numPts );
globalGS->pgmIndex = PREPROGRAM;
fsg_SetUpProgramPtrs(key, globalGS);
fsg_SetUpTablePtrs(key);
#ifdef DEBUG
globalGS->glyphProgram = true;
#endif
result = fnt_Execute( key->elementInfoRec.interpreterElements, instructionPtr,
instructionPtr + sizeOfInstructions, globalGS, traceFunc );
#ifdef RELEASE_MEM_FRAG
fsg_ReleaseProgramPtrs(key, globalGS);
#endif
if (result)
return result;
}
/* Now make everything into one big glyph. */
if ( key->weGotComponents && !finalCompositePass ) {
int16 n, ctr;
int32 xOffset, yOffset;
/* Fix start points and end points */
n = 0;
if ( key->totalComponents != GLYPHELEMENT )
n += elementPtr->ep[-1] + 1; /* number of points */
if ( !key->localTIsIdentity )
fsg_LocalPostTransformGlyph( key, &key->localTMatrix );
if ( key->compFlags & ARGS_ARE_XY_VALUES ) {
xOffset = key->arg1;
yOffset = key->arg2;
xOffset = globalGS->ScaleFunc( globalGS, xOffset );
yOffset = globalGS->ScaleFunc( globalGS, yOffset );
if ( !key->identityTransformation ) {
/* transform offsets into this funky domain */
xOffset = FixMul( globalGS->xStretch, xOffset );
yOffset = FixMul( globalGS->yStretch, yOffset );
}
if ( key->compFlags & ROUND_XY_TO_GRID ) {
xOffset += fnt_pixelSize/2; xOffset &= ~(fnt_pixelSize-1);
yOffset += fnt_pixelSize/2; yOffset &= ~(fnt_pixelSize-1);
}
} else {
xOffset = elementPtr->x[ key->arg1 - n ] - elementPtr->x[ key->arg2 ];
yOffset = elementPtr->y[ key->arg1 - n ] - elementPtr->y[ key->arg2 ];
}
/* shift all the points == Align the component */
fsg_ShiftChar( key, xOffset, yOffset, NUMBEROFPOINTS(elementPtr) - 1 );
/*
* Remember this component's phantom points after we've munged it
*/
if (key->compFlags & USE_MY_METRICS)
{
ArrayIndex index = elementPtr->ep[ elementPtr->nc - 1 ] + 1;
F26Dot6* x = &elementPtr->x[ index ];
F26Dot6* y = &elementPtr->y[ index ];
key->devLSB.x = *x++;
key->devLSB.y = *y++;
key->devRSB.x = *x;
key->devRSB.y = *y;
key->useMyMetrics = true;
}
/* reverse contours if needed; <8> not any more */
if ( key->totalComponents != GLYPHELEMENT ) {
/* Fix start points and end points */
for ( ctr = 0; ctr < elementPtr->nc; ctr++ ) {
elementPtr->sp[ctr] += n;
elementPtr->ep[ctr] += n;
}
}
}
if ( finalCompositePass )
{
/*
* This doesn't work recursively yet, but then again, nothing does.
*/
if (key->useMyMetrics)
{
ArrayIndex index = elementPtr->ep[ elementPtr->nc - 1 ] + 1;
F26Dot6* x = &elementPtr->x[ index ];
F26Dot6* y = &elementPtr->y[ index ];
*x++ = key->devLSB.x;
*y++ = key->devLSB.y;
*x = key->devRSB.x;
*y = key->devRSB.y;
key->useMyMetrics = false;
}
elementPtr->x = save_x;
elementPtr->y = save_y;
elementPtr->ox = save_ox;
elementPtr->oy = save_oy;
elementPtr->oox = save_oox;
elementPtr->ooy = save_ooy;
elementPtr->sp = save_sp;
elementPtr->ep = save_ep;
elementPtr->onCurve = save_onCurve;
elementPtr->f = save_f;
elementPtr->nc = save_nc;
}
key->scanControl = globalGS->localParBlock.scanControl; /*rwb */
return NO_ERR;
}
/*
* Internal routine. changed to use pointer <3>
*/
static void fsg_InitLocalT( fsg_SplineKey* key )
{
register Fixed* p = &key->localTMatrix.transform[0][0];
register Fixed one = ONEFIX;
register Fixed zero = 0;
*p++ = one;
*p++ = zero;
*p++ = zero;
*p++ = zero;
*p++ = one;
*p++ = zero;
*p++ = zero;
*p++ = zero;
*p = one; /* Internal routines assume ONEFIX here, though client assumes ONEFRAC */
}
/*
* fsg_GridFit
*/
int fsg_GridFit( register fsg_SplineKey* key, voidFunc traceFunc, boolean useHints )
{
int result;
int16 elementCount;
fnt_GlobalGraphicStateType* globalGS = GLOBALGSTATE(key);
fsg_SetUpElement( key, TWILIGHTZONE );/* TWILIGHT ZONE ELEMENT */
elementCount = GLYPHELEMENT;
key->weGotComponents = false;
key->compFlags = NON_OVERLAPPING;
key->useMyMetrics = false;
/* This also calls fsg_InnerGridFit() .*/
if( globalGS->localParBlock.instructControl & NOGRIDFITFLAG ) useHints = false;
key->localTIsIdentity = true;
fsg_InitLocalT( key );
if ( (result = sfnt_ReadSFNT( key, &elementCount, key->glyphIndex, useHints, traceFunc )) == NO_ERR )
{
key->elementInfoRec.interpreterElements[GLYPHELEMENT].nc = key->totalContours;
if ( key->weGotComponents )
fsg_SetUpElement( key, GLYPHELEMENT ); /* Set it up again so we can transform */
fsg_PostTransformGlyph( key, &key->currentTMatrix );
}
return result;
}