You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1630 lines
47 KiB
1630 lines
47 KiB
/*
|
|
* Adobe Universal Font Library
|
|
*
|
|
* Copyright (c) 1996 Adobe Systems Inc.
|
|
* All Rights Reserved
|
|
*
|
|
* UFOttt1.c
|
|
*
|
|
*
|
|
* $Header:
|
|
*/
|
|
|
|
/* -------------------------------------------------------------------------
|
|
Header Includes
|
|
--------------------------------------------------------------------------- */
|
|
#include "UFOTTT1.h"
|
|
#include "UFLMem.h"
|
|
#include "UFLErr.h"
|
|
#include "UFLPriv.h"
|
|
#include "UFLStd.h"
|
|
#include "UFLMath.h"
|
|
#include "ParseTT.h"
|
|
#include "UFLVm.h"
|
|
|
|
#if UNIX
|
|
#include <sys/varargs.h>
|
|
#else
|
|
#include <stdarg.h>
|
|
#endif
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Constant
|
|
--------------------------------------------------------------------------- */
|
|
|
|
#define kEExecKey 55665
|
|
#define kCSKey 4330
|
|
|
|
/**************************************************************************************
|
|
TYPE 1 commands for use with CharString(). The high word contains the
|
|
number of operands on the stack, and the loword contains the encoding
|
|
of the command. For two byte commands the LSB of the low word contains
|
|
12 decimal and the MSB of the low word contains the second byte of the
|
|
code. See Chapter 6 of the Black Book for further details.
|
|
***************************************************************************************/
|
|
#define kT1cscStartChar 0xFFFFFFFF /* dummy command to signal start of character definition. */
|
|
|
|
/*
|
|
y dy hstem(1). Declares the vertical range of a horizontal stem zone b/w the y coordinates y and y+dy,
|
|
where y is relative to the y coordinate of the left sidebearing point.
|
|
*/
|
|
#define kT1cscHStem 0x00020001
|
|
|
|
/*
|
|
x dx vstem(3). Declares the horizontal range of a vertical stem zone b/w the x coordinates x and x+dx,
|
|
where x is relative to the x coordinate of the left sidebearing point.
|
|
*/
|
|
#define kT1cscVStem 0x00020003
|
|
|
|
/*
|
|
dy vmoveto(4). For vertical moveto. This is equivalent to 0 dy rmoveto.
|
|
*/
|
|
#define kT1cscVMoveTo 0x00010004
|
|
|
|
/*
|
|
dx dy rlineto(5). Behaves like rlineto in the PostScript language.
|
|
*/
|
|
#define kT1cscRLineTo 0x00020005
|
|
|
|
/*
|
|
dx hlineto(6). For horizontal lineto. Equivalent to dx 0 rlineto.
|
|
*/
|
|
#define kT1cscHLineTo 0x00010006
|
|
|
|
/*
|
|
dy vlineto(7). For vertical lineto. Equivalent to 0 dy rlineto.
|
|
*/
|
|
#define kT1cscVLineTo 0x00010007
|
|
|
|
/*
|
|
dx1 dy1 dx2 dy2 dx3 dy3 rrcurveto(8). For relative rcuveto.
|
|
The arguments to the command are relative to each other.
|
|
Equivalent to dx1 dy1 (dx1+ dx2) (dy1 + dy2) (dx1+ dx2 + dx3) (dy1 + dy2 + dy3) rcurveto.
|
|
*/
|
|
#define kT1cscRRCurveTo 0x00060008
|
|
|
|
/*
|
|
closepath(9). Close a subpath.
|
|
*/
|
|
#define kT1cscClosePath 0x00000009
|
|
|
|
/*
|
|
sbx sby wx wy sbw (12 7). Sets the left sidebearing point to (sbx, sby) and sets
|
|
the character width vetor to (wx, wy) in character space.
|
|
*/
|
|
#define kT1cscSBW 0x0004070C
|
|
|
|
/*
|
|
sbx wx hsbw (13). Sets the left sidebearing point at (sbx, 0) and sets the
|
|
character width vector to (wx, 0) in character space.
|
|
*/
|
|
#define kT1cscHSBW 0x0002000D
|
|
|
|
/*
|
|
endchar(14). Finishes a charstring outline definition and
|
|
must be the last command in a character's outline.
|
|
*/
|
|
#define kT1cscEndChar 0x0000000E
|
|
|
|
/*
|
|
dx dy rmoveto(15). Behaves like rmoveto in PostScript.
|
|
*/
|
|
#define kT1cscRMoveTo 0x00020015
|
|
|
|
/*
|
|
dx hmoveto(22). For horizontal moveto. Equivalent to dx 0 rmoveto.
|
|
*/
|
|
#define kT1cscHMoveTo 0x00010016
|
|
|
|
/*
|
|
dy1 dx2 dy2 dx3 vhcurveto(30). For vertical-horizontal curveto.
|
|
Equivalent to 0 dy1 dx2 dy2 dx3 0 rrcureveto.
|
|
*/
|
|
#define kT1cscVHCurveTo 0x0004001E
|
|
|
|
/*
|
|
dx1 dx2 dy2 dy3 hvcurveto(31). For horizontal-vertical curveto.
|
|
Equivalent to dx1 0 dx2 dy2 0 dy3 rrcurveto.
|
|
*/
|
|
#define kT1cscHVCurveTo 0x0004001F
|
|
|
|
/***********************************************************************
|
|
CS Data buffer size
|
|
************************************************************************/
|
|
#define kCSBufInitSize 1024 /* Initial size of TTT1CSBuf */
|
|
#define kCSGrow 512 /* Amount to grow CharString buffer */
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Global variables
|
|
--------------------------------------------------------------------------- */
|
|
|
|
/* The 4 random number that is output at the beginning of a charstring. See blackbook. */
|
|
static unsigned char randomBytes[] = { 71, 36, 181, 202 };
|
|
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Macros
|
|
--------------------------------------------------------------------------- */
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Implementation
|
|
--------------------------------------------------------------------------- */
|
|
UFLErrCode CharString( TTT1FontStruct *pFont, unsigned long cmd, ...);
|
|
|
|
/************************************** CSBuf Implementation **********************************************/
|
|
static CSBufStruct *
|
|
CSBufInit(
|
|
const UFLMemObj *pMem
|
|
)
|
|
{
|
|
CSBufStruct *p;
|
|
|
|
p = (CSBufStruct *)UFLNewPtr( pMem, sizeof( *p ) );
|
|
if ( p )
|
|
{
|
|
p->pBuf = (char*) UFLNewPtr( pMem, kCSBufInitSize );
|
|
if ( p->pBuf )
|
|
{
|
|
p->ulSize = kCSBufInitSize;
|
|
p->pEnd = p->pBuf + kCSBufInitSize;
|
|
p->pPos = p->pBuf;
|
|
p->pMemObj = (UFLMemObj *)pMem;
|
|
}
|
|
else
|
|
{
|
|
UFLDeletePtr( pMem, p );
|
|
p = 0;
|
|
}
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
static void
|
|
CSBufCleanUp(
|
|
CSBufStruct *h
|
|
)
|
|
{
|
|
if ( h )
|
|
{
|
|
if ( h->pBuf )
|
|
{
|
|
UFLDeletePtr( h->pMemObj, h->pBuf );
|
|
h->pBuf = 0;
|
|
}
|
|
UFLDeletePtr( h->pMemObj, h );
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CSBufGrowBuffer
|
|
*
|
|
* Function: Grows the currently allocated CharString buffer by
|
|
* kCSGrow bytes.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static UFLBool
|
|
CSBufGrowBuffer(
|
|
CSBufStruct *h
|
|
)
|
|
{
|
|
UFLBool retVal;
|
|
|
|
unsigned long len = (unsigned long)CSBufCurrentLen( h );
|
|
|
|
retVal = UFLEnlargePtr( h->pMemObj, (void**)&h->pBuf, (unsigned long)(CSBufCurrentSize( h ) + kCSGrow), 1 );
|
|
if ( retVal )
|
|
{
|
|
h->ulSize += kCSGrow;
|
|
h->pEnd = h->pBuf + h->ulSize;
|
|
h->pPos = h->pBuf + len;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
/****************************************************************
|
|
*
|
|
* CSBufCheckSize
|
|
*
|
|
* Function: Check to see if the current size of the
|
|
* buffer can fit the len bytes data, if not, grow the
|
|
* buffer
|
|
*
|
|
**************************************************************/
|
|
static UFLBool
|
|
CSBufCheckSize(
|
|
CSBufStruct *h,
|
|
const unsigned long len
|
|
)
|
|
{
|
|
UFLBool retVal = 1;
|
|
|
|
while ( retVal && ((unsigned long)CSBufFreeLen( h ) < len) )
|
|
{
|
|
retVal = CSBufGrowBuffer( h );
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/****************************************************************
|
|
*
|
|
* CSBufAddNumber
|
|
*
|
|
* Function: Converts a long int into the Type 1 representation of
|
|
* numbers (described in Chapter 6 of the Black Book.)
|
|
* The basic idea is they have a few special ranges
|
|
* where they can represent the long in < 4 bytes and
|
|
* store a long + prefix for everything else.
|
|
*
|
|
* The if statements show the range of numbers and the
|
|
* body of the if statements compute the representation
|
|
* for that range. The formulas were derived by reversing
|
|
* the formulas given in the book (which tells how to convert
|
|
* an encoded number back to a long.) As an example take the
|
|
* 108 <= dw <= 1131 range. The derivation is as follows:
|
|
*
|
|
* dw = ((v - 247) * 256) + w + 108. Find v,w given dw.
|
|
* dw - 108 = ((v - 247) * 256) + w
|
|
* v - 247 = (dw - 108) / 256
|
|
* *** v = 247 + (dw - 108) / 256 ***
|
|
* *** w = (dw - 108) % 256 ***
|
|
*
|
|
* The rest of the derivations are no harder than this one.
|
|
*
|
|
*
|
|
**************************************************************/
|
|
|
|
static UFLErrCode
|
|
CSBufAddNumber(
|
|
CSBufStruct *h,
|
|
long dw
|
|
)
|
|
{
|
|
dw = UFLTruncFixedToShort( dw ); /* Truncate fraction */
|
|
|
|
|
|
/* Make sure buffer has room */
|
|
if (CSBufCheckSize(h, 5) == 0 )
|
|
{
|
|
return kErrOutOfMemory;
|
|
}
|
|
|
|
/* Encode number based on its value */
|
|
if (-107 <= dw && dw <= 107)
|
|
CSBufAddChar( h, (char)(dw + 139) );
|
|
else if (108 <= dw && dw <= 1131)
|
|
{
|
|
dw -= 108;
|
|
CSBufAddChar( h, (char)((dw >> 8) + 247) );
|
|
CSBufAddChar( h, (char)(dw) ); /* Just the low byte */
|
|
} /* end else */
|
|
else if (-1131 <= dw && dw <= -108)
|
|
{
|
|
dw += 108;
|
|
CSBufAddChar( h, (char)((-dw >> 8) + 251) );
|
|
CSBufAddChar( h, (char)(-dw) ); /* Just the low byte */
|
|
} /* end else if */
|
|
else
|
|
{
|
|
CSBufAddChar( h, (char)255 );
|
|
CSBufAddChar( h, (char)(dw >> 24) );
|
|
CSBufAddChar( h, (char)(dw >> 16) );
|
|
CSBufAddChar( h, (char)(dw >> 8) );
|
|
CSBufAddChar( h, (char)(dw) );
|
|
} /* end else */
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
static void
|
|
Encrypt(
|
|
const unsigned char *inBuf,
|
|
const unsigned char *outBuf,
|
|
long inLen,
|
|
long *outLen,
|
|
unsigned short *key
|
|
)
|
|
{
|
|
register unsigned char cipher;
|
|
register unsigned char *plainSource = (unsigned char *)inBuf;
|
|
register unsigned char *cipherDest = (unsigned char *)outBuf;
|
|
register unsigned short R = *key;
|
|
|
|
*outLen = inLen;
|
|
while ( --inLen >= 0 )
|
|
{
|
|
cipher = (*plainSource++ ^ (unsigned char)(R >> 8));
|
|
R = (unsigned short)(((unsigned short)cipher + R) * 52845 + 22719);
|
|
*cipherDest++ = cipher;
|
|
} /* end while */
|
|
*key = R;
|
|
} /* end Encrypt() */
|
|
|
|
static UFLErrCode
|
|
EExec(
|
|
UFLHANDLE stream,
|
|
unsigned char *inBuf,
|
|
UFLsize_t inLen,
|
|
unsigned short *pEExecKey
|
|
)
|
|
{
|
|
unsigned char buff[128]; /* Temporary buffer for output data */
|
|
UFLsize_t bytesLeft, bytesEncrypt, maxEncrypt;
|
|
long bytesOut;
|
|
unsigned char* pb;
|
|
UFLErrCode retVal = kNoErr;
|
|
|
|
pb = inBuf;
|
|
bytesLeft = inLen;
|
|
|
|
maxEncrypt = sizeof(buff);
|
|
while ( bytesLeft > 0 )
|
|
{
|
|
bytesEncrypt = min( bytesLeft, maxEncrypt ) ;
|
|
Encrypt( pb, buff, bytesEncrypt, &bytesOut, pEExecKey );
|
|
pb += bytesEncrypt;
|
|
bytesLeft -= bytesEncrypt;
|
|
retVal = StrmPutAsciiHex( stream, (const char*)buff, bytesOut );
|
|
|
|
if ( retVal != kNoErr )
|
|
break;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/*
|
|
* BeginEExec
|
|
*
|
|
* Function: Signals that we wish to start generating the eexec
|
|
* portion of the Type 1 font. The first four bytes of
|
|
* a Type 1 font must be randomly generated and satisfy
|
|
* two constraints which basically ensure that they do
|
|
* not generate whitespace or hexadecimal characters.
|
|
* For more details read Chapter 7 of the Black Book.
|
|
*/
|
|
static UFLErrCode
|
|
BeginEExec(
|
|
UFOStruct *pUFO
|
|
)
|
|
{
|
|
UFLErrCode retVal;
|
|
UFLHANDLE stream = pUFO->pUFL->hOut;
|
|
char nilStr[] = "\0\0"; // An empty/nil string.
|
|
TTT1FontStruct *pFont = (TTT1FontStruct *) pUFO->pAFont->hFont;
|
|
|
|
retVal = StrmPutStringEOL( stream, nilStr );
|
|
|
|
if ( kNoErr == retVal )
|
|
{
|
|
if ( pFont->info.bEExec )
|
|
{
|
|
StrmPutStringEOL( stream, "currentfile eexec" );
|
|
|
|
if ( kNoErr == retVal )
|
|
pFont->eexecKey = (unsigned short)kEExecKey;
|
|
|
|
if ( kNoErr == retVal )
|
|
retVal = EExec( stream, randomBytes, 4, &pFont->eexecKey );
|
|
}
|
|
else
|
|
{
|
|
StrmPutStringEOL( stream, "systemdict begin" );
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* EndEExec
|
|
*
|
|
* Function: Signals the client is done generating the eexec portion
|
|
* of a Type 1 font. The function tells eexec function in printer
|
|
* that eexec data are over by sending 512 zeroes at the end.
|
|
*
|
|
*
|
|
***************************************************************************/
|
|
|
|
static UFLErrCode
|
|
EndEExec(
|
|
UFOStruct *pUFO
|
|
)
|
|
{
|
|
TTT1FontStruct *pFont = (TTT1FontStruct *) pUFO->pAFont->hFont;
|
|
static char *closeStr = "mark currentfile closefile ";
|
|
UFLErrCode retVal = kNoErr;
|
|
UFLHANDLE stream = pUFO->pUFL->hOut;
|
|
short i;
|
|
|
|
if ( !pFont->info.bEExec )
|
|
{
|
|
retVal = StrmPutStringEOL( stream, "end" );
|
|
}
|
|
else
|
|
{
|
|
retVal = EExec( stream, (unsigned char*)closeStr, UFLstrlen( closeStr ), &pFont->eexecKey );
|
|
|
|
for ( i = 0; i < 8 && retVal == kNoErr; i++ )
|
|
retVal = StrmPutStringEOL( stream, "0000000000000000000000000000000000000000000000000000000000000000" );
|
|
|
|
if ( kNoErr == retVal )
|
|
retVal = StrmPutStringEOL( stream, "cleartomark" );
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
static UFLErrCode
|
|
PutLine(
|
|
UFOStruct *pUFO,
|
|
char *line
|
|
)
|
|
{
|
|
TTT1FontStruct *pFont = (TTT1FontStruct *) pUFO->pAFont->hFont;
|
|
UFLErrCode retVal;
|
|
#ifdef WIN_ENV
|
|
static char c[2] = { kWinLineEnd, kLineEnd };
|
|
#else
|
|
static char c[1] = { kLineEnd };
|
|
#endif
|
|
|
|
if ( 0 == pFont->info.bEExec )
|
|
retVal = StrmPutStringEOL( pUFO->pUFL->hOut, line );
|
|
else
|
|
{
|
|
/* MWCWP1 doesn't like the implicit cast from char* to unsigned char* --jfu */
|
|
retVal = EExec( pUFO->pUFL->hOut, (unsigned char*) line, UFLstrlen( line ), &pFont->eexecKey );
|
|
if ( retVal == kNoErr )
|
|
#ifdef WIN_ENV
|
|
retVal = EExec( pUFO->pUFL->hOut, c, 2, &pFont->eexecKey );
|
|
#else
|
|
/* MWCWP1 doesn't like the implicit cast from char* to unsigned char* --jfu */
|
|
retVal = EExec( pUFO->pUFL->hOut, (unsigned char*) c, 1, &pFont->eexecKey );
|
|
#endif
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* DownloadFontHeader
|
|
*
|
|
*
|
|
* Function: Download an empty font. After this action, glyphs
|
|
* can be added to the font.
|
|
*
|
|
***************************************************************************/
|
|
static UFLErrCode
|
|
DownloadFontHeader(
|
|
UFOStruct *pUFO
|
|
)
|
|
{
|
|
UFLErrCode retVal;
|
|
char buf[128];
|
|
UFLHANDLE stream;
|
|
char **pp;
|
|
TTT1FontStruct *pFont = (TTT1FontStruct *) pUFO->pAFont->hFont;
|
|
|
|
const static char *lenIV = "/lenIV -1 def";
|
|
|
|
const static char *type1Hdr[] =
|
|
{
|
|
"/PaintType 0 def",
|
|
"/FontType 1 def",
|
|
"/FontBBox { 0 0 0 0 } def", /* Assuming that the font does not use the seac command, see black book page 13 */
|
|
"AddFontInfoBegin", /* Goodname */
|
|
"AddFontInfo",
|
|
"AddFontInfoEnd",
|
|
"currentdict",
|
|
"end",
|
|
""
|
|
};
|
|
|
|
/* Private dict definition */
|
|
const static char *privateDict[] =
|
|
{
|
|
"dup /Private 7 dict dup begin",
|
|
"/BlueValues [] def",
|
|
"/MinFeature {16 16} def",
|
|
"/password 5839 def",
|
|
"/ND {def} def",
|
|
"/NP {put} def",
|
|
""
|
|
};
|
|
|
|
const static char *rdDef[] =
|
|
{
|
|
"/RD {string currentfile exch readstring pop} def\n",
|
|
"/RD {string currentfile exch readhexstring pop} def\n"
|
|
} ;
|
|
|
|
|
|
if ( pUFO->flState != kFontInit )
|
|
return kErrInvalidState;
|
|
|
|
stream = pUFO->pUFL->hOut;
|
|
retVal = StrmPutStringEOL( stream, "11 dict begin" );
|
|
if ( kNoErr == retVal )
|
|
{
|
|
UFLsprintf( buf, CCHOF(buf), "/FontName /%s def", pUFO->pszFontName );
|
|
retVal = StrmPutStringEOL( stream, buf );
|
|
}
|
|
|
|
/* Put font matrix */
|
|
if ( kNoErr == retVal )
|
|
{
|
|
retVal = StrmPutString( stream, "/FontMatrix " );
|
|
if ( kNoErr == retVal )
|
|
retVal = StrmPutString( stream, "[1 " );
|
|
if ( kNoErr == retVal )
|
|
retVal = StrmPutFixed( stream, pFont->info.matrix.a );
|
|
if ( kNoErr == retVal )
|
|
retVal = StrmPutString( stream, "div 0 0 1 " );
|
|
if ( kNoErr == retVal )
|
|
retVal = StrmPutFixed( stream, pFont->info.matrix.d );
|
|
if ( kNoErr == retVal )
|
|
retVal = StrmPutStringEOL( stream, "div 0 0 ] def" );
|
|
|
|
}
|
|
|
|
/* Put font encoding */
|
|
if ( kNoErr == retVal )
|
|
retVal = StrmPutString( stream, "/Encoding " );
|
|
if ( kNoErr == retVal )
|
|
{
|
|
if ( pUFO->pszEncodeName == 0 )
|
|
retVal = StrmPutString( stream, gnotdefArray );
|
|
else
|
|
retVal = StrmPutString( stream, pUFO->pszEncodeName );
|
|
}
|
|
if ( retVal == kNoErr )
|
|
retVal = StrmPutStringEOL( stream, " def" );
|
|
|
|
/* Put type1 header */
|
|
for ( pp = (char **)type1Hdr; **pp && retVal == kNoErr; pp++ )
|
|
retVal = StrmPutStringEOL( stream, *pp );
|
|
|
|
/* Goodname */
|
|
pUFO->dwFlags |= UFO_HasFontInfo;
|
|
pUFO->dwFlags |= UFO_HasG2UDict;
|
|
|
|
/* Put the systemdict on top of the dict stack ( this is what 'eexec' does ).*/
|
|
if ( kNoErr == retVal )
|
|
{
|
|
BeginEExec( pUFO );
|
|
}
|
|
|
|
|
|
for ( pp = (char**)privateDict; **pp && retVal == kNoErr; pp++ )
|
|
{
|
|
retVal = PutLine( pUFO, *pp );
|
|
}
|
|
|
|
/* Define lenIV = -1 which means no extra byte and no encryption. */
|
|
if ( 0 == pFont->info.bEExec )
|
|
retVal = StrmPutStringEOL( stream, lenIV );
|
|
|
|
/* Define RD base on the output format */
|
|
if ( 0 == pFont->info.bEExec )
|
|
PutLine( pUFO, ( StrmCanOutputBinary( stream ) ) ? (char *)rdDef[0] : (char *)rdDef[1] );
|
|
else
|
|
{
|
|
PutLine( pUFO, (char *)rdDef[0] );
|
|
}
|
|
|
|
/* Define the CharString dict */
|
|
UFLsprintf( buf, CCHOF(buf), "2 index /CharStrings %d dict dup begin", pFont->info.fData.maxGlyphs );
|
|
PutLine( pUFO, buf );
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
static UFLErrCode
|
|
DownloadFontFooter(
|
|
UFOStruct *pUFO
|
|
)
|
|
{
|
|
UFLErrCode retVal;
|
|
UFLHANDLE stream = pUFO->pUFL->hOut;
|
|
char **eftr;
|
|
TTT1FontStruct *pFont = (TTT1FontStruct *) pUFO->pAFont->hFont;
|
|
|
|
/* Finish up the encrypted portion */
|
|
static char *encryptFtr[] =
|
|
{
|
|
"end",
|
|
"end",
|
|
"put",
|
|
"put",
|
|
"dup /FontName get exch definefont pop",
|
|
""
|
|
};
|
|
|
|
|
|
retVal = kNoErr;
|
|
for ( eftr = encryptFtr; **eftr && retVal == kNoErr; eftr++ )
|
|
{
|
|
retVal = PutLine( pUFO, *eftr );
|
|
}
|
|
|
|
if ( retVal == kNoErr )
|
|
retVal = EndEExec( pUFO );
|
|
|
|
return retVal;
|
|
}
|
|
|
|
static UFLErrCode
|
|
DownloadCharString(
|
|
UFOStruct *pUFO,
|
|
const char *glyphName
|
|
)
|
|
{
|
|
char buf[128];
|
|
UFLErrCode retVal;
|
|
UFLHANDLE stream;
|
|
unsigned long bufLen;
|
|
UFLsize_t len = 0;
|
|
TTT1FontStruct *pFont = (TTT1FontStruct *) pUFO->pAFont->hFont;
|
|
|
|
retVal = kNoErr;
|
|
stream = pUFO->pUFL->hOut;
|
|
|
|
bufLen = (unsigned long)CSBufCurrentLen( pFont->pCSBuf );
|
|
|
|
//
|
|
// Note that for user-mode driver, UFLsprintf() returns HRESULT.
|
|
//
|
|
#ifdef WIN32KERNEL
|
|
len = UFLsprintf( buf, CCHOF(buf), "/%s %ld RD ", glyphName, bufLen );
|
|
#else // !WIN32KERNEL
|
|
if (SUCCEEDED(UFLsprintf( buf, CCHOF(buf), "/%s %ld RD ", glyphName, bufLen )))
|
|
{
|
|
len = strlen(buf);
|
|
}
|
|
#endif
|
|
|
|
if ( pFont->info.bEExec )
|
|
retVal = EExec( stream, (unsigned char*)buf, len, &pFont->eexecKey );
|
|
else
|
|
{
|
|
// Fix Adobe Bug #233904: PS error when TBCP
|
|
// Do not send 0D 0A after RD.
|
|
if (StrmCanOutputBinary( stream ))
|
|
{
|
|
retVal = StrmPutString( stream, (const char*)buf );
|
|
}
|
|
else
|
|
{
|
|
retVal = StrmPutStringEOL( stream, (const char*)buf );
|
|
}
|
|
}
|
|
|
|
if ( kNoErr == retVal )
|
|
{
|
|
if ( pFont->info.bEExec )
|
|
{
|
|
retVal = EExec( stream, (unsigned char*)pFont->pCSBuf->pBuf, (UFLsize_t) bufLen, &pFont->eexecKey );
|
|
if ( kNoErr == retVal )
|
|
retVal = EExec( stream, (unsigned char*)" ND ", (UFLsize_t) 4, &pFont->eexecKey );
|
|
}
|
|
else
|
|
{
|
|
if ( StrmCanOutputBinary( stream ) )
|
|
retVal = StrmPutBytes( stream, (const char*)pFont->pCSBuf->pBuf, (UFLsize_t) bufLen, 0 );
|
|
else
|
|
retVal = StrmPutAsciiHex( stream, (const char*)pFont->pCSBuf->pBuf, bufLen );
|
|
|
|
if ( kNoErr == retVal )
|
|
retVal = StrmPutStringEOL( stream, (const char*)" ND " );
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
static UFLErrCode
|
|
DefineNotDefCharString(
|
|
UFOStruct *pUFO
|
|
)
|
|
{
|
|
TTT1FontStruct *pFont = (TTT1FontStruct *) pUFO->pAFont->hFont;
|
|
UFLErrCode retVal = kNoErr;
|
|
|
|
retVal = CharString( pFont, kT1cscStartChar );
|
|
|
|
if ( kNoErr == retVal )
|
|
retVal = CharString( pFont, kT1cscSBW, 0L, 0L, 0L, 0L ); /* make the origin stay the same */
|
|
|
|
if ( kNoErr == retVal )
|
|
retVal = CharString( pFont, kT1cscEndChar );
|
|
|
|
if ( kNoErr == retVal )
|
|
retVal = DownloadCharString( pUFO, ".notdef" );
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
static UFLErrCode
|
|
BeginCharString(
|
|
TTT1FontStruct *pFont
|
|
)
|
|
{
|
|
if ( pFont->info.bEExec )
|
|
{
|
|
/* Output 4 random number as defined in the black book */
|
|
unsigned char* rb = randomBytes;
|
|
short i;
|
|
|
|
if ( 0 == CSBufCheckSize( pFont->pCSBuf, 4 ) )
|
|
{
|
|
return kErrOutOfMemory;
|
|
}
|
|
else
|
|
{
|
|
for ( i = 0; i < 4; i++, rb++ )
|
|
CSBufAddChar( pFont->pCSBuf, *rb );
|
|
}
|
|
}
|
|
return kNoErr;
|
|
}
|
|
|
|
static UFLErrCode
|
|
EndCharString(
|
|
TTT1FontStruct *pFont
|
|
)
|
|
{
|
|
if ( pFont->info.bEExec )
|
|
{
|
|
unsigned long len = (unsigned long)CSBufCurrentLen( pFont->pCSBuf );
|
|
unsigned short key = kCSKey;
|
|
|
|
/* MWCWP1 doesn't like the implicit casts from char* to const unsigned char* --jfu */
|
|
Encrypt( (const unsigned char*) CSBufBuffer( pFont->pCSBuf ),
|
|
(const unsigned char*) CSBufBuffer( pFont->pCSBuf ),
|
|
(long)len, (long*)&len, &key );
|
|
}
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* AddGlyph
|
|
*
|
|
*
|
|
* Function: Adds a single glyph to the font by calling the client
|
|
* outline callback routine.
|
|
*
|
|
***************************************************************************/
|
|
static UFLErrCode
|
|
AddGlyph(
|
|
UFOStruct *pUFO,
|
|
UFLGlyphID glyph,
|
|
const char *glyphName
|
|
)
|
|
{
|
|
UFLErrCode retVal = kNoErr;
|
|
UFLFixedPoint pt[3], currentPoint;
|
|
UFLFixed xWidth, yWidth, xSB, ySB;
|
|
UFLFontProcs *pFontProcs;
|
|
TTT1FontStruct *pFont = (TTT1FontStruct *) pUFO->pAFont->hFont;
|
|
UFLBool bYAxisNegative = 1;
|
|
//this flag determines whether the char string's Yaxis grows in
|
|
//positive(lower left) or negative(upper left) direction from the origin.
|
|
//For w95 ufoenc.CreateGlyphOutlineIter(), bYAxisNegative = 0
|
|
//Font wNT40/50, ufoenc.CreateGlyphoutlineIter(), bYAxisNegative = 1;
|
|
//ang 11/17/97
|
|
long lArgs[6];
|
|
|
|
|
|
pFontProcs = (UFLFontProcs *)&pUFO->pUFL->fontProcs;
|
|
|
|
/* Whatever is in glyph, pass back to client */
|
|
if ( pFontProcs->pfCreateGlyphOutlineIter( pUFO->hClientData, glyph, &xWidth, &yWidth, &xSB, &ySB, &bYAxisNegative ) )
|
|
{
|
|
UFLBool cont = 1;
|
|
do{
|
|
switch ( pFontProcs->pfNextOutlineSegment( pUFO->hClientData, &pt[0], &pt[1], &pt[2] ) )
|
|
{
|
|
case kUFLOutlineIterDone:
|
|
default:
|
|
if ( pFontProcs->pfDeleteGlyphOutlineIter )
|
|
pFontProcs->pfDeleteGlyphOutlineIter( pUFO->hClientData );
|
|
cont = 0;
|
|
break;
|
|
|
|
case kUFLOutlineIterBeginGlyph:
|
|
/* Signal start of character definition */
|
|
retVal = CharString( pFont, kT1cscStartChar );
|
|
if ( retVal == kNoErr )
|
|
{
|
|
/* Output the sidebearing and width information. */
|
|
retVal = CharString( pFont, kT1cscSBW, UFLTruncFixed(xSB), UFLTruncFixed(ySB),
|
|
UFLTruncFixed(xWidth), UFLTruncFixed(yWidth) );
|
|
/* Initialize the current point to be the origin */
|
|
currentPoint.x = xSB;
|
|
currentPoint.y = ySB;
|
|
}
|
|
break;
|
|
|
|
case kUFLOutlineIterEndGlyph:
|
|
break;
|
|
|
|
case kUFLOutlineIterMoveTo:
|
|
if (bYAxisNegative)
|
|
{
|
|
retVal = CharString( pFont, kT1cscRMoveTo,
|
|
UFLTruncFixed(pt[0].x - currentPoint.x),
|
|
UFLTruncFixed(currentPoint.y - pt[0].y));
|
|
}
|
|
else
|
|
{
|
|
// In NT, do Truncate AFTER subtract. In Win95, do truncate BEFORE subtract.
|
|
retVal = CharString( pFont, kT1cscRMoveTo,
|
|
UFLTruncFixed(pt[0].x) - UFLTruncFixed(currentPoint.x),
|
|
UFLTruncFixed(pt[0].y) - UFLTruncFixed(currentPoint.y));
|
|
}
|
|
|
|
/* Remember last point so we can generate relative commands */
|
|
currentPoint = pt[0];
|
|
break;
|
|
|
|
case kUFLOutlineIterLineTo:
|
|
if (bYAxisNegative)
|
|
{
|
|
retVal = CharString( pFont, kT1cscRLineTo,
|
|
UFLTruncFixed(pt[0].x - currentPoint.x),
|
|
UFLTruncFixed(currentPoint.y - pt[0].y));
|
|
}
|
|
else
|
|
{
|
|
// In NT, do Truncate AFTER subtract. In Win95, do truncate BEFORE subtract.
|
|
retVal = CharString( pFont, kT1cscRLineTo,
|
|
UFLTruncFixed(pt[0].x) - UFLTruncFixed(currentPoint.x),
|
|
UFLTruncFixed(pt[0].y) - UFLTruncFixed(currentPoint.y));
|
|
}
|
|
currentPoint = pt[0];
|
|
break;
|
|
|
|
case kUFLOutlineIterCurveTo:
|
|
/* Convert points so that they match with rrcurveto arguments */
|
|
if (bYAxisNegative)
|
|
{
|
|
retVal = CharString( pFont, kT1cscRRCurveTo,
|
|
UFLTruncFixed( pt[0].x - currentPoint.x ),
|
|
UFLTruncFixed( currentPoint.y - pt[0].y ),
|
|
UFLTruncFixed(pt[1].x - pt[0].x),
|
|
UFLTruncFixed(pt[0].y - pt[1].y),
|
|
UFLTruncFixed(pt[2].x - pt[1].x),
|
|
UFLTruncFixed(pt[1].y - pt[2].y) );
|
|
}
|
|
else
|
|
{
|
|
// In NT, do Truncate AFTER subtract. In Win95, do truncate BEFORE subtract.
|
|
lArgs[0] = UFLTruncFixed( pt[0].x);
|
|
lArgs[0] -= UFLTruncFixed(currentPoint.x );
|
|
lArgs[1] = UFLTruncFixed( pt[0].y);
|
|
lArgs[1] -= UFLTruncFixed(currentPoint.y);
|
|
lArgs[2] = UFLTruncFixed(pt[1].x);
|
|
lArgs[2] -= UFLTruncFixed(pt[0].x);
|
|
lArgs[3] = UFLTruncFixed(pt[1].y);
|
|
lArgs[3] -= UFLTruncFixed(pt[0].y);
|
|
lArgs[4] = UFLTruncFixed(pt[2].x);
|
|
lArgs[4] -= UFLTruncFixed(pt[1].x);
|
|
lArgs[5] = UFLTruncFixed(pt[2].y);
|
|
lArgs[5] -= UFLTruncFixed(pt[1].y) ;
|
|
retVal = CharString( pFont, kT1cscRRCurveTo,
|
|
lArgs[0], lArgs[1], lArgs[2], lArgs[3], lArgs[4], lArgs[5] );
|
|
}
|
|
currentPoint = pt[2];
|
|
break;
|
|
|
|
case kUFLOutlineIterClose:
|
|
{
|
|
retVal = CharString( pFont, kT1cscClosePath );
|
|
break;
|
|
}
|
|
} /* switch() */
|
|
|
|
if ( cont && retVal != kNoErr )
|
|
cont = 0;
|
|
|
|
} while ( cont );
|
|
|
|
if ( retVal == kNoErr )
|
|
retVal = CharString( pFont, kT1cscEndChar );
|
|
|
|
if ( retVal == kNoErr )
|
|
{
|
|
retVal = DownloadCharString( pUFO, glyphName );
|
|
}
|
|
}
|
|
else retVal = kErrGetGlyphOutline;
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
static UFLErrCode
|
|
DownloadAddGlyphHeader(
|
|
UFOStruct *pUFO
|
|
)
|
|
{
|
|
unsigned char buf[256];
|
|
UFLErrCode retVal;
|
|
UFLHANDLE stream;
|
|
char **hdr;
|
|
TTT1FontStruct *pFont = (TTT1FontStruct *) pUFO->pAFont->hFont;
|
|
const static char *encryptHdrU[] =
|
|
{
|
|
"findfont dup",
|
|
"/Private get begin",
|
|
"/CharStrings get begin",
|
|
""
|
|
};
|
|
|
|
retVal = kNoErr;
|
|
stream = pUFO->pUFL->hOut;
|
|
|
|
retVal = BeginEExec( pUFO );
|
|
|
|
if ( kNoErr == retVal )
|
|
{
|
|
UFLsize_t len = 0;
|
|
|
|
//
|
|
// Note that for user-mode driver, UFLsprintf() returns HRESULT.
|
|
//
|
|
#ifdef WIN32KERNEL
|
|
len = UFLsprintf( (char*)buf, CCHOF(buf), "/%s ", pUFO->pszFontName );
|
|
#else // !WIN32KERNEL
|
|
if (SUCCEEDED(UFLsprintf( (char*)buf, CCHOF(buf), "/%s ", pUFO->pszFontName )))
|
|
{
|
|
len = strlen(buf);
|
|
}
|
|
#endif
|
|
|
|
if ( pFont->info.bEExec )
|
|
retVal = EExec( stream, buf, len, &pFont->eexecKey );
|
|
else
|
|
retVal = StrmPutStringEOL( stream, (const char*)buf );
|
|
}
|
|
|
|
for ( hdr = (char**)encryptHdrU; retVal == kNoErr && **hdr; hdr++ )
|
|
{
|
|
if ( pFont->info.bEExec )
|
|
retVal = EExec( stream, (unsigned char*)*hdr, UFLstrlen(*hdr), &pFont->eexecKey );
|
|
else
|
|
retVal = StrmPutStringEOL( stream, (const char*)*hdr );
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
static UFLErrCode
|
|
DownloadAddGlyphFooter(
|
|
UFOStruct *pUFO
|
|
)
|
|
{
|
|
UFLErrCode retVal;
|
|
static char *addGlyphFtr = "end end";
|
|
|
|
retVal = PutLine( pUFO, addGlyphFtr );
|
|
if ( kNoErr == retVal )
|
|
retVal = EndEExec( pUFO );
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
*
|
|
* CharString
|
|
*
|
|
* Function: Translates symbolic Type 1 character commands into
|
|
* their encoded, encrypted equivalent. The list of
|
|
* available commands is defined in the constant section.
|
|
* They are used by passing the command constant followed
|
|
* by the long arguments required by the function.
|
|
*
|
|
* Example: CharString(lppd, kT1cscRMoveTo, lx, ly);
|
|
*
|
|
* To make a character definition use kT1cscStartChar, followed
|
|
* by all of the Type 1 character commands, and ending with
|
|
* kT1cscEndChar. The buffer contains the CharString
|
|
* encrypted/encoded representation. Given the length and the
|
|
* properly encrypted data, the caller has enough information
|
|
* to generate PS code that will add the character to a font
|
|
* definition. For more detail see Chapters 2 and 6 in the
|
|
* Black Book.
|
|
*
|
|
***************************************************************************/
|
|
UFLErrCode
|
|
CharString(
|
|
TTT1FontStruct *pFont,
|
|
unsigned long cmd,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
long args[10];
|
|
unsigned short argCount, i, j;
|
|
UFLErrCode retVal = kNoErr;
|
|
|
|
switch ( cmd )
|
|
{
|
|
case kT1cscStartChar:
|
|
{
|
|
/* Allocate the buffer */
|
|
CSBufRewind( pFont->pCSBuf );
|
|
return BeginCharString( pFont );
|
|
}
|
|
|
|
default:
|
|
/* get the variable arguments */
|
|
va_start(arglist, cmd);
|
|
j = ((unsigned short)(cmd >> 16)) & 0xffff;
|
|
|
|
for (i=0; i<j; i++)
|
|
{
|
|
args[i] = va_arg(arglist, long);
|
|
}
|
|
va_end(arglist);
|
|
|
|
/* Attempt to optimize the command */
|
|
switch ( cmd ) {
|
|
case kT1cscSBW:
|
|
/* This can be reduced to an HSBW if the Y components are zero */
|
|
if ( args[1] || args[3] )
|
|
break;
|
|
args[1] = args[2];
|
|
cmd = kT1cscHSBW;
|
|
break;
|
|
|
|
case kT1cscRMoveTo:
|
|
/* This can be reduced to a horizontal or vertical
|
|
movement if one of the components is zero.
|
|
*/
|
|
if ( 0 == args[1] )
|
|
{
|
|
cmd = kT1cscHMoveTo;
|
|
}
|
|
else if ( 0 == args[0] )
|
|
{
|
|
args[0] = args[1];
|
|
cmd = kT1cscVMoveTo;
|
|
}
|
|
break;
|
|
|
|
case kT1cscRLineTo:
|
|
/* This can be reduced to a horizontal or vertical
|
|
line if one of the components is zero.
|
|
*/
|
|
if ( 0 == args[1] )
|
|
{
|
|
cmd = kT1cscHLineTo;
|
|
}
|
|
else if ( 0 == args[0] )
|
|
{
|
|
args[0] = args[1];
|
|
cmd = kT1cscVLineTo;
|
|
}
|
|
break;
|
|
|
|
case kT1cscRRCurveTo:
|
|
/*
|
|
This can be reduced to a simpler curve operator if the tangents
|
|
at the endpoints of the Bezier are horizontal or vertical
|
|
*/
|
|
if ( 0 == args[1] && 0 == args[4] )
|
|
{
|
|
args[1] = args[2];
|
|
args[2] = args[3];
|
|
args[3] = args[5];
|
|
cmd = kT1cscHVCurveTo;
|
|
}
|
|
else if ( 0 == args[0] && 0 == args[5] )
|
|
{
|
|
args[0] = args[1];
|
|
args[1] = args[2];
|
|
args[2] = args[3];
|
|
args[3] = args[4];
|
|
cmd = kT1cscVHCurveTo;
|
|
}
|
|
break;
|
|
} /* switch (cmd) */
|
|
|
|
/* arg count stored in HIWORD */
|
|
argCount = ((unsigned short) (((long) (cmd) >> 16) & 0x0000FFFF));
|
|
|
|
/*
|
|
If buffer isn't big enough to hold this command expand buffer first.
|
|
Exit if we can't grow buffer.
|
|
Note: The formula (wArgCount * 5 + 2) assumes the worst case size
|
|
requirement for the current command (all arguments stored
|
|
as full longs and a two byte command).
|
|
*/
|
|
if ( 0 == CSBufCheckSize( pFont->pCSBuf, (unsigned long)( argCount * 5 + 2 ) ) )
|
|
{
|
|
retVal = kErrOutOfMemory;
|
|
}
|
|
else
|
|
{
|
|
/* Push the numbers onto the stack */
|
|
i = 0;
|
|
while ( retVal == kNoErr && argCount-- )
|
|
{
|
|
retVal = CSBufAddNumber( pFont->pCSBuf, args[i++] );
|
|
}
|
|
}
|
|
|
|
/* Push the command onto the stack */
|
|
if ( kNoErr == retVal )
|
|
{
|
|
char c = (char) (cmd & 0x000000FF);
|
|
|
|
CSBufAddChar( pFont->pCSBuf, c );
|
|
if ( 12 == c )
|
|
{ /* two byte command */
|
|
CSBufAddChar( pFont->pCSBuf, (char) ((cmd >> 8) & 0x000000FF) );
|
|
}
|
|
|
|
/* If this isn't the end of a character definition return success */
|
|
if ( kT1cscEndChar == cmd )
|
|
{
|
|
/* We have finished the character: encrypt it if necessary */
|
|
retVal = EndCharString( pFont );
|
|
}
|
|
}
|
|
|
|
} /* switch (cmd) */
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/***********************************
|
|
Public Functions
|
|
***********************************/
|
|
|
|
void
|
|
TTT1FontCleanUp(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
TTT1FontStruct *pFont;
|
|
|
|
if (pUFObj->pAFont == nil)
|
|
return;
|
|
|
|
pFont = (TTT1FontStruct *) pUFObj->pAFont->hFont;
|
|
|
|
if ( pFont )
|
|
{
|
|
if ( pFont->pCSBuf != nil )
|
|
{
|
|
CSBufCleanUp( pFont->pCSBuf );
|
|
}
|
|
|
|
pFont->pCSBuf = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
TTT1VMNeeded(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMNeeded,
|
|
unsigned long *pFCNeeded
|
|
)
|
|
{
|
|
UFLErrCode retVal = kNoErr;
|
|
short i;
|
|
unsigned long totalGlyphs;
|
|
TTT1FontStruct *pFont;
|
|
unsigned short wIndex;
|
|
|
|
if (pUFObj->flState < kFontInit)
|
|
return (kErrInvalidState);
|
|
|
|
if ( pFCNeeded )
|
|
*pFCNeeded = 0;
|
|
|
|
pFont = (TTT1FontStruct *) pUFObj->pAFont->hFont;
|
|
|
|
if (pGlyphs == nil || pGlyphs->pGlyphIndices == nil || pVMNeeded == nil)
|
|
return kErrInvalidParam;
|
|
|
|
totalGlyphs = 0;
|
|
|
|
/* Scan the list, check what characters that we have downloaded */
|
|
if ( pUFObj->pUFL->bDLGlyphTracking && pGlyphs->pCharIndex)
|
|
{
|
|
UFLmemcpy( (const UFLMemObj* ) pUFObj->pMem,
|
|
pUFObj->pAFont->pVMGlyphs,
|
|
pUFObj->pAFont->pDownloadedGlyphs,
|
|
(UFLsize_t) (GLYPH_SENT_BUFSIZE( pFont->info.fData.cNumGlyphs)));
|
|
for ( i = 0; i < pGlyphs->sCount; i++ )
|
|
{
|
|
/* use glyphIndex to track - fix bug when we do T0/T1 */
|
|
wIndex = (unsigned short) pGlyphs->pGlyphIndices[i] & 0x0000FFFF; /* LOWord is the real GID */
|
|
if (wIndex >= UFO_NUM_GLYPHS(pUFObj) )
|
|
continue;
|
|
|
|
if ( !IS_GLYPH_SENT( pUFObj->pAFont->pVMGlyphs, wIndex ) )
|
|
{
|
|
SET_GLYPH_SENT_STATUS( pUFObj->pAFont->pVMGlyphs, wIndex );
|
|
totalGlyphs++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
totalGlyphs = pGlyphs->sCount;
|
|
|
|
if ( pUFObj->flState == kFontInit )
|
|
*pVMNeeded = kVMTTT1Header;
|
|
else
|
|
*pVMNeeded = 0;
|
|
|
|
*pVMNeeded += totalGlyphs * kVMTTT1Char;
|
|
|
|
*pVMNeeded = VMRESERVED( *pVMNeeded );
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
/***************************************************************************
|
|
*
|
|
* DownloadIncrFont
|
|
*
|
|
*
|
|
* Function: Adds all of the characters from pGlyphs that aren't already
|
|
* downloaded for the TrueType font.
|
|
*
|
|
* Note: pCharIndex is used to track which char(in this font) is downloaded or not
|
|
* It can be nil if client doesn't wish to track - e.g. Escape(DownloadFace)
|
|
* It has no relationship with ppGlyphNames.
|
|
* E.g., ppGlyphNames[0]="/A", pCharIndex[0]=6, pGlyphIndices[0]=1000: means
|
|
* To download glyphID 1000 as Char-named "/A" and Also, remember the 6th-char is downloaded
|
|
*
|
|
* ppGlphNames is optional - if not provided, UFL will parse "post" table to find from GlyphID
|
|
* - it it is provided, we may use it as a "hint" for the glyphName - use it if parse failed.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#pragma optimize("", off)
|
|
|
|
UFLErrCode
|
|
TTT1FontDownloadIncr(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMUsage,
|
|
unsigned long *pFCUsage
|
|
)
|
|
{
|
|
UFLGlyphID *glyphs;
|
|
short i, hasCharToAdd;
|
|
short hasCharToEncode;
|
|
UFLErrCode retVal;
|
|
char *pGoodName;
|
|
unsigned short wIndex;
|
|
UFLBool bGoodName; // GoodName
|
|
char pGlyphName[32]; // GoodName
|
|
|
|
if (pUFObj->flState < kFontInit)
|
|
return (kErrInvalidState);
|
|
|
|
if ( pFCUsage )
|
|
*pFCUsage = 0;
|
|
|
|
if ( pGlyphs == nil || pGlyphs->pGlyphIndices == nil)
|
|
return kErrInvalidParam;
|
|
|
|
/* We don't support download full font */
|
|
if ( pGlyphs->sCount == -1 )
|
|
return kErrNotImplement;
|
|
|
|
retVal = kNoErr;
|
|
|
|
glyphs = pGlyphs->pGlyphIndices;
|
|
|
|
hasCharToAdd = 1; // Assume has some char to add
|
|
hasCharToEncode = 0;
|
|
/* If AddChar - First check if there is any chars to Add! */
|
|
if (pUFObj->flState == kFontHasChars &&
|
|
pUFObj->pUFL->bDLGlyphTracking != 0 &&
|
|
pGlyphs->pCharIndex != nil)
|
|
{
|
|
hasCharToAdd = 0; /* if asked to AddChar and totrack, check if there is any to add */
|
|
for ( i = 0; i < pGlyphs->sCount; i++ )
|
|
{
|
|
/* use glyphIndex to track - fix bug when we do T0/T1 */
|
|
wIndex = (unsigned short) glyphs[i] & 0x0000FFFF; /* LOWord is the real GID */
|
|
|
|
if (wIndex >= UFO_NUM_GLYPHS(pUFObj) )
|
|
continue;
|
|
|
|
if (!IS_GLYPH_SENT( pUFObj->pAFont->pDownloadedGlyphs, wIndex ))
|
|
{
|
|
hasCharToAdd = 1;
|
|
break;
|
|
}
|
|
if (!IS_GLYPH_SENT( pUFObj->pUpdatedEncoding, pGlyphs->pCharIndex[i] ))
|
|
hasCharToEncode = 1;
|
|
}
|
|
}
|
|
|
|
if (hasCharToAdd==0)
|
|
{
|
|
// This code is to fix bug 288988.
|
|
if (hasCharToEncode)
|
|
UpdateEncodingVector(pUFObj, pGlyphs, 0, pGlyphs->sCount);
|
|
if (pVMUsage) *pVMUsage = 0 ;
|
|
return retVal; /* no error, no VM used */
|
|
}
|
|
|
|
/* Download the font header if this is the first time we download the font */
|
|
if ( pUFObj->flState == kFontInit )
|
|
{
|
|
retVal = DownloadFontHeader( pUFObj );
|
|
if ( pVMUsage )
|
|
*pVMUsage = kVMTTT1Header;
|
|
}
|
|
else
|
|
{
|
|
retVal = DownloadAddGlyphHeader( pUFObj );
|
|
if ( pVMUsage )
|
|
*pVMUsage = 0;
|
|
}
|
|
|
|
/* Every font must have a .notdef character! */
|
|
if ( kNoErr == retVal && pUFObj->flState == kFontInit )
|
|
{
|
|
retVal = DefineNotDefCharString( pUFObj );
|
|
if ( kNoErr == retVal && pVMUsage )
|
|
*pVMUsage += kVMTTT1Char;
|
|
}
|
|
|
|
/* Download the new glyphs */
|
|
if(retVal == kNoErr)
|
|
{
|
|
// Skip the ones don't exist. Don't stop when there's error
|
|
for ( i = 0; i < pGlyphs->sCount; ++i)
|
|
{
|
|
/* use glyphIndex to track - fix bug when we do T0/T1 */
|
|
wIndex = (unsigned short) glyphs[i] & 0x0000FFFF; /* LOWord is the real GID */
|
|
if (wIndex >= UFO_NUM_GLYPHS(pUFObj) )
|
|
continue;
|
|
|
|
if ( 0 == pUFObj->pUFL->bDLGlyphTracking ||
|
|
pGlyphs->pCharIndex == nil || // DownloadFace
|
|
pUFObj->pEncodeNameList || // DownloadFace
|
|
!IS_GLYPH_SENT( pUFObj->pAFont->pDownloadedGlyphs, wIndex ) )
|
|
{
|
|
// GoodName
|
|
pGoodName = pGlyphName;
|
|
bGoodName = FindGlyphName(pUFObj, pGlyphs, i, wIndex, &pGoodName);
|
|
|
|
// Fix bug 274008 Check Glyph Name only for DownloadFace.
|
|
if (pUFObj->pEncodeNameList)
|
|
{
|
|
if ((UFLstrcmp( pGoodName, Hyphen ) == 0) && (i == 45))
|
|
{
|
|
// Add /minus to CharString
|
|
//if ( kNoErr == retVal )
|
|
retVal = AddGlyph( pUFObj, glyphs[i], Minus);
|
|
}
|
|
if ((UFLstrcmp( pGoodName, Hyphen ) == 0) && (i == 173))
|
|
{
|
|
// Add /sfthyphen to CharString
|
|
//if ( kNoErr == retVal )
|
|
retVal = AddGlyph( pUFObj, glyphs[i], SftHyphen);
|
|
}
|
|
|
|
if (!ValidGlyphName(pGlyphs, i, wIndex, pGoodName))
|
|
continue;
|
|
// Send only one ".notdef"
|
|
if ((UFLstrcmp( pGoodName, Notdef ) == 0) &&
|
|
(wIndex == (unsigned short) (glyphs[0] & 0x0000FFFF)) &&
|
|
IS_GLYPH_SENT( pUFObj->pAFont->pDownloadedGlyphs, wIndex ))
|
|
continue;
|
|
}
|
|
|
|
//if ( kNoErr == retVal )
|
|
retVal = AddGlyph( pUFObj, glyphs[i], pGoodName);
|
|
|
|
if ( kNoErr == retVal )
|
|
{
|
|
SET_GLYPH_SENT_STATUS( pUFObj->pAFont->pDownloadedGlyphs, wIndex );
|
|
if (bGoodName) // GoodName
|
|
SET_GLYPH_SENT_STATUS( pUFObj->pAFont->pCodeGlyphs, wIndex );
|
|
|
|
if ( pVMUsage )
|
|
*pVMUsage += kVMTTT1Char;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Always download font footer and update encoding vector regardless of
|
|
retVal. This is because passthrough code may try to use this font */
|
|
retVal = ( pUFObj->flState == kFontInit ) ? DownloadFontFooter( pUFObj ) : DownloadAddGlyphFooter( pUFObj );
|
|
|
|
/* update Encoding vector with the good names if necessary*/
|
|
UpdateEncodingVector(pUFObj, pGlyphs, 0, pGlyphs->sCount);
|
|
|
|
/* GoodName */
|
|
/* Update the FontInfo with Unicode information. */
|
|
if ((kNoErr == retVal) && (pGlyphs->sCount > 0) &&
|
|
(pUFObj->dwFlags & UFO_HasG2UDict) &&
|
|
(pUFObj->pUFL->outDev.lPSLevel >= kPSLevel2) && // Don't do this for level1 printers
|
|
!(pUFObj->lNumNT4SymGlyphs))
|
|
{
|
|
/* Check pUFObj->pAFont->pCodeGlyphs to see if we really need to update it. */
|
|
for ( i = 0; i < pGlyphs->sCount; i++ )
|
|
{
|
|
wIndex = (unsigned short) glyphs[i] & 0x0000FFFF; /* LOWord is the real GID. */
|
|
if (wIndex >= UFO_NUM_GLYPHS(pUFObj) )
|
|
continue;
|
|
|
|
if (!IS_GLYPH_SENT( pUFObj->pAFont->pCodeGlyphs, wIndex ) )
|
|
{
|
|
// Found at least one not updated, do it (once) for all.
|
|
retVal = UpdateCodeInfo(pUFObj, pGlyphs, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( kNoErr == retVal )
|
|
{
|
|
pUFObj->flState = kFontHasChars;
|
|
}
|
|
|
|
if ( pVMUsage )
|
|
*pVMUsage = VMRESERVED( *pVMUsage );
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
#pragma optimize("", on)
|
|
|
|
/* Send PS code to undefine fonts: /UDF should be defined properly by client
|
|
* to something like:
|
|
/UDF
|
|
{
|
|
IsLevel2
|
|
{undefinefont}
|
|
{ pop }ifelse
|
|
} bind def
|
|
*/
|
|
UFLErrCode
|
|
TTT1UndefineFont(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
UFLErrCode retVal = kNoErr;
|
|
char buf[128];
|
|
UFLHANDLE stream;
|
|
|
|
if (pUFObj->flState < kFontHeaderDownloaded) return retVal;
|
|
|
|
stream = pUFObj->pUFL->hOut;
|
|
UFLsprintf( buf, CCHOF(buf), "/%s UDF", pUFObj->pszFontName );
|
|
retVal = StrmPutStringEOL( stream, buf );
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFOStruct *
|
|
TTT1FontInit(
|
|
const UFLMemObj *pMem,
|
|
const UFLStruct *pUFL,
|
|
const UFLRequest *pRequest
|
|
)
|
|
{
|
|
TTT1FontStruct *pFont = nil;
|
|
UFLTTT1FontInfo *pInfo;
|
|
UFOStruct *pUFObj;
|
|
long maxGlyphs;
|
|
|
|
/* MWCWP1 doesn't like the implicit cast from void* to UFOStruct* --jfu */
|
|
pUFObj = (UFOStruct*) UFLNewPtr( pMem, sizeof( UFOStruct ) );
|
|
if (pUFObj == 0)
|
|
return 0;
|
|
|
|
/* Initialize data */
|
|
UFOInitData(pUFObj, UFO_TYPE1, pMem, pUFL, pRequest,
|
|
(pfnUFODownloadIncr) TTT1FontDownloadIncr,
|
|
(pfnUFOVMNeeded) TTT1VMNeeded,
|
|
(pfnUFOUndefineFont) TTT1UndefineFont,
|
|
(pfnUFOCleanUp) TTT1FontCleanUp,
|
|
(pfnUFOCopy) CopyFont );
|
|
|
|
/* pszFontName should be ready/allocated - if not FontName, cannot continue */
|
|
if (pUFObj->pszFontName == nil || pUFObj->pszFontName[0] == '\0')
|
|
{
|
|
UFLDeletePtr(pMem, pUFObj);
|
|
return nil;
|
|
}
|
|
|
|
pInfo = (UFLTTT1FontInfo *)pRequest->hFontInfo;
|
|
|
|
maxGlyphs = pInfo->fData.cNumGlyphs;
|
|
|
|
/* a convenience pointer used in GetNumGlyph() - must be set now*/
|
|
pUFObj->pFData = &(pInfo->fData); /* Temporary assignment !! */
|
|
if (maxGlyphs == 0)
|
|
maxGlyphs = GetNumGlyphs( pUFObj );
|
|
|
|
/*
|
|
* On NT4 a non-zero value will be set to pInfo->lNumNT4SymGlyphs for
|
|
* symbolic TrueType font with platformID 3/encodingID 0. If it's set, it
|
|
* is the real maxGlyphs value.
|
|
*/
|
|
pUFObj->lNumNT4SymGlyphs = pInfo->lNumNT4SymGlyphs;
|
|
|
|
if (pUFObj->lNumNT4SymGlyphs)
|
|
maxGlyphs = pInfo->lNumNT4SymGlyphs;
|
|
|
|
/*
|
|
* We now use Glyph Index to track which glyph is downloaded, so use
|
|
* maxGlyphs.
|
|
*/
|
|
if ( NewFont(pUFObj, sizeof(TTT1FontStruct), maxGlyphs) == kNoErr )
|
|
{
|
|
pFont = (TTT1FontStruct*) pUFObj->pAFont->hFont;
|
|
|
|
pFont->info = *pInfo;
|
|
|
|
/* a convenience pointer */
|
|
pUFObj->pFData = &(pFont->info.fData);
|
|
|
|
/*
|
|
* Get ready to find out correct glyphNames from "post" table - set
|
|
* correct pUFO->pFData->fontIndex and offsetToTableDir.
|
|
*/
|
|
if ( pFont->info.fData.fontIndex == FONTINDEX_UNKNOWN )
|
|
pFont->info.fData.fontIndex = GetFontIndexInTTC(pUFObj);
|
|
|
|
/* Get num of Glyphs in this TT file if not set yet */
|
|
if (pFont->info.fData.cNumGlyphs == 0)
|
|
pFont->info.fData.cNumGlyphs = maxGlyphs;
|
|
|
|
if (pFont->pCSBuf == nil)
|
|
pFont->pCSBuf = CSBufInit( pMem );
|
|
|
|
if (pFont->pCSBuf == nil)
|
|
{
|
|
vDeleteFont( pUFObj );
|
|
UFLDeletePtr( pUFObj->pMem, pUFObj );
|
|
return nil;
|
|
}
|
|
|
|
if ( pUFObj->pUpdatedEncoding == 0 )
|
|
{
|
|
pUFObj->pUpdatedEncoding = (unsigned char *)UFLNewPtr( pMem, GLYPH_SENT_BUFSIZE(256) );
|
|
}
|
|
|
|
if ( pUFObj->pUpdatedEncoding != 0 ) /* completed initialization */
|
|
pUFObj->flState = kFontInit;
|
|
}
|
|
|
|
return pUFObj;
|
|
}
|
|
|