|
|
/******************************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; }
|