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.
4768 lines
156 KiB
4768 lines
156 KiB
/*
|
|
* Adobe Universal Font Library
|
|
*
|
|
* Copyright (c) 1996 Adobe Systems Inc.
|
|
* All Rights Reserved
|
|
*
|
|
* UFOT42.c
|
|
*
|
|
*
|
|
* $Header:
|
|
*/
|
|
|
|
|
|
/*===============================================================================*
|
|
* Include files used by this interface *
|
|
*===============================================================================*/
|
|
#include "UFLPriv.h"
|
|
#include "UFOT42.h"
|
|
#include "UFLMem.h"
|
|
#include "UFLMath.h"
|
|
#include "UFLStd.h"
|
|
#include "UFLErr.h"
|
|
#include "UFLPS.h"
|
|
#include "ParseTT.h"
|
|
#include "UFLVm.h"
|
|
#include "ttformat.h"
|
|
|
|
|
|
/*
|
|
* Private function prototypes
|
|
*/
|
|
UFLErrCode
|
|
T42VMNeeded(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMNeeded,
|
|
unsigned long *pFCNeeded
|
|
);
|
|
|
|
UFLErrCode
|
|
T42FontDownloadIncr(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMUsage,
|
|
unsigned long *pFCUsage
|
|
);
|
|
|
|
UFLErrCode
|
|
T42UndefineFont(
|
|
UFOStruct *pUFObj
|
|
);
|
|
|
|
UFLErrCode
|
|
DefaultGetRotatedGIDs(
|
|
UFOStruct *pUFObj,
|
|
T42FontStruct *pFont,
|
|
UFLFontProcs *pFontProcs
|
|
);
|
|
|
|
static unsigned long
|
|
GetLenByScanLoca(
|
|
void PTR_PREFIX *locationTable,
|
|
unsigned short wGlyfIndex,
|
|
unsigned long cNumGlyphs,
|
|
int iLongFormat
|
|
);
|
|
|
|
|
|
/*=============================================================================
|
|
|
|
TrueType Table Description
|
|
|
|
cmap - This table defines the mapping of character codes to the glyph index
|
|
values used in the font. It may contain more than one subtable, in
|
|
order to support more than one character encoding scheme. Character
|
|
codes that do not correspond to any glyph in the font should be
|
|
mapped to glyph index 0. The glyph at this location must be a
|
|
special glyph representing a missing character.
|
|
|
|
cvt - This table contains a list of values that can be referenced by
|
|
instructions. They can be used, among other things, to control
|
|
characteristics for different glyphs.
|
|
|
|
fpgm - This table is similar to the CVT Program, except that it is only run
|
|
once, when the font is first used. It is used only for FDEFs and
|
|
IDEFs. Thus the CVT Program need not contain function definitions.
|
|
However, the CVT Program may redefine existing FDEFs or IDEFs.
|
|
FDEFS - Functional defs. IDEFs - Intruction defs.
|
|
|
|
glyf - This table contains information that describes the glyphs in the font.
|
|
|
|
head - This table gives global information about the font.
|
|
Table version number 0x00010000 for version 1.0.
|
|
FIXED fontRevision Set by font manufacturer.
|
|
ULONG checkSumAdjustment To compute: set it to 0, sum
|
|
the entire font as ULONG, then
|
|
store 0xB1B0AFBA - sum.
|
|
ULONG magicNumber Set to 0x5F0F3CF5.
|
|
USHORT flags Bit 0 - baseline for font at y=0
|
|
Bit 1 - left sidebearing at x=0
|
|
Bit 2 - instructions may depend
|
|
on point size
|
|
Bit 3 - force ppem to integer
|
|
values for all internal
|
|
scaler math; may use
|
|
fractional ppem sizes
|
|
if this bit is clear
|
|
USHORT unitsPerEm Valid range is from 16 to 16384
|
|
longDateTime created International date (8-byte field).
|
|
longDateTime modified International date (8-byte field).
|
|
FWORD xMin For all glyph bounding boxes.
|
|
FWORD yMin For all glyph bounding boxes.
|
|
FWORD xMax For all glyph bounding boxes.
|
|
FWORD yMax For all glyph bounding boxes.
|
|
USHORT macStyle Bit 0 bold (if set to 1)
|
|
Bit 1 italic (if set to 1)
|
|
Bits 2-15 reserved (set to 0).
|
|
USHORT lowestRecPPEM Smallest readable size in pixels.
|
|
SHORT fontDirectionHint 0 Fully mixed directional glyphs
|
|
1 Only strongly left to right
|
|
2 Like 1 but also contains neutrals1
|
|
-1 Only strongly right to left
|
|
-2 Like -1 but also contains neutrals.
|
|
SHORT indexToLocFormat 0 for short offsets, 1 for long.
|
|
SHORT glyphDataFormat 0 for current format.
|
|
|
|
hhea - This table contains information for horizontal layout.
|
|
Type Name Description
|
|
FIXED Table version number 0x00010000 for version 1.0.
|
|
FWORD Ascender Typographic ascent.
|
|
FWORD Descender Typographic descent.
|
|
FWORD LineGap Typographic line gap. Negative
|
|
LineGap values are treated as zero
|
|
in Windows 3.1, System 6, and System 7.
|
|
UFWORD advanceWidthMax Maximum advance width value in hmtx table.
|
|
FWORD minLeftSideBearing Minimum left sidebearing value in hmtx table.
|
|
FWORD minRightSideBearing Minimum right sidebearing value.
|
|
Calculated as Min(aw - lsb - (xMax - xMin)).
|
|
FWORD xMaxExtent Max(lsb + (xMax - xMin)).
|
|
SHORT caretSlopeRise Used to calculate the slope of the
|
|
cursor (rise/run); 1 for vertical.
|
|
SHORT caretSlopeRun 0 for vertical.
|
|
SHORT (reserved) set to 0
|
|
SHORT (reserved) set to 0
|
|
SHORT (reserved) set to 0
|
|
SHORT (reserved) set to 0
|
|
SHORT (reserved) set to 0
|
|
SHORT metricDataFormat 0 for current format.
|
|
USHORT numberOfHMetrics Number of hMetric entries in hmtx
|
|
table; may be smaller than the total
|
|
number of glyphs in the font.
|
|
|
|
hmtx - Horizontal metrics
|
|
|
|
loca - The indexToLoc table stores the offsets to the locations of the
|
|
glyphs in the font, relative to the beginning of the glyphData
|
|
table. In order to compute the length of the last glyph element,
|
|
there is an extra entry after the last valid index. By definition,
|
|
index zero points to the missing character, which is the character
|
|
that appears if a character is not found in the font. The missing
|
|
character is commonly represented by a blank box or a space. If the
|
|
font does not contain an outline for the missing character, then the
|
|
first and second offsets should have the same value. This also
|
|
applies to any other character without an outline, such as the space
|
|
character. Most routines will look at the 'maxp' table to determine
|
|
the number of glyphs in the font, but the value in the ‘loca’ table
|
|
should agree. There are two versions of this table, the short and
|
|
the long. The version is specified in the indexToLocFormat entry in
|
|
the head' table.
|
|
|
|
maxp - This table establishes the memory requirements for this font.
|
|
Type Name Description
|
|
Fixed Table version number 0x00010000 for version 1.0.
|
|
USHORT numGlyphs The number of glyphs in the font.
|
|
USHORT maxPoints Maximum points in a non-composite glyph.
|
|
USHORT maxContours Maximum contours in a non-composite glyph.
|
|
USHORT maxCompositePoints Maximum points in a composite glyph.
|
|
USHORT maxCompositeContours Maximum contours in a composite glyph.
|
|
USHORT maxZones 1 if instructions do not use the twilight zone (Z0)
|
|
2 if instructions do use Z0
|
|
This should be set to 2 in most cases.
|
|
USHORT maxTwilightPoints Maximum points used in Z0.
|
|
USHORT maxStorage Number of Storage Area locations.
|
|
USHORT maxFunctionDefs Number of FDEFs.
|
|
USHORT maxInstructionDefs Number of IDEFs.
|
|
USHORT maxStackElements Maximum stack depth2.
|
|
USHORT maxSizeOfInstructions Maximum byte count for glyph instructions.
|
|
USHORT maxComponentElements Maximum number of components
|
|
referenced at "top level" for any
|
|
composite glyph.
|
|
USHORT maxComponentDepth Maximum levels of recursion; 1 for
|
|
simple components.
|
|
|
|
prep - The Control Value Program consists of a set of TrueType instructions
|
|
that will be executed whenever the font or point size or
|
|
transformation matrix change and before each glyph is interpreted.
|
|
Any instruction is legal in the CVT Program but since no glyph is
|
|
associated with it, instructions intended to move points within a
|
|
particular glyph outline cannot be used in the CVT Program. The name
|
|
'prep' is anachronistic.
|
|
|
|
===============================================================================*/
|
|
|
|
|
|
static char *RequiredTables_default[MINIMALNUMBERTABLES] = {
|
|
"cvt ",
|
|
"fpgm", /* This table is missing from many fonts. */
|
|
"glyf",
|
|
"head",
|
|
"hhea",
|
|
"hmtx",
|
|
"loca",
|
|
"maxp",
|
|
"prep"
|
|
};
|
|
|
|
static char *RequiredTables_2015[MINIMALNUMBERTABLES] = {
|
|
"cvt ",
|
|
"fpgm", /* This table is missing from many fonts. */
|
|
"glyf",
|
|
"head",
|
|
"hhea",
|
|
"hmtx",
|
|
// "loca", /* This huge table is Not needed on 2015 Pritners. */
|
|
"maxp",
|
|
"prep",
|
|
|
|
/* This must be the last (dummy) entry. Don't add anything after this. */
|
|
"zzzz"
|
|
};
|
|
|
|
char *gcidSuffix[NUM_CIDSUFFIX] = {
|
|
"CID",
|
|
"CIDR",
|
|
"CID32K",
|
|
"CID32KR"
|
|
};
|
|
|
|
static char* RDString = " RDS "; /* Fix bug Adobe #233904 */
|
|
|
|
|
|
typedef struct {
|
|
long startU;
|
|
long endU;
|
|
long startL;
|
|
long endL;
|
|
} CODERANGE;
|
|
|
|
typedef struct {
|
|
short sMaxCount; // Maximum number of glyphs
|
|
short sCount; // Number of glyps we're holding
|
|
unsigned short *pGlyphs; // Pointer to array of glyph indices.
|
|
} COMPOSITEGLYPHS;
|
|
|
|
|
|
#if 1
|
|
|
|
static CODERANGE gHalfWidthChars[] = {
|
|
{0x0020, 0x007E, 0x20, 0x7E}, /* CJK ASCII chars */
|
|
{0xFF60, 0xFF9F, 0x20, 0x5F}, /* 0x20 to 0x5F is made up to make the localcode range the size. */
|
|
{0xFFA0, 0xFFDF, 0xA0, 0xDF}, /* HalfWidth J-Katakana and K-Hangul (see Unicode Book P.383) */
|
|
{0, 0, 0, 0} /* terminator */
|
|
};
|
|
|
|
#else
|
|
|
|
/*
|
|
* This could be more accurite than the one above. But we don't use this until
|
|
* it becomes really necessary.
|
|
*/
|
|
static CODERANGE gHalfWidthChars[] = {
|
|
{0x0020, 0x007E, 0x20, 0x7E}, /* ASCII (0x20-0x7E) */
|
|
{0xFF61, 0xFF9F, 0xA1, 0xDF}, /* Half-width Katakana (0xA1-0xDF) */
|
|
{0xFFA0, 0xFFDC, 0x40, 0x7C}, /* HalfWidth jamo (0x40-0x7C) */
|
|
{0, 0, 0, 0} /* terminator */
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
#define NUM_HALFWIDTHCHARS \
|
|
((short) (gHalfWidthChars[0].endL - gHalfWidthChars[0].startL + 1) + \
|
|
(gHalfWidthChars[1].endL - gHalfWidthChars[1].startL + 1) + \
|
|
(gHalfWidthChars[2].endL - gHalfWidthChars[2].startL + 1) + \
|
|
(gHalfWidthChars[3].endL - gHalfWidthChars[3].startL + 1) + 1 )
|
|
|
|
|
|
/*
|
|
* CIDSysInfo "(Adobe) (WinCharSetFFFF) 0" is registered for Win95 driver. Re-use it here.
|
|
*/
|
|
static UFLCMapInfo CMapInfo_FF_H = {"WinCharSetFFFF-H", 1, 0, "Adobe", "WinCharSetFFFF", 0};
|
|
static UFLCMapInfo CMapInfo_FF_V = {"WinCharSetFFFF-V", 1, 1, "Adobe", "WinCharSetFFFF", 0};
|
|
static UFLCMapInfo CMapInfo_FF_H2 = {"WinCharSetFFFF-H2", 1, 0, "Adobe", "WinCharSetFFFF", 0};
|
|
static UFLCMapInfo CMapInfo_FF_V2 = {"WinCharSetFFFF-V2", 1, 1, "Adobe", "WinCharSetFFFF", 0};
|
|
|
|
#define CIDSUFFIX 0
|
|
#define CIDSUFFIX_R 1
|
|
#define CIDSUFFIX_32K 2
|
|
#define CIDSUFFIX_32KR 3
|
|
|
|
|
|
/* Magic Baseline Numbers: */
|
|
#define TT_BASELINE_X "0.15"
|
|
#define TT_BASELINE_Y "0.85"
|
|
|
|
|
|
/*
|
|
* Function implementations
|
|
*/
|
|
|
|
void
|
|
T42FontCleanUp(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
T42FontStruct *pFont;
|
|
|
|
if (pUFObj->pAFont == nil)
|
|
return;
|
|
|
|
pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
|
|
if (pFont == nil)
|
|
return;
|
|
|
|
if (pFont->pHeader != nil)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pHeader);
|
|
pFont->pHeader = nil;
|
|
}
|
|
|
|
if (pFont->pMinSfnt != nil)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pMinSfnt);
|
|
pFont->pMinSfnt = nil;
|
|
}
|
|
|
|
if (pFont->pStringLength != nil)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pStringLength);
|
|
pFont->pStringLength = nil;
|
|
}
|
|
|
|
if (pFont->pLocaTable != nil)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pLocaTable);
|
|
pFont->pLocaTable = nil;
|
|
}
|
|
|
|
if (pFont->pRotatedGlyphIDs != nil)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pRotatedGlyphIDs);
|
|
pFont->pRotatedGlyphIDs = nil;
|
|
}
|
|
}
|
|
|
|
|
|
unsigned long
|
|
GetFontTable(
|
|
UFOStruct *pUFObj,
|
|
unsigned long tableName,
|
|
unsigned char *pTable,
|
|
unsigned long bufferSize // Fixed bug 516514
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
unsigned long tableSize;
|
|
|
|
/* Get the size of the table. */
|
|
tableSize = GETTTFONTDATA(pUFObj,
|
|
tableName, 0L,
|
|
nil, 0L,
|
|
pFont->info.fData.fontIndex);
|
|
|
|
/* Read the table in. */
|
|
if (pTable && tableSize)
|
|
{
|
|
// Fixed bug 516514. make sure the buffer is big enough
|
|
if (tableSize > bufferSize)
|
|
tableSize = bufferSize;
|
|
|
|
tableSize = GETTTFONTDATA(pUFObj,
|
|
tableName, 0L,
|
|
pTable, tableSize,
|
|
pFont->info.fData.fontIndex);
|
|
|
|
/*
|
|
* Special hack to fix #185003 and #308981
|
|
* Avoid useless maxSizeOfInstructions check in TrueType rasterizer by
|
|
* setting the highest value. maxSizeOfInstructions field in 'maxp'
|
|
* table is at byte offset 26 and 27.
|
|
*/
|
|
if (tableName == MAXP_TABLE)
|
|
pTable[26] = pTable[27] = 0xff;
|
|
}
|
|
|
|
return tableSize;
|
|
}
|
|
|
|
|
|
void *
|
|
GetSfntTable(
|
|
unsigned char *sfnt,
|
|
unsigned long tableName
|
|
)
|
|
{
|
|
TableDirectoryStruct *pTableDirectory = (TableDirectoryStruct *)sfnt;
|
|
TableEntryStruct *pTableEntry = (TableEntryStruct *)((char *)pTableDirectory
|
|
+ sizeof (TableDirectoryStruct));
|
|
unsigned short i = 0;
|
|
|
|
while (i < MOTOROLAINT(pTableDirectory->numTables))
|
|
{
|
|
if (pTableEntry->tag == tableName)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pTableEntry = (TableEntryStruct *)((char *)pTableEntry + sizeof (TableEntryStruct));
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (i < MOTOROLAINT(pTableDirectory->numTables))
|
|
{
|
|
if (pTableEntry->offset)
|
|
return (void *)(sfnt + MOTOROLALONG(pTableEntry->offset));
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
|
|
unsigned long
|
|
GetTableSize(
|
|
UFOStruct *pUFObj,
|
|
unsigned char *pHeader,
|
|
unsigned long tableName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This function returns the size of a table within this In-Memory-Version
|
|
pHeader if it is present - If Not present, read-in from the orginal font
|
|
header - we need this because 'loca' won't be in pHeader for CID/42, but
|
|
we need its size!.
|
|
|
|
--*/
|
|
|
|
{
|
|
TableDirectoryStruct *pTableDirectory = (TableDirectoryStruct *)pHeader;
|
|
TableEntryStruct *pTableEntry = (TableEntryStruct *)((char *)pTableDirectory
|
|
+ sizeof (TableDirectoryStruct));
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
unsigned short i;
|
|
|
|
for (i = 0; i < MOTOROLAINT(pTableDirectory->numTables); i++)
|
|
{
|
|
if (pTableEntry->tag == tableName)
|
|
break;
|
|
else
|
|
pTableEntry = (TableEntryStruct *)((char *)pTableEntry + sizeof (TableEntryStruct));
|
|
}
|
|
|
|
//
|
|
// 'loca' table can be 0 length in 'sfnts': just get it from the font.
|
|
// Bug 229911 ang 9/12/97
|
|
//
|
|
if ((i < MOTOROLAINT(pTableDirectory->numTables))
|
|
&& ((unsigned long)MOTOROLALONG(pTableEntry->length) > 0))
|
|
{
|
|
return ((unsigned long)MOTOROLALONG(pTableEntry->length));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We don't have this table in pHeader. So find out the size from
|
|
// orignal font file.
|
|
//
|
|
return GETTTFONTDATA(pUFObj,
|
|
tableName, 0L,
|
|
nil, 0L,
|
|
pFont->info.fData.fontIndex);
|
|
}
|
|
}
|
|
|
|
|
|
unsigned long
|
|
GetGlyphTableSize(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
|
|
return GetTableSize(pUFObj, pFont->pHeader, GLYF_TABLE);
|
|
}
|
|
|
|
|
|
unsigned long
|
|
GetTableDirectory(
|
|
UFOStruct *pUFObj,
|
|
TableDirectoryStruct *pTableDir
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
unsigned long size = sizeof (TableDirectoryStruct);
|
|
|
|
if (pTableDir == 0)
|
|
return size; /* Return the size only. */
|
|
|
|
/*
|
|
* TTCHeader or TableDirectoryStruct starts from the beginning of the font
|
|
* file.
|
|
*/
|
|
size = GETTTFONTDATA(pUFObj,
|
|
nil, 0L,
|
|
pTableDir, sizeof (TableDirectoryStruct),
|
|
0);
|
|
|
|
/*
|
|
* Check if this is a TTC file - only uses first 4 bytes of pTableDIR.
|
|
*/
|
|
if (BIsTTCFont(*((unsigned long *)((char *)pTableDir))))
|
|
{
|
|
/* Parse TTCHeader to get correct offsetToTableDir from fontIndex. */
|
|
size = pFont->info.fData.offsetToTableDir
|
|
= GetOffsetToTableDirInTTC(pUFObj, pFont->info.fData.fontIndex);
|
|
|
|
if (size > 0)
|
|
{
|
|
/* Now get the correct TableDirectory from the TTC file. */
|
|
size = GETTTFONTDATA(pUFObj,
|
|
nil, pFont->info.fData.offsetToTableDir,
|
|
pTableDir, sizeof (TableDirectoryStruct),
|
|
pFont->info.fData.fontIndex);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Do some basic check - better fail than crash. NumTables must be
|
|
* reasonable.
|
|
*/
|
|
if ((MOTOROLAINT(pTableDir->numTables) < 3)
|
|
|| (MOTOROLAINT(pTableDir->numTables) > 50))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
unsigned long
|
|
GetTableEntry(
|
|
UFOStruct *pUFObj,
|
|
TableEntryStruct *pTableEntry,
|
|
TableDirectoryStruct *pTableDir
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
unsigned long size;
|
|
|
|
if (pTableDir == 0)
|
|
return 0; /* We need the TableDirectoryStruct to get the entry. */
|
|
|
|
size = MOTOROLAINT(pTableDir->numTables) * sizeof (TableEntryStruct);
|
|
|
|
if (pTableEntry == 0)
|
|
return size; /* Return the size only. */
|
|
|
|
/* TableEntryStruct starts right after the TableDirectory. */
|
|
size = GETTTFONTDATA(pUFObj,
|
|
nil, pFont->info.fData.offsetToTableDir + sizeof (TableDirectoryStruct),
|
|
pTableEntry, size,
|
|
pFont->info.fData.fontIndex);
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
unsigned long
|
|
GetFontHeaderSize(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
TableDirectoryStruct tableDir;
|
|
unsigned long size;
|
|
|
|
/* Need to fill in tableDir for GetTableEntry(). */
|
|
size = GetTableDirectory(pUFObj, &tableDir);
|
|
|
|
if (size != 0)
|
|
size += GetTableEntry(pUFObj, 0, &tableDir); /* Get size only. */
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
GetFontHeader(
|
|
UFOStruct *pUFObj,
|
|
unsigned char *pHeader
|
|
)
|
|
{
|
|
unsigned char* tempHeader = pHeader;
|
|
TableDirectoryStruct* pTableDir = (TableDirectoryStruct *)tempHeader;
|
|
unsigned long size = GetTableDirectory(pUFObj, pTableDir);
|
|
|
|
tempHeader += size; /* Move past table directory. */
|
|
|
|
size = GetTableEntry(pUFObj, (TableEntryStruct *)tempHeader, pTableDir);
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
|
|
unsigned long
|
|
GetNumGlyphsInGlyphTable(
|
|
UFOStruct *pUFO
|
|
)
|
|
{
|
|
unsigned long dwSize;
|
|
Type42HeaderStruct headTable;
|
|
short indexToLocFormat;
|
|
unsigned long numGlyphs, realNumGlyphs;
|
|
unsigned long locaSize;
|
|
unsigned long PTR_PREFIX *pLoca;
|
|
unsigned long i;
|
|
|
|
/* Get numGlyphs - 4th and 5th byte in 'maxp' table. See MaxPTableStruct. */
|
|
numGlyphs = GetNumGlyphs(pUFO);
|
|
|
|
if (numGlyphs == 0)
|
|
return 0; /* We don't understand this format. */
|
|
|
|
/*
|
|
* Get indexToLocFormat.
|
|
* Because of unknown reason the compiler claims that the size of
|
|
* Type42HeaderStruct (or its object) is 56 rather than 54 so that we
|
|
* cannot get the contents of 'head' table by single GETTTFONTDATA call.
|
|
* Instead, we call the function twice, once to get the size of 'head'
|
|
* table and then to get its contents.
|
|
*/
|
|
dwSize = GETTTFONTDATA(pUFO,
|
|
HEAD_TABLE, 0L,
|
|
nil, 0L,
|
|
pUFO->pFData->fontIndex);
|
|
|
|
if ((dwSize == 0) || (dwSize == 0xFFFFFFFFL))
|
|
return 0; /* No 'head' table. This should never happen. */
|
|
|
|
// Fixed bug 516508. case 2
|
|
if (dwSize > sizeof(Type42HeaderStruct))
|
|
dwSize = sizeof(Type42HeaderStruct);
|
|
|
|
dwSize = GETTTFONTDATA(pUFO,
|
|
HEAD_TABLE, 0L,
|
|
&headTable, dwSize,
|
|
pUFO->pFData->fontIndex);
|
|
|
|
if ((dwSize == 0) || (dwSize == 0xFFFFFFFFL))
|
|
return 0; /* Still something is wrong. */
|
|
|
|
indexToLocFormat = MOTOROLAINT(headTable.indexToLocFormat);
|
|
|
|
/*
|
|
* Allocate a buffer to hold 'loca' table and read it into memory.
|
|
*/
|
|
locaSize = (numGlyphs + 1) * (indexToLocFormat ? 4 : 2);
|
|
|
|
pLoca = UFLNewPtr(pUFO->pMem, locaSize);
|
|
|
|
if (pLoca)
|
|
{
|
|
dwSize = GETTTFONTDATA(pUFO,
|
|
LOCA_TABLE, 0L,
|
|
pLoca, locaSize,
|
|
pUFO->pFData->fontIndex);
|
|
}
|
|
else
|
|
dwSize = 0;
|
|
|
|
/*
|
|
* Get real number of glyphs.
|
|
*/
|
|
realNumGlyphs = 0;
|
|
|
|
if (pLoca && (dwSize != 0) && (dwSize != 0xFFFFFFFFL))
|
|
{
|
|
/* Assume good until find otherwise. */
|
|
|
|
if (indexToLocFormat)
|
|
{
|
|
unsigned long dwLoca, dwLocaNext;
|
|
unsigned long PTR_PREFIX *pLongLoca;
|
|
|
|
pLongLoca = (unsigned long PTR_PREFIX *)pLoca;
|
|
|
|
for (i = 0; i < numGlyphs; i++)
|
|
{
|
|
dwLoca = MOTOROLALONG(pLongLoca[i]);
|
|
dwLocaNext = MOTOROLALONG(pLongLoca[i + 1]);
|
|
|
|
/* Check for 0 and duplicate. */
|
|
if ((dwLoca != 0) && (dwLoca != dwLocaNext))
|
|
{
|
|
realNumGlyphs++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned short wLoca, wLocaNext;
|
|
unsigned short PTR_PREFIX *pShortLoca;
|
|
|
|
pShortLoca = (unsigned short PTR_PREFIX *)pLoca;
|
|
|
|
for (i = 0; i < numGlyphs; i++)
|
|
{
|
|
wLoca = MOTOROLAINT(pShortLoca[i]);
|
|
wLocaNext = MOTOROLAINT(pShortLoca[i + 1]);
|
|
|
|
/* Check for 0 and duplicate. */
|
|
if ((wLoca != 0) && (wLoca != wLocaNext))
|
|
{
|
|
realNumGlyphs++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pLoca)
|
|
UFLDeletePtr(pUFO->pMem, pLoca);
|
|
|
|
return realNumGlyphs;
|
|
}
|
|
|
|
|
|
void
|
|
GetAverageGlyphSize(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
unsigned long glyfTableSize = GetGlyphTableSize(pUFObj);
|
|
unsigned long cGlyphs;
|
|
|
|
if (UFO_NUM_GLYPHS(pUFObj) == 0)
|
|
pFont->info.fData.cNumGlyphs = GetNumGlyphs(pUFObj);
|
|
|
|
cGlyphs = GetNumGlyphsInGlyphTable(pUFObj);
|
|
|
|
if ((UFO_NUM_GLYPHS(pUFObj) != 0) && (cGlyphs != 0))
|
|
pFont->averageGlyphSize = glyfTableSize / cGlyphs;
|
|
else
|
|
pFont->averageGlyphSize = 0;
|
|
}
|
|
|
|
|
|
#pragma optimize("", off)
|
|
|
|
//
|
|
// fix Whistler bug 251303: prevent overrun of the tablesPresent array
|
|
//
|
|
#define PRESENT_TABLE_ENTRIES MINIMALNUMBERTABLES+2
|
|
|
|
unsigned long
|
|
GenerateMinimalSfnt(
|
|
UFOStruct* pUFObj,
|
|
char** requiredTables,
|
|
UFLBool bFullFont
|
|
)
|
|
{
|
|
unsigned long tablesPresent[PRESENT_TABLE_ENTRIES];
|
|
UFLBool hasloca;
|
|
|
|
T42FontStruct *pFont;
|
|
TableDirectoryStruct *pTableDir;
|
|
TableEntryStruct *pTableEntry;
|
|
unsigned char huge *pCurrentMinSfnt;
|
|
|
|
unsigned short currentTable, numberOfTables, numberOfRealTables;
|
|
unsigned long size;
|
|
|
|
TableEntryStruct *pGlyphTableEntry;
|
|
unsigned char *glyfData;
|
|
|
|
TableEntryStruct tableEntry;
|
|
unsigned long tableSize;
|
|
|
|
unsigned short i;
|
|
|
|
|
|
//
|
|
// Bug fix 229911: ang 9/12/97
|
|
// Check if RequiredTables has 'loca'. If not, remember to add 0-length one
|
|
// as the last entry.
|
|
//
|
|
hasloca = 0;
|
|
|
|
for (i = 0; i < MINIMALNUMBERTABLES; i++)
|
|
{
|
|
if (UFLstrcmp(requiredTables[i], "loca") == 0)
|
|
hasloca = 1;
|
|
|
|
tablesPresent[i] = (unsigned long)0xFFFFFFFF;
|
|
}
|
|
|
|
//
|
|
// Initialize the additional entries
|
|
//
|
|
for (i = MINIMALNUMBERTABLES ; i < PRESENT_TABLE_ENTRIES ; i++)
|
|
{
|
|
tablesPresent[i] = (unsigned long)0xFFFFFFFF;
|
|
}
|
|
|
|
//
|
|
// Set up the primary pointers.
|
|
//
|
|
pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
pTableDir = (TableDirectoryStruct *)pFont->pHeader;
|
|
pTableEntry = (TableEntryStruct *)((char *)(pFont->pHeader) + sizeof (TableDirectoryStruct));
|
|
pCurrentMinSfnt = (unsigned char huge *)pFont->pMinSfnt;
|
|
|
|
//
|
|
// Determine how many tables are actually present in pHeader (not in the
|
|
// original TTF!).
|
|
//
|
|
numberOfTables = 0;
|
|
|
|
for (i = 0; i < MINIMALNUMBERTABLES; i++)
|
|
{
|
|
if (GetTableSize(pUFObj, pFont->pHeader, *(unsigned long *)(requiredTables[i])))
|
|
{
|
|
tablesPresent[numberOfTables] = *(unsigned long *)requiredTables[i];
|
|
++numberOfTables;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add extra entry if necessary.
|
|
//
|
|
if (!bFullFont)
|
|
numberOfTables += 1; // for 'gdir' table entry as the T42 indication
|
|
|
|
if (!hasloca)
|
|
numberOfTables += 1; // for 0-length 'loca' table entry
|
|
|
|
//
|
|
// size will have the required size for the minimum 'sfnts' at the end.
|
|
//
|
|
size = sizeof (TableDirectoryStruct) + sizeof (TableEntryStruct) * numberOfTables;
|
|
|
|
//
|
|
// Initialize the table directory.
|
|
//
|
|
if (pFont->pMinSfnt)
|
|
{
|
|
TableDirectoryStruct tableDir;
|
|
unsigned long dwVersion = 1;
|
|
|
|
tableDir.version = MOTOROLAINT(dwVersion);
|
|
tableDir.numTables =
|
|
tableDir.searchRange =
|
|
tableDir.entrySelector =
|
|
tableDir.rangeshift =
|
|
tableDir.numTables = MOTOROLAINT(numberOfTables);
|
|
|
|
UFLmemcpy((const UFLMemObj *)pUFObj->pMem,
|
|
pCurrentMinSfnt,
|
|
&tableDir,
|
|
sizeof (TableDirectoryStruct));
|
|
|
|
pCurrentMinSfnt += sizeof (TableDirectoryStruct);
|
|
}
|
|
|
|
//
|
|
// Initialize the table entries. Initialization of 'glyf' table entry will
|
|
// be done later in order to make sure to put it at the end of the minimum
|
|
// 'sfnts'.
|
|
//
|
|
// Note that we do linear search to find a table directory entry. This is
|
|
// becasue some TT fonts don't have sorted table directory so that we can't
|
|
// do binary search. (This is a fix for #310998.)
|
|
//
|
|
pGlyphTableEntry = nil;
|
|
glyfData = nil;
|
|
numberOfRealTables = MOTOROLAINT(pTableDir->numTables);
|
|
|
|
for (currentTable = 0; currentTable < numberOfTables; currentTable++)
|
|
{
|
|
TableEntryStruct *pEntry = pTableEntry;
|
|
|
|
for (i = 0; i < numberOfRealTables; i++)
|
|
{
|
|
if (tablesPresent[currentTable] == pEntry->tag)
|
|
{
|
|
if (pFont->pMinSfnt)
|
|
{
|
|
if (pEntry->tag == GLYF_TABLE)
|
|
{
|
|
glyfData = pCurrentMinSfnt;
|
|
}
|
|
else
|
|
{
|
|
tableEntry.tag = pEntry->tag;
|
|
tableEntry.checkSum = pEntry->checkSum;
|
|
tableEntry.offset = MOTOROLALONG(size);
|
|
tableEntry.length = pEntry->length;
|
|
|
|
UFLmemcpy((const UFLMemObj *)pUFObj->pMem,
|
|
pCurrentMinSfnt,
|
|
&tableEntry,
|
|
sizeof (TableEntryStruct));
|
|
}
|
|
|
|
pCurrentMinSfnt += sizeof (TableEntryStruct);
|
|
}
|
|
|
|
if (pEntry->tag == GLYF_TABLE)
|
|
{
|
|
pGlyphTableEntry = pEntry;
|
|
}
|
|
else
|
|
{
|
|
tableSize = MOTOROLALONG(pEntry->length);
|
|
size += BUMP4BYTE(tableSize);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
pEntry = (TableEntryStruct *)((char *)pEntry + sizeof (TableEntryStruct));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update 'glyf' table entry lastly.
|
|
//
|
|
if (glyfData && pGlyphTableEntry && pFont->pMinSfnt)
|
|
{
|
|
tableEntry.tag = pGlyphTableEntry->tag;
|
|
tableEntry.checkSum = pGlyphTableEntry->checkSum;
|
|
tableEntry.offset = MOTOROLALONG(size);
|
|
tableEntry.length = pGlyphTableEntry->length;
|
|
|
|
UFLmemcpy((const UFLMemObj *)pUFObj->pMem,
|
|
glyfData,
|
|
&tableEntry,
|
|
sizeof (TableEntryStruct));
|
|
}
|
|
|
|
if (pGlyphTableEntry && bFullFont)
|
|
{
|
|
tableSize = MOTOROLALONG(pGlyphTableEntry->length);
|
|
size += BUMP4BYTE(tableSize);
|
|
}
|
|
|
|
//
|
|
// Special 'gdir' and 'loca' table entry handling.
|
|
//
|
|
if (!bFullFont && pFont->pMinSfnt)
|
|
{
|
|
tableEntry.tag = *(unsigned long *)"gdir";
|
|
tableEntry.checkSum = 0;
|
|
tableEntry.offset = 0;
|
|
tableEntry.length = 0;
|
|
|
|
UFLmemcpy((const UFLMemObj *)pUFObj->pMem,
|
|
pCurrentMinSfnt,
|
|
&tableEntry,
|
|
(long)sizeof (TableEntryStruct));
|
|
|
|
pCurrentMinSfnt += sizeof (TableEntryStruct);
|
|
}
|
|
|
|
if (!hasloca && pFont->pMinSfnt)
|
|
{
|
|
tableEntry.tag = LOCA_TABLE;
|
|
tableEntry.checkSum = 0;
|
|
tableEntry.offset = 0;
|
|
tableEntry.length = 0;
|
|
|
|
UFLmemcpy((const UFLMemObj *)pUFObj->pMem,
|
|
pCurrentMinSfnt,
|
|
&tableEntry,
|
|
(long)sizeof (TableEntryStruct));
|
|
|
|
pCurrentMinSfnt += sizeof (TableEntryStruct);
|
|
}
|
|
|
|
//
|
|
// Copy the required tables after the entries.
|
|
//
|
|
if (pFont->pMinSfnt)
|
|
{
|
|
unsigned long bytesRemaining;
|
|
|
|
pTableEntry = (TableEntryStruct *)((char *)pFont->pMinSfnt + sizeof (TableDirectoryStruct));
|
|
|
|
if (!bFullFont)
|
|
--numberOfTables; // Because there is no 'gdir' table.
|
|
|
|
if (!hasloca)
|
|
--numberOfTables; // Because we treat 'loca' table as 0-length.
|
|
|
|
for (i = 0; i < (unsigned short)numberOfTables; i++)
|
|
{
|
|
if (tablesPresent[i] != GLYF_TABLE)
|
|
{
|
|
bytesRemaining = MOTOROLALONG(pTableEntry->length);
|
|
bytesRemaining = BUMP4BYTE(bytesRemaining);
|
|
|
|
// Fixed bug 516514
|
|
GetFontTable(pUFObj, tablesPresent[i], pCurrentMinSfnt, bytesRemaining);
|
|
|
|
pCurrentMinSfnt += bytesRemaining;
|
|
}
|
|
|
|
pTableEntry = (TableEntryStruct *)((char *)pTableEntry + sizeof (TableEntryStruct));
|
|
}
|
|
|
|
//
|
|
// Copy 'glyf' table lastly.
|
|
//
|
|
if (bFullFont)
|
|
{
|
|
bytesRemaining = MOTOROLALONG(pGlyphTableEntry->length);
|
|
bytesRemaining = BUMP4BYTE(bytesRemaining);
|
|
|
|
// Fixed bug 516514
|
|
GetFontTable(pUFObj, GLYF_TABLE, pCurrentMinSfnt, bytesRemaining);
|
|
}
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
#pragma optimize("", on)
|
|
|
|
|
|
UFLErrCode
|
|
GetMinSfnt(
|
|
UFOStruct *pUFObj,
|
|
UFLBool bFullFont
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
char **requiredTables = RequiredTables_default;
|
|
UFLErrCode retVal = kNoErr;
|
|
|
|
//
|
|
// IF CID Type 42, then we are sure we can omit the huge 'loca' table
|
|
// because Send-TT-as-CID/Type42 is only supported on 2015 or above
|
|
// printers.
|
|
//
|
|
if (IS_TYPE42CID(pUFObj->lDownloadFormat))
|
|
{
|
|
requiredTables = RequiredTables_2015;
|
|
}
|
|
|
|
if (pFont->pMinSfnt == 0)
|
|
{
|
|
unsigned long headerSize, sfntSize;
|
|
|
|
/* Get the size of the portion of the Type font we need. */
|
|
headerSize = GetFontHeaderSize(pUFObj);
|
|
|
|
if (headerSize == 0)
|
|
return kErrOutOfMemory; /* Some thing wrong when getting header. */
|
|
|
|
if ((pFont->pHeader = (unsigned char *)UFLNewPtr(pUFObj->pMem, headerSize)) == nil)
|
|
return kErrOutOfMemory;
|
|
|
|
GetFontHeader(pUFObj, pFont->pHeader);
|
|
|
|
/* Calculate minimal /sfnts size for Incr or full download. */
|
|
sfntSize = GenerateMinimalSfnt(pUFObj, requiredTables, bFullFont);
|
|
|
|
if ((pFont->pMinSfnt = (unsigned char *)UFLNewPtr(pUFObj->pMem, sfntSize)) == nil)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pHeader);
|
|
pFont->pHeader = nil;
|
|
|
|
return kErrOutOfMemory;
|
|
}
|
|
|
|
/* Creates our sfnt - minSfnt. We then work on this minSfnt. */
|
|
GenerateMinimalSfnt(pUFObj, requiredTables, bFullFont);
|
|
|
|
if (retVal == kNoErr)
|
|
pFont->minSfntSize = sfntSize;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
unsigned long
|
|
GetNextLowestOffset(
|
|
TableEntryStruct *pTableEntry,
|
|
TableEntryStruct **ppCurrentTable,
|
|
short numTables,
|
|
unsigned long leastOffset
|
|
)
|
|
{
|
|
unsigned long lowestFound = 0xFFFFFFFFL;
|
|
short i;
|
|
|
|
for (i = 0; i < numTables; ++i)
|
|
{
|
|
if (((unsigned long)MOTOROLALONG(pTableEntry->offset) > leastOffset)
|
|
&& ((unsigned long)MOTOROLALONG(pTableEntry->offset) < lowestFound))
|
|
{
|
|
lowestFound = (unsigned long)MOTOROLALONG(pTableEntry->offset);
|
|
*ppCurrentTable = pTableEntry;
|
|
}
|
|
|
|
pTableEntry = (TableEntryStruct *)((char *)pTableEntry + sizeof (TableEntryStruct));
|
|
}
|
|
|
|
return lowestFound;
|
|
}
|
|
|
|
|
|
unsigned long
|
|
GetBestGlyfBreak(
|
|
UFOStruct *pUFObj,
|
|
unsigned char *sfnt,
|
|
unsigned long upperLimit,
|
|
UFLBool longGlyfs
|
|
)
|
|
{
|
|
unsigned long retVal = 0xFFFFFFFFL;
|
|
unsigned long dwGlyphStart = 0xFFFFFFFFL;
|
|
unsigned long dwTableSize;
|
|
unsigned short numGlyphs;
|
|
unsigned short i;
|
|
|
|
/* Get the size of loca table. */
|
|
dwTableSize = GetTableSize(pUFObj, sfnt, LOCA_TABLE);
|
|
|
|
if (0 == dwTableSize)
|
|
return retVal;
|
|
|
|
if (longGlyfs)
|
|
{
|
|
unsigned long PTR_PREFIX *locationTable =
|
|
(unsigned long PTR_PREFIX *)GetSfntTable(sfnt, LOCA_TABLE);
|
|
|
|
if (locationTable)
|
|
{
|
|
numGlyphs = (unsigned short)(dwTableSize / sizeof (unsigned long));
|
|
|
|
for (i = 0; i < numGlyphs; i++)
|
|
{
|
|
if (MOTOROLALONG(*locationTable) > upperLimit)
|
|
{
|
|
retVal = dwGlyphStart ;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if ((MOTOROLALONG(*locationTable) & 0x03L) == 0)
|
|
{
|
|
/* Remember "good" guy. */
|
|
dwGlyphStart = MOTOROLALONG(*locationTable);
|
|
}
|
|
locationTable++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
short PTR_PREFIX* locationTable =
|
|
(short PTR_PREFIX*)GetSfntTable(sfnt, LOCA_TABLE);
|
|
|
|
if (locationTable)
|
|
{
|
|
numGlyphs = (unsigned short)(dwTableSize / sizeof (unsigned short));
|
|
upperLimit /= 2;
|
|
|
|
for (i = 0; i < numGlyphs; i++)
|
|
{
|
|
if ((unsigned long)(MOTOROLAINT(*locationTable)) >= upperLimit)
|
|
{
|
|
retVal = dwGlyphStart;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if ((MOTOROLAINT(*locationTable) & 0x01) == 0)
|
|
{
|
|
/* Remember "good" guy. */
|
|
dwGlyphStart =
|
|
(unsigned long)(2L * (unsigned short)MOTOROLAINT(*locationTable));
|
|
}
|
|
locationTable++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CalculateStringLength(
|
|
UFOStruct *pUFObj,
|
|
T42FontStruct *pFont,
|
|
unsigned long tableSize
|
|
)
|
|
{
|
|
unsigned long *stringLength = pFont->pStringLength;
|
|
unsigned long *maxStringLength = stringLength + tableSize;
|
|
|
|
if (pFont->minSfntSize >= THIRTYTWOK)
|
|
{
|
|
unsigned long glyphTableStart = 0L;
|
|
unsigned long nextOffset = 0L; /* Offset for the current point */
|
|
unsigned long prevOffset = 0L; /* Offset for the previous breakpoint */
|
|
|
|
TableEntryStruct *pTableEntry = (TableEntryStruct *)(pFont->pMinSfnt + sizeof (TableDirectoryStruct));
|
|
TableDirectoryStruct *pTableDir = (TableDirectoryStruct *)pFont->pMinSfnt;
|
|
TableEntryStruct *pCurrentTable;
|
|
|
|
do
|
|
{
|
|
nextOffset = GetNextLowestOffset(pTableEntry,
|
|
&pCurrentTable,
|
|
(short)MOTOROLAINT(pTableDir->numTables),
|
|
nextOffset);
|
|
|
|
if (nextOffset == (unsigned long)0xFFFFFFFF)
|
|
{
|
|
/* No more data. */
|
|
break ;
|
|
}
|
|
|
|
if ((nextOffset + MOTOROLALONG(pCurrentTable->length) - prevOffset) > THIRTYTWOK)
|
|
{
|
|
/*
|
|
* Total size is more that 64K.
|
|
*/
|
|
|
|
unsigned long dwNewPoint; /* Offset from the beginning of glyph table */
|
|
|
|
if (pCurrentTable->tag == GLYF_TABLE)
|
|
{
|
|
// DCR -- to improve perfomance, don't need this for Incr downloading.
|
|
|
|
/*
|
|
* If we stopped just on 'glyf' table, get the break points
|
|
* to be inside the table but between two glyphs.
|
|
*/
|
|
glyphTableStart = nextOffset; /* Next segment starts here. */
|
|
|
|
dwNewPoint = 0L;
|
|
|
|
while (1)
|
|
{
|
|
dwNewPoint = GetBestGlyfBreak(pUFObj, pFont->pMinSfnt,
|
|
prevOffset + THIRTYTWOK - glyphTableStart,
|
|
(UFLBool)(pFont->headTable.indexToLocFormat ? 1 : 0));
|
|
|
|
if (dwNewPoint == 0xFFFFFFFF)
|
|
{
|
|
/* No next point. */
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
nextOffset = glyphTableStart + dwNewPoint;
|
|
prevOffset = nextOffset; /* New segment starts here. */
|
|
|
|
*stringLength = nextOffset; /* Save this breakpoint. */
|
|
stringLength++; /* Next breakpoint goes there. */
|
|
|
|
if (stringLength >= maxStringLength)
|
|
return kErrOutOfBoundary;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Save the break point at Table Boundry. */
|
|
prevOffset = nextOffset; /* New segment starts here. */
|
|
|
|
*stringLength = nextOffset; /* Save this breakpoint. */
|
|
stringLength++; /* Next breakpoint goes there. */
|
|
|
|
if (stringLength >= maxStringLength)
|
|
return kErrOutOfBoundary;
|
|
|
|
/*
|
|
* Break the single table at 64K boundry -- regardless
|
|
* what TT Spec says.
|
|
*/
|
|
|
|
/* Tried on a 2016.102 printer. It works. 10-11-1995 */
|
|
glyphTableStart = nextOffset; /* Next segment starts here */
|
|
|
|
dwNewPoint = 0L;
|
|
|
|
while (1)
|
|
{
|
|
/*
|
|
* We use 64K here becasue we only break a table when
|
|
* ABSOLUTELY necessary >64K.
|
|
*/
|
|
dwNewPoint += SIXTYFOURK;
|
|
|
|
if (dwNewPoint > MOTOROLALONG(pCurrentTable->length))
|
|
{
|
|
/* No next point. */
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
nextOffset = glyphTableStart + dwNewPoint;
|
|
prevOffset = nextOffset; /* New segment starts here. */
|
|
|
|
*stringLength = nextOffset;
|
|
stringLength++; /* Next breakpoint goes there. */
|
|
|
|
if (stringLength >= maxStringLength)
|
|
return kErrOutOfBoundary;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while (1);
|
|
}
|
|
|
|
*stringLength = pFont->minSfntSize + 1; /* Always close the breakpoints list. */
|
|
stringLength++;
|
|
|
|
if (stringLength >= maxStringLength)
|
|
return kErrOutOfBoundary;
|
|
|
|
*stringLength = 0; /* Always close the breakpoints list with 0!!! */
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
FillInHeadTable(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
|
|
// Fixed bug 516514
|
|
if (GetFontTable(pUFObj, HEAD_TABLE, (unsigned char *)&pFont->headTable,
|
|
sizeof(Type42HeaderStruct)) == 0)
|
|
return kErrBadTable;
|
|
// else
|
|
// return kNoErr;
|
|
|
|
|
|
// WCC 5/14/98 convert all motorola bytes.
|
|
pFont->headTable.tableVersionNumber = MOTOROLALONG(pFont->headTable.tableVersionNumber);
|
|
pFont->headTable.fontRevision = MOTOROLALONG(pFont->headTable.fontRevision);
|
|
pFont->headTable.checkSumAdjustment = MOTOROLALONG(pFont->headTable.checkSumAdjustment);
|
|
pFont->headTable.magicNumber = MOTOROLALONG(pFont->headTable.magicNumber);
|
|
pFont->headTable.flags = MOTOROLAINT(pFont->headTable.flags);
|
|
pFont->headTable.unitsPerEm = MOTOROLAINT(pFont->headTable.unitsPerEm);
|
|
|
|
// Need to convert timeCreated and timeModified.
|
|
pFont->headTable.xMin = MOTOROLAINT(pFont->headTable.xMin);
|
|
pFont->headTable.yMin = MOTOROLAINT(pFont->headTable.yMin);
|
|
pFont->headTable.xMax = MOTOROLAINT(pFont->headTable.xMax);
|
|
pFont->headTable.yMax = MOTOROLAINT(pFont->headTable.yMax);
|
|
|
|
pFont->headTable.macStyle = MOTOROLAINT(pFont->headTable.macStyle);
|
|
pFont->headTable.lowestRecPPEM = MOTOROLAINT(pFont->headTable.lowestRecPPEM);
|
|
pFont->headTable.fontDirectionHint = MOTOROLAINT(pFont->headTable.fontDirectionHint);
|
|
pFont->headTable.indexToLocFormat = MOTOROLAINT(pFont->headTable.indexToLocFormat);
|
|
pFont->headTable.glyfDataFormat = MOTOROLAINT(pFont->headTable.glyfDataFormat);
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
|
|
short
|
|
PSSendSfntsBinary(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
char huge *glyphs = (char huge *)pFont->pMinSfnt;
|
|
unsigned long minSfntSize = pFont->minSfntSize;
|
|
unsigned long *breakHere = pFont->pStringLength;
|
|
unsigned long dwLen = *breakHere;
|
|
UFLHANDLE stream = pUFObj->pUFL->hOut;
|
|
short nSubStr = 1;
|
|
short i = 0;
|
|
|
|
if (dwLen > minSfntSize)
|
|
{
|
|
/* There's only 1 string. */
|
|
dwLen--;
|
|
|
|
StrmPutInt(stream, dwLen + 1);
|
|
StrmPutString(stream, RDString);
|
|
StrmPutBytes(stream, glyphs, (UFLsize_t)dwLen, 0);
|
|
StrmPutString(stream, "0");
|
|
|
|
return nSubStr; /* It is 1 -- only one string. */
|
|
}
|
|
|
|
StrmPutInt(stream, dwLen + 1);
|
|
StrmPutString(stream, RDString);
|
|
StrmPutBytes(stream, glyphs, (UFLsize_t)dwLen, 0);
|
|
StrmPutString(stream, "0");
|
|
|
|
glyphs = glyphs + dwLen;
|
|
|
|
while (breakHere[i] <= minSfntSize)
|
|
{
|
|
dwLen = breakHere[i + 1] - breakHere[i];
|
|
|
|
if (breakHere[i + 1] > minSfntSize)
|
|
dwLen--;
|
|
|
|
StrmPutInt(stream, dwLen + 1);
|
|
StrmPutString(stream, RDString);
|
|
StrmPutBytes(stream, glyphs, (UFLsize_t)dwLen, 0);
|
|
StrmPutStringEOL(stream, "0");
|
|
|
|
glyphs = glyphs+dwLen;
|
|
|
|
i++;
|
|
nSubStr++;
|
|
}
|
|
|
|
return nSubStr;
|
|
}
|
|
|
|
|
|
short
|
|
PSSendSfntsAsciiHex(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
char huge *glyphs = (char huge *)pFont->pMinSfnt;
|
|
unsigned long minSfntSize = pFont->minSfntSize;
|
|
unsigned long *breakHere = pFont->pStringLength;
|
|
unsigned long dwBreak = *breakHere - 1;
|
|
UFLHANDLE stream = pUFObj->pUFL->hOut;
|
|
short bytesSent = 1;
|
|
short nSubStr = 1;
|
|
unsigned long i;
|
|
|
|
StrmPutString(stream, "<");
|
|
|
|
for (i = 0; i < minSfntSize; i++)
|
|
{
|
|
StrmPutAsciiHex(stream, glyphs, 1);
|
|
|
|
++glyphs;
|
|
++bytesSent;
|
|
|
|
if (i == dwBreak)
|
|
{
|
|
if (dwBreak != minSfntSize)
|
|
{
|
|
StrmPutStringEOL(stream, "00>");
|
|
|
|
bytesSent = 1;
|
|
StrmPutString(stream, "<");
|
|
}
|
|
|
|
dwBreak = *(++breakHere) - 1 ;
|
|
nSubStr++;
|
|
}
|
|
|
|
/*
|
|
* We already have a control (stream->Out->AddEOL) when to add a EOL.
|
|
*
|
|
* if (!(bytesSent % 40))
|
|
* {
|
|
* StrmPutStringEOL(stream, nilStr);
|
|
* bytesSent = 1;
|
|
* }
|
|
*/
|
|
}
|
|
|
|
StrmPutString(stream, "00>");
|
|
|
|
return nSubStr;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
CalcBestGlyfTableBreaks(
|
|
UFOStruct *pUFObj,
|
|
unsigned long upperLimit,
|
|
unsigned long tableSize
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
unsigned long *stringLength = pFont->pStringLength;
|
|
unsigned long *maxStringLength = stringLength + tableSize;
|
|
|
|
unsigned long prevOffset = 0L; /* Offset for the previous breakpoint */
|
|
unsigned long nextOffset = 0xFFFFFFFFL; /* Offset for the current point */
|
|
|
|
unsigned long glyfTableSize = GetTableSize(pUFObj, pFont->pHeader, GLYF_TABLE);
|
|
unsigned long locaTableSize = GetTableSize(pUFObj, pFont->pHeader, LOCA_TABLE);
|
|
|
|
*stringLength = 0L; /* Start with offset 0. */
|
|
stringLength++;
|
|
|
|
if (glyfTableSize > upperLimit)
|
|
{
|
|
unsigned short numGlyphs;
|
|
unsigned short i; /* 'loca' table entries counter */
|
|
|
|
if (pFont->headTable.indexToLocFormat)
|
|
{
|
|
/* long offsets */
|
|
unsigned long PTR_PREFIX *locationTable = (unsigned long PTR_PREFIX *)pFont->pLocaTable;
|
|
|
|
numGlyphs = (unsigned short)(locaTableSize / sizeof (unsigned long));
|
|
|
|
for (i = 0; i < numGlyphs; i++)
|
|
{
|
|
unsigned long dwTmp = MOTOROLALONG(*locationTable);
|
|
|
|
if ((dwTmp > (prevOffset + upperLimit))
|
|
&& (nextOffset != prevOffset))
|
|
{
|
|
*stringLength = nextOffset;
|
|
stringLength++;
|
|
|
|
if (stringLength >= maxStringLength)
|
|
return kErrOutOfBoundary;
|
|
|
|
prevOffset = nextOffset;
|
|
}
|
|
else
|
|
{
|
|
if ((dwTmp & 0x03L) == 0)
|
|
nextOffset = dwTmp;
|
|
|
|
locationTable++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned short PTR_PREFIX *locationTable = (unsigned short PTR_PREFIX *)pFont->pLocaTable;
|
|
|
|
numGlyphs = (unsigned short)(locaTableSize / sizeof (unsigned short));
|
|
|
|
for (i = 0; i < numGlyphs; i++)
|
|
{
|
|
unsigned short iTmp = MOTOROLAINT(*locationTable);
|
|
|
|
if (((2L * (unsigned long)iTmp) > (prevOffset + upperLimit))
|
|
&& (nextOffset != prevOffset))
|
|
{
|
|
*stringLength = nextOffset;
|
|
stringLength++;
|
|
|
|
if (stringLength >= maxStringLength)
|
|
return kErrOutOfBoundary;
|
|
|
|
prevOffset = nextOffset;
|
|
}
|
|
else
|
|
{
|
|
if ((iTmp & 0x01) == 0)
|
|
nextOffset = 2L * (unsigned long)iTmp;
|
|
|
|
locationTable++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*stringLength = glyfTableSize; /* Close the breakpoints list. */
|
|
stringLength++;
|
|
|
|
if (stringLength >= maxStringLength)
|
|
return kErrOutOfBoundary;
|
|
|
|
*stringLength = 0; /* Always close the breakpoints list with 0!!! */
|
|
|
|
return kNoErr;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
GenerateGlyphStorageExt(
|
|
UFOStruct *pUFObj,
|
|
unsigned long tableSize
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
unsigned long *stringLength = pFont->pStringLength;
|
|
unsigned long upperLimit = SFNT_STRINGSIZE; /* 0x3FFE */
|
|
UFLHANDLE stream = pUFObj->pUFL->hOut;
|
|
UFLErrCode retVal;
|
|
short i;
|
|
|
|
retVal = CalcBestGlyfTableBreaks(pUFObj, upperLimit, tableSize);
|
|
if (retVal != kNoErr)
|
|
return retVal;
|
|
|
|
/*
|
|
* Send down the array of Glyph strings.
|
|
*/
|
|
|
|
retVal = StrmPutStringEOL(stream, nilStr);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, "[");
|
|
|
|
for (i = 1; (retVal == kNoErr) && (stringLength[i] != 0); i++)
|
|
{
|
|
unsigned long stringSize;
|
|
|
|
#if 0
|
|
//
|
|
// For Chinese Font SongTi, the very last stringLength is incorrect:
|
|
// glyfSize = 7068416, but the last glyf breaks at 6890292.
|
|
// That means the very last glyf is 178124 - this is impossible.
|
|
// Either GDI is not returning correct number or our function
|
|
// GetTableSize() is wrong. Untill we fix our problem or get a better
|
|
// build of Win95, this is a temp fix. ?????. 10-12-95
|
|
//
|
|
if (stringLength[i] > stringLength[i-1] + 0xFFFF)
|
|
stringSize = (unsigned long)0x3FFF; // 16K. This is a bogus entry anyway.
|
|
else
|
|
#endif
|
|
stringSize = stringLength[i] - stringLength[i-1];
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutInt(stream, stringSize + 1);
|
|
|
|
if (retVal == kNoErr)
|
|
{
|
|
if (i % 13 == 0)
|
|
retVal = StrmPutStringEOL(stream, nilStr);
|
|
else
|
|
retVal = StrmPutString(stream, " ");
|
|
}
|
|
}
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, "] AllocGlyphStorage");
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
unsigned short
|
|
GetTableDirectoryOffset(
|
|
T42FontStruct *pFont,
|
|
unsigned long tableName
|
|
)
|
|
{
|
|
TableDirectoryStruct* tableDirectory = (TableDirectoryStruct *)pFont->pMinSfnt;
|
|
TableEntryStruct* tableEntry = (TableEntryStruct *)((char *)tableDirectory
|
|
+ sizeof (TableDirectoryStruct));
|
|
unsigned short offset = sizeof (TableDirectoryStruct);
|
|
unsigned short i = 0;
|
|
|
|
while (i < MOTOROLAINT(tableDirectory->numTables))
|
|
{
|
|
if (tableEntry->tag == tableName)
|
|
break;
|
|
else
|
|
{
|
|
tableEntry = (TableEntryStruct *)((char *)tableEntry + sizeof (TableEntryStruct));
|
|
offset += sizeof (TableEntryStruct);
|
|
i++;
|
|
}
|
|
}
|
|
return offset;
|
|
}
|
|
|
|
|
|
/* Sorting and Searching functions for an array of longs */
|
|
|
|
// Function to compare longs
|
|
static short
|
|
CompareLong(
|
|
const long x,
|
|
const long y
|
|
)
|
|
{
|
|
if (x == y)
|
|
return 0;
|
|
else if (x < y)
|
|
return -1;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
// Function to swap pointers to longs
|
|
static void
|
|
SwapLong(
|
|
long *a,
|
|
long *b
|
|
)
|
|
{
|
|
if (a != b)
|
|
{
|
|
long tmp = *a;
|
|
*a = *b;
|
|
*b = tmp;
|
|
}
|
|
}
|
|
|
|
|
|
/* This is a tailored version of shortsort. Works only for array of longs. */
|
|
static void
|
|
ShortsortLong(
|
|
char *lo,
|
|
char *hi,
|
|
unsigned short width,
|
|
short (*comp)(const long, const long)
|
|
)
|
|
{
|
|
while (hi > lo)
|
|
{
|
|
char *max = lo;
|
|
char *p;
|
|
|
|
for (p = lo + width; p <= hi; p += width)
|
|
{
|
|
if (comp(*(long *)p, *(long *)max) > 0)
|
|
max = p;
|
|
}
|
|
|
|
SwapLong((long *)max, (long *)hi);
|
|
|
|
hi -= width;
|
|
}
|
|
}
|
|
|
|
|
|
/* Function to Sort the array between lo and hi (inclusive) */
|
|
void
|
|
QsortLong(
|
|
char* base,
|
|
unsigned short num,
|
|
unsigned short width,
|
|
short (*comp)(const long, const long)
|
|
)
|
|
{
|
|
char *lo, *hi; /* ends of sub-array currently sorting */
|
|
char *mid; /* points to middle of subarray */
|
|
char *loguy, *higuy; /* traveling pointers for partition step */
|
|
unsigned short size; /* size of the sub-array */
|
|
short stkptr; /* stack for saving sub-array to be processed */
|
|
char *lostk[16], *histk[16];
|
|
|
|
/* Testing shows that this is a good value. */
|
|
const unsigned short CUTOFF0 = 8;
|
|
|
|
/*
|
|
* Note: the number of stack entries required is no more than
|
|
* 1 + log2(size), so 16 is sufficient for any array with <=64K elems.
|
|
*/
|
|
if ((num < 2) || (width == 0))
|
|
return; /* Nothing to do. */
|
|
|
|
stkptr = 0; /* Initialize stack. */
|
|
|
|
lo = (char *)base;
|
|
hi = (char *)base + width * (num - 1); /* Initialize limits. */
|
|
|
|
/*
|
|
* This entry point is for pseudo-recursion calling: setting lo and hi and
|
|
* jumping to here is like recursion, but stkptr is prserved, locals aren't,
|
|
* so we preserve stuff on the stack.
|
|
*/
|
|
sort_recurse:
|
|
|
|
size = (unsigned short)((hi - lo) / width + 1); /* Number of el's to sort */
|
|
|
|
if (size <= CUTOFF0)
|
|
{
|
|
ShortsortLong(lo, hi, width, comp);
|
|
}
|
|
else
|
|
{
|
|
mid = lo + (size / 2) * width; /* Find middle element. */
|
|
SwapLong((long *)mid, (long *)lo); /* Wwap it to beginning of array. */
|
|
|
|
loguy = lo;
|
|
higuy = hi + width;
|
|
|
|
/*
|
|
* Note that higuy decreases and loguy increases on every iteration,
|
|
* so loop must terminate.
|
|
*/
|
|
while(1)
|
|
{
|
|
do
|
|
{
|
|
loguy += width;
|
|
} while (loguy <= hi && comp(*(long *)loguy, *(long *)lo) <= 0);
|
|
|
|
do
|
|
{
|
|
higuy -= width;
|
|
} while (higuy > lo && comp(*(long *)higuy, *(long *)lo) >= 0);
|
|
|
|
if (higuy < loguy)
|
|
break;
|
|
|
|
SwapLong((long *)loguy, (long *)higuy);
|
|
}
|
|
|
|
SwapLong((long *)lo, (long *)higuy); /* Put partition element in place. */
|
|
|
|
if ((higuy - 1 - lo) >= (hi - loguy))
|
|
{
|
|
if ((lo + width) < higuy)
|
|
{
|
|
lostk[stkptr] = lo;
|
|
histk[stkptr] = higuy - width;
|
|
++stkptr; /* Save big recursion for later. */
|
|
}
|
|
|
|
if (loguy < hi)
|
|
{
|
|
lo = loguy;
|
|
goto sort_recurse; /* Do small recursion. */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (loguy < hi)
|
|
{
|
|
lostk[stkptr] = loguy;
|
|
histk[stkptr] = hi;
|
|
++stkptr; /* Save big recursion for later. */
|
|
}
|
|
|
|
if ((lo + width) < higuy)
|
|
{
|
|
hi = higuy - width;
|
|
goto sort_recurse; /* Do small recursion. */
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We have sorted the array, except for any pending sorts on the stack.
|
|
* Check if there are any, and do them.
|
|
*/
|
|
--stkptr;
|
|
|
|
if (stkptr >= 0)
|
|
{
|
|
lo = lostk[stkptr];
|
|
hi = histk[stkptr];
|
|
goto sort_recurse; /* Pop subarray from stack. */
|
|
}
|
|
else
|
|
return; /* All subarrays done. */
|
|
}
|
|
|
|
|
|
/* This is a tailored version of the CRT bsearch(). */
|
|
void *
|
|
BsearchLong (
|
|
const long key,
|
|
const char *base,
|
|
unsigned short num,
|
|
unsigned short width,
|
|
short (*compare)(const long, const long)
|
|
)
|
|
{
|
|
char *lo = (char *)base;
|
|
char *hi = (char *)base + (num - 1) * width;
|
|
|
|
while (lo <= hi)
|
|
{
|
|
unsigned short half;
|
|
|
|
if (half = (num / 2))
|
|
{
|
|
short result;
|
|
char *mid = lo + (num & 1 ? half : (half - 1)) * width;
|
|
|
|
if (!(result = (*compare)(key, *(long *)mid)))
|
|
return mid;
|
|
else if (result < 0)
|
|
{
|
|
hi = mid - width;
|
|
num = num & 1 ? half : half - 1;
|
|
}
|
|
else
|
|
{
|
|
lo = mid + width;
|
|
num = half;
|
|
}
|
|
}
|
|
else if (num)
|
|
return ((*compare)((long)key, *(long *)lo) ? nil : lo);
|
|
else
|
|
break;
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
DefaultGetRotatedGIDs(
|
|
UFOStruct *pUFObj,
|
|
T42FontStruct *pFont,
|
|
UFLFontProcs *pFontProcs
|
|
)
|
|
{
|
|
UFLErrCode retVal = kNoErr;
|
|
unsigned short num = 0; // Remember the number of GIDs.
|
|
long *pFoundGID;
|
|
short subTable;
|
|
unsigned long offset;
|
|
short i;
|
|
|
|
/*
|
|
* Don't forget to double the size. We expect extra GIDs coming from 'GSUB'
|
|
* or 'mort' table.
|
|
*/
|
|
pFont->pRotatedGlyphIDs = (long *)UFLNewPtr(pUFObj->pMem, (NUM_HALFWIDTHCHARS + 1) * sizeof (long) * 2);
|
|
if (!pFont->pRotatedGlyphIDs)
|
|
return kErrOutOfMemory;
|
|
|
|
/*
|
|
* To scan through TTF's 'cmap' table to fingure out the glyph ids for all
|
|
* characters in the range for romans and single byte chars.
|
|
*/
|
|
if (!pFontProcs->pfGetGlyphID)
|
|
GetGlyphIDEx(pUFObj, 0, 0, &subTable, &offset, GGIEX_HINT_INIT);
|
|
|
|
pFoundGID = pFont->pRotatedGlyphIDs;
|
|
|
|
for (i = 0;
|
|
(gHalfWidthChars[i].startU != gHalfWidthChars[i].endU)
|
|
&& (gHalfWidthChars[i].startU != 0);
|
|
i++)
|
|
{
|
|
long unicode, localcode;
|
|
|
|
for (unicode = gHalfWidthChars[i].startU, localcode = gHalfWidthChars[i].startL;
|
|
unicode <= gHalfWidthChars[i].endU;
|
|
unicode++, localcode++)
|
|
{
|
|
unsigned long gi;
|
|
|
|
if (pFontProcs->pfGetGlyphID)
|
|
gi = pFontProcs->pfGetGlyphID(pUFObj->hClientData,
|
|
(unsigned short)unicode,
|
|
(unsigned short)localcode);
|
|
else
|
|
gi = GetGlyphIDEx(pUFObj, unicode, localcode,
|
|
&subTable, &offset, GGIEX_HINT_GET);
|
|
|
|
if (gi > (unsigned long)UFO_NUM_GLYPHS(pUFObj))
|
|
gi = 0;
|
|
|
|
if (gi != 0)
|
|
{
|
|
*pFoundGID = (long)gi;
|
|
pFoundGID++;
|
|
num++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We will have to treat all Half-width single characters as
|
|
// "space" because we don't want to place a Double-Byte
|
|
// /.notdef as rotated.
|
|
//
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pFontProcs->pfGetRotatedGSUBs) // Fix #316070
|
|
{
|
|
// OK to trancate long to unsigned short.
|
|
num += (unsigned short)pFontProcs->pfGetRotatedGSUBs(
|
|
pUFObj->hClientData,
|
|
pFont->pRotatedGlyphIDs,
|
|
num);
|
|
}
|
|
|
|
pFont->numRotatedGlyphIDs = num;
|
|
|
|
//
|
|
// Now, sort the array so that we can search quicker later.
|
|
//
|
|
QsortLong((char *)(pFont->pRotatedGlyphIDs),
|
|
pFont->numRotatedGlyphIDs,
|
|
4,
|
|
CompareLong);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
T42GetRotatedGIDs(
|
|
UFOStruct *pUFObj,
|
|
T42FontStruct *pFont
|
|
)
|
|
{
|
|
UFLFontProcs *pFontProcs = (UFLFontProcs *)&(pUFObj->pUFL->fontProcs);
|
|
|
|
/* Assume this first in order to fall back to the default logic. */
|
|
UFLErrCode retVal = kErrOSFunctionFailed;
|
|
|
|
pFont->numRotatedGlyphIDs = 0;
|
|
|
|
if (pFontProcs->pfGetRotatedGIDs)
|
|
{
|
|
long nGlyphs = pFontProcs->pfGetRotatedGIDs(pUFObj->hClientData, nil, 0, nil);
|
|
|
|
if (nGlyphs > 0)
|
|
{
|
|
pFont->pRotatedGlyphIDs = (long *)UFLNewPtr(pUFObj->pMem, (nGlyphs + 1) * sizeof (long));
|
|
|
|
if (pFont->pRotatedGlyphIDs)
|
|
{
|
|
pFontProcs->pfGetRotatedGIDs(pUFObj->hClientData, pFont->pRotatedGlyphIDs, nGlyphs, nil);
|
|
pFont->numRotatedGlyphIDs = (unsigned short)nGlyphs;
|
|
retVal = kNoErr;
|
|
}
|
|
else
|
|
retVal = kErrOutOfMemory;
|
|
}
|
|
else
|
|
retVal = (nGlyphs == 0) ? kNoErr: kErrOSFunctionFailed;
|
|
}
|
|
|
|
if (retVal == kErrOSFunctionFailed)
|
|
{
|
|
/*
|
|
* Default logic: scan TTF's cmap to get GIDs for CJK half-width chars.
|
|
*/
|
|
retVal = DefaultGetRotatedGIDs(pUFObj, pFont, pFontProcs);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFLBool
|
|
IsDoubleByteGI(
|
|
unsigned short gi,
|
|
long *pGlyphIDs,
|
|
short length
|
|
)
|
|
{
|
|
void *index;
|
|
|
|
// Return True if gi is NOT in the pGlyphIDs - index==nil.
|
|
index = BsearchLong((long)gi, (char *)pGlyphIDs, length, 4, CompareLong);
|
|
|
|
return ((index == nil) ? 1 : 0);
|
|
}
|
|
|
|
|
|
/*============================================================================*
|
|
* Begin Code to support more than 32K glyphs *
|
|
*============================================================================*/
|
|
|
|
/******************************************************************************
|
|
*
|
|
* T42SendCMapWinCharSetFFFF_V
|
|
*
|
|
* Make a vertical CMap based on known Rotated Glyph-indices (1 Byte chars).
|
|
* Create a CMapType 1 CMap. Since this CMap is different for different font,
|
|
* the CMapName is passed in by caller as lpNewCmap. The resulting CMap uses
|
|
* 2 or 4(lGlyphs>32K) CMaps: e.g.
|
|
*
|
|
* [/TT31c1db0t0cid /TT31c1db0t0cidR]
|
|
* or
|
|
* [/TT31c1db0t0cid /TT31c1db0t0cidR /TT31c1db0t0cid32K /MSTT31c1db0t0cid32KR]
|
|
*
|
|
******************************************************************************/
|
|
|
|
UFLErrCode
|
|
T42SendCMapWinCharSetFFFF_V(
|
|
UFOStruct *pUFObj,
|
|
long *pRotatedGID,
|
|
short wLength,
|
|
UFLCMapInfo *pCMap,
|
|
char *pNewCmap,
|
|
unsigned long lGlyphs,
|
|
UFLHANDLE stream,
|
|
char *strmbuf,
|
|
size_t cchstrmbuf
|
|
)
|
|
{
|
|
short nCount, nCount32K, nLen, i, j;
|
|
unsigned short wPrev, wCurr;
|
|
UFLErrCode retVal;
|
|
UFLBool bCMapV2 = (pCMap == &CMapInfo_FF_V2) ? 1 : 0;
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf,
|
|
"/CIDInit /ProcSet findresource begin "
|
|
"12 dict begin begincmap /%s usecmap",
|
|
pCMap->CMapName);
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
/*
|
|
* Create CIDSystemInfo unique for this font. Since this CMap will refer to
|
|
* more than one font, the CIDSystmInfo is going to be an array.
|
|
*/
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "/CIDSystemInfo [3 dict dup begin");
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "/Registry (%s) def", pCMap->Registry);
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "/Ordering (%s) def", pNewCmap);
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "/Supplement 0 def");
|
|
|
|
if (lGlyphs <= NUM_32K_1)
|
|
UFLsprintf(strmbuf, cchstrmbuf, "end dup] def");
|
|
else
|
|
UFLsprintf(strmbuf, cchstrmbuf, "end dup dup dup] def");
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "/CMapName /%s def", pNewCmap);
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
/* Fix /CIDInit /ProcSet bug: need "/WMode 1 def" explicitly. */
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "/WMode 1 def");
|
|
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "0 beginusematrix [0 1 -1 0 0 0] endusematrix");
|
|
|
|
if ((retVal == kNoErr) && bCMapV2)
|
|
retVal = StrmPutStringEOL(stream, "2 beginusematrix [0 1 -1 0 0 0] endusematrix");
|
|
|
|
/* Skip to emit begin~endcidrange if there is no rotated GIDs. */
|
|
if (wLength == 0)
|
|
goto SENDCMAPFFFF_V_ENDCMAP;
|
|
|
|
/*
|
|
* Count how many different Glyph-indices are there in pRotatedGID.
|
|
* It must be sorted and there may be duplicates so that we count only
|
|
* unique GIDs.
|
|
*/
|
|
wPrev = (unsigned short)*pRotatedGID;
|
|
nCount = nCount32K = 0;
|
|
|
|
if (wPrev > NUM_32K_1)
|
|
nCount32K++;
|
|
else
|
|
nCount++;
|
|
|
|
for (i = 0; i < wLength; i++)
|
|
{
|
|
wCurr = (unsigned short)*(pRotatedGID + i);
|
|
if (wPrev == wCurr)
|
|
continue;
|
|
else
|
|
{
|
|
wPrev = wCurr;
|
|
if (wPrev > NUM_32K_1)
|
|
nCount32K++;
|
|
else
|
|
nCount++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Emit 0 to 32K rotated GIDs to font number 1.
|
|
*/
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "1 usefont");
|
|
|
|
if (100 < nCount)
|
|
UFLsprintf(strmbuf, cchstrmbuf, "100 begincidrange");
|
|
else
|
|
UFLsprintf(strmbuf, cchstrmbuf, "%d begincidrange", nCount);
|
|
|
|
wPrev = (unsigned short)*(pRotatedGID);
|
|
|
|
if (retVal == kNoErr)
|
|
{
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, wPrev);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, wPrev);
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "%u", wPrev);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
nLen = 1;
|
|
for (i = 1; i < wLength; i++)
|
|
{
|
|
wCurr = (unsigned short)*(pRotatedGID + i);
|
|
|
|
/*
|
|
* This potion is for 0 to 32K glyphs - the pRotatedGID are sorted,
|
|
* so we can just break out of the loop here.
|
|
*/
|
|
if (wCurr > NUM_32K_1)
|
|
break;
|
|
|
|
if (wPrev == wCurr)
|
|
continue;
|
|
else
|
|
{
|
|
wPrev = wCurr;
|
|
nLen++;
|
|
}
|
|
|
|
if (retVal == kNoErr)
|
|
{
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, wPrev);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, wPrev);
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "%u", wPrev);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
if (nLen % 100 == 0)
|
|
{
|
|
if (nCount - nLen > 100)
|
|
UFLsprintf(strmbuf, cchstrmbuf, "endcidrange\n100 begincidrange");
|
|
else if (nCount - nLen > 0)
|
|
UFLsprintf(strmbuf, cchstrmbuf, "endcidrange\n%d begincidrange", nCount - nLen);
|
|
else
|
|
UFLsprintf(strmbuf, cchstrmbuf, " ");
|
|
}
|
|
else
|
|
continue; /* Do next record. */
|
|
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "endcidrange");
|
|
|
|
/*
|
|
* Emit 32K+ GIDs.
|
|
*/
|
|
if (NUM_32K_1 < lGlyphs)
|
|
{
|
|
/*
|
|
* Build two more re-mappings using CMAP-WinCharSetFFFF-V2, which is
|
|
* created from CMAP-WinCharSetFFFF-H2 specifying 32K+ glyphs as
|
|
* font number 1. (See the definition of CMAP-WinCharSetFFFF-H2 in
|
|
* CMap_FF.ps.) Since font number 1 is already used for 0 to 32K
|
|
* rotated GIDs above, we need to redefine the range for 32K+
|
|
* unrotated GIDs as font number 2, *then* define the range for 32K+
|
|
* rotated GIDs as font number 3. (Here is the font array we are
|
|
* assuming: [000, 000R, 00032K, 00032KR])
|
|
*
|
|
* Note also that when this is a %hostfont% font (bCMapV2 is 0), we
|
|
* don't need to use CMAP-WinCharSetFFFF-V2 but CMAP-WinCharSetFFFF-V
|
|
* instead. But we still need to emit 32K+ glyph cidrange here.
|
|
* In this case, we don't send '3 usefont' so that the cidrange lines
|
|
* are emitted as continuation for font number 1.
|
|
*/
|
|
|
|
if (bCMapV2)
|
|
{
|
|
/*
|
|
* Emit font number 2 range.
|
|
*/
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "2 usefont");
|
|
|
|
nCount = (int)((long)lGlyphs - (long)NUM_32K_1 + 0xFE) / 0xFF;
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "%d begincidrange", nCount);
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
/*
|
|
* We assume NUM_32K_1 ends at 00 (such as 0xFF00, or 0xFE00...).
|
|
*/
|
|
for (i = 0; i < nCount; i++)
|
|
{
|
|
wPrev = (unsigned short) (i * 0x100 + (long)NUM_32K_1);
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, wPrev);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, (unsigned short)(wPrev + 0xFF));
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "%u", (unsigned short)(i * 0x100));
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "endcidrange");
|
|
}
|
|
|
|
if (0 < nCount32K)
|
|
{
|
|
/*
|
|
* Emit rotated GIDs of font number 3 or 1 if not using
|
|
* '2' version of VCMap (which means this is a %hostfont%
|
|
* font that has 32K+ glyphs.)
|
|
*/
|
|
if ((retVal == kNoErr) && bCMapV2)
|
|
retVal = StrmPutStringEOL(stream, "3 usefont");
|
|
|
|
wPrev = (unsigned short)*pRotatedGID;
|
|
|
|
for (j = 0; j < wLength; j++)
|
|
{
|
|
wCurr = (unsigned short)*(pRotatedGID + j);
|
|
wPrev = wCurr;
|
|
|
|
if (wPrev > NUM_32K_1)
|
|
break; /* Found the start point. */
|
|
}
|
|
|
|
if (100 < nCount32K)
|
|
UFLsprintf(strmbuf, cchstrmbuf, "100 begincidrange");
|
|
else
|
|
UFLsprintf(strmbuf, cchstrmbuf, "%d begincidrange", nCount32K);
|
|
|
|
if (retVal == kNoErr)
|
|
{
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, wPrev);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, wPrev);
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "%u", bCMapV2 ? wPrev - NUM_32K_1 : wPrev);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
nLen = 1;
|
|
for (i = j; i < wLength; i++)
|
|
{
|
|
wCurr = (unsigned short)*(pRotatedGID + i);
|
|
|
|
if (wPrev == wCurr)
|
|
continue;
|
|
else
|
|
{
|
|
wPrev = wCurr;
|
|
nLen++;
|
|
}
|
|
|
|
if (retVal == kNoErr)
|
|
{
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, wPrev);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutWordAsciiHex(stream, wPrev);
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "%u", bCMapV2 ? wPrev - NUM_32K_1 : wPrev);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
if (nLen % 100 == 0)
|
|
{
|
|
if (100 < nCount - nLen)
|
|
UFLsprintf(strmbuf, cchstrmbuf, "endcidrange 100 begincidrange");
|
|
else if (0 < nCount - nLen)
|
|
UFLsprintf(strmbuf, cchstrmbuf, "endcidrange %d begincidrange", nCount-nLen);
|
|
else
|
|
UFLsprintf(strmbuf, cchstrmbuf, " ");
|
|
}
|
|
else
|
|
continue; /* Do next record. */
|
|
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "endcidrange");
|
|
|
|
/* End of additional 32K+ CMap code. */
|
|
}
|
|
}
|
|
|
|
SENDCMAPFFFF_V_ENDCMAP:
|
|
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, "endcmap CMapName currentdict "
|
|
"/CMap defineresource pop end end");
|
|
|
|
return retVal;
|
|
}
|
|
|
|
/*============================================================================*
|
|
* End Code To Support More Than 32K Glyphs *
|
|
*============================================================================*/
|
|
|
|
|
|
long
|
|
AdjBBox(
|
|
long value,
|
|
UFLBool lowerleft
|
|
)
|
|
{
|
|
if (lowerleft)
|
|
{
|
|
if (value > 0)
|
|
return (value - 1);
|
|
else if (value < 0)
|
|
return (value + 1);
|
|
else
|
|
return (value);
|
|
}
|
|
else
|
|
{
|
|
if (value > 0)
|
|
return (value + 1);
|
|
if (value < 0)
|
|
return (value - 1);
|
|
else
|
|
return (value);
|
|
}
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
T42CreateBaseFont(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMUsage,
|
|
UFLBool bFullFont,
|
|
char *pHostFontName
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
UFLFontProcs *pFontProcs = (UFLFontProcs *)&(pUFObj->pUFL->fontProcs);
|
|
UFLHANDLE stream = pUFObj->pUFL->hOut;
|
|
UFLErrCode retVal = kNoErr;
|
|
unsigned long cidCount, tableSize, tableSize1, sizeUsed;
|
|
UFLCMapInfo *pCMap;
|
|
char strmbuf[256];
|
|
|
|
|
|
/* Sanity check */
|
|
if (pFont == nil)
|
|
return kErrInvalidHandle;
|
|
|
|
/*
|
|
* Download procsets.
|
|
*/
|
|
if (pUFObj->pUFL->outDev.pstream->pfDownloadProcset == 0)
|
|
return kErrDownloadProcset;
|
|
|
|
if (!pUFObj->pUFL->outDev.pstream->pfDownloadProcset(pUFObj->pUFL->outDev.pstream, kT42Header))
|
|
return kErrDownloadProcset;
|
|
|
|
if (IS_TYPE42CID_KEYEDFONT(pUFObj->lDownloadFormat))
|
|
{
|
|
if (!pUFObj->pUFL->outDev.pstream->pfDownloadProcset(pUFObj->pUFL->outDev.pstream, kCMap_FF))
|
|
return kErrDownloadProcset;
|
|
}
|
|
|
|
|
|
/*
|
|
* There is a bumpy road ahead when kFontInit2 state.
|
|
*/
|
|
if (UFO_FONT_INIT2(pUFObj))
|
|
goto T42CreateBaseFont_FontInit2_1;
|
|
|
|
|
|
/*
|
|
* Generate the minimal sfnt.
|
|
*/
|
|
retVal = GetMinSfnt(pUFObj, bFullFont);
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = FillInHeadTable(pUFObj);
|
|
|
|
if (kNoErr == retVal)
|
|
pFont->info.fData.cNumGlyphs = GetNumGlyphs(pUFObj);
|
|
|
|
if (kNoErr == retVal)
|
|
{
|
|
tableSize = GetTableSize(pUFObj, pFont->pMinSfnt, LOCA_TABLE);
|
|
|
|
if (tableSize)
|
|
{
|
|
/*
|
|
* The following code includes fix for #317027 and #316096: load
|
|
* 'loca' table and set the extra glyph offset entry if it's
|
|
* missing and the delta from the last glyph offset is less than
|
|
* 4K for safety.
|
|
*/
|
|
unsigned long expectedTableSize = pFont->info.fData.cNumGlyphs + 1;
|
|
|
|
expectedTableSize *= pFont->headTable.indexToLocFormat ? 4 : 2;
|
|
|
|
// Fixed bug 516514
|
|
if (expectedTableSize > tableSize)
|
|
{
|
|
sizeUsed = expectedTableSize;
|
|
pFont->pLocaTable = UFLNewPtr(pUFObj->pMem, expectedTableSize);
|
|
}
|
|
else
|
|
{
|
|
sizeUsed = tableSize;
|
|
pFont->pLocaTable = UFLNewPtr(pUFObj->pMem, tableSize);
|
|
}
|
|
|
|
if (pFont->pLocaTable)
|
|
{
|
|
if (GetFontTable(pUFObj, LOCA_TABLE, (unsigned char *)pFont->pLocaTable, sizeUsed) == 0)
|
|
{
|
|
retVal = kErrGetFontData;
|
|
}
|
|
else if (expectedTableSize > tableSize)
|
|
{
|
|
unsigned long glyfTableSize = GetTableSize(pUFObj, pFont->pMinSfnt, GLYF_TABLE);
|
|
unsigned char *pTable, *pExtraEntry;
|
|
unsigned long lastValidOffset;
|
|
|
|
pTable = (unsigned char *)pFont->pLocaTable;
|
|
|
|
if (pFont->headTable.indexToLocFormat)
|
|
{
|
|
unsigned long *pLastEntry =
|
|
(unsigned long *)(pTable + (pFont->info.fData.cNumGlyphs - 1) * 4);
|
|
|
|
lastValidOffset = MOTOROLALONG(*pLastEntry);
|
|
|
|
if (glyfTableSize - lastValidOffset < 4097)
|
|
{
|
|
pExtraEntry = (unsigned char *)(pLastEntry + 1);
|
|
|
|
*pExtraEntry++ = (unsigned char)((glyfTableSize & 0xFF000000) >> 24);
|
|
*pExtraEntry++ = (unsigned char)((glyfTableSize & 0x00FF0000) >> 16);
|
|
*pExtraEntry++ = (unsigned char)((glyfTableSize & 0x0000FF00) >> 8);
|
|
*pExtraEntry = (unsigned char)((glyfTableSize & 0x000000FF));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned short *pLastEntry =
|
|
(unsigned short *)(pTable + (pFont->info.fData.cNumGlyphs - 1) * 2);
|
|
|
|
lastValidOffset = MOTOROLAINT(*pLastEntry);
|
|
|
|
if (glyfTableSize - lastValidOffset < 4097)
|
|
{
|
|
pExtraEntry = (unsigned char *)(pLastEntry + 1);
|
|
|
|
*pExtraEntry++ = (unsigned char)((glyfTableSize & 0x0000FF00) >> 8);
|
|
*pExtraEntry = (unsigned char)((glyfTableSize & 0x000000FF));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
retVal = kErrOutOfMemory;
|
|
}
|
|
else
|
|
retVal = kErrGetFontData;
|
|
}
|
|
|
|
if (kNoErr == retVal)
|
|
{
|
|
/* Fix blue screen bug 278017. */
|
|
tableSize = pFont->minSfntSize; /* instead of GetGlyphTableSize(pUFObj) */
|
|
|
|
if (!bFullFont)
|
|
tableSize += GetGlyphTableSize(pUFObj);
|
|
|
|
if (((tableSize / SFNT_STRINGSIZE) * 5 / 4) > NUM_16KSTR)
|
|
tableSize = (tableSize / SFNT_STRINGSIZE) * 5 / 4;
|
|
else
|
|
tableSize = NUM_16KSTR;
|
|
|
|
tableSize1 = tableSize + 1;
|
|
|
|
pFont->pStringLength =
|
|
(unsigned long *)UFLNewPtr(pUFObj->pMem, tableSize1 * sizeof(unsigned long));
|
|
|
|
if (pFont->pStringLength)
|
|
retVal = CalculateStringLength(pUFObj, pFont, tableSize1);
|
|
else
|
|
retVal = kErrOutOfMemory;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// /sfnts initialization is done. Actual downloading begins here.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
* Send out left upper right lower values.
|
|
*/
|
|
if ((kNoErr == retVal) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
// Fixed bug #516915
|
|
if (0 == pFont->headTable.unitsPerEm)
|
|
retVal = kErrGetFontData;
|
|
else
|
|
{
|
|
/*
|
|
* The first four values are the font bounding box. We convert all
|
|
* floats into 24.8 fixed values. Make sure the bounding box doesn't
|
|
* get truncated down to a smaller area.
|
|
*/
|
|
UFLsprintfEx(strmbuf, CCHOF(strmbuf), "%f %f %f %f",
|
|
(AdjBBox((long)pFont->headTable.xMin, 1) << 8) / (long)pFont->headTable.unitsPerEm,
|
|
(AdjBBox((long)pFont->headTable.yMin, 1) << 8) / (long)pFont->headTable.unitsPerEm,
|
|
(AdjBBox((long)pFont->headTable.xMax, 0) << 8) / (long)pFont->headTable.unitsPerEm,
|
|
(AdjBBox((long)pFont->headTable.yMax, 0) << 8) / (long)pFont->headTable.unitsPerEm);
|
|
|
|
retVal = StrmPutStringEOL(pUFObj->pUFL->hOut, strmbuf);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Send out encoding name.
|
|
*/
|
|
if ((kNoErr == retVal) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/*
|
|
* Always emit Encoding array filled with /.notdef (due to bug fix
|
|
* #273021).
|
|
*/
|
|
retVal = StrmPutString(stream, gnotdefArray);
|
|
}
|
|
|
|
/*
|
|
* Send out font name.
|
|
*/
|
|
if ((kNoErr == retVal) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/*
|
|
* If CID-keyed font, then append "CID" to the CIDFont name so that
|
|
* CID_Resource is also consisted of the original fontName.
|
|
*/
|
|
if (IS_TYPE42CID_KEYEDFONT(pUFObj->lDownloadFormat))
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s", pFont->info.CIDFontName, gcidSuffix[0]);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /%s", pUFObj->pszFontName);
|
|
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
|
|
/*
|
|
* First landing place when kFontInit2 state.
|
|
*/
|
|
T42CreateBaseFont_FontInit2_1:
|
|
|
|
|
|
/*
|
|
* Setup for CID-keyed-font or CIDFont-Resource downloading.
|
|
*/
|
|
if ((kNoErr == retVal) && IS_TYPE42CID(pUFObj->lDownloadFormat))
|
|
{
|
|
//
|
|
// hasvmtx is used to determine whether to call the AddT42vmtxEntry
|
|
// function later.
|
|
//
|
|
unsigned long tblSize = GETTTFONTDATA(pUFObj,
|
|
VMTX_TABLE, 0L,
|
|
nil, 0L,
|
|
pFont->info.fData.fontIndex);
|
|
|
|
pUFObj->pAFont->hasvmtx = tblSize ? 1 : 0;
|
|
|
|
if (pFont->info.bUseIdentityCMap)
|
|
{
|
|
UFLBool bUseCMap2 = 0;
|
|
cidCount = UFO_NUM_GLYPHS(pUFObj);
|
|
|
|
/*
|
|
* Use '2' version of CMap if the number of glyphs are greater
|
|
* than 32K *and* this is not a %hostfont% font.
|
|
*/
|
|
if((NUM_32K_1 < cidCount) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
bUseCMap2 = 1;
|
|
|
|
if (IS_TYPE42CID_H(pUFObj->lDownloadFormat))
|
|
pCMap = bUseCMap2 ? &CMapInfo_FF_H2 : &CMapInfo_FF_H;
|
|
else
|
|
pCMap = bUseCMap2 ? &CMapInfo_FF_V2 : &CMapInfo_FF_V;
|
|
}
|
|
else
|
|
{
|
|
cidCount = pFont->info.CIDCount;
|
|
|
|
/* If CMap is provided, use it. */
|
|
pCMap = &(pFont->info.CMap);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Need one more warp when kFontInit2 state.
|
|
*/
|
|
if (UFO_FONT_INIT2(pUFObj))
|
|
goto T42CreateBaseFont_FontInit2_2;
|
|
|
|
|
|
/*
|
|
* Begin font dictionary download.
|
|
*/
|
|
|
|
if ((kNoErr == retVal)
|
|
&& IS_TYPE42CID(pUFObj->lDownloadFormat)
|
|
&& !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/*
|
|
* If downloading CID Type 42, add CIDSysInfo, CIDCount, CIDMap, and
|
|
* CDevProc.
|
|
*/
|
|
|
|
/* Registry, Ordering, and Suppliment */
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf),
|
|
"(%s) (%s) %d",
|
|
pCMap->Registry, pCMap->Ordering, pCMap->Supplement);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
/* CIDCount */
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "%lu", min(cidCount, (long)NUM_32K_1));
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
/* CIDMap */
|
|
if (pFontProcs->pfGetCIDMap
|
|
&& (tableSize = pFontProcs->pfGetCIDMap(pUFObj->hClientData, nil, 0)))
|
|
{
|
|
char* pCIDMap = UFLNewPtr(pUFObj->pMem, tableSize);
|
|
|
|
if (pCIDMap)
|
|
{
|
|
tableSize = pFontProcs->pfGetCIDMap(pUFObj->hClientData, pCIDMap, tableSize);
|
|
|
|
/* The pCIDMap is already ASCII, so just send it using PutBytes(). */
|
|
if (kNoErr == retVal)
|
|
StrmPutBytes(stream, pCIDMap, (UFLsize_t) tableSize, 1);
|
|
|
|
UFLDeletePtr(pUFObj->pMem, pCIDMap);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* IDStr creates an Identity string.
|
|
* WCC - IDStrNull creates a strings which maps all CIDs to GID 0.
|
|
* Bug #260864. Use IDStrNull for Character Code mode.
|
|
*/
|
|
if (pFont->info.bUpdateCIDMap)
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "%lu IDStrNull", min(cidCount - 1, (long)NUM_32K_1));
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "%lu IDStr", min(cidCount - 1, (long)NUM_32K_1));
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
/*
|
|
* CDevProc
|
|
*
|
|
* Further investigation due to #351487 led us to download Metrics2
|
|
* array with TopSideBearing/EM as vy for EVERY glyph and generate
|
|
* the following metrics in CDevProc:
|
|
*
|
|
* W1x = 0
|
|
* W1y = -AdvancedHeight / EM
|
|
* vx = descender / EM
|
|
* vy = ury + TopSideBearing / EM
|
|
*
|
|
* According to this, the CDevProc became very simple like this:
|
|
*
|
|
* {pop 4 index add}
|
|
*
|
|
* On the other hand, if the TrueType font doesn't have 'vmtx' table,
|
|
* then the driver never download Metrics2 for any glyph at all and
|
|
* the following CDevProc is use instead:
|
|
*
|
|
* {5 {pop} repeat 0 -1 descender/em ascender/em}
|
|
*
|
|
* This is an agreement between the driver and %hostfont% teams to
|
|
* make the inks from %hostfont% RIP and non %hostfont% RIP match.
|
|
* (...but this is not actually the same CDevProc %hostfont% RIP
|
|
* uses. Ascender and descender values %hostfont% RIP uses are the
|
|
* ones from 'vhea' or 'hhea'. Whereas, ascender and descender values
|
|
* the driver uses to generate this CDevProc are from 'OS/2' or 'hhea'.
|
|
* A font, almost always, has 'OS/2' and 'hhea', hence the CDevProc
|
|
* downloaded by the driver and the one generated by %hostfont% RIP
|
|
* aren't same normally.)
|
|
*
|
|
* Other bug numbers related with this problem are 277035, 277063,
|
|
* 303540, and 309104.
|
|
*/
|
|
{
|
|
if (pUFObj->pAFont->hasvmtx)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "{pop 4 index add}bind");
|
|
}
|
|
else
|
|
{
|
|
long em, w1y, vx, vy, tsb, vasc;
|
|
UFLBool bUseDef;
|
|
|
|
GetMetrics2FromTTF(pUFObj, 0, &em, &w1y, &vx, &vy, &tsb, &bUseDef, 1, &vasc);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf),
|
|
"{5{pop}repeat 0 -1 %ld %ld div %ld %ld div}bind",
|
|
vx, em, vy, em);
|
|
}
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "CIDT42Begin");
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
else if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/* Plain Type 42 format */
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, "Type42DictBegin");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Either Type42DictBegin or CIDT42Begin has just emitted.
|
|
// Begin downloading /sfnts array
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, "[");
|
|
|
|
if (kNoErr == retVal)
|
|
{
|
|
/* Remember Number of strings of all otherTables sent. */
|
|
if (StrmCanOutputBinary(stream))
|
|
pFont->cOtherTables = PSSendSfntsBinary(pUFObj);
|
|
else
|
|
pFont->cOtherTables = PSSendSfntsAsciiHex(pUFObj);
|
|
}
|
|
|
|
if ((kNoErr == retVal) && !bFullFont)
|
|
retVal = GenerateGlyphStorageExt(pUFObj, tableSize1);
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, "]def ");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// /sfnts array downloading completed. Then emit extra info, such as
|
|
// FontInfo, FSType, and XUID.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
if ((kNoErr == retVal) && !bFullFont && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/* Invoke procedure to prepare for 2015 incremental downloading. */
|
|
retVal = StrmPutInt(stream, GetTableDirectoryOffset(pFont, LOCA_TABLE));
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, " ");
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutInt(stream, GetTableDirectoryOffset(pFont, GLYF_TABLE));
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, " ");
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, "PrepFor2015");
|
|
}
|
|
|
|
/*
|
|
* Add FontInfo dict if 'post' table is not good as of today. We only need
|
|
* this info in FontInfo dict.
|
|
*/
|
|
if ((kNoErr == retVal) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
retVal = StrmPutStringEOL(stream, "AddFontInfoBegin");
|
|
pUFObj->dwFlags |= UFO_HasFontInfo;
|
|
}
|
|
|
|
/*
|
|
* GoodName
|
|
* Ignore to test whether this font has good 'post' table and always emit
|
|
* AddFontInfo to include glyph name to Unicode mapping.
|
|
*/
|
|
// if (!BHasGoodPostTable(pUFObj))
|
|
// {
|
|
if ((kNoErr == retVal) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "AddFontInfo");
|
|
|
|
if (kNoErr == retVal)
|
|
{
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
pUFObj->dwFlags |= UFO_HasG2UDict;
|
|
}
|
|
}
|
|
// }
|
|
|
|
/*
|
|
* Add more font properties to FontInfo of the current dict.
|
|
*/
|
|
if ((kNoErr == retVal)
|
|
&& pFontProcs->pfAddFontInfo
|
|
&& !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
char *pBuffer;
|
|
int bufLen = 1000;
|
|
|
|
pBuffer = UFLNewPtr(pUFObj->pMem, bufLen);
|
|
|
|
if (pBuffer)
|
|
{
|
|
pFontProcs->pfAddFontInfo(pUFObj->hClientData, pBuffer, bufLen);
|
|
retVal = StrmPutStringEOL(stream, pBuffer);
|
|
|
|
UFLDeletePtr(pUFObj->pMem, pBuffer);
|
|
}
|
|
|
|
pBuffer = nil;
|
|
}
|
|
|
|
if ((kNoErr == retVal) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/* Fixing bug 284250. Add /FSType to FontInfoDict. */
|
|
long fsType;
|
|
|
|
if ((fsType = GetOS2FSType(pUFObj)) == -1)
|
|
fsType = 4;
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/FSType %ld def", fsType);
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
/*
|
|
* End FontInfo.
|
|
*/
|
|
if ((kNoErr == retVal) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
retVal = StrmPutStringEOL(stream, "AddFontInfoEnd");
|
|
|
|
/*
|
|
* Optionally add XUID.
|
|
*/
|
|
if ((kNoErr == retVal) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
unsigned long sSize = pUFObj->pAFont->Xuid.sSize;
|
|
|
|
if (sSize)
|
|
{
|
|
unsigned long *pXUID = pUFObj->pAFont->Xuid.pXUID;
|
|
|
|
retVal = StrmPutString(stream, "[");
|
|
|
|
while (sSize)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "16#%x ", *pXUID);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, strmbuf);
|
|
|
|
pXUID++;
|
|
sSize--;
|
|
}
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "] AddXUID");
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* End font dictionary download.
|
|
*/
|
|
if (IS_TYPE42CID(pUFObj->lDownloadFormat) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/* End CID Type 42 CIDFont resource creation. */
|
|
if (kNoErr == retVal)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "CIDT42End");
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
}
|
|
else if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/* End plain Type 42 font creation. */
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, "Type42DictEnd");
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// End downloading with Type42DictEnd or CIDT42End.
|
|
//
|
|
// When the font is a Roman TrueType font, a ready-to-use, Type 42 font
|
|
// has been defined.
|
|
//
|
|
// When the font is a CJK TrueType font, a CIDFont resource has been
|
|
// defined. But it's just a CIDFont and we still need to perform extra
|
|
// work in order to define a CID-Keyed font, which is:
|
|
//
|
|
// 1. Define a CMap with rotated GlyphIDs if this is a vertical font.
|
|
// 2. Do composefont with the CIDFont and the CMap(s).
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/*
|
|
* Final landing place when kFontInit2 state.
|
|
*/
|
|
T42CreateBaseFont_FontInit2_2:
|
|
|
|
|
|
/*
|
|
* At this point, a CIDFont resource is created. If the request is to
|
|
* do kTTType42CID_Resource, we are done.
|
|
*/
|
|
if ((kNoErr == retVal) && IS_TYPE42CID_KEYEDFONT(pUFObj->lDownloadFormat))
|
|
{
|
|
/*
|
|
* Instantiate the CMap resource if do composefont - notice a convention
|
|
* used here: CMAP-cmapname is used to instantiate cmapname.
|
|
* See CMap_FF.ps as an example.
|
|
*/
|
|
if (kNoErr == retVal)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "CMAP-%s", pCMap->CMapName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
/*
|
|
* Now we can construct CID-keyed font from the CIDFont reosurce and CMap.
|
|
*
|
|
* e.g. /TT3782053888t0 /WinCharSetFFFF-H [/TT3782053888t0cid] composefont pop
|
|
*
|
|
* !!!BUT!!!, if there are more than 32K glyphs (like some Korean TT Fonts),
|
|
* we need to make copies of the CIDFont Resource and make use of more than
|
|
* one CMap - it's ugly, but it's the only way to do it. PPeng, 11-12-1996
|
|
*/
|
|
if (pUFObj->lDownloadFormat == kTTType42CID_H)
|
|
{
|
|
/*
|
|
* Horizontal
|
|
* We need 1 or 2 CIDFonts when downloading it by ourselves.
|
|
* But, when this font is available as %hostfont%, we can simple
|
|
* composefont it without any trick.
|
|
*/
|
|
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
if (cidCount <= NUM_32K_1)
|
|
{
|
|
/*
|
|
* We create a CID-keyed font using only one CIDFont.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s /%s [/%s%s] composefont pop",
|
|
pUFObj->pszFontName,
|
|
pCMap->CMapName,
|
|
pFont->info.CIDFontName, gcidSuffix[0]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We create a CID-keyed font using two CIDFonts.
|
|
* Make a copy of the CIDFont so we can access 32K+ glyphs.
|
|
*
|
|
* But, when this is a %hostfont% font, we don't need to
|
|
* create a copy. Simply do composefont.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "%lu dup 1 sub %lu IDStr2 /%s%s /%s%s T42CIDCP32K",
|
|
cidCount - (long)NUM_32K_1, (long)NUM_32K_1,
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_32K],
|
|
pFont->info.CIDFontName, gcidSuffix[0]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s /%s [/%s%s ",
|
|
pUFObj->pszFontName, pCMap->CMapName,
|
|
pFont->info.CIDFontName, gcidSuffix[0]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s] composefont pop",
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_32K]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* %hostfont% support
|
|
* Simply composefont this %hostfont% font with
|
|
* %%IncludeResource DSC comment.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "%%%%IncludeResource: CIDFont %s",
|
|
pHostFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s /%s [/%s] composefont pop",
|
|
pUFObj->pszFontName,
|
|
pCMap->CMapName,
|
|
pHostFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Vertical
|
|
* We need 2 or 4 CIDFonts when downloading it by ourselves.
|
|
* But, when this font is available as %hostfont%, we can simple
|
|
* composefont it without any trick.
|
|
*/
|
|
|
|
/*
|
|
* Prior to composefont, instanciate a veritcal CMap and rearrange
|
|
* it with rotated glyph IDs.
|
|
*/
|
|
char *newCMapName;
|
|
DWORD cbCMapNameSize;
|
|
|
|
cbCMapNameSize = UFLstrlen(pCMap->CMapName)
|
|
+ UFLstrlen(pFont->info.CIDFontName)
|
|
+ 1;
|
|
|
|
newCMapName = (char*)UFLNewPtr(pUFObj->pMem, cbCMapNameSize);
|
|
if (newCMapName)
|
|
UFLsprintf(newCMapName, cbCMapNameSize / sizeof(char),
|
|
"%s%s",
|
|
pCMap->CMapName, pFont->info.CIDFontName);
|
|
else
|
|
retVal = kErrOutOfMemory;
|
|
|
|
/* Get rotated glyph IDs. */
|
|
if (kNoErr == retVal)
|
|
retVal = T42GetRotatedGIDs(pUFObj, pFont);
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = T42SendCMapWinCharSetFFFF_V(pUFObj, pFont->pRotatedGlyphIDs,
|
|
(short)(pFont->numRotatedGlyphIDs),
|
|
pCMap, newCMapName, cidCount,
|
|
stream, strmbuf, CCHOF(strmbuf));
|
|
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
if (cidCount <= NUM_32K_1)
|
|
{
|
|
/*
|
|
* We need 2 CIDFonts.
|
|
* Make a copy of the CIDFont so we can access rotated
|
|
* glyphs.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s /%s%s T42CIDCPR",
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_R],
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
/* Now create a CID-Keyed Font using the two CIDFonts. */
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s /%s [/%s%s /%s%s] composefont pop",
|
|
pUFObj->pszFontName,
|
|
newCMapName,
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX],
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_R]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We need 4 CIDFonts.
|
|
* Make copies of the CIDFont so we can access 32K+ glyphs.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "%lu dup 1 sub %lu IDStr2 /%s%s /%s%s T42CIDCP32K",
|
|
cidCount - (long)NUM_32K_1, (long)NUM_32K_1,
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_32K],
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s /%s%s T42CIDCPR",
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_R],
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s /%s%s T42CIDCPR",
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_32KR],
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_32K]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
/*
|
|
* Now create a CID-Keyed Font using the four CIDFonts.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s /%s [/%s%s ",
|
|
pUFObj->pszFontName, newCMapName,
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s /%s%s /%s%s] composefont pop",
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_R],
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_32K],
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_32KR] );
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* %hostfont% support
|
|
* CIDMap bug has to be fixed on HostFont capable RIP. No need
|
|
* to split glyphs in multiple CIDFonts even if the numbers of
|
|
* the glyphs are greater than 32K.
|
|
*/
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "%%%%IncludeResource: CIDFont %s", pHostFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
/*
|
|
* Fix 384736: GDI and %hostfont%-RIP get ascender and
|
|
* descender values from different tables; GDI gets them from
|
|
* 'OS/2' or 'hhea' vs. %hostfont%-RIP gets them from 'vhea' or
|
|
* 'hhea'. This causes the output on the screen and ink from
|
|
* %hostfont%-RIP different. To adjust 'the policy difference'
|
|
* with three types of real-world CJK TrueType fonts -
|
|
* 1) the good, which has 'vhea' and 'vmtx', and ascender and
|
|
* descender values are consistent throughout 'OS/2',
|
|
* 'vhea', and 'hhea' tables.
|
|
* 2) the bad, which doesn't have 'vhea' and/or 'vmtx' tables.
|
|
* 3) the ugry, which has 'vhea' and/or 'vmtx' tables but
|
|
* their ascender and descender values are inconsistent
|
|
* throughout 'OS/2', 'vhea', and 'hhea' tables.
|
|
* - the driver needs to change glyph metrics by installing
|
|
* either special CDevProc for 3 or adjusted FontMatrix for 2.
|
|
*/
|
|
{
|
|
long em, w1y, vx, vy, tsb, vasc;
|
|
UFLBool bUseDef;
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s ", pHostFontName, gcidSuffix[CIDSUFFIX]);
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, strmbuf);
|
|
|
|
GetMetrics2FromTTF(pUFObj, 0, &em, &w1y, &vx, &vy, &tsb, &bUseDef, 1, &vasc);
|
|
|
|
if (pUFObj->pAFont->hasvmtx && (vy != vasc))
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "%ld %ld sub %ld div", vy, vasc, em);
|
|
}
|
|
else if (!pUFObj->pAFont->hasvmtx)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "{5{pop}repeat 0 -1 %ld %ld div %ld %ld div}bind", vx, em, vy, em);
|
|
}
|
|
else
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "true");
|
|
}
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " /%s hfDef42CID", pHostFontName);
|
|
}
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s /%s hfDefRT42CID",
|
|
pUFObj->pszFontName, gcidSuffix[CIDSUFFIX_R],
|
|
pHostFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s /%s [/%s%s /%s%s] composefont pop",
|
|
pUFObj->pszFontName,
|
|
newCMapName,
|
|
pHostFontName, gcidSuffix[CIDSUFFIX],
|
|
pUFObj->pszFontName, gcidSuffix[CIDSUFFIX_R]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
if (newCMapName)
|
|
UFLDeletePtr(pUFObj->pMem, newCMapName);
|
|
}
|
|
}
|
|
else if (HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/*
|
|
* %hostfont% support
|
|
* Redefine the font using the already existing TrueType host font with
|
|
* a unque name so that we can reencode its encoding vector freely. We
|
|
* want empty CharStrings so that we give true to hfRedefFont.
|
|
*/
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "\n%%%%IncludeResource: font %s", pHostFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s true /%s hfRedefFont", pUFObj->pszFontName, pHostFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// The TrueType font has been Downloaded and defined. Cleanup mess.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
if ((kNoErr == retVal) && bFullFont)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pStringLength);
|
|
pFont->pStringLength = nil;
|
|
}
|
|
|
|
if (pFont->pMinSfnt)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pMinSfnt);
|
|
pFont->pMinSfnt = nil;
|
|
}
|
|
|
|
/*
|
|
* Free buffers allocated when error occurred. (bug #293130)
|
|
*/
|
|
if (kNoErr != retVal)
|
|
{
|
|
if (pFont->pHeader != nil)
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pHeader);
|
|
pFont->pHeader = nil;
|
|
|
|
if (pFont->pStringLength != nil)
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pStringLength);
|
|
pFont->pStringLength = nil;
|
|
|
|
if (pFont->pLocaTable != nil)
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pLocaTable);
|
|
pFont->pLocaTable = nil;
|
|
|
|
if (pFont->pRotatedGlyphIDs != nil)
|
|
UFLDeletePtr(pUFObj->pMem, pFont->pRotatedGlyphIDs);
|
|
pFont->pRotatedGlyphIDs = nil;
|
|
}
|
|
|
|
/*
|
|
* Change the font state.
|
|
*/
|
|
if (kNoErr == retVal)
|
|
{
|
|
if (pUFObj->flState == kFontInit2)
|
|
{
|
|
/* This is a duplicate so that it should have char(s). */
|
|
pUFObj->flState = kFontHasChars;
|
|
}
|
|
else
|
|
pUFObj->flState = kFontHeaderDownloaded;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
/*=============================================================================*
|
|
* PutT42Char and its sub functions *
|
|
*=============================================================================*/
|
|
|
|
UFLErrCode
|
|
T42UpdateCIDMap(
|
|
UFOStruct *pUFObj,
|
|
unsigned short wGlyfIndex,
|
|
unsigned short cid,
|
|
char *cidFontName,
|
|
UFLHANDLE stream,
|
|
char *strmbuf,
|
|
size_t cchstrmbuf
|
|
)
|
|
{
|
|
UFLErrCode retVal = kNoErr;
|
|
|
|
/* (2 * cid) is the BYTE-index in CIDMap. */
|
|
UFLsprintf(strmbuf, cchstrmbuf, "%ld ", (long)(2 * cid));
|
|
retVal = StrmPutString(stream, strmbuf);
|
|
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutWordAsciiHex(stream, wGlyfIndex);
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, " /%s UpdateCIDMap", cidFontName);
|
|
if (retVal == kNoErr)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
AddT42vmtxEntry(
|
|
UFOStruct *pUFObj,
|
|
unsigned short wGlyfIndex,
|
|
unsigned short cid,
|
|
char *cidFontName,
|
|
UFLHANDLE stream,
|
|
char *strmbuf,
|
|
size_t cchstrmbuf
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
UFLErrCode retVal = kNoErr;
|
|
long em, w1y, vx, vy, tsb, vasc;
|
|
UFLBool bUseDef;
|
|
|
|
/*
|
|
* Add vertical metrics array Metrics2 for every glyph regardless of
|
|
* writing mode (Fix #351487) if its 'vmtx' exists.
|
|
*
|
|
* The elements of Metrics2 array should basically look like this:
|
|
*
|
|
* [0 -AdvanceHeight/EM Descender/EM Ascender/EM]
|
|
*
|
|
* But, to support both fixed and proportional fonts universally we set
|
|
* TopSideBearing/EM as vy instead and add ury to it in CDevProc. So the
|
|
* array now looks like this:
|
|
*
|
|
* [0 -AdvanceHeight/EM Descender/EM TopSideBearing/EM]
|
|
*
|
|
* In CDevProc TopSideBearing/EM and ury are added to get real vy value
|
|
* for the glyph. See the code emitting /CDevProc in the T42CreateBaseFont
|
|
* function above for the details.
|
|
*/
|
|
|
|
if (pUFObj->pAFont->hasvmtx)
|
|
{
|
|
GetMetrics2FromTTF(pUFObj, wGlyfIndex, &em, &w1y, &vx, &vy, &tsb, &bUseDef, 0, &vasc);
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf,
|
|
"%ld [0 %ld %ld div %ld %ld div %ld %ld div] /%s T0AddT42Mtx2",
|
|
(long)cid, -w1y, em, vx, em, tsb, em, cidFontName);
|
|
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
unsigned short
|
|
GetCIDAndCIDFontName(
|
|
UFOStruct *pUFObj,
|
|
unsigned short wGid,
|
|
char *cidFontName,
|
|
size_t cchFontName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Retunrs cid - a number and the cidFontName.
|
|
|
|
--*/
|
|
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
unsigned short cid = 0;
|
|
|
|
if (IS_TYPE42CID_KEYEDFONT(pUFObj->lDownloadFormat))
|
|
{
|
|
/*
|
|
* For CID-Keyed font, we control the CIDFont name.
|
|
*/
|
|
if (pFont->info.bUseIdentityCMap && (wGid > NUM_32K_1))
|
|
{
|
|
/*
|
|
* 32K+ glyphs are re-mapped to the 32K CIDFont.
|
|
*/
|
|
UFLsprintf(cidFontName, cchFontName, "%s%s",
|
|
pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX_32K]);
|
|
|
|
cid = (unsigned short)((long)wGid-(long)NUM_32K_1);
|
|
}
|
|
else
|
|
{
|
|
UFLsprintf(cidFontName, cchFontName, "%s%s", pFont->info.CIDFontName, gcidSuffix[CIDSUFFIX]);
|
|
|
|
cid = wGid;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UFLsprintf(cidFontName, cchFontName, "%s", pUFObj->pszFontName);
|
|
|
|
/*
|
|
* Don't know how to assign a CID. Return zero.
|
|
*/
|
|
}
|
|
|
|
return cid;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
PutT42Char(
|
|
UFOStruct *pUFObj,
|
|
unsigned short wGlyfIndex,
|
|
unsigned short wCid,
|
|
COMPOSITEGLYPHS *pCompGlyphs,
|
|
char *strmbuf,
|
|
size_t cchstrmbuf
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
unsigned long *glyphRanges = pFont->pStringLength;
|
|
UFLHANDLE stream = pUFObj->pUFL->hOut;
|
|
UFLErrCode retVal = kNoErr;
|
|
UFLBool bMoreComp = 0;
|
|
|
|
unsigned short cid, i, wIndex, wCompFlags;
|
|
unsigned long glyphOffset, glyphLength;
|
|
char *pGlyph;
|
|
char *pCompTmp;
|
|
char cidFontName[64];
|
|
|
|
if (wGlyfIndex > UFO_NUM_GLYPHS(pUFObj))
|
|
{
|
|
/*
|
|
* If the requested glyph is out of range, pretend it is downloaded
|
|
* without error.
|
|
*/
|
|
return kNoErr;
|
|
}
|
|
|
|
/* indexToLocFormat contains 0 for short offsets and 1 for long. */
|
|
if (pFont->headTable.indexToLocFormat)
|
|
{
|
|
unsigned long PTR_PREFIX *locationTable = (unsigned long PTR_PREFIX *)pFont->pLocaTable;
|
|
|
|
/*
|
|
* Bad font protection: some fonts have bad 'loca' data for a few
|
|
* glyphs. These bad glyphs will be treated as /.notdef.
|
|
*/
|
|
// if (MOTOROLALONG(locationTable[wGlyfIndex + 1]) < MOTOROLALONG(locationTable[wGlyfIndex]))
|
|
// return kNoErr;
|
|
|
|
/* Get the offset to the glyph from the beginning of the glyf table. */
|
|
glyphOffset = MOTOROLALONG(locationTable[wGlyfIndex]);
|
|
|
|
if ((MOTOROLALONG(locationTable[wGlyfIndex + 1]) < MOTOROLALONG(locationTable[wGlyfIndex]))
|
|
|| ((MOTOROLALONG(locationTable[wGlyfIndex + 1]) - MOTOROLALONG(locationTable[wGlyfIndex])) > 16384L))
|
|
{
|
|
glyphLength = GetLenByScanLoca(locationTable,
|
|
wGlyfIndex,
|
|
UFO_NUM_GLYPHS(pUFObj),
|
|
pFont->headTable.indexToLocFormat);
|
|
}
|
|
else
|
|
{
|
|
glyphLength = (unsigned long)MOTOROLALONG(locationTable[wGlyfIndex + 1]) - glyphOffset;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned short PTR_PREFIX *locationTable = (unsigned short PTR_PREFIX*)pFont->pLocaTable;
|
|
|
|
/*
|
|
* Bad font protection: some fonts have bad 'loca' data for a few
|
|
* glyphs. These bad glyphs will be treated as /.notdef.
|
|
* /
|
|
// if (MOTOROLAINT(locationTable[wGlyfIndex + 1]) < MOTOROLAINT(locationTable[wGlyfIndex]))
|
|
// return kNoErr;
|
|
|
|
/* Get the offset to the glyph from the beginning of the glyf table. */
|
|
glyphOffset = (unsigned long)MOTOROLAINT(locationTable[wGlyfIndex]) * 2;
|
|
|
|
if ((MOTOROLAINT(locationTable[wGlyfIndex + 1]) < MOTOROLAINT(locationTable[wGlyfIndex]))
|
|
|| ((MOTOROLAINT(locationTable[wGlyfIndex + 1]) - MOTOROLAINT(locationTable[wGlyfIndex])) > 16384))
|
|
{
|
|
glyphLength = GetLenByScanLoca(locationTable,
|
|
wGlyfIndex,
|
|
UFO_NUM_GLYPHS(pUFObj),
|
|
pFont->headTable.indexToLocFormat);
|
|
}
|
|
else
|
|
{
|
|
glyphLength = (unsigned long)MOTOROLAINT(locationTable[wGlyfIndex + 1]) * 2 - glyphOffset;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* GlyphIndices that have no glyph description point to the same offset.
|
|
* So, GlyphLength becomes 0. Handle these as special cases for 2015 and
|
|
* pre-2015.
|
|
*/
|
|
if (!glyphLength)
|
|
{
|
|
/* Send parameters for /AddT42Char procedure. */
|
|
retVal = StrmPutStringEOL(stream, nilStr);
|
|
|
|
/*
|
|
* Locate /sfnts string number in which the glyph occurs and offset of
|
|
* the glyph in "that" string.
|
|
*/
|
|
for (i = 1; glyphRanges[i] != 0; i++)
|
|
{
|
|
if (glyphOffset < glyphRanges[i])
|
|
{
|
|
i--; /* Gives the "actual" string index (as opposed to string number). */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Send index of /sfnts string in which this glyph belongs. Check if a
|
|
* valid index i was found.
|
|
*/
|
|
if (glyphRanges[i] == 0)
|
|
{
|
|
/*
|
|
* Oops, this should not have happened. But it will with Monotype
|
|
* Sorts or any font whose last few glyphs are not defined.
|
|
* Roll back i to point to glyph index 0, the bullet character.
|
|
* Anyway, it does not matter where this glyph (with no description)
|
|
* points to, really. Only 2015 needs a real entry in /GlyphDirectory,
|
|
* even for glyphs with no description, ie, the entry:
|
|
* /GlyphIndex < > def in the dict /GlyphDirectory.
|
|
*/
|
|
i = 0;
|
|
glyphOffset = 0;
|
|
}
|
|
|
|
retVal = StrmPutInt(stream, pFont->cOtherTables + i);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, " ");
|
|
|
|
/* Send offset of the glyph in the particular /sfnts string. */
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutInt(stream, glyphOffset - glyphRanges[i]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, " ");
|
|
|
|
/* Send the glyph index. */
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutInt(stream, wGlyfIndex);
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, " <> ");
|
|
|
|
if (IS_TYPE42CID(pUFObj->lDownloadFormat))
|
|
{
|
|
cid = GetCIDAndCIDFontName(pUFObj, wGlyfIndex, cidFontName, CCHOF(cidFontName));
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "/%s T0AddT42Char ", cidFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
if (!pFont->info.bUseIdentityCMap)
|
|
cid = wCid;
|
|
|
|
AddT42vmtxEntry(pUFObj, wGlyfIndex, wCid, cidFontName, stream, strmbuf, cchstrmbuf);
|
|
|
|
if (pFont->info.bUpdateCIDMap)
|
|
T42UpdateCIDMap(pUFObj, wGlyfIndex, wCid, cidFontName, stream, strmbuf, cchstrmbuf);
|
|
}
|
|
else
|
|
{
|
|
UFLsprintf(strmbuf, cchstrmbuf, "/%s AddT42Char ", pUFObj->pszFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
return retVal;
|
|
} /* if ( !glyphLength ) */
|
|
|
|
|
|
/*
|
|
* Get the physical glyph data to lpGlyph.
|
|
*/
|
|
pGlyph = (char *)UFLNewPtr(pUFObj->pMem, glyphLength);
|
|
|
|
if (pGlyph == nil)
|
|
retVal = kErrOutOfMemory;
|
|
|
|
if (0 == GETTTFONTDATA(pUFObj,
|
|
GLYF_TABLE, glyphOffset,
|
|
pGlyph, glyphLength,
|
|
pFont->info.fData.fontIndex))
|
|
{
|
|
retVal = kErrGetFontData;
|
|
}
|
|
|
|
/*
|
|
* Handle Composite Characters.
|
|
*/
|
|
if ((kNoErr == retVal) && (*((short *)pGlyph) == MINUS_ONE))
|
|
{
|
|
pCompTmp = pGlyph;
|
|
pCompTmp += 10; /* Move to beginning of glyph description. */
|
|
|
|
do
|
|
{
|
|
wCompFlags = MOTOROLAINT(*((unsigned short *)pCompTmp));
|
|
wIndex = MOTOROLAINT(((unsigned short *)pCompTmp)[1]);
|
|
|
|
/*
|
|
* Download the first "component" glyph of this composite
|
|
* character.
|
|
*/
|
|
if ((wIndex < UFO_NUM_GLYPHS(pUFObj))
|
|
&& !IS_GLYPH_SENT( pUFObj->pAFont->pDownloadedGlyphs, wIndex))
|
|
{
|
|
if (pFont->info.bUseIdentityCMap)
|
|
{
|
|
if (wIndex > NUM_32K_1)
|
|
{
|
|
/* 32K+ glyphs are re-mapped to the 32K CIDFont. */
|
|
cid = (unsigned short)((long)wIndex - (long)NUM_32K_1);
|
|
}
|
|
else
|
|
{
|
|
cid = wIndex;
|
|
}
|
|
}
|
|
else
|
|
cid = 0; /* Don't know the wCid. */
|
|
|
|
retVal = PutT42Char(pUFObj, wIndex, cid, pCompGlyphs, strmbuf, cchstrmbuf);
|
|
|
|
if (retVal == kNoErr)
|
|
{
|
|
SET_GLYPH_SENT_STATUS(pUFObj->pAFont->pDownloadedGlyphs, wIndex);
|
|
|
|
/*
|
|
* If we ran out of space to keep track of the composite
|
|
* componets then allocate more space.
|
|
*/
|
|
if ((pCompGlyphs->sCount >= pCompGlyphs->sMaxCount)
|
|
&& (pCompGlyphs->pGlyphs != nil))
|
|
{
|
|
short sEnlargeSize = pCompGlyphs->sMaxCount + 50;
|
|
|
|
if (UFLEnlargePtr(pUFObj->pMem,
|
|
(void **)&pCompGlyphs->pGlyphs,
|
|
(sEnlargeSize * sizeof (unsigned short)), 1))
|
|
{
|
|
pCompGlyphs->sMaxCount = sEnlargeSize;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* For some reason we can't get more space.
|
|
* Then just don't do this at all.
|
|
*/
|
|
UFLDeletePtr(pUFObj->pMem, pCompGlyphs->pGlyphs);
|
|
|
|
pCompGlyphs->pGlyphs = nil;
|
|
pCompGlyphs->sCount = pCompGlyphs->sMaxCount = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Remember which composite glyph componet we downloaded.
|
|
*/
|
|
if (pCompGlyphs->pGlyphs)
|
|
{
|
|
*(pCompGlyphs->pGlyphs + pCompGlyphs->sCount) = wIndex;
|
|
pCompGlyphs->sCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check for other components in this composite character.
|
|
*/
|
|
if ((kNoErr == retVal) && (wCompFlags & MORE_COMPONENTS))
|
|
{
|
|
bMoreComp = 1;
|
|
|
|
/*
|
|
* Find out how far we need to advance lpCompTmp to get to next
|
|
* component of the composite character.
|
|
*/
|
|
if (wCompFlags & ARG_1_AND_2_ARE_WORDS)
|
|
pCompTmp += 8;
|
|
else
|
|
pCompTmp += 6;
|
|
|
|
/*
|
|
* Check what kind of scaling is done on the glyph component.
|
|
*/
|
|
if (wCompFlags & WE_HAVE_A_SCALE)
|
|
{
|
|
pCompTmp += 2;
|
|
}
|
|
else
|
|
{
|
|
if (wCompFlags & WE_HAVE_AN_X_AND_Y_SCALE)
|
|
{
|
|
pCompTmp += 4;
|
|
}
|
|
else
|
|
{
|
|
if (wCompFlags & WE_HAVE_A_TWO_BY_TWO)
|
|
pCompTmp += 8;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bMoreComp = 0;
|
|
}
|
|
|
|
} while (bMoreComp && (kNoErr == retVal)); /* do~while loop */
|
|
} /* If composite character */
|
|
|
|
/*
|
|
* Locate /sfnts string number in which the glyph occurs and offset of
|
|
* the glyph in "that" string.
|
|
*/
|
|
if (kNoErr == retVal)
|
|
{
|
|
i = 1;
|
|
while (glyphRanges[i] != 0)
|
|
{
|
|
if (glyphOffset < glyphRanges[i])
|
|
{
|
|
i--; /* Gives the "actual" string index (as opposed to string number). */
|
|
break;
|
|
}
|
|
i++; /* Go to the next string and check if Glyph belongs there. */
|
|
}
|
|
}
|
|
|
|
/* Send index of /sfnts string in which this glyph belongs. */
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutInt(stream, pFont->cOtherTables + i);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, " ");
|
|
|
|
/* Send offset of the glyph in the particular /sfnts string. */
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutInt(stream, glyphOffset-glyphRanges[i]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, " ");
|
|
|
|
/* Send the glyph index. */
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutInt(stream, wGlyfIndex);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, " ");
|
|
|
|
|
|
/* Download the glyph in binary (or) AsciiHex format. */
|
|
if (kNoErr == retVal)
|
|
{
|
|
if (StrmCanOutputBinary(stream))
|
|
{
|
|
retVal = StrmPutInt(stream, glyphLength);
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, RDString);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutBytes(stream, pGlyph, (UFLsize_t)glyphLength, 0);
|
|
}
|
|
else
|
|
{
|
|
retVal = StrmPutString(stream, "<");
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutAsciiHex(stream, pGlyph, glyphLength);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, ">");
|
|
}
|
|
}
|
|
|
|
if (IS_TYPE42CID(pUFObj->lDownloadFormat))
|
|
{
|
|
cid = GetCIDAndCIDFontName(pUFObj, wGlyfIndex, cidFontName, CCHOF(cidFontName));
|
|
|
|
UFLsprintf(strmbuf, cchstrmbuf, "/%s T0AddT42Char ", cidFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
if (!pFont->info.bUseIdentityCMap)
|
|
cid = wCid;
|
|
|
|
AddT42vmtxEntry(pUFObj, wGlyfIndex, cid, cidFontName, stream, strmbuf, cchstrmbuf);
|
|
|
|
if (pFont->info.bUpdateCIDMap)
|
|
T42UpdateCIDMap(pUFObj, wGlyfIndex, wCid, cidFontName, stream, strmbuf, cchstrmbuf);
|
|
|
|
}
|
|
else
|
|
{
|
|
UFLsprintf(strmbuf, cchstrmbuf, "/%s AddT42Char ", pUFObj->pszFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
if (pGlyph)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, pGlyph);
|
|
pGlyph = nil;
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
T42AddChars(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs
|
|
)
|
|
{
|
|
UFLHANDLE stream = pUFObj->pUFL->hOut;
|
|
UFLErrCode retVal = kNoErr;
|
|
unsigned short cid = 0;
|
|
short totalGlyphs = 0;
|
|
|
|
unsigned short wIndex;
|
|
UFLGlyphID *glyphs;
|
|
COMPOSITEGLYPHS compGlyphs;
|
|
char strmbuf[128];
|
|
short i;
|
|
|
|
/*
|
|
* Save a copy of Downloaded glpyh list. This is used to update CharStrings
|
|
* later.
|
|
*/
|
|
UFLmemcpy((const UFLMemObj*)pUFObj->pMem,
|
|
pUFObj->pAFont->pVMGlyphs,
|
|
pUFObj->pAFont->pDownloadedGlyphs,
|
|
(UFLsize_t)(GLYPH_SENT_BUFSIZE(UFO_NUM_GLYPHS(pUFObj))));
|
|
|
|
/*
|
|
* Keep track of composite glyphs that might of been downloaded.
|
|
*/
|
|
compGlyphs.sMaxCount = pGlyphs->sCount * 2;
|
|
compGlyphs.sCount = 0;
|
|
|
|
/*
|
|
* Update the charstring uses GoodNames only if the Encoding vector is nil.
|
|
*/
|
|
if(pUFObj->pszEncodeName == nil)
|
|
compGlyphs.pGlyphs = nil;
|
|
else
|
|
compGlyphs.pGlyphs = (unsigned short *)UFLNewPtr(pUFObj->pMem,
|
|
compGlyphs.sMaxCount * sizeof (unsigned short));
|
|
|
|
if (compGlyphs.pGlyphs == nil)
|
|
compGlyphs.sMaxCount = 0;
|
|
|
|
/*
|
|
* The main loop for downloading the glyphs of the given string.
|
|
*/
|
|
glyphs = pGlyphs->pGlyphIndices;
|
|
|
|
for (i = 0; kNoErr == retVal && i < pGlyphs->sCount; i++)
|
|
{
|
|
/* LOWord is the real GID. */
|
|
wIndex = (unsigned short)(glyphs[i] & 0x0000FFFF);
|
|
|
|
if (wIndex >= UFO_NUM_GLYPHS(pUFObj))
|
|
continue;
|
|
|
|
if (!IS_GLYPH_SENT(pUFObj->pAFont->pDownloadedGlyphs, wIndex))
|
|
{
|
|
if (pGlyphs->pCharIndex)
|
|
cid = pGlyphs->pCharIndex[i];
|
|
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
retVal = PutT42Char(pUFObj, wIndex, cid, &compGlyphs, strmbuf, CCHOF(strmbuf));
|
|
|
|
SET_GLYPH_SENT_STATUS(pUFObj->pAFont->pDownloadedGlyphs, wIndex);
|
|
totalGlyphs++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Make sure that .notdef is sent.
|
|
*/
|
|
if ((kNoErr == retVal) && (pUFObj->flState >= kFontInit))
|
|
{
|
|
if (!IS_GLYPH_SENT(pUFObj->pAFont->pDownloadedGlyphs, 0))
|
|
{
|
|
cid = 0; /* Don't know its CID. */
|
|
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
retVal = PutT42Char(pUFObj, 0x0000, cid, &compGlyphs, strmbuf, CCHOF(strmbuf));
|
|
|
|
if (kNoErr == retVal)
|
|
{
|
|
SET_GLYPH_SENT_STATUS(pUFObj->pAFont->pDownloadedGlyphs, 0);
|
|
totalGlyphs++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Update the charstring uses GoodNames if the Encoding vector is nil.
|
|
*/
|
|
if ((kNoErr == retVal) && (pUFObj->pszEncodeName == nil) && (totalGlyphs > 0))
|
|
{
|
|
/*
|
|
* Begin CharStirng re-encoding.
|
|
*/
|
|
|
|
UFLBool bAddCompGlyphAlternate = 0;
|
|
UFLBool bGoodName;
|
|
char *pGoodName;
|
|
|
|
retVal = StrmPutString(stream, "/");
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, pUFObj->pszFontName);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, " findfont /CharStrings get begin");
|
|
|
|
/*
|
|
* If we ran out of space in keeping with Composite Glyph Component,
|
|
* then add composite component to Encoding the long way.
|
|
*/
|
|
if (!compGlyphs.pGlyphs)
|
|
{
|
|
bAddCompGlyphAlternate = 1;
|
|
compGlyphs.sCount = compGlyphs.sMaxCount =0;
|
|
}
|
|
|
|
/*
|
|
* Update the CharStrings with all of the newly added Glyphs.
|
|
* First go through the Main Glyph Index arrays.
|
|
*/
|
|
for (i = 0; (kNoErr == retVal) && (i < (pGlyphs->sCount + compGlyphs.sCount)); i++)
|
|
{
|
|
/*
|
|
* Get glyph index from either the regular glyphs list or the
|
|
* composite list. LOWord is the read GID in either case.
|
|
*/
|
|
|
|
if (i < pGlyphs->sCount)
|
|
wIndex = (unsigned short)(glyphs[i] & 0x0000FFFF);
|
|
else
|
|
wIndex = (unsigned short)(compGlyphs.pGlyphs[i - pGlyphs->sCount] & 0x0000FFFF);
|
|
|
|
if (wIndex >= UFO_NUM_GLYPHS(pUFObj))
|
|
continue;
|
|
|
|
if ((0 == pUFObj->pUFL->bDLGlyphTracking)
|
|
|| (pGlyphs->pCharIndex == nil) // DownloadFace
|
|
|| (pUFObj->pEncodeNameList) // DownloadFace
|
|
|| !IS_GLYPH_SENT(pUFObj->pAFont->pVMGlyphs, wIndex))
|
|
{
|
|
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. */
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s %d def", Minus, wIndex);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
if ((UFLstrcmp(pGoodName, Hyphen) == 0) && (i == 173))
|
|
{
|
|
/* Add /sfthyphen to CharString. */
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s %d def", SftHyphen, wIndex);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
|
|
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->pVMGlyphs, wIndex))
|
|
continue;
|
|
}
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, "/");
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, pGoodName);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " %d def", wIndex);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
SET_GLYPH_SENT_STATUS(pUFObj->pAFont->pVMGlyphs, wIndex);
|
|
|
|
if (bGoodName)
|
|
SET_GLYPH_SENT_STATUS(pUFObj->pAFont->pCodeGlyphs, wIndex);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Do composite font this way only if we ran out of space.
|
|
*/
|
|
if (bAddCompGlyphAlternate)
|
|
{
|
|
/*
|
|
* Now go through all VMGlyphs to see if there is any glyph are
|
|
* downloaded as part of Composite glyph above. - fix bug 217228.
|
|
* PPeng, 6-12-1997
|
|
*/
|
|
for (wIndex = 0;
|
|
(kNoErr == retVal) && (wIndex < UFO_NUM_GLYPHS(pUFObj));
|
|
wIndex++)
|
|
{
|
|
if ((0 == pUFObj->pUFL->bDLGlyphTracking)
|
|
/* || (pGlyphs->pCharIndex == nil) */
|
|
|| (IS_GLYPH_SENT(pUFObj->pAFont->pDownloadedGlyphs, wIndex)
|
|
&& !IS_GLYPH_SENT(pUFObj->pAFont->pVMGlyphs, wIndex)))
|
|
{
|
|
/*
|
|
* For composite glyphs, always try to use its good name.
|
|
*/
|
|
pGoodName = GetGlyphName(pUFObj,
|
|
(unsigned long)wIndex,
|
|
nil,
|
|
&bGoodName);
|
|
|
|
retVal = StrmPutString(stream, "/");
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutString(stream, pGoodName);
|
|
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), " %d def", wIndex);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
SET_GLYPH_SENT_STATUS(pUFObj->pAFont->pVMGlyphs, wIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* End CharStirng re-encoding.
|
|
*/
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, "end");
|
|
}
|
|
|
|
/*
|
|
* Update the Encoding vector if we use GoodNames.
|
|
*/
|
|
if ((kNoErr == retVal) && (pUFObj->pszEncodeName == nil) && (pGlyphs->sCount > 0))
|
|
{
|
|
/*
|
|
* Check pUFObj->pUpdatedEncoding to see if we really need to update it.
|
|
*/
|
|
for (i = 0; i < pGlyphs->sCount; i++)
|
|
{
|
|
if ((0 == pUFObj->pUFL->bDLGlyphTracking)
|
|
|| (pGlyphs->pCharIndex == nil) // DownloadFace
|
|
|| (pUFObj->pEncodeNameList) // DownloadFace
|
|
|| !IS_GLYPH_SENT(pUFObj->pUpdatedEncoding, pGlyphs->pCharIndex[i]))
|
|
{
|
|
/* Found at least one not updated, do it (once) for all. */
|
|
retVal = UpdateEncodingVector(pUFObj, pGlyphs, 0, pGlyphs->sCount);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Update the FontInfo with Unicode information.
|
|
*/
|
|
if ((kNoErr == retVal)
|
|
&& (pGlyphs->sCount > 0)
|
|
&& (pUFObj->dwFlags & UFO_HasG2UDict)
|
|
&& !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/*
|
|
* Check pUFObj->pAFont->pCodeGlyphs to see if we really need to update
|
|
* it.
|
|
*/
|
|
for (i = 0; i < pGlyphs->sCount; i++)
|
|
{
|
|
/* LOWord is the real GID. */
|
|
wIndex = (unsigned short)(glyphs[i] & 0x0000FFFF);
|
|
|
|
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 (compGlyphs.pGlyphs)
|
|
{
|
|
UFLDeletePtr(pUFObj->pMem, compGlyphs.pGlyphs);
|
|
compGlyphs.pGlyphs = nil;
|
|
}
|
|
|
|
/*
|
|
* Downloading glyph(s) is done. Change the font state.
|
|
*/
|
|
if (kNoErr ==retVal)
|
|
pUFObj->flState = kFontHasChars;
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
T42VMNeeded(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMNeeded,
|
|
unsigned long *pFCNeeded
|
|
)
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
UFLErrCode retVal = kNoErr;
|
|
unsigned long vmUsed = 0;
|
|
UFLBool bFullFont;
|
|
UFLGlyphID *glyphs;
|
|
|
|
if (pUFObj->flState < kFontInit)
|
|
return kErrInvalidState;
|
|
|
|
if ((pGlyphs == nil) || (pGlyphs->pGlyphIndices == nil) || (pVMNeeded == nil))
|
|
return kErrInvalidParam;
|
|
|
|
*pVMNeeded = 0;
|
|
|
|
if (pFCNeeded)
|
|
*pFCNeeded = 0;
|
|
|
|
glyphs = pGlyphs->pGlyphIndices;
|
|
|
|
bFullFont = (pGlyphs->sCount == -1) ? 1 : 0;
|
|
|
|
if ((0 == pFont->minSfntSize) || (pFont->pHeader == nil))
|
|
retVal = GetMinSfnt(pUFObj, bFullFont);
|
|
|
|
if (kNoErr == retVal)
|
|
{
|
|
unsigned long totalGlyphs = 0;
|
|
|
|
/*
|
|
* Scan the list, check what characters that we have downloaded.
|
|
*/
|
|
if (!bFullFont)
|
|
{
|
|
short i;
|
|
|
|
UFLmemcpy((const UFLMemObj *)pUFObj->pMem,
|
|
pUFObj->pAFont->pVMGlyphs,
|
|
pUFObj->pAFont->pDownloadedGlyphs,
|
|
(UFLsize_t)(GLYPH_SENT_BUFSIZE(UFO_NUM_GLYPHS(pUFObj))));
|
|
|
|
for (i = 0; i < pGlyphs->sCount; i++)
|
|
{
|
|
/* LOWord is the real GID. */
|
|
unsigned short wIndex = (unsigned short)(glyphs[i] & 0x0000FFFF);
|
|
|
|
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 = UFO_NUM_GLYPHS(pUFObj);
|
|
}
|
|
|
|
/*
|
|
* Start with the size of the minimal sfnt if the header has not been
|
|
* sent yet.
|
|
*/
|
|
if (pUFObj->flState < kFontHeaderDownloaded)
|
|
{
|
|
vmUsed = pFont->minSfntSize;
|
|
}
|
|
|
|
/*
|
|
* If incremental downloading and there are glyphs to check, add these
|
|
* to total VMUsage of each glyph is the average size of each glyph in
|
|
* the glyf table.
|
|
*/
|
|
if (bFullFont == 0)
|
|
{
|
|
if (GETPSVERSION(pUFObj) < 2015)
|
|
{
|
|
/*
|
|
* For pre2015 printers, we need to pre-allocate VM for all
|
|
* Glyphs. The VM for whole font is allocated when the Header
|
|
* is Sent.
|
|
*/
|
|
if (pUFObj->flState < kFontHeaderDownloaded)
|
|
{
|
|
vmUsed += GetGlyphTableSize(pUFObj);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* After header is sent on pre-2015 printer, no more VM
|
|
* allocation for adding chars, so set to 0 -- VM for both
|
|
* Header and Glyph table are allocate already!
|
|
*/
|
|
vmUsed = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (glyphs != nil)
|
|
{
|
|
/* Check if this has been calculated yet. */
|
|
if (pFont->averageGlyphSize == 0)
|
|
GetAverageGlyphSize(pUFObj);
|
|
|
|
/* If this is still zero, there's a problem with the sfnt. */
|
|
if (pFont->averageGlyphSize == 0)
|
|
retVal = kErrBadTable;
|
|
else
|
|
vmUsed += totalGlyphs * pFont->averageGlyphSize;
|
|
|
|
/*
|
|
* Fix bug 256940: make it compatible with 95 driver.
|
|
* jjia 7/2/98
|
|
*/
|
|
if ((IS_TYPE42CID(pUFObj->lDownloadFormat))
|
|
&& (pUFObj->flState < kFontHeaderDownloaded))
|
|
{
|
|
vmUsed += (UFO_NUM_GLYPHS(pUFObj)) * 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((kNoErr == retVal) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
*pVMNeeded = VMT42RESERVED(vmUsed);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
/*
|
|
* Currently this function is not called from any place.
|
|
*/
|
|
|
|
UFLErrCode
|
|
DownloadFullFont(
|
|
UFOStruct *pUFObj
|
|
)
|
|
{
|
|
UFLErrCode retVal = kNoErr;
|
|
|
|
/*
|
|
* Can only download full font if no header has been downloaded before.
|
|
* The only possible state that meets this requirement is kFontInit.
|
|
*/
|
|
if (pUFObj->flState != kFontInit)
|
|
return kErrInvalidState;
|
|
|
|
/* Create and download the full font. */
|
|
retVal = T42CreateBaseFont(pUFObj, nil, nil, 1);
|
|
|
|
if (retVal == kNoErr)
|
|
pUFObj->flState = kFontFullDownloaded;
|
|
|
|
return retVal;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* T42FontDownloadIncr
|
|
*
|
|
* Function: Adds all of the characters from pGlyphs that aren't already
|
|
* downloaded for the TrueType font.
|
|
*
|
|
******************************************************************************/
|
|
|
|
UFLErrCode
|
|
T42FontDownloadIncr(
|
|
UFOStruct *pUFObj,
|
|
const UFLGlyphsInfo *pGlyphs,
|
|
unsigned long *pVMUsage,
|
|
unsigned long *pFCUsage
|
|
)
|
|
{
|
|
UFLErrCode retVal = kNoErr;
|
|
char *pHostFontName = nil;
|
|
|
|
if (pFCUsage)
|
|
*pFCUsage = 0;
|
|
|
|
/*
|
|
* Sanity checks.
|
|
*/
|
|
if (pUFObj->flState < kFontInit)
|
|
return kErrInvalidState;
|
|
|
|
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);
|
|
|
|
/*
|
|
* Check the VM usage - before sending the Header. On Pre-2015 printers,
|
|
* VMUsage is 0 after the header is downloaded (pre-allocate).
|
|
*/
|
|
if (!HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
retVal = T42VMNeeded(pUFObj, pGlyphs, pVMUsage, nil); /* nil for pFCUsage */
|
|
|
|
/*
|
|
* Create a base font if it has not been done yet.
|
|
*/
|
|
if (pUFObj->flState == kFontInit)
|
|
retVal = T42CreateBaseFont(pUFObj, pGlyphs, pVMUsage, 0, pHostFontName);
|
|
|
|
/*
|
|
* Download the glyphs.
|
|
*/
|
|
if (kNoErr == retVal)
|
|
retVal = T42AddChars(pUFObj, pGlyphs);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFLErrCode
|
|
T42UndefineFont(
|
|
UFOStruct *pUFObj
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
Send PS code to undefine fonts: /UDF and /UDR should be defined properly
|
|
by client to something like:
|
|
|
|
/UDF
|
|
{
|
|
IsLevel2
|
|
{undefinefont}
|
|
{ pop }ifelse
|
|
} bind def
|
|
/UDR
|
|
{
|
|
IsLevel2
|
|
{undefineresource}
|
|
{ pop pop }ifelse
|
|
} bind def
|
|
|
|
--*/
|
|
|
|
{
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
UFLErrCode retVal = kNoErr;
|
|
UFLHANDLE stream = pUFObj->pUFL->hOut;
|
|
char strmbuf[256];
|
|
short int i;
|
|
|
|
if (pUFObj->flState < kFontHeaderDownloaded)
|
|
return retVal;
|
|
|
|
/*
|
|
* If the font is a Type 42 CID-keyed font, then undefine its CIDFont
|
|
* resources first. (We don't care to leave its CMaps in VM.)
|
|
* But if the font is created on a HostFont system, no need to undefine the
|
|
* resources since we didn't donwload them.
|
|
*/
|
|
if (IS_TYPE42CID_KEYEDFONT(pUFObj->lDownloadFormat) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
{
|
|
/*
|
|
* Undefine CIDFont resources: there are 4 possible CIDFonts.
|
|
*
|
|
* e.g. /TT37820t0CID, /TT37820t0CIDR, /TT37820t0CID32K, /TT37820t0CID32KR
|
|
*
|
|
* We can send "udefineresource" for all of them; the command is very
|
|
* forgiving.
|
|
*/
|
|
for (i = 0; i < NUM_CIDSUFFIX; i++)
|
|
{
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s%s /CIDFont UDR", pUFObj->pszFontName, gcidSuffix[i]);
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Undefine the font.
|
|
*/
|
|
if (IS_TYPE42CIDFONT_RESOURCE(pUFObj->lDownloadFormat) && !HOSTFONT_IS_VALID_UFO(pUFObj))
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s /CIDFont UDR", pUFObj->pszFontName);
|
|
else
|
|
UFLsprintf(strmbuf, CCHOF(strmbuf), "/%s UDF", pUFObj->pszFontName);
|
|
|
|
if (kNoErr == retVal)
|
|
retVal = StrmPutStringEOL(stream, strmbuf);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
|
|
UFOStruct *
|
|
T42FontInit(
|
|
const UFLMemObj *pMem,
|
|
const UFLStruct *pUFL,
|
|
const UFLRequest *pRequest
|
|
)
|
|
{
|
|
UFOStruct *pUFObj = (UFOStruct *)UFLNewPtr(pMem, sizeof (UFOStruct));
|
|
UFLTTFontInfo *pInfo;
|
|
long maxGlyphs;
|
|
|
|
if (pUFObj == nil)
|
|
return nil;
|
|
|
|
/* Initialize data. */
|
|
UFOInitData(pUFObj, UFO_TYPE42, pMem, pUFL, pRequest,
|
|
(pfnUFODownloadIncr) T42FontDownloadIncr,
|
|
(pfnUFOVMNeeded) T42VMNeeded,
|
|
(pfnUFOUndefineFont) T42UndefineFont,
|
|
(pfnUFOCleanUp) T42FontCleanUp,
|
|
(pfnUFOCopy) CopyFont);
|
|
|
|
/*
|
|
* pszFontName should be allocated and initialized. If not, cannot continue.
|
|
*/
|
|
if ((pUFObj->pszFontName == nil) || (pUFObj->pszFontName[0] == '\0'))
|
|
{
|
|
UFLDeletePtr(pMem, pUFObj);
|
|
return nil;
|
|
}
|
|
|
|
pInfo = (UFLTTFontInfo*)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);
|
|
|
|
if (NewFont(pUFObj, sizeof (T42FontStruct), maxGlyphs) == kNoErr)
|
|
{
|
|
unsigned long sSize;
|
|
unsigned long *pXUID;
|
|
T42FontStruct *pFont = (T42FontStruct *)pUFObj->pAFont->hFont;
|
|
|
|
pFont->info = *pInfo;
|
|
|
|
/*
|
|
* A convenience pointer - set to the permanent one.
|
|
*/
|
|
pUFObj->pFData = &(pFont->info.fData); /* !!! Real assignment !!! */
|
|
|
|
/*
|
|
* Get ready to find out correct glyphNames from 'post' table -
|
|
* set correct pFont->info.fData.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;
|
|
|
|
/*
|
|
* Copy or Set XUID array to our UFLXUID structure.
|
|
*/
|
|
sSize = pInfo->fData.xuid.sSize;
|
|
|
|
if (sSize == 0)
|
|
{
|
|
/*
|
|
* 'sSize == 0' means that UFL needs to figure out the XUID.
|
|
*/
|
|
|
|
// Fixed bug 387970. We have to initialize offsetToTableDir to make
|
|
// CreateXUIDArray work for ttc font.
|
|
pFont->info.fData.offsetToTableDir =
|
|
GetOffsetToTableDirInTTC(pUFObj, pFont->info.fData.fontIndex);
|
|
|
|
sSize = CreateXUIDArray(pUFObj, nil);
|
|
|
|
pXUID = (unsigned long *)UFLNewPtr(pUFObj->pMem,
|
|
sSize * sizeof (unsigned long));
|
|
|
|
if (pXUID)
|
|
sSize = CreateXUIDArray(pUFObj, pXUID);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The XUID is passed in by client - just copy it.
|
|
*/
|
|
pXUID = (unsigned long *)UFLNewPtr(pUFObj->pMem,
|
|
sSize * sizeof (unsigned long));
|
|
|
|
|
|
if (pXUID)
|
|
{
|
|
UFLmemcpy(pUFObj->pMem,
|
|
pXUID, pInfo->fData.xuid.pXUID,
|
|
sSize * sizeof (unsigned long));
|
|
}
|
|
}
|
|
|
|
if (sSize && pXUID)
|
|
{
|
|
pUFObj->pAFont->Xuid.sSize = sSize;
|
|
pUFObj->pAFont->Xuid.pXUID = pXUID;
|
|
}
|
|
else if (pXUID)
|
|
UFLDeletePtr(pUFObj->pMem, pXUID);
|
|
|
|
/*
|
|
* More initializations
|
|
*/
|
|
pFont->cOtherTables = 0;
|
|
pFont->pHeader = nil;
|
|
pFont->pMinSfnt = nil;
|
|
pFont->pStringLength = nil;
|
|
pFont->pLocaTable = nil;
|
|
pFont->minSfntSize = 0;
|
|
pFont->averageGlyphSize = 0;
|
|
pFont->pRotatedGlyphIDs = nil;
|
|
|
|
pUFObj->pUpdatedEncoding = (unsigned char *)UFLNewPtr(pMem, GLYPH_SENT_BUFSIZE(256));
|
|
|
|
if (pUFObj->pUpdatedEncoding != 0)
|
|
{
|
|
/*
|
|
* Completed initialization. Change the state.
|
|
*/
|
|
pUFObj->flState = kFontInit;
|
|
}
|
|
}
|
|
|
|
return pUFObj;
|
|
}
|
|
|
|
|
|
static unsigned long
|
|
GetLenByScanLoca(
|
|
void PTR_PREFIX *locationTable,
|
|
unsigned short wGlyfIndex,
|
|
unsigned long cNumGlyphs,
|
|
int iLongFormat
|
|
)
|
|
{
|
|
unsigned long GlyphLen = 0;
|
|
unsigned long nextGlyphOffset = 0xFFFFFFFF;
|
|
unsigned long i;
|
|
|
|
if (iLongFormat)
|
|
{
|
|
unsigned long PTR_PREFIX* locaTableL = locationTable;
|
|
|
|
for (i = 0; i < cNumGlyphs; i++)
|
|
{
|
|
if ((MOTOROLALONG(locaTableL[i]) > MOTOROLALONG(locaTableL[wGlyfIndex]))
|
|
&& (MOTOROLALONG(locaTableL[i]) < nextGlyphOffset))
|
|
{
|
|
nextGlyphOffset = MOTOROLALONG(locaTableL[i]);
|
|
}
|
|
}
|
|
|
|
if (nextGlyphOffset != 0xFFFFFFFF)
|
|
GlyphLen = nextGlyphOffset - MOTOROLALONG(locaTableL[wGlyfIndex]);
|
|
}
|
|
else
|
|
{
|
|
unsigned short PTR_PREFIX* locaTableS = locationTable;
|
|
|
|
for (i = 0; i < cNumGlyphs; i++)
|
|
{
|
|
if ((MOTOROLAINT(locaTableS[i]) > MOTOROLAINT(locaTableS[wGlyfIndex]))
|
|
&& (MOTOROLAINT(locaTableS[i]) < nextGlyphOffset))
|
|
{
|
|
nextGlyphOffset = MOTOROLAINT(locaTableS[i]);
|
|
}
|
|
}
|
|
|
|
if (nextGlyphOffset != 0xFFFFFFFF)
|
|
GlyphLen = (nextGlyphOffset - MOTOROLAINT(locaTableS[wGlyfIndex])) * 2;
|
|
}
|
|
|
|
return GlyphLen;
|
|
}
|