Leaked source code of windows server 2003
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

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