/* * 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 #include #else #ifdef MAC_ENV #include #endif #include #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; }