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.
1516 lines
47 KiB
1516 lines
47 KiB
/*
|
|
* Adobe Universal Font Library
|
|
*
|
|
* Copyright (c) 1996 Adobe Systems Inc.
|
|
* All Rights Reserved
|
|
*
|
|
* UFOCFF.c - Compact Font Format Object
|
|
*
|
|
******************************************************************************
|
|
*
|
|
* Note about SUBSET_PREFIX and more comment for VRT2_FEATURE_DISABLED
|
|
*
|
|
* When we donwload a font, its /FontName or /CIDFontName can be any name we
|
|
* want. If the name folows the following format:
|
|
* SUBSET_PREFIX+RealFontName
|
|
* where SUBSET_PREFIX is a string consited of six characters, each of them is
|
|
* either 'a' ~ 'p' or 'A' ~ 'P', then Distiller4 takes RealFontName part as
|
|
* the font's real name. e.g. abcdef+Helvetica -> Distiller4 realizes that this
|
|
* this font's real font name is Helvetica.
|
|
* We, Adobe Windows Driver Group, decided to go for it (bug #291934). At the
|
|
* same time, we also deciced to remve the code for 'vrt2' feature incapable
|
|
* CJK OpenType font, that is, remove #ifdef/#endif with VRT2_FEATURE_DISABLED
|
|
* because virtually any CJK OpenType fonts are supposed to have 'vrt2'
|
|
* feature. Otherwise vertical version of such CJK OpenType font can't be
|
|
* supported (by ATM or CoolType). Thus, there will be no #ifdef/#endif section
|
|
* with VRT2_FEATURE_DISABLED keyword in this code and the sentence "But, just
|
|
* in case, ....at compile time." in the following note is now obsolite.
|
|
* You can retrieve the removed code from the version 16 or below of this file
|
|
* in SourceSafe if you want.
|
|
*
|
|
* --- This note is now obsolete. ---------------------------------------------
|
|
*
|
|
* Note about 'vrt2' feature and VRT2_FEATURE_DISABLED
|
|
*
|
|
* OTF-based fonts will only have their "@" capability enabled if they have a
|
|
* 'vrt2' feature in their 'GSUB' table; otherwise only horizontal typographic
|
|
* rendering is enabled. When the 'vrt2' feature exists in a font, the font
|
|
* vendor claims that all of the glyphs for the @ variant of the font should be
|
|
* rotated before display / print. Thus, on neither NT4 nor W2K, the PostScript
|
|
* driver doesn't even have to call GlyhAttrs to find out which @ glyphs are
|
|
* rotated; they all are. But, just in case, the logic for rotating @ glyphs is
|
|
* also provided and it will be enabled when VRT2_FEATURE_DISABLED flag is set
|
|
* at compile time.
|
|
*-----------------------------------------------------------------------------
|
|
*
|
|
* $Header:
|
|
*/
|
|
|
|
#include "UFLMem.h"
|
|
#include "UFLErr.h"
|
|
#include "UFLPriv.h"
|
|
#include "UFLVm.h"
|
|
#include "UFLStd.h"
|
|
#include "UFLMath.h"
|
|
#include "UFLPS.h"
|
|
#include "ParseTT.h"
|
|
#include "UFOCff.h"
|
|
#include "UFOt42.h"
|
|
#include "ttformat.h"
|
|
|
|
|
|
#ifdef UNIX
|
|
#include <sys/varargs.h>
|
|
#include <assert.h>
|
|
#else
|
|
#ifdef MAC_ENV
|
|
#include <assert.h>
|
|
#endif
|
|
#include <stdarg.h>
|
|
#endif
|
|
|
|
static unsigned char *pSubrNames[4] = {
|
|
(unsigned char*) "F0Subr",
|
|
(unsigned char*) "F1Subr",
|
|
(unsigned char*) "F2Subr",
|
|
(unsigned char*) "HSSubr"
|
|
};
|
|
|
|
#define VER_WO_OTHERSUBRS 51
|
|
|
|
|
|
/*
|
|
* Maximum known supplement number. This number is used to decide whether
|
|
* GlyphName2Unicode table should be downloaded.
|
|
*/
|
|
#define ADOBE_JAPAN1_MAXKNOWN 4
|
|
#define ADOBE_KOREA1_MAXKNOWN 1
|
|
#define ADOBE_GB1_MAXKNOWN 2
|
|
#define ADOBE_CNS1_MAXKNOWN 0
|
|
|
|
/*
|
|
* Macro to check whether they are known ordering and supplement.
|
|
*/
|
|
#define KNOWN_OS(o, on, s, max) (!UFLstrcmp((o), (on)) && ((0 <= (s)) && ((s) < (max))))
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Callback Functions
|
|
*
|
|
******************************************************************************/
|
|
|
|
static unsigned long int
|
|
AllocateMem(
|
|
void PTR_PREFIX *PTR_PREFIX *hndl,
|
|
unsigned long int size,
|
|
void PTR_PREFIX *clientHook
|
|
)
|
|
{
|
|
UFOStruct *pUFO = (UFOStruct *)clientHook;
|
|
|
|
if ((size == 0) && (*hndl == nil))
|
|
return 1;
|
|
|
|
if (size == 0)
|
|
{
|
|
UFLDeletePtr(pUFO->pMem, *hndl);
|
|
*hndl = nil;
|
|
return 1;
|
|
}
|
|
|
|
if (*hndl == nil)
|
|
{
|
|
*hndl = UFLNewPtr(pUFO->pMem, size);
|
|
|
|
return (unsigned long int)(ULONG_PTR)*hndl;
|
|
}
|
|
else
|
|
{
|
|
return (unsigned long int)UFLEnlargePtr(pUFO->pMem, (void **)hndl, size, 1);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* We do not support seeking for this function. */
|
|
static int
|
|
PutBytesAtPos(
|
|
unsigned char PTR_PREFIX *pData,
|
|
long int position,
|
|
unsigned short int length,
|
|
void PTR_PREFIX *clientHook
|
|
)
|
|
{
|
|
if (position >= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (length > 0)
|
|
{
|
|
UFOStruct *pUFO = (UFOStruct *)clientHook;
|
|
|
|
if (kNoErr == StrmPutBytes(pUFO->pUFL->hOut,
|
|
(const char *)pData,
|
|
(UFLsize_t)length,
|
|
(const UFLBool)StrmCanOutputBinary(pUFO->pUFL->hOut)))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
static int
|
|
GetBytesFromPos(
|
|
unsigned char PTR_PREFIX * PTR_PREFIX *ppData,
|
|
long int position,
|
|
unsigned short int length,
|
|
void PTR_PREFIX *clientHook
|
|
)
|
|
{
|
|
UFOStruct *pUFO = (UFOStruct *)clientHook;
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFO->pAFont->hFont;
|
|
int retVal = 0; /* Set retVal to failure. */
|
|
|
|
/*
|
|
* Check to see if the client passes us a whole cff table.
|
|
*/
|
|
if (pFont->info.ppFontData)
|
|
{
|
|
/*
|
|
* Get the data from the table by ourself.
|
|
*/
|
|
if ((unsigned long int)(position + length) <= pFont->info.fontLength)
|
|
{
|
|
*ppData = (unsigned char PTR_PREFIX *)*pFont->info.ppFontData + position;
|
|
|
|
retVal = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UFLCFFReadBuf *pReadBuf = pFont->pReadBuf;
|
|
|
|
if (0 == pReadBuf->cbBuf)
|
|
{
|
|
pReadBuf->pBuf = (unsigned char PTR_PREFIX *)UFLNewPtr(pUFO->pMem, length);
|
|
|
|
if (pReadBuf->pBuf)
|
|
pReadBuf->cbBuf = length;
|
|
else
|
|
return 0;
|
|
}
|
|
else if (pReadBuf->cbBuf < length)
|
|
{
|
|
UFLEnlargePtr(pUFO->pMem, (void **)&pReadBuf->pBuf, length, 0);
|
|
pReadBuf->cbBuf = length;
|
|
}
|
|
|
|
/*
|
|
* Fall back to read from callback function.
|
|
*/
|
|
retVal = (int)GETTTFONTDATA(pUFO,
|
|
CFF_TABLE,
|
|
position,
|
|
pReadBuf->pBuf,
|
|
length,
|
|
pFont->info.fData.fontIndex);
|
|
|
|
*ppData = (unsigned char PTR_PREFIX *)pReadBuf->pBuf;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Private Functions
|
|
*
|
|
******************************************************************************/
|
|
|
|
static void *
|
|
SetMemory(
|
|
void *dest,
|
|
int c,
|
|
unsigned short int count
|
|
)
|
|
{
|
|
return UFLmemsetShort(dest, c, (size_t) count);
|
|
}
|
|
|
|
|
|
static unsigned short int
|
|
StringLength(
|
|
const char PTR_PREFIX *string
|
|
)
|
|
{
|
|
return (unsigned short int)UFLstrlen(string);
|
|
}
|
|
|
|
|
|
static void
|
|
MemCpy(
|
|
void PTR_PREFIX *dest,
|
|
const void PTR_PREFIX *src,
|
|
unsigned short int count
|
|
)
|
|
{
|
|
memcpy(dest, (void*)src, (size_t)count);
|
|
}
|
|
|
|
|
|
static int
|
|
AsciiToInt(
|
|
const char* string
|
|
)
|
|
{
|
|
return atoi(string);
|
|
}
|
|
|
|
|
|
static long
|
|
StringToLong(
|
|
const char *nptr,
|
|
char **endptr,
|
|
int base
|
|
)
|
|
{
|
|
return UFLstrtol(nptr, endptr, base);
|
|
}
|
|
|
|
|
|
static int
|
|
StrCmp(
|
|
const char PTR_PREFIX *string1,
|
|
const char PTR_PREFIX *string2
|
|
)
|
|
{
|
|
return UFLstrcmp(string1, string2);
|
|
}
|
|
|
|
|
|
static int
|
|
GetCharName(
|
|
XFhandle handle,
|
|
void *client,
|
|
XCFGlyphID glyphID,
|
|
char PTR_PREFIX *charName,
|
|
unsigned short int length
|
|
)
|
|
{
|
|
if (client)
|
|
{
|
|
/*
|
|
* Copy the charname by ourself because the name string returned from
|
|
* XCF is not NULL terminated.
|
|
*/
|
|
unsigned short int i;
|
|
|
|
/* UFLsprintf((char*)client, "%s", charName); */
|
|
|
|
for (i = 0; i < length; i++)
|
|
*((char *)client)++ = *charName++;
|
|
|
|
*((char *)client) = '\0';
|
|
|
|
return XCF_Ok;
|
|
}
|
|
|
|
return XCF_InternalError;
|
|
}
|
|
|
|
|
|
static int
|
|
GIDToCID(
|
|
XFhandle handle,
|
|
void PTR_PREFIX *client,
|
|
XCFGlyphID glyphID,
|
|
unsigned short int cid
|
|
)
|
|
{
|
|
if (client)
|
|
{
|
|
unsigned short int *pCid = (unsigned short int *)client;
|
|
*pCid = cid;
|
|
return XCF_Ok;
|
|
}
|
|
|
|
return XCF_InternalError;
|
|
}
|
|
|
|
|
|
static void
|
|
getFSType(
|
|
XFhandle h,
|
|
long PTR_PREFIX *pfsType,
|
|
void PTR_PREFIX *clientHook
|
|
)
|
|
{
|
|
UFOStruct* pUFO;
|
|
long fsType;
|
|
|
|
if (!pfsType)
|
|
return;
|
|
|
|
*pfsType = -1; /* "Don't put FSType" by default. */
|
|
|
|
if (!(pUFO = (UFOStruct*)clientHook))
|
|
return;
|
|
|
|
fsType = GetOS2FSType(pUFO);
|
|
|
|
if(0 <= fsType)
|
|
*pfsType = fsType;
|
|
}
|
|
|
|
|
|
/* GOODNAME */
|
|
static void
|
|
isKnownROS(XFhandle h,
|
|
long PTR_PREFIX *pknownROS,
|
|
char PTR_PREFIX *R,
|
|
Card16 lenR,
|
|
char PTR_PREFIX *O,
|
|
Card16 lenO,
|
|
long S,
|
|
void PTR_PREFIX *clientHook
|
|
)
|
|
{
|
|
UFOStruct *pUFO;
|
|
|
|
if (!pknownROS)
|
|
return;
|
|
|
|
*pknownROS = 0;
|
|
|
|
if (!(pUFO = (UFOStruct*)clientHook))
|
|
return;
|
|
|
|
if ((lenR < 32) && (lenO < 32))
|
|
{
|
|
char Registry[32], Ordering[32];
|
|
int i;
|
|
|
|
for (i = 0; i < (int) lenR; i++)
|
|
Registry[i] = (char) R[i];
|
|
|
|
Registry[lenR] = '\0';
|
|
|
|
for (i = 0; i < (int)lenO; i++)
|
|
Ordering[i] = (char) O[i];
|
|
|
|
Ordering[lenO] = '\0';
|
|
|
|
if (!UFLstrcmp(Registry, "Adobe"))
|
|
{
|
|
if ( KNOWN_OS(Ordering, "Japan1", S, ADOBE_JAPAN1_MAXKNOWN)
|
|
|| KNOWN_OS(Ordering, "Korea1", S, ADOBE_KOREA1_MAXKNOWN)
|
|
|| KNOWN_OS(Ordering, "GB1", S, ADOBE_GB1_MAXKNOWN )
|
|
|| KNOWN_OS(Ordering, "CNS1", S, ADOBE_CNS1_MAXKNOWN ))
|
|
{
|
|
*pknownROS = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*pknownROS)
|
|
pUFO->pAFont->knownROS = 1;
|
|
else
|
|
{
|
|
pUFO->pAFont->knownROS = 0;
|
|
pUFO->dwFlags |= UFO_HasG2UDict;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
printfError(
|
|
const char *format, ...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
int retval = 0;
|
|
char buf[512];
|
|
|
|
va_start(arglist, format);
|
|
if (SUCCEEDED(StringCchVPrintfA(buf, CCHOF(buf), format, arglist)))
|
|
{
|
|
retval = strlen(buf);
|
|
}
|
|
va_end(arglist);
|
|
return retval;
|
|
}
|
|
|
|
|
|
enum XCF_Result
|
|
CFFInitFont(
|
|
UFOStruct *pUFO,
|
|
CFFFontStruct *pFont
|
|
)
|
|
{
|
|
XCF_CallbackStruct callbacks = {0};
|
|
XCF_ClientOptions options = {0};
|
|
|
|
char fontName[256];
|
|
|
|
/*
|
|
* Initialize XCF_CallbackStruct object.
|
|
*/
|
|
|
|
/* Stream output functions */
|
|
callbacks.putBytes = PutBytesAtPos;
|
|
callbacks.putBytesHook = (void PTR_PREFIX *)pUFO;
|
|
callbacks.outputPos = (XCF_OutputPosFunc)nil;
|
|
callbacks.outputPosHook = (void PTR_PREFIX *)0;
|
|
callbacks.getBytes = GetBytesFromPos;
|
|
callbacks.getBytesHook = (void PTR_PREFIX *)pUFO;
|
|
callbacks.allocate = AllocateMem;
|
|
callbacks.allocateHook = (void PTR_PREFIX *)pUFO;
|
|
callbacks.pFont = 0;
|
|
callbacks.fontLength = 0;
|
|
|
|
/* C Standard library functions */
|
|
callbacks.strlen = (XCF_strlen)StringLength;
|
|
callbacks.memcpy = (XCF_memcpy)MemCpy;
|
|
callbacks.memset = (XCF_memset)SetMemory;
|
|
callbacks.xcfSprintf = (XCF_sprintf)UFLsprintf;
|
|
callbacks.printfError = (XCF_printfError)printfError;
|
|
callbacks.atoi = (XCF_atoi)AsciiToInt;
|
|
callbacks.strtol = (XCF_strtol)StringToLong;
|
|
callbacks.atof = (XCF_atof)nil; /* not required */
|
|
callbacks.strcmp = (XCF_strcmp)StrCmp;
|
|
|
|
/* Glyph ID functions */
|
|
callbacks.gidToCharName = (XCF_GIDToCharName)GetCharName;
|
|
callbacks.gidToCID = (XCF_GIDToCID)GIDToCID;
|
|
callbacks.getCharStr = (XCF_GetCharString)nil;
|
|
callbacks.getCharStrHook = (void PTR_PREFIX *)nil;
|
|
callbacks.getFSType = (XCF_GetFSType)getFSType;
|
|
callbacks.getFSTypeHook = (void PTR_PREFIX *)pUFO;
|
|
|
|
/* GOODNAME */
|
|
callbacks.isKnownROS = (XCF_IsKnownROS)isKnownROS;
|
|
callbacks.isKnownROSHook = (void PTR_PREFIX *)pUFO;
|
|
|
|
/*
|
|
* Initialize XCF_ClientOptions object.
|
|
*/
|
|
|
|
options.fontIndex = 0; /* font index w/i a CFF font set */
|
|
options.uniqueIDMethod = pFont->info.uniqueIDMethod; /* UniqueID method */
|
|
options.uniqueID = pFont->info.uniqueID;
|
|
options.subrFlatten = (pFont->info.subrFlatten == kFlattenSubrs) ? XCF_FLATTEN_SUBRS : XCF_KEEP_SUBRS; /* Flatten subrs */
|
|
// lenIV = -1 will fail on some clones bug 354368
|
|
// options.lenIV = (pUFO->pUFL->outDev.lPSLevel > kPSLevel1) ? (unsigned int)-1 : 4;
|
|
options.lenIV = 0;
|
|
options.hexEncoding = StrmCanOutputBinary(pUFO->pUFL->hOut) ? 0 : 1;
|
|
options.eexecEncryption = (pUFO->pUFL->outDev.lPSLevel > kPSLevel1) ? 0 : 1;
|
|
options.outputCharstrType = 1; /* (pUFO->pUFL->outDev.lPSLevel > kPSLevel2) ? 2 : 1 */
|
|
options.maxBlockSize = pFont->info.maxBlockSize;
|
|
|
|
/*
|
|
* XCF_ClientOptions.dlOptions initialization
|
|
*/
|
|
if (pFont->info.usePSName)
|
|
options.dlOptions.notdefEncoding = 1;
|
|
else
|
|
options.dlOptions.notdefEncoding = 0;
|
|
|
|
options.dlOptions.useSpecialEncoding = (pFont->info.useSpecialEncoding) ? 1 : 0;
|
|
options.dlOptions.encodeName = (unsigned char PTR_PREFIX *)pUFO->pszEncodeName;
|
|
|
|
if (pFont->info.escDownloadFace)
|
|
options.dlOptions.fontName = (unsigned char PTR_PREFIX *)pUFO->pszFontName;
|
|
else
|
|
{
|
|
if (pFont->info.type1)
|
|
{
|
|
if (pUFO->subfontNumber < 0x100)
|
|
CREATE_ADCFXX_FONTNAME(UFLsprintf, fontName, CCHOF(fontName),
|
|
pUFO->subfontNumber, pFont->info.baseName);
|
|
else
|
|
CREATE_ADXXXX_FONTNAME(UFLsprintf, fontName, CCHOF(fontName),
|
|
pUFO->subfontNumber, pFont->info.baseName);
|
|
}
|
|
else
|
|
{
|
|
/* Reuse vifinfo.nPlatformID to fix #507985. */
|
|
if (pUFO->vpfinfo.nPlatformID == kUFLVPFPlatformID9x)
|
|
{
|
|
if (pUFO->lDownloadFormat == kCFFCID_H)
|
|
UFLsprintf(fontName, CCHOF(fontName), "%s%s", CFFPREFIX_H, pFont->info.baseName);
|
|
else
|
|
UFLsprintf(fontName, CCHOF(fontName), "%s%s", CFFPREFIX_V, pFont->info.baseName);
|
|
}
|
|
else
|
|
UFLsprintf(fontName, CCHOF(fontName), "%s%s", CFFPREFIX, pFont->info.baseName);
|
|
}
|
|
|
|
options.dlOptions.fontName = (unsigned char PTR_PREFIX *)fontName;
|
|
}
|
|
|
|
options.dlOptions.otherSubrNames =
|
|
(pUFO->pUFL->outDev.lPSVersion >= VER_WO_OTHERSUBRS)
|
|
? 0 : (unsigned char PTR_PREFIX * PTR_PREFIX *)pSubrNames;
|
|
|
|
return XCF_Init(&pFont->hFont, &callbacks, &options);
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Public Functions
|
|
*
|
|
******************************************************************************/
|
|
|
|
void
|
|
CFFFontCleanUp(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
CFFFontStruct *pFont;
|
|
UFLCFFReadBuf *pReadBuf;
|
|
|
|
if (pUFObj->pAFont == nil)
|
|
return;
|
|
|
|
pFont = (CFFFontStruct *)pUFObj->pAFont->hFont;
|
|
|
|
if (pFont == nil)
|
|
return;
|
|
|
|
if (pFont->hFont)
|
|
{
|
|
XCF_CleanUp(&pFont->hFont);
|
|
pFont->hFont = nil;
|
|
}
|
|
|
|
pReadBuf = pFont->pReadBuf;
|
|
|
|
if (pReadBuf->pBuf)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pReadBuf->pBuf);
|
|
pReadBuf->pBuf = nil;
|
|
}
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFUpdateEncodingVector1(
|
|
UFOStruct *pUFO,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
const short cGlyphs,
|
|
const UFLGlyphID *pGlyphIndices
|
|
)
|
|
{
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFO->pAFont->hFont;
|
|
UFLHANDLE stream = pUFO->pUFL->hOut;
|
|
UFLErrCode retCode = kNoErr;
|
|
char strmbuf[256];
|
|
short i;
|
|
|
|
/* Sanity checks */
|
|
if (0 == cGlyphs)
|
|
return kNoErr;
|
|
|
|
if ((0 == pFont) || (0 == pGlyphIndices))
|
|
return kErrInvalidParam;
|
|
|
|
/*
|
|
* Do '/FontName findfont /Encoding get'.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s findfont /Encoding get", pUFO->pszFontName);
|
|
retCode = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
for (i = 0; (retCode == kNoErr) && (i < cGlyphs) && *pGlyphIndices; i++, pGlyphIndices++)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "dup %d /", i);
|
|
retCode = StrmPutString(stream, strmbuf);
|
|
|
|
if (retCode == kNoErr)
|
|
{
|
|
XCF_GlyphIDsToCharNames(pFont->hFont,
|
|
1,
|
|
(XCFGlyphID PTR_PREFIX *)pGlyphIndices, /* list of glyphIDs */
|
|
strmbuf,
|
|
sizeof(strmbuf));
|
|
retCode = StrmPutString(stream, strmbuf);
|
|
}
|
|
|
|
if (retCode == kNoErr)
|
|
retCode = StrmPutStringEOL(stream, " put");
|
|
}
|
|
|
|
StrmPutStringEOL(stream, "pop");
|
|
|
|
return retCode;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFUpdateEncodingVector(
|
|
UFOStruct *pUFO,
|
|
const short cGlyphs,
|
|
const UFLGlyphID *pGlyphIndices,
|
|
const unsigned short *pGlyphNameIndex
|
|
)
|
|
{
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFO->pAFont->hFont;
|
|
UFLHANDLE stream = pUFO->pUFL->hOut;
|
|
UFLErrCode retCode = kNoErr;
|
|
const UFLGlyphID *pGlyphIndices2 = pGlyphIndices;
|
|
const unsigned short *pGlyphNameIndex2 = pGlyphNameIndex;
|
|
char strmbuf[256];
|
|
short i;
|
|
|
|
/* Sanity checks */
|
|
if (0 == cGlyphs)
|
|
return kNoErr;
|
|
|
|
if ((0 == pFont) || (0 == pGlyphNameIndex) || (0 == pGlyphIndices))
|
|
return kErrInvalidParam;
|
|
|
|
/*
|
|
* Do we really need to update?
|
|
*/
|
|
for (i = 0; i < cGlyphs; i++, pGlyphNameIndex2++, pGlyphIndices2++)
|
|
{
|
|
if ((*pGlyphNameIndex2 > 0) && (*pGlyphNameIndex2 <= 255))
|
|
{
|
|
if (!IS_GLYPH_SENT(pUFO->pUpdatedEncoding, *pGlyphNameIndex2))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cGlyphs <= i)
|
|
return kNoErr;
|
|
|
|
/*
|
|
* Do '/FontName findfont /Encoding get'.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s findfont /Encoding get", pUFO->pszFontName);
|
|
retCode = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
for (i = 0; (retCode == kNoErr) && (i < cGlyphs); i++, pGlyphNameIndex++, pGlyphIndices++)
|
|
{
|
|
if ((*pGlyphNameIndex > 0) && (*pGlyphNameIndex <= 255))
|
|
{
|
|
if (!IS_GLYPH_SENT(pUFO->pUpdatedEncoding, *pGlyphNameIndex))
|
|
{
|
|
/*
|
|
* Do "dup index /Charactername put."
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "dup %d /", *pGlyphNameIndex);
|
|
retCode = StrmPutString(stream, strmbuf);
|
|
|
|
if (kNoErr == retCode)
|
|
{
|
|
if (XCF_Ok == XCF_GlyphIDsToCharNames(pFont->hFont,
|
|
1,
|
|
(XCFGlyphID PTR_PREFIX *)pGlyphIndices, /* list of glyphIDs */
|
|
strmbuf,
|
|
sizeof(strmbuf)))
|
|
{
|
|
retCode = StrmPutString(stream, strmbuf);
|
|
}
|
|
else
|
|
retCode = kErrUnknown;
|
|
}
|
|
|
|
if (kNoErr == retCode)
|
|
retCode = StrmPutStringEOL(stream, " put");
|
|
|
|
if (kNoErr == retCode)
|
|
SET_GLYPH_SENT_STATUS(pUFO->pUpdatedEncoding, *pGlyphNameIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
StrmPutStringEOL(stream, "pop");
|
|
|
|
return retCode;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFCreateBaseFont(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMUsage,
|
|
char *pHostFontName
|
|
)
|
|
{
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFObj->pAFont->hFont;
|
|
UFLHANDLE stream = pUFObj->pUFL->hOut;
|
|
UFLErrCode retCode = kNoErr;
|
|
char strmbuf[512];
|
|
|
|
/* Sanity checks */
|
|
if (pUFObj->flState < kFontInit)
|
|
return kErrInvalidState;
|
|
|
|
if ((pFont == nil) || (pFont->hFont == nil))
|
|
return kErrInvalidHandle;
|
|
|
|
/*
|
|
* Download procsets.
|
|
*/
|
|
switch (pUFObj->lDownloadFormat)
|
|
{
|
|
case kCFF:
|
|
if (pUFObj->pUFL->outDev.lPSVersion <= VER_WO_OTHERSUBRS)
|
|
{
|
|
/*
|
|
* Only download the required OtherSubr procset if the printer
|
|
* version is less than 51 and we have not download anything.
|
|
*/
|
|
if (pUFObj->pUFL->outDev.pstream->pfDownloadProcset == 0)
|
|
return kErrDownloadProcset;
|
|
|
|
if (!pUFObj->pUFL->outDev.pstream->pfDownloadProcset(pUFObj->pUFL->outDev.pstream, kCFFHeader))
|
|
return kErrDownloadProcset;
|
|
}
|
|
break;
|
|
|
|
case kCFFCID_H:
|
|
case kCFFCID_V:
|
|
if (!pUFObj->pUFL->outDev.pstream->pfDownloadProcset(pUFObj->pUFL->outDev.pstream, kCMap_FF))
|
|
return kErrDownloadProcset;
|
|
|
|
if (pUFObj->bPatchQXPCFFCID)
|
|
{
|
|
if (!pUFObj->pUFL->outDev.pstream->pfDownloadProcset(pUFObj->pUFL->outDev.pstream, kCMap_90msp))
|
|
return kErrDownloadProcset;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Donwload the font's dictionary and the glyph data.
|
|
*/
|
|
if (!UFO_FONT_INIT2(pUFObj))
|
|
{
|
|
enum XCF_Result status;
|
|
|
|
/*
|
|
* Fixed bug 366539. hasvmtx is used to determine whether to call the
|
|
* CFFUpdateMetrics2 function later.
|
|
*/
|
|
unsigned long tblSize = GETTTFONTDATA(pUFObj,
|
|
VMTX_TABLE, 0L,
|
|
nil, 0L,
|
|
pFont->info.fData.fontIndex);
|
|
|
|
pUFObj->pAFont->hasvmtx = tblSize ? 1 : 0;
|
|
|
|
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
status = XCF_DownloadFontIncr(pFont->hFont,
|
|
pGlyphs->sCount,
|
|
pGlyphs->pGlyphIndices,
|
|
(pGlyphs->pCharIndex == 0)
|
|
? nil
|
|
: (unsigned char PTR_PREFIX * PTR_PREFIX *)pGlyphs->ppGlyphNames,
|
|
pVMUsage);
|
|
|
|
if (XCF_Ok != status)
|
|
retCode = kErrXCFCall;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* %hostfont% support
|
|
* When this is a %hostfont% emit %%IncludeResource DSC comment prior to
|
|
* create the font.
|
|
*/
|
|
if ((kNoErr == retCode) && HOSTFONT_IS_VALID_UFO(pUFObj) && !UFO_FONT_INIT2(pUFObj))
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "\n%%%%IncludeResource: %s %s",
|
|
(pUFObj->lDownloadFormat == kCFF) ? "font" : "CIDFont",
|
|
pHostFontName);
|
|
|
|
if (kNoErr == retCode)
|
|
retCode = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
if ((kNoErr == retCode) && IS_CFFCID(pUFObj->lDownloadFormat))
|
|
{
|
|
/*
|
|
* Instanciate Identity-H or -V CMap.
|
|
*
|
|
* When 'vrt2' feature is enabled (and which is default for OTF based
|
|
* CJKV fonts), simply compose Identity-V CMap and the CIDFont
|
|
* downloaded suffice.
|
|
*/
|
|
if (pUFObj->lDownloadFormat == kCFFCID_H)
|
|
{
|
|
retCode = StrmPutStringEOL(stream, "CMAP-WinCharSetFFFF-H");
|
|
|
|
/* Special for Quark */
|
|
if ((kNoErr == retCode) && pUFObj->bPatchQXPCFFCID)
|
|
retCode = StrmPutStringEOL(stream, "CMAP-90msp-RKSJ-H");
|
|
}
|
|
else
|
|
{
|
|
retCode = StrmPutStringEOL(stream, "CMAP-WinCharSetFFFF-V");
|
|
|
|
/* Special for Quark */
|
|
if ((kNoErr == retCode) && pUFObj->bPatchQXPCFFCID)
|
|
retCode = StrmPutStringEOL(stream, "CMAP-90msp-RKSJ-H CMAP-90msp-RKSJ-QV");
|
|
}
|
|
|
|
if (kNoErr == retCode)
|
|
{
|
|
/*
|
|
* Create the CID-Keyed font.
|
|
*/
|
|
UFLBool bRequire_vmtx = pUFObj->pAFont->hasvmtx && HOSTFONT_REQUIRE_VMTX;
|
|
|
|
if (pUFObj->lDownloadFormat == kCFFCID_H)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s /WinCharSetFFFF-H", pUFObj->pszFontName);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s /WinCharSetFFFF-V", pUFObj->pszFontName);
|
|
if (kNoErr == retCode)
|
|
retCode = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/* Reuse vifinfo.nPlatformID to fix #507985. */
|
|
if (pUFObj->vpfinfo.nPlatformID == kUFLVPFPlatformID9x)
|
|
{
|
|
if (pUFObj->lDownloadFormat == kCFFCID_H)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "[/%s%s] composefont pop", CFFPREFIX_H, pFont->info.baseName);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "[/%s%s] composefont pop", CFFPREFIX_V, pFont->info.baseName);
|
|
}
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "[/%s%s] composefont pop", CFFPREFIX, pFont->info.baseName);
|
|
}
|
|
else if (!bRequire_vmtx)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "[/%s] composefont pop", pHostFontName);
|
|
else
|
|
{
|
|
if (UFL_CIDFONT_SHARED)
|
|
{
|
|
if (!UFO_FONT_INIT2(pUFObj))
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s %s /%s hfMkCIDFont",
|
|
pHostFontName, HFPOSTFIX, HFCIDCDEVPROC, pHostFontName);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "[/%s%s] composefont pop", pHostFontName, HFPOSTFIX);
|
|
}
|
|
else
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s%s %s /%s hfMkCIDFont",
|
|
pHostFontName, HFPOSTFIX,
|
|
(pUFObj->lDownloadFormat == kCFFCID_H) ? "h" : "v",
|
|
HFCIDCDEVPROC, pHostFontName);
|
|
}
|
|
}
|
|
|
|
if (kNoErr == retCode)
|
|
retCode = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
/*
|
|
* Special for Quark
|
|
*/
|
|
if ((kNoErr == retCode) && pUFObj->bPatchQXPCFFCID)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%sQ", pUFObj->pszFontName);
|
|
retCode = StrmPutString(stream, strmbuf);
|
|
|
|
if (pUFObj->lDownloadFormat == kCFFCID_H)
|
|
{
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/* Reuse vifinfo.nPlatformID to fix #507985. */
|
|
if (pUFObj->vpfinfo.nPlatformID == kUFLVPFPlatformID9x)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-H [/%s%s] composefont pop",
|
|
CFFPREFIX_H, pFont->info.baseName);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-H [/%s%s] composefont pop",
|
|
CFFPREFIX, pFont->info.baseName);
|
|
}
|
|
else if (!bRequire_vmtx)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-H [/%s] composefont pop",
|
|
pHostFontName);
|
|
}
|
|
else
|
|
{
|
|
if (UFL_CIDFONT_SHARED)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-H [/%s%s] composefont pop",
|
|
pHostFontName, HFPOSTFIX);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-H [/%s%s%s] composefont pop",
|
|
pHostFontName, HFPOSTFIX, "h");
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
/* Added 'dup dup' for bug 346287. */
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/* Reuse vifinfo.nPlatformID to fix #507985. */
|
|
if (pUFObj->vpfinfo.nPlatformID == kUFLVPFPlatformID9x)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-QV [/%s%s dup dup] composefont pop",
|
|
CFFPREFIX_V, pFont->info.baseName);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-QV [/%s%s dup dup] composefont pop",
|
|
CFFPREFIX, pFont->info.baseName);
|
|
}
|
|
else if (!bRequire_vmtx)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-QV [/%s dup dup] composefont pop",
|
|
pHostFontName);
|
|
}
|
|
else
|
|
{
|
|
if (UFL_CIDFONT_SHARED)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-QV [/%s%s dup dup] composefont pop",
|
|
pHostFontName, HFPOSTFIX);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /90msp-RKSJ-QV [/%s%s%s dup dup] composefont pop",
|
|
pHostFontName, HFPOSTFIX, "v");
|
|
}
|
|
}
|
|
|
|
if (kNoErr == retCode)
|
|
retCode = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
}
|
|
}
|
|
else if ((kNoErr == retCode) && HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/*
|
|
* Redefine the font using the already existing OpenType host font with
|
|
* a unique name so that we can reencode its encoding vector freely. We
|
|
* don't want empty CharStrings so that we give false to hfRedefFont.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s false /%s hfRedefFont",
|
|
pUFObj->pszFontName, pHostFontName);
|
|
if (kNoErr == retCode)
|
|
retCode = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
/*
|
|
* Change the font state. (skip kFontHeaderDownloaded state.)
|
|
*/
|
|
if (kNoErr == retCode)
|
|
pUFObj->flState = kFontHasChars;
|
|
|
|
return retCode;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFAddChars(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMUsage
|
|
)
|
|
{
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFObj->pAFont->hFont;
|
|
UFLErrCode retCode = kNoErr;
|
|
|
|
/* Sanity checks */
|
|
if (pUFObj->flState < kFontHeaderDownloaded)
|
|
return kErrInvalidState;
|
|
|
|
if ((pFont == nil) || (pFont->hFont == nil))
|
|
return kErrInvalidHandle;
|
|
|
|
/*
|
|
* Download the glyphs.
|
|
*/
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
enum XCF_Result status;
|
|
|
|
status = XCF_DownloadFontIncr(pFont->hFont,
|
|
pGlyphs->sCount,
|
|
pGlyphs->pGlyphIndices,
|
|
(pGlyphs->pCharIndex == 0)
|
|
? nil
|
|
: (unsigned char PTR_PREFIX * PTR_PREFIX *)pGlyphs->ppGlyphNames,
|
|
pVMUsage);
|
|
|
|
if (XCF_Ok != status)
|
|
retCode = kErrXCFCall;
|
|
}
|
|
|
|
/*
|
|
* Change the font state.
|
|
*/
|
|
if (kNoErr == retCode)
|
|
pUFObj->flState = kFontHasChars;
|
|
|
|
return retCode;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFUpdateMetrics2(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
char *pHostFontName
|
|
)
|
|
{
|
|
UFLErrCode retVal = kNoErr;
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFObj->pAFont->hFont;
|
|
UFLHANDLE stream = pUFObj->pUFL->hOut;
|
|
char strmbuf[256];
|
|
unsigned short wIndex;
|
|
UFLBool bRequire_vmtx = pUFObj->pAFont->hasvmtx && HOSTFONT_REQUIRE_VMTX;
|
|
|
|
if ((!HOSTFONT_IS_VALID_UFO(pUFObj) || bRequire_vmtx) && (pGlyphs->sCount > 0))
|
|
{
|
|
UFLGlyphID *glyphs = pGlyphs->pGlyphIndices;
|
|
unsigned short i;
|
|
unsigned short *pCIDs = (unsigned short*)UFLNewPtr(pUFObj->pMem, pGlyphs->sCount * sizeof (unsigned short));
|
|
|
|
if (pCIDs)
|
|
retVal = CFFGIDsToCIDs(pFont, pGlyphs->sCount, glyphs, pCIDs);
|
|
else
|
|
retVal = kErrOutOfMemory;
|
|
|
|
if (kNoErr != retVal)
|
|
{
|
|
if (pCIDs)
|
|
UFLDeletePtr(pUFObj->pMem, pCIDs);
|
|
return retVal;
|
|
}
|
|
|
|
/*
|
|
* Check pUFObj->pAFont->pCodeGlyphs to see if we really need to update
|
|
* it.
|
|
*/
|
|
for (i = 0; i < (unsigned short) pGlyphs->sCount; i++)
|
|
{
|
|
unsigned short 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))
|
|
{
|
|
long em, w1y, vx, vy, tsb, vasc;
|
|
UFLBool bUseDef;
|
|
|
|
GetMetrics2FromTTF(pUFObj, wIndex, &em, &w1y, &vx, &vy, &tsb, &bUseDef, 0, &vasc);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "%ld [0 %ld %ld %ld] ", (long)pCIDs[i], -w1y, vx, tsb);
|
|
retVal = StrmPutString(stream, strmbuf);
|
|
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/* Reuse vifinfo.nPlatformID to fix #507985. */
|
|
if (pUFObj->vpfinfo.nPlatformID == kUFLVPFPlatformID9x)
|
|
{
|
|
if (pUFObj->lDownloadFormat == kCFFCID_H)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s T0AddCFFMtx2", CFFPREFIX_H, pFont->info.baseName);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s T0AddCFFMtx2", CFFPREFIX_V, pFont->info.baseName);
|
|
}
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /%s%s T0AddCFFMtx2", CFFPREFIX, pFont->info.baseName);
|
|
}
|
|
else
|
|
{
|
|
if (UFL_CIDFONT_SHARED)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /%s%s T0AddCFFMtx2", pHostFontName, HFPOSTFIX);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /%s%s%s T0AddCFFMtx2",
|
|
pHostFontName, HFPOSTFIX,
|
|
(pUFObj->lDownloadFormat == kCFFCID_H) ? "h" : "v");
|
|
}
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
if (kNoErr == retVal)
|
|
SET_GLYPH_SENT_STATUS(pUFObj->pAFont->pDownloadedGlyphs, wIndex);
|
|
}
|
|
}
|
|
|
|
UFLDeletePtr(pUFObj->pMem, pCIDs);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFReencode(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMUsage,
|
|
char *pHostFontName
|
|
)
|
|
{
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFObj->pAFont->hFont;
|
|
UFLErrCode retCode = kNoErr;
|
|
|
|
/* Sanity checks */
|
|
if (pUFObj->flState < kFontHeaderDownloaded)
|
|
return kErrInvalidState;
|
|
|
|
if ((pFont == nil) || (pFont->hFont == nil))
|
|
return kErrInvalidHandle;
|
|
|
|
/*
|
|
* Reencode the encoding vector and define good glyph names.
|
|
*/
|
|
if (kNoErr == retCode)
|
|
{
|
|
if (pFont->info.usePSName)
|
|
{
|
|
if (pGlyphs->pCharIndex == 0)
|
|
retCode = CFFUpdateEncodingVector1(
|
|
(UFOStruct *)pUFObj,
|
|
pGlyphs,
|
|
pGlyphs->sCount,
|
|
pGlyphs->pGlyphIndices);
|
|
else
|
|
retCode = CFFUpdateEncodingVector(
|
|
(UFOStruct *)pUFObj,
|
|
pGlyphs->sCount,
|
|
pGlyphs->pGlyphIndices,
|
|
pGlyphs->pCharIndex);
|
|
}
|
|
|
|
/*
|
|
* Adobe Bug #366539 and #388111: Download Metrics2 for vertical writing
|
|
*
|
|
* Note: to remember the glyphs downloaded for Metrics2 we use
|
|
* pUFObj->pAFont->pDownloadedGlyphs. There is another bitmap data,
|
|
* pUFObj->pAFont->pCodeGlyphs, to remember the glyphs downloaded
|
|
* for GoodGlyphName. They must be used independently. Do not use
|
|
* pDownloadedGlyphs for GoodGlyphName and pCodeGlyphs for Metrics2.
|
|
*/
|
|
if ((kNoErr == retCode) && IS_CFFCID(pUFObj->lDownloadFormat))
|
|
{
|
|
retCode = CFFUpdateMetrics2(pUFObj, pGlyphs, pHostFontName);
|
|
}
|
|
|
|
/*
|
|
* GOODNAME
|
|
*/
|
|
if ((kNoErr == retCode)
|
|
&& (pGlyphs->sCount > 0)
|
|
&& (pUFObj->dwFlags & UFO_HasG2UDict)
|
|
&& (IS_CFFCID(pUFObj->lDownloadFormat))
|
|
&& !(pUFObj->pAFont->knownROS))
|
|
{
|
|
UFLGlyphID *glyphs = pGlyphs->pGlyphIndices;
|
|
unsigned short i;
|
|
|
|
/*
|
|
* Check pUFObj->pAFont->pCodeGlyphs to see if we really need to
|
|
* update it.
|
|
*/
|
|
for (i = 0; i < (unsigned short) pGlyphs->sCount; i++)
|
|
{
|
|
unsigned short 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.
|
|
*/
|
|
retCode = UpdateCodeInfo(pUFObj, pGlyphs, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return retCode;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFFontDownloadIncr(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMUsage,
|
|
unsigned long *pFCUsage
|
|
)
|
|
{
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFObj->pAFont->hFont;
|
|
UFLErrCode retCode = kNoErr;
|
|
char *pHostFontName = nil;
|
|
|
|
if (pFCUsage)
|
|
*pFCUsage = 0;
|
|
|
|
/*
|
|
* Sanity checks.
|
|
*/
|
|
if ((pGlyphs == nil) || (pGlyphs->pGlyphIndices == nil) || (pGlyphs->sCount == 0))
|
|
return kErrInvalidParam;
|
|
|
|
/*
|
|
* No need to download if the full font has already been downloaded.
|
|
*/
|
|
if (pUFObj->flState == kFontFullDownloaded)
|
|
return kNoErr;
|
|
|
|
/*
|
|
* Check %hostfont% status prior to download anything.
|
|
*/
|
|
HostFontValidateUFO(pUFObj, &pHostFontName);
|
|
|
|
if (pUFObj->flState == kFontInit)
|
|
{
|
|
/*
|
|
* Create a base font (and the glyphs) if it has not been done yet.
|
|
*/
|
|
retCode = CFFCreateBaseFont(pUFObj, pGlyphs, pVMUsage, pHostFontName);
|
|
|
|
if (kNoErr == retCode)
|
|
retCode = CFFReencode(pUFObj, pGlyphs, pVMUsage, pHostFontName);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Download the glyphs.
|
|
*/
|
|
retCode = CFFAddChars(pUFObj, pGlyphs, pVMUsage);
|
|
|
|
if (kNoErr == retCode)
|
|
retCode = CFFReencode(pUFObj, pGlyphs, pVMUsage, pHostFontName);
|
|
}
|
|
|
|
return retCode;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFVMNeeded(
|
|
const UFOStruct *pUFO,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMNeeded,
|
|
unsigned long *pFCNeeded
|
|
)
|
|
{
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFO->pAFont->hFont;
|
|
enum XCF_Result status;
|
|
unsigned short cDLGlyphs;
|
|
|
|
if (pVMNeeded)
|
|
*pVMNeeded = 0;
|
|
|
|
if (pFCNeeded)
|
|
*pFCNeeded = 0;
|
|
|
|
if ((pFont == nil) || (pFont->hFont == nil))
|
|
return kErrInvalidHandle;
|
|
|
|
status = XCF_CountDownloadGlyphs(pFont->hFont,
|
|
pGlyphs->sCount,
|
|
(XCFGlyphID *)pGlyphs->pGlyphIndices,
|
|
&cDLGlyphs);
|
|
|
|
if (XCF_Ok != status)
|
|
return kErrUnknown;
|
|
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFO))
|
|
{
|
|
if (pVMNeeded)
|
|
*pVMNeeded = cDLGlyphs * kVMTTT1Char;
|
|
|
|
if (pUFO->flState == kFontInit)
|
|
{
|
|
if (pVMNeeded)
|
|
*pVMNeeded += kVMTTT1Header;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned long tblSize = GETTTFONTDATA(pUFO,
|
|
VMTX_TABLE, 0L,
|
|
nil, 0L,
|
|
pFont->info.fData.fontIndex);
|
|
|
|
if (tblSize && HOSTFONT_REQUIRE_VMTX)
|
|
{
|
|
if (pVMNeeded)
|
|
*pVMNeeded = cDLGlyphs * HFVMM2SZ;
|
|
}
|
|
}
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFUndefineFont(
|
|
UFOStruct *pUFO
|
|
)
|
|
{
|
|
CFFFontStruct *pFont = (CFFFontStruct *)pUFO->pAFont->hFont;
|
|
UFLHANDLE stream = pUFO->pUFL->hOut;
|
|
UFLErrCode retVal = kNoErr;
|
|
char strmbuf[256];
|
|
|
|
if ((pFont == nil) || (pFont->hFont == nil))
|
|
return kErrInvalidHandle;
|
|
|
|
if (pUFO->flState == kFontInit)
|
|
return retVal;
|
|
|
|
if ((pUFO->lDownloadFormat == kCFFCID_H) || (pUFO->lDownloadFormat == kCFFCID_V))
|
|
{
|
|
/* Reuse vifinfo.nPlatformID to fix #507985. */
|
|
if (pUFO->vpfinfo.nPlatformID == kUFLVPFPlatformID9x)
|
|
{
|
|
if (pUFO->lDownloadFormat == kCFFCID_H)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s /CIDFont UDR", CFFPREFIX_H, pFont->info.baseName);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s /CIDFont UDR", CFFPREFIX_V, pFont->info.baseName);
|
|
}
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s /CIDFont UDR", CFFPREFIX, pFont->info.baseName);
|
|
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s UDF", pUFO->pszFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CFFGIDsToCIDs(
|
|
const CFFFontStruct *pFont,
|
|
const short cGlyphs,
|
|
const UFLGlyphID *pGIDs,
|
|
unsigned short *pCIDs
|
|
)
|
|
{
|
|
unsigned short int *pCurCIDs = (unsigned short int *)pCIDs;
|
|
UFLGlyphID *pCurGIDs = (UFLGlyphID *)pGIDs;
|
|
UFLErrCode retCode = kNoErr;
|
|
enum XCF_Result status;
|
|
short i;
|
|
|
|
for (i = 0; i < cGlyphs; i++)
|
|
{
|
|
status = XCF_GlyphIDsToCIDs(pFont->hFont,
|
|
1,
|
|
(XCFGlyphID PTR_PREFIX *)pCurGIDs++, /* list of glyphIDs */
|
|
pCurCIDs++);
|
|
|
|
if (XCF_Ok != status)
|
|
{
|
|
retCode = kErrUnknown;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return retCode;
|
|
}
|
|
|
|
|
|
UFOStruct *
|
|
CFFFontInit(
|
|
const UFLMemObj *pMem,
|
|
const UFLStruct *pUFL,
|
|
const UFLRequest *pRequest,
|
|
UFLBool *pTestRestricted
|
|
)
|
|
{
|
|
enum XCF_Result status = XCF_InternalError;
|
|
CFFFontStruct *pFont = nil;
|
|
UFOStruct *pUFObj = (UFOStruct*)UFLNewPtr(pMem, sizeof (UFOStruct));
|
|
UFLCFFFontInfo *pInfo;
|
|
|
|
if (pUFObj == 0)
|
|
return nil;
|
|
|
|
/* Initialize data. */
|
|
UFOInitData(pUFObj, UFO_CFF, pMem, pUFL, pRequest,
|
|
(pfnUFODownloadIncr) CFFFontDownloadIncr,
|
|
(pfnUFOVMNeeded) CFFVMNeeded,
|
|
(pfnUFOUndefineFont) CFFUndefineFont,
|
|
(pfnUFOCleanUp) CFFFontCleanUp,
|
|
(pfnUFOCopy) CopyFont);
|
|
|
|
/*
|
|
* pszFontName should be ready/allocated. If not, cannot continue.
|
|
*/
|
|
if ((pUFObj->pszFontName == nil) || (pUFObj->pszFontName[0] == '\0'))
|
|
{
|
|
UFLDeletePtr(pMem, pUFObj);
|
|
return nil;
|
|
}
|
|
|
|
pInfo = (UFLCFFFontInfo *)pRequest->hFontInfo;
|
|
|
|
if (NewFont(pUFObj, sizeof(CFFFontStruct), pInfo->fData.maxGlyphs) == kNoErr)
|
|
{
|
|
pFont = (CFFFontStruct *)pUFObj->pAFont->hFont;
|
|
|
|
pFont->info = *pInfo;
|
|
|
|
pFont->pReadBuf = &pFont->info.readBuf;
|
|
|
|
/* a convenient pointer */
|
|
pUFObj->pFData = &(pFont->info.fData);
|
|
|
|
pFont->info.fData.cNumGlyphs = GetNumGlyphs(pUFObj);
|
|
|
|
if (pUFObj->pUpdatedEncoding == 0)
|
|
pUFObj->pUpdatedEncoding = (unsigned char *)UFLNewPtr(pMem, GLYPH_SENT_BUFSIZE(256));
|
|
|
|
pFont->hFont = 0;
|
|
|
|
status = CFFInitFont(pUFObj, pFont);
|
|
}
|
|
|
|
if ((XCF_Ok != status) || (pFont == nil) || (pFont->hFont == 0))
|
|
{
|
|
vDeleteFont(pUFObj);
|
|
UFLDeletePtr(pUFObj->pMem, pUFObj);
|
|
return nil;
|
|
}
|
|
else
|
|
{
|
|
if (pTestRestricted)
|
|
{
|
|
unsigned char uc;
|
|
unsigned short int us;
|
|
|
|
XCF_SubsetRestrictions(pFont->hFont, &uc, &us);
|
|
|
|
*pTestRestricted = (BOOL)uc;
|
|
}
|
|
else
|
|
status = XCF_ProcessCFF(pFont->hFont);
|
|
|
|
if (XCF_Ok == status)
|
|
pUFObj->flState = kFontInit;
|
|
else
|
|
{
|
|
vDeleteFont(pUFObj);
|
|
UFLDeletePtr(pUFObj->pMem, pUFObj);
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
return pUFObj;
|
|
}
|