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.
1753 lines
51 KiB
1753 lines
51 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: ufi.c
|
|
*
|
|
* Copyright (c) 1995-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
FPCREATEFONTPACKAGE gfpCreateFontPackage= (FPCREATEFONTPACKAGE)NULL;
|
|
FPMERGEFONTPACKAGE gfpMergeFontPackage = (FPMERGEFONTPACKAGE)NULL;
|
|
|
|
ULONG gulMaxCig = 3000;
|
|
|
|
#ifdef DBGSUBSET
|
|
FLONG gflSubset = 0;
|
|
#endif // DBGSUBSET
|
|
|
|
|
|
/***********************************************************
|
|
* BOOL bAddGlyphIndices(HDC, PUFIHASH, WCHAR, int, BOOL)
|
|
*
|
|
* Adds distinct glyph indices into UFI hash bucket
|
|
*
|
|
* History
|
|
* Dec-13-96 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*
|
|
************************************************************/
|
|
|
|
#define MAX_STACK_STRING 80
|
|
|
|
|
|
BOOL bAddGlyphIndices(HDC hdc, PUFIHASH pBucket, WCHAR *pwsz, int c, UINT flETO)
|
|
{
|
|
BOOL bDelta = pBucket->fs1 & FLUFI_DELTA;
|
|
WCHAR *pwc=pwsz;
|
|
WORD *pgi, *pgiTmp, *pgiEnd;
|
|
PBYTE pb, pbDelta;
|
|
WORD agi[MAX_STACK_STRING];
|
|
BOOL bRet = FALSE;
|
|
|
|
if (c && pwsz)
|
|
{
|
|
if (bDelta && (pBucket->u.ssi.pjDelta == NULL))
|
|
{
|
|
pBucket->u.ssi.cDeltaGlyphs = 0;
|
|
|
|
pBucket->u.ssi.pjDelta = (PBYTE)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, pBucket->u.ssi.cjBits);
|
|
|
|
if (pBucket->u.ssi.pjDelta == NULL)
|
|
{
|
|
WARNING("bAddGlyphIndices: unable to allocate mem for delta glyph indices\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (c > MAX_STACK_STRING)
|
|
{
|
|
pgi = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, c * sizeof(WORD));
|
|
}
|
|
else
|
|
{
|
|
pgi = agi;
|
|
}
|
|
|
|
if (pgi)
|
|
{
|
|
if (flETO & ETO_GLYPH_INDEX)
|
|
{
|
|
RtlCopyMemory((PBYTE)pgi, (PBYTE)pwsz, c*sizeof(WORD));
|
|
}
|
|
|
|
pgiTmp = pgi;
|
|
if ((flETO & ETO_GLYPH_INDEX) ||
|
|
(NtGdiGetGlyphIndicesWInternal(hdc, pwc, c, pgi, 0, TRUE) != GDI_ERROR))
|
|
{
|
|
for (pgiEnd = pgiTmp + c ; pgi < pgiEnd; pgi++)
|
|
{
|
|
BYTE jTmp;
|
|
|
|
pb = pBucket->u.ssi.pjBits + (*pgi >> 3);
|
|
pbDelta = pBucket->u.ssi.pjDelta + (*pgi >> 3);
|
|
|
|
// map to the u.ssi.pjBits and u.ssi.pjDelta if bDelta
|
|
|
|
jTmp = (BYTE)(1 << (*pgi & 7));
|
|
|
|
if (!(*pb & jTmp))
|
|
{
|
|
*pb |= jTmp;
|
|
pBucket->u.ssi.cGlyphsSoFar++;
|
|
|
|
// if this gi is not found in pjBits, it certainly
|
|
// will not be found in pjDelta
|
|
|
|
if (bDelta)
|
|
{
|
|
ASSERTGDI((*pbDelta & jTmp) == 0,
|
|
"pbDelta contains the gi\n");
|
|
*pbDelta |= jTmp;
|
|
pBucket->u.ssi.cDeltaGlyphs++;
|
|
}
|
|
}
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
if (pgiTmp != agi)
|
|
LocalFree(pgiTmp);
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
WARNING("bAddGlyphIndices unable to allocate mem for pgi\n");
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/******************************************************************
|
|
* BOOL bGetDistGlyphIndices(PUFIHASH, USHORT*, BOOL)
|
|
*
|
|
* Get distinct glyph indices from pjMemory in the ufi hash bucket
|
|
* Reverse of bAddGlyphIndices
|
|
* Clean up the u.ssi.pjDelta and u.ssi.cDeltaGlyphs before it return.
|
|
*
|
|
* History
|
|
* Dec-17-96 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*
|
|
*******************************************************************/
|
|
|
|
BOOL bGetDistGlyphIndices(PUFIHASH pBucket, USHORT *pusSubsetKeepList, BOOL bDelta)
|
|
{
|
|
ULONG ulBytes;
|
|
PBYTE pb;
|
|
USHORT gi, index;
|
|
USHORT *pNextGlyph;
|
|
|
|
ulBytes = pBucket->u.ssi.cjBits;
|
|
pb = (bDelta ? pBucket->u.ssi.pjDelta : pBucket->u.ssi.pjBits);
|
|
|
|
for(index = 0, pNextGlyph = pusSubsetKeepList; index < ulBytes; index++, pb++)
|
|
{
|
|
if (*pb)
|
|
{
|
|
gi = index << 3;
|
|
|
|
if (*pb & 0x01)
|
|
{
|
|
*pNextGlyph ++= gi;
|
|
}
|
|
if (*pb & 0x02)
|
|
{
|
|
*pNextGlyph ++= gi+1;
|
|
}
|
|
if (*pb & 0x04)
|
|
{
|
|
*pNextGlyph ++= gi+2;
|
|
}
|
|
if (*pb & 0x08)
|
|
{
|
|
*pNextGlyph ++= gi+3;
|
|
}
|
|
if (*pb & 0x10)
|
|
{
|
|
*pNextGlyph ++= gi+4;
|
|
}
|
|
if (*pb & 0x20)
|
|
{
|
|
*pNextGlyph ++= gi+5;
|
|
}
|
|
if (*pb & 0x40)
|
|
{
|
|
*pNextGlyph ++= gi+6;
|
|
}
|
|
if (*pb & 0x80)
|
|
{
|
|
*pNextGlyph ++= gi+7;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/********************************************************************************
|
|
* BOOL bWriteUFItoDC(PUFIHASH*, PUNIVERSAL_FONT_ID, PUFIHASH, PVOID, ULONG)
|
|
*
|
|
* Write merge font image into the UFI hash table on the print server side.
|
|
* pBucketIn == NULL, indicates a new font subsetting.
|
|
* This is only called on print server
|
|
*
|
|
* History
|
|
* Jan-28-1997 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*
|
|
*********************************************************************************/
|
|
|
|
BOOL bWriteUFItoDC(
|
|
PUFIHASH *ppHashBase,
|
|
PUNIVERSAL_FONT_ID pufi,
|
|
PUFIHASH pBucketIn,// NULL=>First page, else
|
|
PVOID pvBuffer, // points to the merged font image preceeded with DOWNLOADFONTHEADER
|
|
ULONG ulBytes
|
|
)
|
|
{
|
|
PUFIHASH pBucket = pBucketIn;
|
|
ULONG index, ulHeaderSize;
|
|
|
|
ASSERTGDI(pvBuffer != NULL, "pWriteUFItoDC attempts to add an NULL ufi\n");
|
|
|
|
// First page for font subset
|
|
|
|
if (!pBucketIn)
|
|
{
|
|
index = UFI_HASH_VALUE(pufi) % UFI_HASH_SIZE;
|
|
pBucket = LOCALALLOC (offsetof(UFIHASH,u.mvw) + sizeof(MERGEDVIEW));
|
|
|
|
if (pBucket == NULL)
|
|
{
|
|
WARNING("pWriteUFItoDC: unable to allocate mem for glyph indices\n");
|
|
return FALSE;
|
|
}
|
|
|
|
pBucket->ufi = *pufi;
|
|
pBucket->pNext = ppHashBase[index];
|
|
pBucket->fs1 = FLUFI_SERVER; // server side hash bucket
|
|
|
|
ppHashBase[index] = pBucket;
|
|
}
|
|
else
|
|
{
|
|
// pjMemory contains the image of the font subsetted up unil
|
|
// the page preceeding this one. Other info in pBucket is ok.
|
|
|
|
LocalFree(pBucket->u.mvw.pjMem);
|
|
}
|
|
|
|
// pvBuffer includes the DOWNLOADFONTHEADER information
|
|
|
|
pBucket->u.mvw.pjMem = (PBYTE)pvBuffer;
|
|
pBucket->u.mvw.cjMem = ulBytes;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
*
|
|
* Adds an entry to the UFI hash table, this routine only executes
|
|
* on a print client machine.
|
|
*
|
|
* History
|
|
* Dec-16-96 Xudong Wu [tessiew]
|
|
* Modify to return the bucket pointer.
|
|
* 1-27-95 Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*
|
|
***************************************************************************/
|
|
|
|
PUFIHASH pufihAddUFIEntry(
|
|
PUFIHASH *ppHashBase,
|
|
PUNIVERSAL_FONT_ID pufi,
|
|
ULONG ulCig,
|
|
FLONG fl,
|
|
FLONG fs2)
|
|
{
|
|
PUFIHASH pBucket;
|
|
ULONG index;
|
|
ULONG cjGlyphBitfield = (ulCig + 7) / 8;
|
|
|
|
index = UFI_HASH_VALUE(pufi) % UFI_HASH_SIZE;
|
|
pBucket = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
|
|
(fl & FL_UFI_SUBSET) ?
|
|
(offsetof(UFIHASH,u.ssi) + sizeof(SSINFO) + cjGlyphBitfield) :
|
|
offsetof(UFIHASH,u)
|
|
);
|
|
|
|
if (pBucket == NULL)
|
|
{
|
|
WARNING("pufihAddUFIEntry: unable to allocate mem for glyph indices\n");
|
|
return NULL;
|
|
}
|
|
|
|
// these fields are always there
|
|
|
|
pBucket->ufi = *pufi;
|
|
pBucket->pNext = ppHashBase[index];
|
|
pBucket->fs1 = 0;
|
|
pBucket->fs2 = (FSHORT)fs2;
|
|
ppHashBase[index] = pBucket;
|
|
|
|
// these fields are there only for subsetting case
|
|
|
|
if (fl & FL_UFI_SUBSET)
|
|
{
|
|
// all other fields are zero initialized by LocalAlloc
|
|
|
|
ASSERTGDI (ulCig, "no font subsetting for ulCig == 0\n");
|
|
pBucket->u.ssi.cjBits = cjGlyphBitfield; // bitfield size
|
|
pBucket->u.ssi.pjBits = (PBYTE)pBucket + offsetof(UFIHASH,u.ssi) + sizeof(SSINFO);
|
|
}
|
|
|
|
return(pBucket);
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* Checks to see if an entry is in the UFI table.
|
|
*
|
|
* History
|
|
* Dec-13-96 Xudong Wu [tessiew]
|
|
* Changed its return value from BOOL to PUFIHASH.
|
|
* 1-27-95 Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*
|
|
***************************************************************************/
|
|
|
|
|
|
PUFIHASH pufihFindUFIEntry(PUFIHASH *ppHashBase, PUNIVERSAL_FONT_ID pufi, BOOL SubsetHashBase)
|
|
{
|
|
PUFIHASH pBucket;
|
|
ULONG index;
|
|
|
|
index = UFI_HASH_VALUE(pufi) % UFI_HASH_SIZE;
|
|
|
|
pBucket = ppHashBase[index];
|
|
|
|
if( pBucket == NULL )
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
do
|
|
{
|
|
if (UFI_SAME_FILE(&pBucket->ufi,pufi))
|
|
{
|
|
if (SubsetHashBase)
|
|
{
|
|
if ((pBucket->ufi.Index -1)/2 == (pufi->Index -1)/2)
|
|
{
|
|
return (pBucket);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return(pBucket);
|
|
}
|
|
}
|
|
|
|
pBucket = pBucket->pNext;
|
|
} while( pBucket != NULL );
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/************************************************************
|
|
* VOID vRemoveUFIEntry(PUFIHASH*, PUNIVERSAL_FONT_ID)
|
|
*
|
|
* Remove a UFI entry from the UFI hash list
|
|
* Function returns TRUE if UFI doesn't exist in the table.
|
|
* This is happening on the print client, typically when subsetter failed
|
|
* we call this to remove the bucket from ppSubUFIHash table (and then later
|
|
* add it to the ppUFIHash, ie hash table of fonts that are going to be shipped
|
|
* over without subsetting.
|
|
*
|
|
* History
|
|
* Feb-03-97 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*
|
|
***************************************************************************/
|
|
VOID vRemoveUFIEntry(PUFIHASH *ppHashBase, PUNIVERSAL_FONT_ID pufi)
|
|
{
|
|
PUFIHASH pBucket, pPrev;
|
|
ULONG index;
|
|
|
|
index = UFI_HASH_VALUE(pufi) % UFI_HASH_SIZE;
|
|
pPrev = pBucket = ppHashBase[index];
|
|
|
|
while(pBucket)
|
|
{
|
|
if (UFI_SAME_FILE(&pBucket->ufi, pufi) &&
|
|
((pBucket->ufi.Index - 1)/2 == (pufi->Index - 1)/2))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pPrev = pBucket;
|
|
pBucket = pBucket->pNext;
|
|
}
|
|
}
|
|
|
|
if (pBucket != NULL)
|
|
{
|
|
if (pPrev == pBucket)
|
|
{
|
|
ppHashBase[index] = pBucket->pNext;
|
|
}
|
|
else
|
|
{
|
|
pPrev->pNext = pBucket->pNext;
|
|
}
|
|
|
|
// this is only happening for subsetting ufi hash list => u.ssi.pjDelta exists
|
|
|
|
if (pBucket->u.ssi.pjDelta)
|
|
{
|
|
LocalFree(pBucket->u.ssi.pjDelta);
|
|
}
|
|
|
|
LocalFree(pBucket);
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* VOID vFreeUFIHashTable( PUFIHASH *ppHashTable )
|
|
*
|
|
* Frees all the memory allocated for the UFI has table.
|
|
*
|
|
* History
|
|
* 1-27-95 Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*
|
|
***************************************************************************/
|
|
|
|
|
|
VOID vFreeUFIHashTable(PUFIHASH *ppHashTable, FLONG fl)
|
|
{
|
|
PUFIHASH pBucket, *ppHashEnd, pBucketTmp, *ppTableBase;
|
|
|
|
if( ppHashTable == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
ppTableBase = ppHashTable; // save ptr to the base so we can free it later
|
|
|
|
// Next loop through the whole table looking for buckets lists
|
|
|
|
for( ppHashEnd = ppHashTable + UFI_HASH_SIZE;
|
|
ppHashTable < ppHashEnd;
|
|
ppHashTable += 1 )
|
|
{
|
|
pBucket = *ppHashTable;
|
|
|
|
while( pBucket != NULL )
|
|
{
|
|
pBucketTmp = pBucket;
|
|
pBucket = pBucket->pNext;
|
|
|
|
// subsetting hash table
|
|
|
|
if (fl & FL_UFI_SUBSET)
|
|
{
|
|
if (pBucketTmp->fs1 & FLUFI_SERVER) // server, clean the merged font image
|
|
{
|
|
if (pBucketTmp->u.mvw.pjMem)
|
|
{
|
|
LocalFree(pBucketTmp->u.mvw.pjMem);
|
|
}
|
|
}
|
|
else // client, clean the glyph indices list
|
|
{
|
|
if (pBucketTmp->u.ssi.pjDelta)
|
|
{
|
|
LocalFree(pBucketTmp->u.ssi.pjDelta);
|
|
}
|
|
}
|
|
}
|
|
|
|
LocalFree (pBucketTmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ULONG GetRecdEmbedFonts(PUFIHASH *ppHashTable)
|
|
{
|
|
PUFIHASH pBucket, *ppHashEnd;
|
|
ULONG cEmbedFonts = 0;
|
|
|
|
if( ppHashTable == NULL )
|
|
return 0;
|
|
|
|
for( ppHashEnd = ppHashTable + UFI_HASH_SIZE;
|
|
ppHashTable < ppHashEnd;
|
|
ppHashTable += 1 )
|
|
{
|
|
pBucket = *ppHashTable;
|
|
|
|
while( pBucket != NULL )
|
|
{
|
|
cEmbedFonts++;
|
|
pBucket = pBucket->pNext;
|
|
}
|
|
}
|
|
return cEmbedFonts;
|
|
}
|
|
|
|
|
|
typedef union _DLHEADER
|
|
{
|
|
DOWNLOADFONTHEADER dfh;
|
|
double f; // to achieve max alignment
|
|
} DLHEADER;
|
|
|
|
BOOL WriteFontToSpoolFile(PLDC pldc, PUNIVERSAL_FONT_ID pufi, FLONG fl)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
ULONG cwcPathname, cNumFiles;
|
|
WCHAR *pwszFile = NULL;
|
|
WCHAR pwszPathname[MAX_PATH * 3];
|
|
CLIENT_SIDE_FILEVIEW fvw;
|
|
DLHEADER dlh;
|
|
ULONG cjView;
|
|
PVOID pvView = NULL;
|
|
BOOL bMemFont = FALSE, bMapOK = TRUE;
|
|
|
|
#ifdef DBGSUBSET
|
|
FILETIME fileTimeStart, fileTimeEnd;
|
|
DbgPrint("\nWriteFontToSpoolFile called\n");
|
|
|
|
if (gflSubset & FL_SS_SPOOLTIME)
|
|
{
|
|
GetSystemTimeAsFileTime(&fileTimeStart);
|
|
}
|
|
#endif
|
|
|
|
RtlZeroMemory(&dlh, sizeof(DLHEADER));
|
|
|
|
if (NtGdiGetUFIPathname(pufi,
|
|
&cwcPathname,
|
|
pwszPathname,
|
|
&cNumFiles,
|
|
fl,
|
|
&bMemFont,
|
|
&cjView,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
if (cNumFiles == 1)
|
|
{
|
|
ASSERTGDI(cwcPathname <= MAX_PATH, "WriteFontToSpoolFile: cwcPathname\n");
|
|
|
|
if (!bMemFont)
|
|
{
|
|
if (!bMapFileUNICODEClideSide(pwszPathname, &fvw, TRUE))
|
|
{
|
|
bMapOK = FALSE;
|
|
WARNING("WriteFontToSpooler: error map the font file\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// must allocate memory and call again to get the bits:
|
|
|
|
pvView = LocalAlloc( LMEM_FIXED, cjView ) ;
|
|
if (!pvView)
|
|
{
|
|
bMapOK = FALSE;
|
|
WARNING("WriteFontToSpooler: error allocating mem for mem font\n");
|
|
}
|
|
|
|
// Write the bits into the buffer
|
|
|
|
if (!NtGdiGetUFIPathname(pufi,NULL,NULL,NULL,fl,
|
|
NULL,NULL,pvView,NULL,NULL))
|
|
{
|
|
bMapOK = FALSE;
|
|
LocalFree(pvView);
|
|
pvView = NULL;
|
|
WARNING("WriteFontToSpooler: could not get mem bits\n");
|
|
}
|
|
}
|
|
|
|
if (bMapOK)
|
|
{
|
|
DOWNLOADFONTHEADER* pdfh = &dlh.dfh;
|
|
|
|
pdfh->Type1ID = 0;
|
|
pdfh->NumFiles = cNumFiles;
|
|
|
|
if (!bMemFont)
|
|
{
|
|
cjView = fvw.cjView;
|
|
pvView = fvw.pvView;
|
|
}
|
|
|
|
pdfh->FileOffsets[0] = cjView;
|
|
|
|
if (WriteFontDataAsEMFComment(
|
|
pldc,
|
|
EMRI_ENGINE_FONT,
|
|
pdfh,
|
|
sizeof(DLHEADER),
|
|
pvView,
|
|
cjView))
|
|
{
|
|
MFD1("Done writing UFI to printer\n");
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("WriteFontToSpooler: error writing to printer\n");
|
|
}
|
|
|
|
if (bMemFont)
|
|
{
|
|
if (pvView) { LocalFree(pvView);}
|
|
}
|
|
else
|
|
{
|
|
vUnmapFileClideSide(&fvw);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CLIENT_SIDE_FILEVIEW afvw[3];
|
|
ULONG iFile;
|
|
ULONG cjdh;
|
|
|
|
if (cNumFiles > 3)
|
|
return FALSE;
|
|
|
|
ASSERTGDI(cwcPathname <= (cNumFiles * MAX_PATH), "cwcPathname too big\n");
|
|
ASSERTGDI(!bMemFont, "there can not be memory type1 font\n");
|
|
|
|
pwszFile = pwszPathname;
|
|
|
|
bMapOK = TRUE;
|
|
|
|
cjView = 0;
|
|
|
|
for (iFile = 0; iFile < cNumFiles; iFile++)
|
|
{
|
|
if (!bMapFileUNICODEClideSide(pwszFile, &afvw[iFile], TRUE))
|
|
{
|
|
ULONG iFile2;
|
|
bMapOK = FALSE;
|
|
WARNING("WriteFontToSpooler: error mapping the font file\n");
|
|
|
|
for (iFile2 = 0; iFile2 < cNumFiles; iFile2++)
|
|
{
|
|
vUnmapFileClideSide(&afvw[iFile2]);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// advance to the path name of the next font file
|
|
|
|
while (*pwszFile++);
|
|
cjView += ALIGN4(afvw[iFile].cjView);
|
|
}
|
|
|
|
if (bMapOK)
|
|
{
|
|
cjdh = ALIGN8(offsetof(DOWNLOADFONTHEADER, FileOffsets) + cNumFiles * sizeof(ULONG));
|
|
|
|
pvView = LocalAlloc(LMEM_FIXED, cjdh + cjView);
|
|
if (pvView)
|
|
{
|
|
DOWNLOADFONTHEADER* pdfh = (DOWNLOADFONTHEADER *) pvView;
|
|
ULONG dpFile;
|
|
BYTE *pjFile = (BYTE *)pvView + cjdh;
|
|
|
|
RtlZeroMemory(pvView, cjdh); // zero out top portion of the buffer only
|
|
|
|
for (dpFile = 0, iFile = 0; iFile < cNumFiles; iFile++)
|
|
{
|
|
// first offset is implicit at cjdh, the second offset is
|
|
// at ALIGN4(cjView) of the first file etc.
|
|
|
|
dpFile += ALIGN4(afvw[iFile].cjView);
|
|
pdfh->FileOffsets[iFile] = dpFile;
|
|
|
|
RtlCopyMemory(pjFile, afvw[iFile].pvView, afvw[iFile].cjView);
|
|
pjFile += ALIGN4(afvw[iFile].cjView);
|
|
}
|
|
|
|
pdfh->Type1ID = 0; // is this correct?
|
|
pdfh->NumFiles = cNumFiles;
|
|
|
|
if (WriteFontDataAsEMFComment(
|
|
pldc,
|
|
EMRI_TYPE1_FONT,
|
|
pdfh,
|
|
cjdh,
|
|
(BYTE *)pvView + cjdh,
|
|
cjView))
|
|
{
|
|
MFD1("Done writing UFI to printer\n");
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("WriteFontToSpooler: error writing to printer\n");
|
|
}
|
|
|
|
LocalFree(pvView);
|
|
}
|
|
|
|
// clean up
|
|
|
|
for (iFile = 0; iFile < cNumFiles; iFile++)
|
|
{
|
|
vUnmapFileClideSide(&afvw[iFile]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("NtGdiGetUFIPathname failed\n");
|
|
}
|
|
|
|
//timing code
|
|
#ifdef DBGSUBSET
|
|
if (gflSubset & FL_SS_SPOOLTIME)
|
|
{
|
|
GetSystemTimeAsFileTime(&fileTimeEnd);
|
|
DbgPrint("WriteFontToSpoolfile(millisec): %ld\n", (fileTimeEnd.dwLowDateTime - fileTimeStart.dwLowDateTime) / 10000);
|
|
}
|
|
#endif
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 16-Jan-1997 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
|
|
BOOL WriteDesignVectorToSpoolFile (
|
|
PLDC pldc,
|
|
UNIVERSAL_FONT_ID *pufiBase,
|
|
DESIGNVECTOR *pdv,
|
|
ULONG cjDV
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
DOWNLOADDESIGNVECTOR ddv;
|
|
|
|
ddv.ufiBase = *pufiBase;
|
|
RtlCopyMemory(&ddv.dv, pdv, cjDV); // small copy
|
|
|
|
if (WriteFontDataAsEMFComment(
|
|
pldc,
|
|
EMRI_DESIGNVECTOR,
|
|
&ddv,
|
|
offsetof(DOWNLOADDESIGNVECTOR,dv) + cjDV,
|
|
NULL,
|
|
0))
|
|
{
|
|
MFD1("Done writing DesignVector to spool file\n");
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("WriteDesignVectorToSpooler: spooling error\n");
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
/***********************************************************
|
|
* BOOL bAddUFIandWriteSpool(HDC,PUNIVERSAL_FONT_ID,BOOL)
|
|
* Called only on the print client when subsetter failed
|
|
* or when we could not write a subsetted font to the spool file.
|
|
*
|
|
* History
|
|
* Feb-03-1997 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
************************************************************/
|
|
BOOL bAddUFIandWriteSpool(
|
|
HDC hdc,
|
|
PUNIVERSAL_FONT_ID pufi,
|
|
BOOL bSubset,
|
|
FLONG fl
|
|
)
|
|
{
|
|
PLDC pldc;
|
|
UNIVERSAL_FONT_ID ufi = *pufi;
|
|
|
|
pldc = GET_PLDC(hdc);
|
|
|
|
if (pldc == NULL)
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
if(bSubset)
|
|
{
|
|
vRemoveUFIEntry(pldc->ppSubUFIHash, pufi);
|
|
}
|
|
|
|
// We might have freed the bucket entry,
|
|
// which means that pufi pointer might not be valid anymore.
|
|
// That is why we saved it above before calling vRemoveUFIEntry.
|
|
|
|
if (!pufihAddUFIEntry(pldc->ppUFIHash, &ufi, 0, 0, fl) ||
|
|
!WriteFontToSpoolFile(pldc, &ufi, fl))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define QUICK_UFIS 8
|
|
|
|
/**************************************************************************
|
|
* BOOL bDoFontChange( HDC hdc )
|
|
*
|
|
* Called everytime the font changes in the DC. This routines checks to
|
|
* see if the font has already been packaged in the spool file and if not
|
|
* gets the raw bits for it and packages it into the spool file.
|
|
*
|
|
* History
|
|
* Dec-12-96 Xudong Wu [tessiew]
|
|
* Modify it so it can handle the font subsetting.
|
|
* 1-27-95 Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL bDoFontChange( HDC hdc, WCHAR *pwsz, int c, UINT flETO )
|
|
{
|
|
PLDC pldc;
|
|
BOOL bRet = FALSE;
|
|
UNIVERSAL_FONT_ID ufi;
|
|
UNIVERSAL_FONT_ID ufiBase;
|
|
DESIGNVECTOR dv;
|
|
ULONG cjDV = 0;
|
|
ULONG ulBaseCheckSum;
|
|
FLONG fl = 0; // initialization essential
|
|
|
|
pldc = GET_PLDC( hdc );
|
|
|
|
if (pldc == NULL)
|
|
{
|
|
WARNING("bDoFontChange: unable to retrieve pldc\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
pldc->fl &= ~LDC_FONT_CHANGE;
|
|
|
|
if (!NtGdiGetUFI(hdc, &ufi, &dv, &cjDV, &ulBaseCheckSum, &fl))
|
|
{
|
|
WARNING("bDoFontChange: call to GetUFI failed\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
// if the UFI to which we are forcing mapping does not match the new UFI then
|
|
// set forced mapping to the new UFI
|
|
|
|
if((pldc->fl & LDC_FORCE_MAPPING) &&
|
|
(!UFI_SAME_FACE(&pldc->ufi,&ufi) || (pldc->fl & LDC_LINKED_FONTS)))
|
|
{
|
|
INT NumLinkedUFIs;
|
|
|
|
if (!UFI_SAME_FACE(&pldc->ufi, &ufi))
|
|
{
|
|
if(!MF_ForceUFIMapping(hdc, &ufi))
|
|
{
|
|
WARNING("bDoFontChange: call to MF_ForceUFIMapping failed\n");
|
|
return(FALSE);
|
|
}
|
|
pldc->ufi = ufi;
|
|
}
|
|
|
|
if(NtGdiAnyLinkedFonts())
|
|
{
|
|
UNIVERSAL_FONT_ID QuickLinks[QUICK_UFIS];
|
|
PUNIVERSAL_FONT_ID pUFIs = NULL;
|
|
|
|
NumLinkedUFIs = NtGdiGetLinkedUFIs(hdc, NULL, 0);
|
|
|
|
if (NumLinkedUFIs > 0)
|
|
{
|
|
pldc->fl |= LDC_LINKED_FONTS;
|
|
|
|
if(NumLinkedUFIs <= QUICK_UFIS)
|
|
{
|
|
pUFIs = QuickLinks;
|
|
}
|
|
else
|
|
{
|
|
pUFIs = LocalAlloc(LMEM_FIXED, NumLinkedUFIs * sizeof(UNIVERSAL_FONT_ID));
|
|
}
|
|
}
|
|
|
|
if (pUFIs)
|
|
{
|
|
if(NumLinkedUFIs = NtGdiGetLinkedUFIs(hdc,pUFIs,NumLinkedUFIs))
|
|
{
|
|
INT u;
|
|
WORD *pgi = NULL, agi[MAX_STACK_STRING];
|
|
BOOL bNeedLinkFont = FALSE;
|
|
|
|
bRet = TRUE;
|
|
|
|
if((pldc->fl & LDC_DOWNLOAD_FONTS) &&
|
|
c && pwsz && !(flETO & ETO_GLYPH_INDEX))
|
|
{
|
|
if (c > MAX_STACK_STRING)
|
|
{
|
|
pgi = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, c * sizeof(WORD));
|
|
}
|
|
else
|
|
{
|
|
pgi = agi;
|
|
}
|
|
|
|
// check whether there are glyphs from linked font
|
|
|
|
if (pgi &&
|
|
NtGdiGetGlyphIndicesW(hdc, pwsz, c, pgi, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
|
|
{
|
|
for (u = 0; u < c; u++)
|
|
{
|
|
if (pgi[u] == 0xffff)
|
|
{
|
|
bNeedLinkFont = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bNeedLinkFont = TRUE; // ship them, just in case
|
|
}
|
|
|
|
if (bNeedLinkFont)
|
|
{
|
|
for(u = 0; u < NumLinkedUFIs; u++)
|
|
{
|
|
if(pufihFindUFIEntry(pldc->ppUFIHash, &pUFIs[u], FALSE))
|
|
{
|
|
// already in spool file or on remote machine so skip it
|
|
continue;
|
|
}
|
|
|
|
#if DBG
|
|
DbgPrint("Writing link to spooler\n");
|
|
#endif
|
|
|
|
// WHAT IS fs2 flag that should be passed to these 2 functions ???
|
|
|
|
if(!pufihAddUFIEntry(pldc->ppUFIHash, &pUFIs[u], 0, 0, 0) ||
|
|
!WriteFontToSpoolFile(pldc,&pUFIs[u], 0))
|
|
{
|
|
WARNING("GDI32:error writing linked font to spooler\n");
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
if (bRet)
|
|
{
|
|
pldc->fl &= ~LDC_LINKED_FONTS;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pgi && (pgi != agi))
|
|
{
|
|
LocalFree(pgi);
|
|
}
|
|
}
|
|
|
|
if(bRet)
|
|
{
|
|
// If there are no linked UFI's we still need to metafile the call
|
|
// so that the server knows to turn off linking.
|
|
|
|
bRet = MF_SetLinkedUFIs(hdc, pUFIs, (UINT)NumLinkedUFIs);
|
|
}
|
|
|
|
if(pUFIs != QuickLinks)
|
|
{
|
|
LocalFree(pUFIs);
|
|
}
|
|
|
|
if(!bRet)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if( UFI_DEVICE_FONT(&ufi) ||
|
|
!(pldc->fl & LDC_DOWNLOAD_FONTS) )
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
// now comes the interesting part:
|
|
// If this is a mm instance, we send the base font first (if not sent already)
|
|
// and then we send the design vector with the ufi of the base font.
|
|
|
|
ufiBase = ufi;
|
|
|
|
if (fl & FL_UFI_DESIGNVECTOR_PFF)
|
|
{
|
|
// little bit dirty, we should not know what is in ufi
|
|
|
|
ufiBase.CheckSum = ulBaseCheckSum;
|
|
}
|
|
|
|
// pldc->ppUFIHash is used to remember all remote fonts which have been
|
|
// copied into the spool file without subset. Once it is in spool file,
|
|
// there is no need to copy again.
|
|
|
|
if (pufihFindUFIEntry(pldc->ppUFIHash, &ufiBase, FALSE) == NULL)
|
|
{
|
|
|
|
if (fl & FL_UFI_DESIGNVECTOR_PFF)
|
|
{
|
|
pufihAddUFIEntry(pldc->ppUFIHash, &ufiBase,0, 0, fl);
|
|
bRet = WriteFontToSpoolFile(pldc, &ufiBase, fl);
|
|
|
|
// now since this is a mm instance, write a design vector object in the spool file
|
|
// if we have not done it already
|
|
|
|
if (bRet)
|
|
{
|
|
if (!pufihFindUFIEntry(pldc->ppDVUFIHash, &ufi, FALSE))
|
|
{
|
|
pufihAddUFIEntry(pldc->ppDVUFIHash, &ufi,0, 0, fl);
|
|
bRet = WriteDesignVectorToSpoolFile(pldc, &ufiBase, &dv, cjDV);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BOOL bFontSubset = TRUE, bSubsetFail = FALSE;
|
|
PUFIHASH pBucket;
|
|
|
|
// Check the ppSubUFIHash to see whether ufi already exists
|
|
|
|
if ((pBucket = pufihFindUFIEntry(pldc->ppSubUFIHash, &ufi, TRUE)) == NULL)
|
|
{
|
|
ULONG ulCig = NtGdiGetGlyphIndicesW(hdc, NULL, 0, NULL, 0);
|
|
DWORD cjGlyf = NtGdiGetFontData(hdc, 'fylg', 0, NULL, 0);
|
|
|
|
// Subset only if ulCig > gulMaxCig AND this is a tt font, not OTF,
|
|
// Which we test by making sure the font has 'glyf' table. ('fylg',)
|
|
|
|
if (bFontSubset = ((ulCig != GDI_ERROR) && (ulCig > gulMaxCig) && (cjGlyf != GDI_ERROR) && cjGlyf))
|
|
{
|
|
#ifdef DBGSUBSET
|
|
DbgPrint("bDoFontChange cig= %lx\n", ulCig);
|
|
#endif
|
|
|
|
if (!(pBucket = pufihAddUFIEntry(pldc->ppSubUFIHash, &ufi, ulCig, FL_UFI_SUBSET, fl)) ||
|
|
!(bRet = bAddGlyphIndices(hdc, pBucket, pwsz, c, flETO)))
|
|
{
|
|
bSubsetFail = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(bRet = bAddGlyphIndices(hdc, pBucket, pwsz, c, flETO)))
|
|
{
|
|
bSubsetFail = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bFontSubset && !bSubsetFail)
|
|
{
|
|
pldc->fl |= LDC_FONT_SUBSET;
|
|
}
|
|
else
|
|
{
|
|
bRet = bAddUFIandWriteSpool(hdc, &ufi, bFontSubset,fl);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
BOOL bRecordEmbedFonts(HDC hdc)
|
|
{
|
|
ULONG cEmbedFonts;
|
|
UNIVERSAL_FONT_ID ufi;
|
|
DESIGNVECTOR dv;
|
|
ULONG cjDV = 0;
|
|
ULONG ulBaseCheckSum;
|
|
KERNEL_PVOID embFontID;
|
|
FLONG fl = 0;
|
|
PLDC pldc;
|
|
|
|
if (!NtGdiGetEmbUFI(hdc, &ufi, &dv, &cjDV, &ulBaseCheckSum, &fl, &embFontID)) // get UFI
|
|
return FALSE;
|
|
|
|
if ((fl & (FL_UFI_PRIVATEFONT | FL_UFI_MEMORYFONT)) && embFontID )
|
|
{
|
|
if ((pldc = GET_PLDC(hdc)) == NULL)
|
|
return FALSE;
|
|
|
|
if (!pufihFindUFIEntry(pldc->ppUFIHash, &ufi, FALSE)) // new UFI
|
|
{
|
|
if(!pufihAddUFIEntry(pldc->ppUFIHash, &ufi, 0, 0, 0))
|
|
return FALSE;
|
|
else
|
|
{
|
|
if (!NtGdiChangeGhostFont(&embFontID, TRUE))
|
|
{
|
|
vRemoveUFIEntry(pldc->ppUFIHash, &ufi);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!WriteFontDataAsEMFComment(
|
|
pldc,
|
|
EMRI_EMBED_FONT_EXT,
|
|
&embFontID,
|
|
sizeof(VOID *),
|
|
NULL,
|
|
0))
|
|
{
|
|
NtGdiChangeGhostFont(&embFontID, FALSE); // Can't record it into the spool file
|
|
return FALSE;
|
|
}
|
|
|
|
// check to see whether it gets all of the embedded fonts
|
|
|
|
cEmbedFonts = NtGdiGetEmbedFonts();
|
|
|
|
if (cEmbedFonts != 0xFFFFFFFF &&
|
|
(cEmbedFonts == 1 || cEmbedFonts == GetRecdEmbedFonts(pldc->ppUFIHash)))
|
|
{
|
|
pldc->fl &= ~LDC_EMBED_FONTS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**************************************************************************
|
|
* BOOL RemoteRasterizerCompatible()
|
|
*
|
|
* This routine is used if we are about to print using remote EMF. If a
|
|
* Type 1 font rasterizer has been installed on the client machine, we need
|
|
* to query the remote machine to make sure that it has a rasterizer that is
|
|
* compatable with the local version. If it isn't, we will return false
|
|
* telling the caller that we should go RAW.
|
|
*
|
|
* History
|
|
* 6-4-96 Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL gbQueriedRasterizerVersion = FALSE;
|
|
UNIVERSAL_FONT_ID gufiLocalType1Rasterizer;
|
|
|
|
BOOL RemoteRasterizerCompatible(HANDLE hSpooler)
|
|
{
|
|
// if we haven't queried the rasterizer for the version yet do so first
|
|
|
|
UNIVERSAL_FONT_ID ufi;
|
|
LARGE_INTEGER TimeStamp;
|
|
|
|
if(!gbQueriedRasterizerVersion)
|
|
{
|
|
// we have a contract with NtGdiQueryFonts (the routine called by the spooler
|
|
// on the remote machine) that if a Type1 rasterizer is installed, the UFI
|
|
// for it will always be first in the UFI list returned. So we can call
|
|
// NtGdiQueryFonts
|
|
|
|
if(!NtGdiQueryFonts(&gufiLocalType1Rasterizer, 1, &TimeStamp))
|
|
{
|
|
WARNING("Unable to get local Type1 information\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
gbQueriedRasterizerVersion = TRUE;
|
|
}
|
|
|
|
if(!UFI_TYPE1_RASTERIZER(&gufiLocalType1Rasterizer))
|
|
{
|
|
// no need to disable remote printing if there is no ATM driver installed
|
|
return(TRUE);
|
|
}
|
|
|
|
// Since we made it this far there must be a Type1 rasterizer on the local machine.
|
|
// Let's find out the version number of the Type1 rasterizer (if one is installed)
|
|
// on the print server.
|
|
|
|
|
|
if((*fpQueryRemoteFonts)(hSpooler, &ufi, 1 ) &&
|
|
(UFI_SAME_RASTERIZER_VERSION(&gufiLocalType1Rasterizer,&ufi)))
|
|
{
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
WARNING("Remote Type1 rasterizer missing or wrong version. Going RAW\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
* VOID* AllocCallback(VOID* pvBuffer, size_t size)
|
|
*
|
|
* Passed to CreateFontPackage() to allocate or reallocate memory
|
|
*
|
|
* History
|
|
* Jan-07-97 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*****************************************************************/
|
|
void* WINAPIV AllocCallback(void* pvBuffer, size_t size)
|
|
{
|
|
if (size == 0)
|
|
{
|
|
return (void*)NULL;
|
|
}
|
|
else
|
|
{
|
|
return ((void*)(LocalAlloc(LMEM_FIXED, size)));
|
|
}
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
* VOID* ReAllocCallback(VOID* pvBuffer, size_t size)
|
|
*
|
|
* Passed to CreateFontPackage() to allocate or reallocate memory
|
|
*
|
|
* History
|
|
* Jan-07-97 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*****************************************************************/
|
|
void* WINAPIV ReAllocCallback(void* pvBuffer, size_t size)
|
|
{
|
|
if (size == 0)
|
|
{
|
|
return (void*)NULL;
|
|
}
|
|
else if (pvBuffer == (void*)NULL)
|
|
{
|
|
return ((void*)(LocalAlloc(LMEM_FIXED, size)));
|
|
}
|
|
else
|
|
{
|
|
return ((void*)(LocalReAlloc(pvBuffer, size, LMEM_MOVEABLE)));
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************
|
|
* VOID* FreeCallback(VOID* pvBuffer)
|
|
*
|
|
* Passed to CreateFontPackage() to free memory
|
|
*
|
|
* History
|
|
* Jan-07-97 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
********************************************************/
|
|
void WINAPIV FreeCallback(void* pvBuffer)
|
|
{
|
|
if (pvBuffer)
|
|
{
|
|
if (LocalFree(pvBuffer))
|
|
{
|
|
WARNING("FreeCallback(): Can't free the local memory\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* BOOL bInitSubsetterFunctionPointer(PVOID *ppfn)
|
|
*
|
|
* the name says it all
|
|
*
|
|
* History
|
|
* Dec-18-96 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*
|
|
******************************************************************************/
|
|
|
|
|
|
BOOL bInitSubsetterFunctionPointer(PVOID *ppfn)
|
|
{
|
|
BOOL bRet = TRUE;
|
|
|
|
if (*ppfn == NULL)
|
|
{
|
|
HANDLE hFontSubset = LoadLibraryW(L"fontsub.dll");
|
|
|
|
if (hFontSubset)
|
|
{
|
|
*ppfn = (PVOID)GetProcAddress(hFontSubset,
|
|
(ppfn == (PVOID *)&gfpCreateFontPackage) ?
|
|
"CreateFontPackage" : "MergeFontPackage");
|
|
|
|
if (*ppfn == NULL)
|
|
{
|
|
FreeLibrary(hFontSubset);
|
|
WARNING("GetProcAddress(fontsub.dll) failed\n");
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("LoadLibrary(fontsub.dll) failed\n");
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* BOOL bDoFontSubset
|
|
*
|
|
* Called everytime we need to subset a font. This routine converts the bit
|
|
* fields of pjMemory/u.ssi.pjDelta in pBucket into a glyph index list and call the
|
|
* font subsetting functions to generate subset/delta font.
|
|
*
|
|
* History
|
|
* Dec-18-96 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*
|
|
******************************************************************************/
|
|
|
|
BOOL bDoFontSubset(PUFIHASH pBucket,
|
|
PUCHAR* ppuchDestBuff, // output: buffer will contain the subsetted image or delta
|
|
ULONG* pulDestSize, // output: size of the buffer above, may be more than needed
|
|
ULONG* pulBytesWritten // output: bytes written into the buffer above
|
|
)
|
|
{
|
|
BOOL bDelta = pBucket->fs1 & FLUFI_DELTA;
|
|
USHORT *pusSubsetKeepList = NULL;
|
|
ULONG cSubset; // number of glyphs to be subsetted
|
|
BOOL bRet = FALSE;
|
|
|
|
#ifdef DBGSUBSET
|
|
FILETIME fileTimeStart, fileTimeEnd;
|
|
if (gflSubset & FL_SS_SUBSETTIME)
|
|
{
|
|
GetSystemTimeAsFileTime(&fileTimeStart);
|
|
}
|
|
#endif
|
|
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
bRet = bInitSubsetterFunctionPointer((PVOID *)&gfpCreateFontPackage);
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
|
|
if (!bRet)
|
|
return FALSE;
|
|
bRet = FALSE;
|
|
|
|
cSubset = bDelta ? pBucket->u.ssi.cDeltaGlyphs : pBucket->u.ssi.cGlyphsSoFar;
|
|
|
|
#ifdef DBGSUBSET
|
|
if (gflSubset & FL_SS_KEEPLIST)
|
|
{
|
|
DbgPrint("\t%ld", cSubset);
|
|
}
|
|
#endif // DBGSUBSET
|
|
|
|
pusSubsetKeepList = (USHORT*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(USHORT) * cSubset);
|
|
|
|
if (pusSubsetKeepList == NULL)
|
|
{
|
|
WARNING("bDoFontSubset unable to allocate memory for pusSubsetKeepList\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// transfer appropriate bit field into glyph indices
|
|
|
|
if (bGetDistGlyphIndices(pBucket, pusSubsetKeepList, bDelta))
|
|
{
|
|
WCHAR pwszPathname[MAX_PATH * 3];
|
|
ULONG cwcPathname, cNumFiles;
|
|
BOOL bMemFont = FALSE, bMapOK = TRUE;
|
|
ULONG cjView;
|
|
PVOID pvView = NULL;
|
|
BOOL bTTC = FALSE;
|
|
ULONG iTTC = 0;
|
|
|
|
if (NtGdiGetUFIPathname(&pBucket->ufi,
|
|
&cwcPathname,
|
|
pwszPathname,
|
|
&cNumFiles,
|
|
pBucket->fs2,
|
|
&bMemFont,
|
|
&cjView,
|
|
NULL,
|
|
&bTTC,
|
|
&iTTC))
|
|
|
|
{
|
|
PVOID pvSrcBuff;
|
|
ULONG ulSrcSize;
|
|
CLIENT_SIDE_FILEVIEW fvw;
|
|
|
|
if (!bMemFont)
|
|
{
|
|
ASSERTGDI(cNumFiles == 1, "bDoFontSubset: cNumFiles != 1\n");
|
|
|
|
if (bMapOK = bMapFileUNICODEClideSide(pwszPathname, &fvw, TRUE))
|
|
{
|
|
pvSrcBuff = (PVOID)fvw.pvView;
|
|
ulSrcSize = fvw.cjView;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pvView = LocalAlloc(LMEM_FIXED, cjView);
|
|
if (pvView)
|
|
{
|
|
if (NtGdiGetUFIPathname(&pBucket->ufi,NULL,NULL,NULL,
|
|
pBucket->fs2,NULL,NULL,pvView,NULL,NULL))
|
|
{
|
|
bMapOK = TRUE;
|
|
pvSrcBuff = (PVOID)pvView;
|
|
ulSrcSize = cjView;
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pvView);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bMapOK)
|
|
{
|
|
// font subsetting
|
|
|
|
ASSERTGDI(gfpCreateFontPackage != NULL, "fonsub.dll is not load\n");
|
|
|
|
if ((*gfpCreateFontPackage)((PUCHAR)pvSrcBuff,
|
|
ulSrcSize,
|
|
ppuchDestBuff,
|
|
pulDestSize,
|
|
pulBytesWritten,
|
|
(USHORT)(bTTC ? 0x000d : 0x0009), // TTFCFP_FLAGS_SUBSET | TTFCFP_FLAGS_GLYPHLIST
|
|
(USHORT)iTTC, // usTTCIndex
|
|
(USHORT)(bDelta ? 2 : 1), // usSubsetFormat
|
|
0, // usSubsetLanguage
|
|
3, // usSubsetPlatform TTFCFP_MS_PLATFORMID
|
|
0xFFFF, // usSubsetEncoding TTFCFP_DONT_CARE
|
|
pusSubsetKeepList,
|
|
(USHORT)cSubset,
|
|
(CFP_ALLOCPROC)AllocCallback,
|
|
(CFP_REALLOCPROC)ReAllocCallback,
|
|
(CFP_FREEPROC)FreeCallback,
|
|
NULL) != 0)
|
|
{
|
|
WARNING("bDofontSubset failed on gfpCreateFontPackage\n");
|
|
}
|
|
else
|
|
{
|
|
if (bDelta) // clean up the u.ssi.pjDelta and u.ssi.cDeltaGlyphs
|
|
{
|
|
LocalFree(pBucket->u.ssi.pjDelta);
|
|
pBucket->u.ssi.pjDelta = NULL;
|
|
pBucket->u.ssi.cDeltaGlyphs = 0;
|
|
}
|
|
else // set fs1 to prepare for the next page.
|
|
{
|
|
pBucket->fs1 = FLUFI_DELTA;
|
|
}
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
if (bMemFont)
|
|
{
|
|
LocalFree(pvView);
|
|
}
|
|
else
|
|
{
|
|
vUnmapFileClideSide(&fvw);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDoFontSubset: failed on bMapFileUNICODEClideSide()\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDoFontSubset: failed on NtGdiGetUFIPathname()\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("bDoFontSubset: failed on bGetDistGlyphIndices()\n");
|
|
}
|
|
|
|
LocalFree(pusSubsetKeepList);
|
|
|
|
//Timing code
|
|
#ifdef DBGSUBSET
|
|
if (gflSubset & FL_SS_SUBSETTIME)
|
|
{
|
|
GetSystemTimeAsFileTime(&fileTimeEnd);
|
|
DbgPrint("\t%ld",
|
|
(fileTimeEnd.dwLowDateTime - fileTimeStart.dwLowDateTime) / 10000);
|
|
}
|
|
#endif
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/************************************************************************************
|
|
* BOOL WriteSubFontToSpoolFile(HANDLE, PUCHAR, ULONG, UNIVERSAL_FONT_ID, BOOL)
|
|
*
|
|
* Write subsetted font or a delta in the print spool file.
|
|
*
|
|
* History
|
|
* Jan-09-97 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*
|
|
*************************************************************************************/
|
|
BOOL WriteSubFontToSpoolFile(
|
|
PLDC pldc,
|
|
PUCHAR puchBuff, // image pointer
|
|
ULONG ulBytesWritten, // bytes to be written to spool file
|
|
UNIVERSAL_FONT_ID *pufi, // ufi of the original font file
|
|
BOOL bDelta // delta or first page
|
|
)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
#ifdef DBGSUBSET
|
|
FILETIME fileTimeStart, fileTimeEnd;
|
|
if (gflSubset & FL_SS_SPOOLTIME)
|
|
{
|
|
GetSystemTimeAsFileTime(&fileTimeStart);
|
|
}
|
|
#endif
|
|
|
|
if (ulBytesWritten)
|
|
{
|
|
DWORD ulID = bDelta ? EMRI_DELTA_FONT : EMRI_SUBSET_FONT;
|
|
|
|
#ifdef DBGSUBSET
|
|
if (gflSubset & FL_SS_BUFFSIZE)
|
|
{
|
|
DbgPrint("\t%ld\n", ulBytesWritten);
|
|
}
|
|
#endif // DBGSUBSET
|
|
|
|
if (WriteFontDataAsEMFComment(
|
|
pldc,
|
|
ulID,
|
|
pufi,
|
|
sizeof(UNIVERSAL_FONT_ID),
|
|
puchBuff,
|
|
ulBytesWritten))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("WriteSubFontToSpooler: error writing to printer\n");
|
|
}
|
|
|
|
LocalFree(puchBuff);
|
|
}
|
|
else
|
|
{
|
|
WARNING("WriteSubFontToSpooler: input ulBytesWritten == 0\n");
|
|
}
|
|
|
|
//timing code
|
|
#ifdef DBGSUBSET
|
|
if (gflSubset & FL_SS_SPOOLTIME)
|
|
{
|
|
GetSystemTimeAsFileTime(&fileTimeEnd);
|
|
DbgPrint("\t%ld", (fileTimeEnd.dwLowDateTime - fileTimeStart.dwLowDateTime) / 10000);
|
|
}
|
|
#endif
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
/************************************************************************************
|
|
* BOOL bMergeSubsetFont(HDC, PVOID, ULONG, PVOID*, ULONG*, BOOL, UNIVERSAL_FONT_ID*)
|
|
*
|
|
* Merge the font delta into a working font containing pages up to this one.
|
|
* This routine is only called on print server
|
|
*
|
|
* History
|
|
* Jan-12-97 Xudong Wu [tessiew]
|
|
* Wrote it.
|
|
*
|
|
*************************************************************************************/
|
|
BOOL bMergeSubsetFont(
|
|
HDC hdc,
|
|
PVOID pvBuf,
|
|
ULONG ulBuf,
|
|
PVOID* ppvOutBuf,
|
|
ULONG* pulOutSize,
|
|
BOOL bDelta,
|
|
UNIVERSAL_FONT_ID *pufi)
|
|
{
|
|
PLDC pldc;
|
|
PBYTE pjBase;
|
|
ULONG ulMergeBuf, ulBytesWritten, ulBaseFontSize = 0;
|
|
PVOID pvMergeBuf, pvBaseFont = NULL;
|
|
UFIHASH *pBucket = NULL;
|
|
BOOL bRet = FALSE;
|
|
|
|
#define SZDLHEADER ((sizeof(DOWNLOADFONTHEADER) + 7)&~7)
|
|
|
|
ENTERCRITICALSECTION(&semLocal);
|
|
bRet = bInitSubsetterFunctionPointer((PVOID *)&gfpMergeFontPackage);
|
|
LEAVECRITICALSECTION(&semLocal);
|
|
|
|
if (!bRet)
|
|
return FALSE;
|
|
|
|
// get the orignal UFI
|
|
|
|
*pufi = *(PUNIVERSAL_FONT_ID) pvBuf;
|
|
|
|
pjBase = (PBYTE)pvBuf + sizeof(UNIVERSAL_FONT_ID);
|
|
ulBuf -= sizeof(UNIVERSAL_FONT_ID);
|
|
|
|
pldc = GET_PLDC(hdc);
|
|
|
|
if (pldc == NULL)
|
|
{
|
|
WARNING("bMergeSubsetFont: unable to retrieve pldc\n");
|
|
return FALSE;
|
|
}
|
|
|
|
ASSERTGDI(!pldc->ppUFIHash, "printer server side ppUFIHash != NULL\n");
|
|
ASSERTGDI(!pldc->ppDVUFIHash,"printer server side ppDVUFIHash != NULL\n");
|
|
|
|
// init the hash table if needed
|
|
|
|
if (pldc->ppSubUFIHash == NULL)
|
|
{
|
|
pldc->ppSubUFIHash = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(PUFIHASH) * UFI_HASH_SIZE);
|
|
|
|
if(pldc->ppSubUFIHash == NULL)
|
|
{
|
|
WARNING("bMergeSubsetFont: unable to allocate UFI hash table2\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// for delta merge, get the font image from pBucket->u.mvw.pjMem
|
|
|
|
if (bDelta)
|
|
{
|
|
pBucket = pufihFindUFIEntry(pldc->ppSubUFIHash, pufi, TRUE);
|
|
|
|
if (!pBucket)
|
|
return FALSE;
|
|
|
|
// We need to exclude the DOWNLOADFONTHEADER
|
|
// information from the pBucket->u.mvw.pjMem
|
|
|
|
pvBaseFont = pBucket->u.mvw.pjMem + SZDLHEADER;
|
|
ulBaseFontSize = pBucket->u.mvw.cjMem - SZDLHEADER;
|
|
}
|
|
|
|
if ((*gfpMergeFontPackage)((UCHAR*)pvBaseFont, ulBaseFontSize,
|
|
(PUCHAR)pjBase, ulBuf,
|
|
(PUCHAR*)&pvMergeBuf, &ulMergeBuf, &ulBytesWritten,
|
|
(USHORT) (bDelta ? 2 : 1), //usMode 1=generate font; 2=delta merge
|
|
(CFP_ALLOCPROC)AllocCallback,
|
|
(CFP_REALLOCPROC)ReAllocCallback,
|
|
(CFP_FREEPROC)FreeCallback,
|
|
NULL) != 0)
|
|
{
|
|
WARNING("MergeSubsetFont failed on funsub!MergeFontPackage\n");
|
|
}
|
|
else
|
|
{
|
|
// In order to use FreeFileView when we delete the font after printing,
|
|
// we need a fake DOWNLOADFONTHEADER
|
|
// before we pass the buffer into kenerl for NtGdiAddRemoteFontToDC call.
|
|
|
|
*pulOutSize = SZDLHEADER + ulBytesWritten;
|
|
*ppvOutBuf = (PVOID*)LocalAlloc(LMEM_FIXED, *pulOutSize);
|
|
|
|
if (*ppvOutBuf == NULL)
|
|
{
|
|
WARNING("bMergeSubsetFont failed to alloc memory\n");
|
|
}
|
|
else
|
|
{
|
|
DOWNLOADFONTHEADER *pdfh;
|
|
|
|
pdfh = (DOWNLOADFONTHEADER*)*ppvOutBuf;
|
|
pdfh->Type1ID = 0;
|
|
pdfh->NumFiles = 1;
|
|
pdfh->FileOffsets[0] = ulBytesWritten;
|
|
|
|
RtlCopyMemory((PVOID)((PBYTE)*ppvOutBuf + SZDLHEADER), pvMergeBuf, ulBytesWritten);
|
|
|
|
if (bWriteUFItoDC(pldc->ppSubUFIHash, pufi, pBucket, *ppvOutBuf, *pulOutSize))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
LocalFree(*ppvOutBuf);
|
|
WARNING("bMergeSubsetFont failed on bWriteUFItoDC\n");
|
|
}
|
|
}
|
|
|
|
// pvMergeBuf comes from the merge routine which uses LMEM_MOVEABLE
|
|
// for memory allocation Needs to be freed by the handle.
|
|
|
|
LocalFree(pvMergeBuf);
|
|
}
|
|
|
|
return bRet;
|
|
}
|