/******************************Module*Header*******************************\ * Module Name: pfeobj.cxx * * Non-inline methods for physical font entry objects. * * Created: 30-Oct-1990 09:32:48 * Author: Gilman Wong [gilmanw] * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/ // #pragma warning (disable: 4509) #include "precomp.hxx" #include "flhack.hxx" BOOL bExtendGlyphSet(FD_GLYPHSET **ppfdgIn, FD_GLYPHSET **ppfdgOut); INT __cdecl CompareRoutine(WCHAR *pwc1, WCHAR *pwc2) { return(*pwc1-*pwc2); } /******************************Public*Routine******************************\ * * ULONG cComputeGISET * * similar to cComputeGlyphSet in mapfile.c, computes the number of *(_wcsicmp(pwszFaceName, pFaceName) == 0)* distinct glyph handles in a font and the number of runs, ie. number of * contiguous ranges of glyph handles * * * History: * 03-Aug-1995 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ ULONG cComputeGISET ( USHORT * pgi, ULONG cgi, GISET * pgiset, ULONG cGiRuns ) { ULONG iRun, iFirst, iFirstNext; ULONG cgiTotal = 0, cgiRun; // now compute cRuns if pgiset == 0 and fill the glyphset if pgiset != 0 for (iFirst = 0, iRun = 0; iFirst < cgi; iRun++, iFirst = iFirstNext) { // find iFirst corresponding to the next range. for (iFirstNext = iFirst + 1; iFirstNext < cgi; iFirstNext++) { if ((pgi[iFirstNext] - pgi[iFirstNext - 1]) > 1) break; } // note that this line here covers the case when there are repetitions // in the pgi array. cgiRun = pgi[iFirstNext-1] - pgi[iFirst] + 1; cgiTotal += cgiRun; if (pgiset != NULL) { pgiset->agirun[iRun].giLow = pgi[iFirst]; pgiset->agirun[iRun].cgi = (USHORT) cgiRun; } } // store results if need be if (pgiset != NULL) { ASSERTGDI(iRun == cGiRuns, "gdisrv! iRun != cRun\n"); pgiset->cGiRuns = cGiRuns; // init the sum before entering the loop pgiset->cgiTotal = cgiTotal; } return iRun; } /******************************Public*Routine******************************\ * * bComputeGISET, similar to ComputeGlyphSet, only for gi's * * History: * 03-Aug-1995 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ #include "stdlib.h" VOID vSortPlacebo ( USHORT *pwc, ULONG cChar ) { ULONG i; for (i = 1; i < cChar; i++) { // upon every entry to this loop the array 0,1,..., (i-1) will be sorted INT j; WCHAR wcTmp = pwc[i]; for (j = i - 1; (j >= 0) && (pwc[j] > wcTmp); j--) { pwc[j+1] = pwc[j]; } pwc[j+1] = wcTmp; } } BOOL bComputeGISET(IFIMETRICS * pifi, PFE * ppfe, GISET **ppgiset) { BOOL bRet = TRUE; *ppgiset = NULL; GISET *pgiset; PFEOBJ pfeObj(ppfe); PFFOBJ pffo(pfeObj.pPFF()); PFD_GLYPHSET pfdg = NULL; BOOL bTT = (BOOL)(pffo.hdev() == (HDEV) gppdevTrueType); if (!bTT) { if (!(pfdg = pfeObj.pfdg())) { return FALSE; } } if (bTT || (pfdg->flAccel & (GS_16BIT_HANDLES | GS_8BIT_HANDLES))) { // first check if this is an accelerated case where handles are the same // as glyph indicies ULONG cig = 0; if (pifi->cjIfiExtra > offsetof(IFIEXTRA, cig)) { cig = ((IFIEXTRA *)(pifi + 1))->cig; } if (bTT && (cig == 0)) // most likely a corrupt font { return FALSE; } if (cig) { // one run only from zero to (cig-1); if (pgiset = (GISET*)PALLOCMEM(offsetof(GISET,agirun) + 1 * sizeof(GIRUN),'slgG')) { // now fill in the array of runs pgiset->cgiTotal = cig; pgiset->cGiRuns = 1; pgiset->agirun[0].giLow = 0; pgiset->agirun[0].cgi = (USHORT)cig; // we are done now *ppgiset = pgiset; } else { bRet = FALSE; } } else { // one of the goofy fonts, we will do as before USHORT *pgi, *pgiBegin; // aloc tmp buffer to contain glyph handles of all glyphs in the font if (pgiBegin = (USHORT*)PALLOCMEM(pfdg->cGlyphsSupported * sizeof(USHORT),'slgG')) { pgi = pgiBegin; for (ULONG iRun = 0; iRun < pfdg->cRuns; iRun++) { HGLYPH *phg, *phgEnd; phg = pfdg->awcrun[iRun].phg; if (phg) // non unicode handles { phgEnd = phg + pfdg->awcrun[iRun].cGlyphs; for ( ; phg < phgEnd; pgi++, phg++) *pgi = (USHORT)(*phg); } else // unicode handles { USHORT wcLo = pfdg->awcrun[iRun].wcLow; USHORT wcHi = wcLo + pfdg->awcrun[iRun].cGlyphs - 1; for ( ; wcLo <= wcHi; wcLo++, phg++) *pgi = wcLo; } } // now sort the array of glyph indicies. This array will be mostly // sorted so that our algorithm is efficient qsort((void*)pgiBegin, pfdg->cGlyphsSupported, sizeof(WORD), (int (__cdecl *)(const void *, const void *))CompareRoutine); // once the array is sorted we can easily compute the number of giRuns ULONG cGiRun = cComputeGISET(pgiBegin, pfdg->cGlyphsSupported, NULL, 0); if (pgiset = (GISET*)PALLOCMEM(offsetof(GISET,agirun) + cGiRun * sizeof(GIRUN),'slgG')) { // now fill in the array of runs cComputeGISET(pgiBegin, pfdg->cGlyphsSupported, pgiset, cGiRun); *ppgiset = pgiset; } else { bRet = FALSE; } VFREEMEM(pgiBegin); } else { bRet = FALSE; } } } if (!bTT) pfeObj.vFreepfdg(); return bRet; } // // This is used to give ppfe->pkp something to point to if a driver // error occurs. That way, we won't waste time calling the driver // again. // FD_KERNINGPAIR gkpNothing = { 0, 0, 0 }; static ULONG ulTimerPFE = 0; /******************************Public*Routine******************************\ * VOID PFEOBJ::vDelete() * * * * Destroy the PFE physical font entry object. * * * * History: * * 30-Oct-1990 -by- Gilman Wong [gilmanw] * * Wrote it. * \**************************************************************************/ VOID PFEOBJ::vDelete() { PDEVOBJ pdo(ppfe->pPFF->hdev); // Save driver allocated resources in PFECLEANUP so that we can later // call the driver to free them. if ((ppfe->pifi->jWinCharSet == SYMBOL_CHARSET) && (ppfe->pfdg != NULL) && (ppfe->pfdg->flAccel & GS_EXTENDED)) { VFREEMEM(ppfe->pfdg); } else { if ((ppfe->pfdg != NULL) && PPFNVALID(pdo,Free)) { pdo.Free(ppfe->pfdg, ppfe->idfdg); } } if (PPFNVALID(pdo,Free)) { pdo.Free(ppfe->pifi, ppfe->idifi); if (ppfe->pkp != &gkpNothing) { pdo.Free(ppfe->pkp , ppfe->idkp ); } } ppfe->pfdg = NULL; ppfe->pifi = NULL; ppfe->pkp = NULL; if (ppfe->pgiset) { VFREEMEM(ppfe->pgiset); ppfe->pgiset = NULL; } // Free object memory and invalidate pointer. ppfe = PPFENULL; } /******************************Public*Routine******************************\ * dpNtmi() * * offset to NTMW_INTERNAL within ENUMFONTDATAW, needed in enumeration * * History: * 19-Nov-1996 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ ULONG PFEOBJ::dpNtmi() { ULONG dpRet = DP_NTMI0; if (ppfe->pifi->flInfo & FM_INFO_TECH_MM) { PTRDIFF dpDesVec = 0; DESIGNVECTOR *pdvSrc; if (ppfe->pifi->cjIfiExtra > offsetof(IFIEXTRA, dpDesignVector)) { dpDesVec = ((IFIEXTRA *)(ppfe->pifi + 1))->dpDesignVector; pdvSrc = (DESIGNVECTOR *)((BYTE *)ppfe->pifi + dpDesVec); dpRet += (pdvSrc->dvNumAxes * sizeof(LONG)); } else { DbgPrint("Test it %d %d \n", ppfe->pifi->cjIfiExtra, offsetof(IFIEXTRA, dpDesignVector)); ASSERTGDI(dpDesVec, "dpDesignVector == 0 for mm instance\n"); } } return dpRet; } /******************************Public*Routine******************************\ * * IsAnyCharsetDbcs * * Does this font support any DBCS charset? * * History: * 22-Jun-1998 -by- Bodin Dresevic [BodinD] * Wrote it. \**************************************************************************/ extern "C" BOOL IsAnyCharsetDbcs(IFIMETRICS *pifi) { BOOL bRet = FALSE; if (IS_ANY_DBCS_CHARSET(pifi->jWinCharSet)) return TRUE; if (pifi->dpCharSets) { BYTE *aCharSets = (BYTE *)pifi + pifi->dpCharSets; for ( ;*aCharSets != DEFAULT_CHARSET; aCharSets++) { if (IS_ANY_DBCS_CHARSET(*aCharSets)) { bRet = TRUE; break; } } } return bRet; } /******************************Public*Routine******************************\ * PFEOBG::pfdg() * * If pfdg is NULL then we need to get it from font driver * If pfdg is valid then we only need to return it. * * Return * FD_GLYPHSET * * * History * 08-March-1999 -by- Yung-Jen Tony Tsai [yungt] * Wrote it. \**************************************************************************/ FD_GLYPHSET * PFEOBJ::pfdg() { PFFOBJ pffo(pPFF()); PDEVOBJ pdo(pffo.hdev()); BOOL bFreeTmp = FALSE; FD_GLYPHSET *pfdgTmp = NULL; ULONG_PTR idGlyphSet; GreAcquireSemaphore(ghsemGlyphSet); if (ppfe->pfdg == NULL) { ASSERTGDI(ppfe->cPfdgRef == 0, "PFEOBJ::pfdg is not matched with cRef\n"); GreReleaseSemaphore(ghsemGlyphSet); BOOL bUMPD = pdo.bUMPD(); pfdgTmp = (FD_GLYPHSET *) pdo.QueryFontTree(pffo.dhpdev(), pffo.hff(), iFont(), QFT_GLYPHSET, &idGlyphSet); GreAcquireSemaphore(ghsemGlyphSet); if (pfdgTmp) { if (ppfe->pfdg == NULL) { ppfe->pfdg = pfdgTmp; ppfe->idfdg = idGlyphSet; // For UMPD if (bUMPD) { if (ppfe->pifi->jWinCharSet == SYMBOL_CHARSET) { FD_GLYPHSET *pfdgNew = NULL; if (bExtendGlyphSet(&pfdgTmp, &pfdgNew)) { bFreeTmp = TRUE; ppfe->pfdg = pfdgNew; } } } } else bFreeTmp = TRUE; } } if (ppfe->pfdg) ppfe->cPfdgRef++; GreReleaseSemaphore(ghsemGlyphSet); if (bFreeTmp) { if (PPFNVALID(pdo,Free)) { pdo.Free(pfdgTmp, idGlyphSet); } } return ppfe->pfdg; } extern "C" VOID ttfdFreeGlyphset(ULONG_PTR iFile, ULONG iFace); /******************************Public*Routine******************************\ * PFEOBG::vFreepfdg() * * If pfdg is valid then we free it. * If pfdg is NULL then return. * * Return * VOID * * History * 08-March-1999 -by- Yung-Jen Tony Tsai [yungt] * Wrote it. \**************************************************************************/ VOID PFEOBJ::vFreepfdg() { PFFOBJ pffo(pPFF()); FD_GLYPHSET *pfdgTmp = NULL; ULONG_PTR idGlyphSet; GreAcquireSemaphore(ghsemGlyphSet); ASSERTGDI(ppfe->cPfdgRef, "cRef of pfdg is wrong\n"); ppfe->cPfdgRef--; if (ppfe->cPfdgRef == 0) { if (pffo.hdev() == (HDEV) gppdevTrueType) { ttfdFreeGlyphset(pffo.hff(), iFont()) ; ppfe->pfdg = NULL; } else { PDEVOBJ pdo(pffo.hdev()); if (pdo.bUMPD() && PPFNVALID(pdo,Free)) { if ((ppfe->pifi->jWinCharSet == SYMBOL_CHARSET) && (ppfe->pfdg != NULL) && (ppfe->pfdg->flAccel & GS_EXTENDED)) { VFREEMEM(ppfe->pfdg); } else { pfdgTmp = ppfe->pfdg; idGlyphSet = ppfe->idfdg; } ppfe->pfdg = NULL; } } } GreReleaseSemaphore(ghsemGlyphSet); if (pfdgTmp) { PDEVOBJ pdo(pffo.hdev()); pdo.Free(pfdgTmp, idGlyphSet); } return; } /******************************Public*Routine******************************\ * * PFEOBJ::flFontType() * * Computes the flags defining the type of this font. Allowed flags are * identical to the flType flags returned in font enumeration. * * Return: * The flags. * * History: * 04-Mar-1992 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ FLONG PFEOBJ::flFontType() { FLONG flRet; IFIOBJ ifio(pifi()); // Compute the FontType flags, simulations are irrelevant flRet = ifio.bTrueType() ? TRUETYPE_FONTTYPE : (ifio.bBitmap() ? RASTER_FONTTYPE : 0); // Add the device flag if this is also a device specific font. flRet |= (bDeviceFont()) ? DEVICE_FONTTYPE : 0; // check if this is a postscript font if (pifi()->flInfo & FM_INFO_TECH_TYPE1) { flRet |= FO_POSTSCRIPT; if (pifi()->flInfo & FM_INFO_TECH_MM) flRet |= FO_MULTIPLEMASTER; if (pifi()->flInfo & FM_INFO_TECH_CFF) flRet |= FO_CFF; } if (ppfe->flPFE & PFE_DBCS_FONT) { flRet |= FO_DBCS_FONT; if (ppfe->flPFE & PFE_VERT_FACE) flRet |= FO_VERT_FACE; } return (flRet); } /******************************Public*Routine******************************\ * PFEOBJ::efstyCompute() * * Compute the ENUMFONTSTYLE from the IFIMETRICS. * * Returns: * The ENUMFONTSTYLE of font. Note that EFSTYLE_SKIP and EFSTYLE_OTHER are * not legal return values for this function. These values are used only * to mark fonts for which another font already exists that fills our * category for a given enumeration of a family. * * History: * 04-Aug-1992 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ ENUMFONTSTYLE PFEOBJ::efstyCompute() { IFIOBJ ifio(pifi()); switch (ifio.fsSelection() & (FM_SEL_ITALIC | FM_SEL_BOLD) ) { case FM_SEL_ITALIC: return EFSTYLE_ITALIC; case FM_SEL_BOLD: return EFSTYLE_BOLD; case FM_SEL_ITALIC | FM_SEL_BOLD: return EFSTYLE_BOLDITALIC; default: return EFSTYLE_REGULAR; } } /******************************Public*Routine******************************\ * COUNT PFEOBJ::cKernPairs * * * * Retrieve the pointer to the array of kerning pairs for this font face. * * The kerning pair array is loaded on demand, so it may or may not already * * be cached in the PFE. * * * * Returns: * * Count of kerning pairs. * * * * History: * * Mon 22-Mar-1993 21:31:15 -by- Charles Whitmer [chuckwh] * * WARNING: Never access a pkp (pointer to a kerning pair) without an * * exception handler! The kerning pairs could be living in a file across * * the net or even on removable media. I've added the try-except here. * * * * 29-Oct-1992 -by- Gilman Wong [gilmanw] * * Wrote it. * \**************************************************************************/ COUNT PFEOBJ::cKernPairs(FD_KERNINGPAIR **ppkp) { // // If the pointer cached in the PFE isn't NULL, we already have the answer. // if ( (*ppkp = ppfe->pkp) != (FD_KERNINGPAIR *) NULL ) return ppfe->ckp; // // Create a PFFOBJ. Needed to create driver user object as well as // provide info needed to call driver function. // PFFOBJ pffo(pPFF()); ASSERTGDI(pffo.bValid(), "gdisrv!cKernPairsPFEOBJ(): invalid PPFF\n"); PDEVOBJ pdo(pffo.hdev()); if ( (ppfe->pkp = (FD_KERNINGPAIR*) pdo.QueryFontTree( pffo.dhpdev(), pffo.hff(), ppfe->iFont, QFT_KERNPAIRS, &ppfe->idkp)) == (FD_KERNINGPAIR *) NULL ) { // // Font has no kerning pairs and didn't even bother to send back // an empty list. By setting pointer to a zeroed FD_KERNINGPAIR and // setting count to zero, we will bail out early and avoid calling // the driver. // ppfe->pkp = &gkpNothing; ppfe->ckp = 0; return 0; } // Find the end of the kerning pair array (indicated by a zeroed out // FD_KERNINGPAIR structure). FD_KERNINGPAIR *pkpEnd = ppfe->pkp; // Be careful, the table isn't guaranteed to stay around! __try { while ((pkpEnd->wcFirst) || (pkpEnd->wcSecond) || (pkpEnd->fwdKern)) pkpEnd += 1; } __except (EXCEPTION_EXECUTE_HANDLER) { pkpEnd = ppfe->pkp = &gkpNothing; } // Return the kerning pair pointer. *ppkp = ppfe->pkp; // // Return count (difference between the beginning and end pointers). // //Sundown truncation ASSERT4GB((LONGLONG)(pkpEnd - ppfe->pkp)); return (ppfe->ckp = (ULONG)(pkpEnd - ppfe->pkp)); } /******************************Public*Routine******************************\ * bValidFont * * Last minute sanity checks to prevent a font that may crash the system * from getting in. We're primarily looking for things like potential * divide-by-zero errors, etc. * * History: * 30-Apr-1993 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ BOOL bValidFont(IFIMETRICS *pifi) { BOOL bRet = TRUE; // Em height is used to compute scaling factors. Must not be zero or // divide-by-zero may result. if (pifi->fwdUnitsPerEm == 0) { WARNING("bValidFont(): fwdUnitsPerEm is zero\n"); bRet = FALSE; } // Font height is used to compute scaling factors. Must not be zero or // divide-by-zero may result. if ((pifi->fwdWinAscender + pifi->fwdWinDescender) == 0) { WARNING("bValidFont(): font height is zero\n"); bRet = FALSE; } return bRet; } /******************************Public*Routine******************************\ * BOOL PFEMEMOBJ::bInit * * This function copies data into the PFE from the supplied buffer. The * calling routine should use the PFEMEMOBJ to create a PFE large enough * * History: * 14-Jan-1991 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ BOOL PFEMEMOBJ::bInit ( PPFF pPFF, // handle to root PFF ULONG iFont, // index of font FD_GLYPHSET *pfdg, // ptr to wc-->hg map ULONG_PTR idfdg, // driver ID for wc-->hg map PIFIMETRICS pifi, // ptr to IFIMETRICS ULONG_PTR idifi, // driver ID for IFIMETRICS BOOL bDeviceFont, // mark as device font PUNIVERSAL_FONT_ID pufi, // PFE_UFIMATCH flag for remote printing BOOL bEUDC // mark as EUDC font ) { // Check font's validity. This is not a comprehensive check, but rather // a last minute check for things that may make the engine crash. Each // font/device driver still needs to make an effort to weed out its own // bad fonts. if (!bValidFont(pifi)) { WARNING("PFEMEMOBJ::bInit(): rejecting REALLY bad font\n"); return FALSE; } // init non-table stuff ppfe->pPFF = pPFF; ppfe->iFont = iFont; ppfe->pfdg = pfdg; ppfe->idfdg = idfdg; ppfe->pifi = pifi; ppfe->idifi = idifi; ppfe->pkp = (FD_KERNINGPAIR *) NULL; ppfe->idkp = (ULONG_PTR) NULL; ppfe->ckp = 0; ppfe->flPFE = 0; ppfe->pid = 0; ppfe->tid = 0; ppfe->cPfdgRef = 0; IFIOBJ ifio(ppfe->pifi); if (IsAnyCharsetDbcs(ppfe->pifi)) ppfe->flPFE |= PFE_DBCS_FONT; if (*ifio.pwszFamilyName() == U_COMMERCIAL_AT) ppfe->flPFE |= PFE_VERT_FACE; // for base font attach full axes info, else, do not. ppfe->cjEfdwPFE = ALIGN4(dpNtmi() + CJ_NTMI0); if (pifi->flInfo & FM_INFO_TECH_MM) // if base mm font { PTRDIFF dpAXIW = 0; AXESLISTW *paxlSrc; if (pifi->cjIfiExtra > offsetof(IFIEXTRA, dpAxesInfoW)) { dpAXIW = ((IFIEXTRA *)(pifi + 1))->dpAxesInfoW; paxlSrc = (AXESLISTW *)((BYTE*)pifi + dpAXIW); ppfe->cjEfdwPFE += (paxlSrc->axlNumAxes * sizeof(AXISINFOW)); } else { ASSERTGDI(dpAXIW, "AxesInfoW needed for base MM font\n"); } } ASSERTGDI(ppfe->cjEfdwPFE >= CJ_EFDW0, "cjEfdwPFE problem\n"); if (bDeviceFont) { ppfe->flPFE |= PFE_DEVICEFONT; } else if(pPFF->ppfv && (pPFF->ppfv[0]->pwszPath == NULL)) { // CAUTION: It is enough to check one font only to determine if remote // or memory if (pPFF->flState & PFF_STATE_MEMORY_FONT) { ppfe->flPFE |= PFE_MEMORYFONT; } else { ppfe->flPFE |= PFE_REMOTEFONT; } ppfe->pid = W32GetCurrentPID(); ppfe->tid = (PW32THREAD)PsGetCurrentThread(); } // For remote printing, fonts are added to the public font table with FR_NOT_ENUM and PFE_UFIMATCH // flags set so that other process won't be able to enum or map the fonts. if (pufi) { ppfe->flPFE |= PFE_UFIMATCH; } #ifdef FE_SB if( bEUDC ) { ppfe->flPFE |= PFE_EUDC; } // mark it as a SBCS system font if the facename is right PWSZ pwszFace = ifio.pwszFaceName(); if(pwszFace[0] == '@') { pwszFace += 1; } if(!_wcsicmp(pwszFace,L"SYSTEM") || !_wcsicmp(pwszFace,L"FIXEDSYS") || !_wcsicmp(pwszFace,L"TERMINAL") || ((!_wcsicmp(pwszFace,L"SMALL FONTS") && ifio.lfCharSet() == SHIFTJIS_CHARSET))) { ppfe->flPFE |= PFE_SBCS_SYSTEM; } // Initialize EUDC QUICKLOOKUP Table // // These field was used, if this font is loaded as FaceName/Default linked EUDC. // ppfe->ql.puiBits = NULL; ppfe->ql.wcLow = 1; ppfe->ql.wcHigh = 0; #endif // Record and increment the time stamp. ppfe->ulTimeStamp = ulTimerPFE; InterlockedIncrement((LONG *) &ulTimerPFE); // Precalculate stuff from the IFIMETRICS. ppfe->iOrientation = ifio.lfOrientation(); // Compute UFI stuff if( ifio.TypeOneID() ) { ppfe->ufi.Index = ifio.TypeOneID(); ppfe->ufi.CheckSum = TYPE1_FONT_TYPE; } else { ppfe->ufi.CheckSum = pPFF->ulCheckSum; ppfe->ufi.Index = iFont; if (pufi) { // need to ensure that ufi of this pfe on the server machine is // the same as it used to be on the client. Client side ufi // one of the pfe's corresponding to this font is pointed to by pufi. ppfe->ufi.Index += ((pufi->Index - 1) & ~1); } } // init the GISET if(!bComputeGISET(pifi, ppfe, &ppfe->pgiset)) return FALSE; // initialize cAlt for this family name, the number of entries in font sub // table that point to this fam name. ppfe->cAlt = 0; // only tt fonts with multiple charsets can be multiply enumerated // as being both themselves and whatever font sub table claims they are if (ppfe->pifi->dpCharSets) { PFONTSUB pfs = gpfsTable; PFONTSUB pfsEnd = gpfsTable + gcfsTable; WCHAR awchCapName[LF_FACESIZE]; // Want case insensitive search, so capitalize the name. cCapString(awchCapName, ifio.pwszFamilyName() , LF_FACESIZE); // Scan through the font substitution table for the key string. PWCHAR pwcA; PWCHAR pwcB; for (; pfs < pfsEnd; pfs++) { // Do the following inline for speed: // // if (!wcsncmpi(pwchFacename, pfs->fcsFace.awch, LF_FACESIZE)) // return (pfs->fcsAltFace.awch); // only those entries in the Font Substitution which have the form // face1,charset1=face2,charset2 // where both charset1 and charset2 are valid charsets // count for enumeration purposes. if (!(pfs->fcsAltFace.fjFlags | pfs->fcsFace.fjFlags)) { for (pwcA=awchCapName,pwcB=pfs->fcsAltFace.awch; *pwcA==*pwcB; pwcA++,pwcB++) { if (*pwcA == 0) { ppfe->aiFamilyName[ppfe->cAlt++] = (BYTE)(pfs-gpfsTable); break; } } } } } return TRUE; } BOOL PFEOBJ::bCheckFamilyName(const WCHAR * pwszFaceName, BOOL bIgonreVertical, BOOL *pbAliasMatch) { PWSZ pFaceName; BOOL bRet; if (pbAliasMatch) { *pbAliasMatch = FALSE; } pFaceName = (PWSZ) (((BYTE*) ppfe->pifi) + ppfe->pifi->dpwszFamilyName); if (bIgonreVertical && (*pFaceName == L'@')) pFaceName++; bRet = (_wcsicmp(pwszFaceName, pFaceName) == 0); if (!bRet && (ppfe->pifi->flInfo & FM_INFO_FAMILY_EQUIV)) { pFaceName += (wcslen(pFaceName) + 1); while(!bRet && *pFaceName) { if (bIgonreVertical && (*pFaceName == L'@')) pFaceName++; bRet = (_wcsicmp(pwszFaceName, pFaceName) == 0); pFaceName += (wcslen(pFaceName) + 1); } // for the font mapper only: If match is found among family name aliases, // increase the font mapping penalty if (pbAliasMatch) { *pbAliasMatch = bRet; } } return bRet; } /******************************Public*Routine******************************\ * BOOL PFEOBJ::bFilterNotEnum() * * Used by bFilterOut() in GreEnumOpen(). It checks whether the pfe should * be filtered out because it is either an embedded font or it is loaded to * the system with FR_NOT_ENUM bit set. * * Returns: * TRUE if embedded or FR_NOT_ENUM set, FALSE otherwise. * * History: * * 12-Jun-1996 -by- Xudong Wu [TessieW] * Wrote it. \**************************************************************************/ BOOL PFEOBJ::bFilterNotEnum() { PFFOBJ pffo(pPFF()); ASSERTGDI(pffo.bValid(), "win32k!PFEOBJ::bFilterEmbPvt(): invalid PPFF\n"); PVTDATA *pPvtData; BOOL bRet = TRUE; if (pffo.bInPrivatePFT()) { // Look for a PvtData block for the current process if ((pPvtData = pffo.pPvtDataMatch()) && (pPvtData->cNotEnum == 0)) { bRet = FALSE; } } // public fonts, filter out FR_NOT_ENUM only else if (pffo.cLoaded()) { bRet = FALSE; } return bRet; } /***********************Public*Routine***********************\ * BOOL PFEOBJ::bPrivate() * * Determine whether the pfe is in private PFT table * * History: * * 16-April-1997 -by- Xudong Wu [TessieW] * Wrote it. *************************************************************/ BOOL PFEOBJ::bPrivate() { return (ppfe->pPFF->pPFT == gpPFTPrivate); } /******************************Public*Routine******************************\ * BOOL PFEOBJ::bEmbedOk() * * Determine if the font is added as embedded by the current process * * Returns: * TRUE if the font is added by the current process as embedded font * FALSE otherwise. * * History: * * 24-Sept-1996 -by- Xudong Wu [TessieW] * Wrote it. \**************************************************************************/ BOOL PFEOBJ::bEmbedOk() { PVTDATA *pPvtData; PFFOBJ pffo(pPFF()); ASSERTGDI(pffo.bValid(), "win32k!PFEOBJ::bEmbedOk(): invalid PPFF\n"); ASSERTGDI(pffo.bInPrivatePFT(), "win32k!PFEOBJ::bEmbedOk(): pfe not in private PFT\n"); // embedded font added by the current process if ((pPvtData = pffo.pPvtDataMatch()) && (pPvtData->fl & (FRW_EMB_TID | FRW_EMB_PID))) { return TRUE; } return FALSE; } /******************************Public*Routine******************************\ * BOOL PFEOBJ::bEmbPvtOk() * * Determine whether the current process has right to mapping this font * * Returns: * TRUE pfe in public PFT or * font has been loaded into Private PFT by the current process * * FALSE otherwise * * History: * * 24-Sept-1996 -by- Xudong Wu [TessieW] * Wrote it. \**************************************************************************/ BOOL PFEOBJ::bEmbPvtOk() { PFFOBJ pffo(pPFF()); ASSERTGDI(pffo.bValid(), "win32k!PFEOBJ::bEmbPvtOk(): invalid PPFF\n"); // can't find the current process ID in the PvtData link list if (pffo.bInPrivatePFT() && (pffo.pPvtDataMatch() == NULL)) { return FALSE; } return TRUE; } /******************************Public*Routine******************************\ * HPFEC PFEOBJ::hpfecGet() * * Get the handle of PFE collect, a new object to reduce the consumption of object handle * * Returns: * Hanlde of PFEC object * History: * * 2-June-1996 -by- Yung-Jen Tony Tsai [YungT] * Wrote it. \**************************************************************************/ HPFEC PFEOBJ::hpfecGet() { PFFOBJ pffo(ppfe->pPFF); ASSERTGDI(((HPFEC)pffo.pfec()->hGet()) != HPFEC_INVALID, " PFEOBJ::hpfecGet error\n"); return((HPFEC)pffo.pfec()->hGet()); } /******************************Public*Routine******************************\ * BOOL PFEOBJ::bFilteredOut(EFFILTER_INFO *peffi) * * Determine if this PFE should be rejected from the enumeration. Various * filtering parameters are passed in via the EFFILTER_INFO structure. * * Returns: * TRUE if font should be rejected, FALSE otherwise. * * History: * 07-Aug-1992 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ BOOL PFEOBJ::bFilteredOut(EFFILTER_INFO *peffi) { IFIOBJ ifio(pifi()); // Always filter out "dead" (fonts waiting to be deleted) fonts and "ghost" // fonts. if ( bDead() || ifio.bGhostFont() ) return TRUE; #ifdef FE_SB // Always filter out fonts that have been loaded as EUDC fonts. if( bEUDC() ) return TRUE; #endif // Raster font filtering. if (peffi->bRasterFilter && ifio.bBitmap()) return TRUE; // TrueType font filtering. The flag is somewhat of a misnomer as it // is intended to exclude TrueType, even though the flag is named // bNonTrueTypeFilter. if (peffi->bNonTrueTypeFilter && ifio.bTrueType()) return(TRUE); // Non-TrueType font filtering. The flag is somewhat of a misnomer as it // is intended to exclude non-TrueType, even though the flag is named // bTrueTypeFilter. if (peffi->bTrueTypeFilter && !ifio.bTrueType()) return TRUE; // Aspect ratio filtering. If an engine bitmap font, we will filter out // unsuitable resolutions. if ( peffi->bAspectFilter && (!bDeviceFont()) && ifio.bBitmap() && ( (peffi->ptlDeviceAspect.x != ifio.pptlAspect()->x) || (peffi->ptlDeviceAspect.y != ifio.pptlAspect()->y) ) ) return TRUE; // GACF_TTIGNORERASTERDUPE compatibility flag filtering. // If any raster fonts exist in the same list as a TrueType font, then // they should be excluded. if ( peffi->bTrueTypeDupeFilter && peffi->cTrueType && ifio.bBitmap()) return TRUE; // Filter out embedded fonts or the fonts with FR_NOT_ENUM bit set. if (bFilterNotEnum()) return TRUE; // In the case of a Generic text driver we must filter out all engine fonts if( ( peffi->bEngineFilter ) && !bDeviceFont() ) { return(TRUE); } // if this is a remote/memory font we don't want to enumerate it if( ppfe->flPFE & (PFE_REMOTEFONT | PFE_MEMORYFONT) ) { return(TRUE); } // finally check out if the font should be eliminated from the // enumeration because it does not contain the charset requested: if (peffi->lfCharSetFilter != DEFAULT_CHARSET) { // the specific charset has been requested, let us see if the font // in question supports it: BYTE jCharSet = jMapCharset((BYTE)peffi->lfCharSetFilter, *this); if (jCharSet != (BYTE)peffi->lfCharSetFilter) return TRUE; // does not support it, filter this font out. } // Passed all tests. return FALSE; } #if DBG /******************************Public*Routine******************************\ * VOID PFEOBJ::vDump () * * Debugging code. * * History: * 25-Feb-1991 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ VOID PFEOBJ::vPrint() { IFIOBJ ifio(pifi()); DbgPrint("\nContents of PFE, PPFE = 0x%p\n", ppfeGet()); DbgPrint("pPFF = 0x%p\n", ppfe->pPFF); DbgPrint("iFont = 0x%lx\n", ppfe->iFont); DbgPrint("lfHeight = 0x%x\n", ifio.lfHeight()); DbgPrint( "Family Name = %ws\n", ifio.pwszFamilyName() ); DbgPrint( "Face Name = %ws\n", ifio.pwszFaceName() ); DbgPrint( "Unique Name = %s\n\n", ifio.pwszUniqueName() ); } /******************************Public*Routine******************************\ * VOID PFEOBJ::vDumpIFI () * * Debugging code. Prints PFE header and IFI metrics. * \**************************************************************************/ VOID PFEOBJ::vPrintAll() { DbgPrint("\nContents of PFE, PPFE = 0x%p\n", ppfeGet()); DbgPrint("pPFF = 0x%p\n", ppfe->pPFF); DbgPrint("iFont = 0x%p\n", ppfe->iFont); DbgPrint("IFI Metrics\n"); vPrintIFIMETRICS(ppfe->pifi); DbgPrint("\n"); } #endif /******************************Public*Routine******************************\ * EFSMEMOBJ::EFSMEMOBJ(COUNT cefe) * * Constructor for font enumeration state (EFSTATE) memory object. * * History: * 07-Aug-1992 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ EFSMEMOBJ::EFSMEMOBJ(COUNT cefe, ULONG iEnumType_) { fs = 0; pefs = (PEFSTATE) HmgAlloc((offsetof(EFSTATE, aefe) + cefe * sizeof(EFENTRY)), EFSTATE_TYPE, HMGR_ALLOC_LOCK); if (pefs != PEFSTATENULL) { vInit(cefe, iEnumType_); } } /******************************Public*Routine******************************\ * EFSMEMOBJ::~EFSMEMOBJ() * * Destructor for font enumeration state (EFSTATE) memory object. * * History: * 07-Aug-1992 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ EFSMEMOBJ::~EFSMEMOBJ() { // If object pointer not null, try to free the object's memory. if (pefs != PEFSTATENULL) { if (fs & EFSMO_KEEPIT) { DEC_EXCLUSIVE_REF_CNT(pefs); } else { #if DBG if (pefs->cExclusiveLock != 1) { RIP("Not 1 EFSMEMOBJ\n"); } #endif HmgFree((HOBJ) pefs->hGet()); } pefs = NULL; } } #define EFS_QUANTUM 16 /******************************Public*Routine******************************\ * BOOL EFSOBJ::bGrow * * Expand the EFENTRY table by the quantum amount. * * Returns: * TRUE if successful, FALSE if failed. * * History: * 07-Aug-1992 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ BOOL EFSOBJ::bGrow (COUNT cefeMinIncrement) { COUNT cefe; BOOL bRet = FALSE; // Allocate a new EFSTATE bigger by the quantum amount. cefe = (COUNT) (pefs->pefeBufferEnd - pefs->aefe); if (cefeMinIncrement < EFS_QUANTUM) cefeMinIncrement = EFS_QUANTUM; cefe += cefeMinIncrement; EFSMEMOBJ efsmo(cefe, this->pefs->iEnumType); // Validate new EFSTATE. if (efsmo.bValid()) { // Copy the enumeration table. efsmo.vXerox(pefs); // Swap the EFSTATEs. if (HmgSwapHandleContents((HOBJ) hefs(),0,(HOBJ) efsmo.hefs(),0,EFSTATE_TYPE)) { // swap pointers PEFSTATE pefsTmp = pefs; pefs = efsmo.pefs; efsmo.pefs = pefsTmp; // destructor will delete old PFT bRet = TRUE; } else WARNING("gdisrv!bGrowEFSOBJ(): handle swap failed\n"); } else WARNING("bGrowEFSOBJ failed alloc\n"); return(bRet); } /******************************Public*Routine******************************\ * BOOL EFSOBJ::bAdd * * * * Add a new EFENTRY to the table with the HPFE and ENUMFONTSTYLE. * * * * Returns: * * FALSE if an error occurs, TRUE otherwise. * * * * History: * * 07-Aug-1992 -by- Gilman Wong [gilmanw] * * Wrote it. * \**************************************************************************/ BOOL EFSOBJ::bAdd(PFE *ppfe, ENUMFONTSTYLE efsty, FLONG fl, ULONG lfCharSetFilter) { // Check if the buffer needs to be expanded. COUNT cefeMinIncrement = 1; // will always enumerate at least one pfe // if EnumFontFamilies is called, will enumerate the font under cAlt more names if (!(fl & FL_ENUMFAMILIESEX)) cefeMinIncrement += ppfe->cAlt; // if EnumFontFamiliesEx is called, and this font supports multiple charsets, // this font will be enumerated no more than MAXCHARSETS times. if ( (fl & FL_ENUMFAMILIESEX) && (lfCharSetFilter == DEFAULT_CHARSET) && ppfe->pifi->dpCharSets ) { cefeMinIncrement = MAXCHARSETS; } if ((pefs->pefeDataEnd + cefeMinIncrement) >= pefs->pefeBufferEnd) { if (!bGrow(cefeMinIncrement)) { // Error code will be saved for us. WARNING("gdisrv!EFSOBJ__bAdd: cannot grow enumeration table\n"); return FALSE; } } // Add the new data and increment the data pointer. PFEOBJ pfeo(ppfe); HPFEC hpfec = pfeo.hpfecGet(); ULONG iFont = ppfe->iFont; pefs->pefeDataEnd->hpfec = hpfec; pefs->pefeDataEnd->iFont = iFont; pefs->pefeDataEnd->efsty = efsty; pefs->pefeDataEnd->fjOverride = 0; // do not override if (fl & FL_ENUMFAMILIESEX) pefs->pefeDataEnd->fjOverride |= FJ_CHARSETOVERRIDE; pefs->pefeDataEnd->jCharSetOverride = (BYTE)lfCharSetFilter; pefs->pefeDataEnd += 1; pefs->cjEfdwTotal += ppfe->cjEfdwPFE; // now check if called from EnumFonts or EnumFontFamilies so that the // names from the // [FontSubstitutes] section in the registry also need to be enumerated if (!(fl & FL_ENUMFAMILIESEX) && ppfe->cAlt) // alt names have to be enumerated too { for (ULONG i = 0; i < ppfe->cAlt; i++) { // the same hpfe, style etc. all the time, only lie about the name and charset pefs->pefeDataEnd->hpfec = hpfec; pefs->pefeDataEnd->iFont = iFont; pefs->pefeDataEnd->efsty = efsty; pefs->pefeDataEnd->fjOverride = (FJ_FAMILYOVERRIDE | FJ_CHARSETOVERRIDE); // do override pefs->pefeDataEnd->iOverride = ppfe->aiFamilyName[i]; pefs->pefeDataEnd->jCharSetOverride = gpfsTable[pefs->pefeDataEnd->iOverride].fcsFace.jCharSet; pefs->pefeDataEnd += 1; pefs->cjEfdwTotal += ppfe->cjEfdwPFE; } } // now see if this is called from EnumFontFamiliesEx if ((fl & FL_ENUMFAMILIESEX) && (lfCharSetFilter == DEFAULT_CHARSET)) { // The font needs to be enumerated once for every charset it supports if (ppfe->pifi->dpCharSets) { BYTE *ajCharSets = (BYTE*)ppfe->pifi + ppfe->pifi->dpCharSets; BYTE *ajCharSetsEnd = ajCharSets + MAXCHARSETS; // first fix up the one entry we just filled above (pefs->pefeDataEnd-1)->jCharSetOverride = ajCharSets[0]; // this is from win95-J sources: #define FEOEM_CHARSET 254 for ( BYTE *pjCharSets = ajCharSets + 1; // skip the first one, used already (*pjCharSets != DEFAULT_CHARSET) && (*pjCharSets != OEM_CHARSET) && (*pjCharSets != FEOEM_CHARSET) && (pjCharSets < ajCharSetsEnd) ; pjCharSets++ ) { // the same hpfe, style etc. all the time, only lie about the name and charset pefs->pefeDataEnd->hpfec = hpfec; pefs->pefeDataEnd->iFont = iFont; pefs->pefeDataEnd->efsty = efsty; pefs->pefeDataEnd->fjOverride = FJ_CHARSETOVERRIDE; pefs->pefeDataEnd->iOverride = 0; pefs->pefeDataEnd->jCharSetOverride = *pjCharSets; pefs->pefeDataEnd += 1; pefs->cjEfdwTotal += ppfe->cjEfdwPFE; } } else // fix up the one entry we just filled above { (pefs->pefeDataEnd-1)->jCharSetOverride = ppfe->pifi->jWinCharSet; } } // Success. return TRUE; } /******************************Public*Routine******************************\ * VOID EFSOBJ::vDelete () * * Destroy the font enumeration state (EFSTATE) memory object. * * History: * 07-Aug-1992 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ VOID EFSOBJ::vDeleteEFSOBJ() { HmgFree((HOBJ) pefs->hGet()); pefs = PEFSTATENULL; } /******************************Member*Function*****************************\ * VOID EFSMEMOBJ::vInit * * Initialize the EFSTATE object. * * History: * 07-Aug-1992 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ VOID EFSMEMOBJ::vInit(COUNT cefe, ULONG iEnumType_) { // HPFE array empty, so initialize all pointer to the beginning of the array. pefs->pefeDataEnd = pefs->aefe; pefs->pefeEnumNext = pefs->aefe; // Except for this one. Set this one to the end of the buffer. pefs->pefeBufferEnd = &pefs->aefe[cefe]; // Initialize the alternate name to NULL. pefs->pfsubOverride = NULL; // init the enum type: pefs->iEnumType = iEnumType_; // empty for now, total enumeration data size is zero pefs->cjEfdwTotal = 0; // We don't need to bother with initializing the array. } /******************************Public*Routine******************************\ * VOID EFSMEMOBJ::vXerox(EFSTATE *pefeSrc) * * Copy the EFENTRYs from the source EFSTATE's table into this EFSTATE's table. * The internal pointers will be updated to be consistent with the data. * * History: * 07-Aug-1992 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ VOID EFSMEMOBJ::vXerox(EFSTATE *pefsSrc) { // // Compute size of the table. // // Sundown truncation ASSERT4GB ((ULONGLONG)(pefs->pefeDataEnd - pefs->aefe)); COUNT cefe = (COUNT)(pefsSrc->pefeDataEnd - pefsSrc->aefe); ASSERTGDI ( cefe >= (COUNT)(pefs->pefeDataEnd - pefs->aefe), "gdisrv!vXeroxEFSMEMOBJ(): table to small\n" ); // // Copy entries. // RtlCopyMemory((PVOID) pefs->aefe, (PVOID) pefsSrc->aefe, (SIZE_T) cefe * sizeof(EFENTRY)); // Fixup the data pointer and size of enumeration data pefs->pefeDataEnd = pefs->aefe + cefe; pefs->cjEfdwTotal = pefsSrc->cjEfdwTotal; // iEnumType has been set at the vInit time, it does not have to be reset now. // Therefore we are done. } /******************************Public*Routine******************************\ * bSetEFSTATEOwner * * Set the owner of the EFSTATE * * if the owner is set to OBJECTOWNER_NONE, this EFSTATE will not be useable * until bSetEFSTATEOwner is called to explicitly give the lfnt to someone else. * * History: * 07-Aug-1992 by Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ BOOL bSetEFSTATEOwner( HEFS hefs, W32PID lPid) { if (lPid == OBJECT_OWNER_CURRENT) { lPid = W32GetCurrentPID(); } return HmgSetOwner((HOBJ) hefs, lPid, EFSTATE_TYPE); } /******************************Public*Routine******************************\ * BOOL bSetFontXform * * Sets the FD_XFORM such that it can be used to realize the physical font * with the dimensions specified in the wish list coordinates). The * World to Device xform (with translations removed) is also returned. * * Returns: * TRUE if successful, FALSE if an error occurs. * * History: * Tue 27-Oct-1992 23:18:39 by Kirk Olynyk [kirko] * Moved it from PFEOBJ.CXX * 19-Sep-1991 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ BOOL PFEOBJ::bSetFontXform ( XDCOBJ &dco, // realize for this device LOGFONTW *pelfw, // wish list (in logical coords) PFD_XFORM pfd_xf, // font transform FLONG fl, FLONG flSim, POINTL* const pptlSim, IFIOBJ& ifio, BOOL bIsLinkedFont // TRUE if the font is linked, FALSE otherwise ) { BOOL bRet; EXFORMOBJ xo(dco, WORLD_TO_DEVICE); // synchronize the transformation if(dco.pdc->iGraphicsMode() == GM_COMPATIBLE) { bRet = bGetNtoD_Win31( pfd_xf, pelfw, ifio, (DCOBJ *)&dco, fl, pptlSim, bIsLinkedFont ); } else // GM_ADVANCED { bRet = bGetNtoD( pfd_xf, pelfw, ifio, (DCOBJ *)&dco, pptlSim ); } if (!bRet) { WARNING( "gdisrv!bSetFontXformPFEOBJ(): failed to get Notional to World xform\n" ); return FALSE; } // // The next line two lines of code flips the sign of the Notional y-coordinates // The effect is that the XFORMOBJ passed over the DDI makes the assumption that // Notional space is such that the y-coordinate increases towards the bottom. // This is opposite to the usual conventions of notional space and the font // driver writers must be made aware of this historical anomaly. // NEGATE_IEEE_FLOAT(pfd_xf->eYX); NEGATE_IEEE_FLOAT(pfd_xf->eYY); // // If the font can be scaled isotropicslly only then we make sure that we send // to the font driver isotropic transformations. // // If a device has set the TA_CR_90 bit, then it is possible // that we will send to the driver a transformation that is equivalent to an isotropic // transformation rotated by a multiple of 90 degress. This is the reason for the // second line of this transformation. // if (ifio.bIsotropicScalingOnly()) { *(LONG*)&(pfd_xf->eXX) = *(LONG*)&(pfd_xf->eYY); *(LONG*)&(pfd_xf->eXY) = *(LONG*)&(pfd_xf->eYX); NEGATE_IEEE_FLOAT(pfd_xf->eXY); } return (TRUE); } /******************************Public*Routine******************************\ * PFE * PFECOBJ::GetPFE(ULONG iFont) * * Get PFE from PFE collect, a new object to reduce the consumption of object handle * * Returns: * memory pointer of PFE * History: * * 2-June-1996 -by- Yung-Jen Tony Tsai [YungT] * Wrote it. \**************************************************************************/ PFE * PFECOBJ::GetPFE(ULONG iFont) { PFE * ppfe = NULL; if (ppfec) { ASSERTGDI(ppfec->pvPFE, "PFECOBJ::GetPFE ppfset->pvPFE is null \n"); ppfe = (PFE *) ((PBYTE) ppfec->pvPFE + ((iFont - 1) * ppfec->cjPFE)); } return ppfe; } /******************************Public*Routine******************************\ * HPFEC PFECOBJ::GetHPFEC() * * Get handle of PFEC from PFE collect, a new object to reduce the consumption of object handle * * Returns: * Handle of PFEC * History: * * 2-June-1996 -by- Yung-Jen Tony Tsai [YungT] * Wrote it. \**************************************************************************/ HPFEC PFECOBJ::GetHPFEC() { ASSERTGDI(ppfec, "PFECOBJ::GetHPFEC ppfec is NULL \n"); return((HPFEC) ppfec->hGet()); }