/*++ Copyright (c) 1996 - 1999 Microsoft Corporation Module Name: fmcallbk.c Abstract: The font module callback helper functions Environment: Windows NT Unidrv driver Revision History: 03/31/97 -eigos- Created --*/ #include "font.h" #define CALL_OEMOUTPUTCHARSTR(type, count, startpoint) \ if(bCOMInterface) \ { \ HComOutputCharStr((POEM_PLUGIN_ENTRY)pPDev->pOemEntry, \ &pPDev->devobj, \ (PUNIFONTOBJ)pUFObj, \ (type), \ (count), \ (startpoint)); \ } \ else \ { \ if (pfnOEMOutputCharStr) \ pfnOEMOutputCharStr(&pPDev->devobj, \ (PUNIFONTOBJ)pUFObj, \ (type), \ (count), \ (startpoint)); \ } #define GET_CHARWIDTH(width, pfontmap, hg) \ if (pfontmap->flFlags & FM_WIDTHRES) \ { \ if (!(width = IGetUFMGlyphWidth(pPDev, pfontmap, hg))) \ width = (INT)pIFIMet->fwdAveCharWidth; \ } \ else \ { \ if (pTrans[hg - 1].ubType & MTYPE_DOUBLE) \ width = pIFIMet->fwdMaxCharInc; \ else \ width = pIFIMet->fwdAveCharWidth; \ } \ if (pfontmap->flFlags & FM_SCALABLE) \ { \ width = LMulFloatLong(&pFontPDev->ctl.eXScale,width); \ } // // Local functions' prototype definition // WCHAR WGHtoUnicode( DWORD dwNumOfRuns, PGLYPHRUN pGlyphRun, HGLYPH hg); // // UNIFONTOBJ callback interface // BOOL UNIFONTOBJ_GetInfo( IN PUNIFONTOBJ pUFObj, IN DWORD dwInfoID, IN PVOID pData, IN DWORD dwDataSize, OUT PDWORD pcbNeeded) /*++ Routine Description: Implementation of UNIFONTOBJ GetInfo function Please refer to DDK Arguments: pUFOBj - a pointer to UNIFONTOBJ dwInfoID - Function ID pData - a pointer to data structure according to dwInfoID dwDataSize - size of pData pcbNeeded - DWORD buffer to return the necessary size of pData Return Value: TRUE if successful, otherwise FALSE. Note: --*/ { PI_UNIFONTOBJ pI_UFObj = (PI_UNIFONTOBJ)pUFObj; GETINFO_GLYPHSTRING* pGlyphString; GETINFO_GLYPHBITMAP* pGlyphBitmap; GETINFO_GLYPHWIDTH* pGlyphWidth; GETINFO_STDVAR* pStdVar; PFONTPDEV pFontPDev; PUNI_GLYPHSETDATA pGlyphData; PTRANSDATA pTrans, pTransOut, pTransOutStart; PMAPTABLE pMapTable; PGLYPHRUN pGlyphRun; HGLYPH *pHGlyph; PDLGLYPH *apdlGlyph; PBYTE pbString, pbOutput; LONG *plWidth, lBuffSize; DWORD *pGlyphID, dwI, dwJ; WCHAR *pUnicode; DWORD dwNumOfVar, dwCount, dwSVID, dwNumOfRuns, dwBuffSize; BOOL bRet; static STDVARIABLE FontStdVariable[FNT_INFO_MAX] = { SV_PRINTDIRECTION, SV_GRAYPERCENT, SV_NEXTFONTID, SV_NEXTGLYPH, SV_FONTHEIGHT, SV_FONTWIDTH, SV_FONTBOLD, SV_FONTITALIC, SV_FONTUNDERLINE, SV_FONTSTRIKETHRU, SV_CURRENTFONTID, SV_TEXTYRES, SV_TEXTXRES, SV_FONTMAXWIDTH }; // // Error check // if (!pI_UFObj ) { ERR(("UNIFONTOBJ_GetInfo(): pUFObj is NULL.\n")); return FALSE; } if (!pData) // // pData == NULL case // Return the necessary buffer size // { bRet = TRUE; if (!pcbNeeded) { ERR(("UNIFONTOBJ_GetInfo(): pData and pcbNeed is NULL.\n")); bRet = FALSE; } else { switch (dwInfoID) { case UFO_GETINFO_FONTOBJ: *pcbNeeded = sizeof(GETINFO_FONTOBJ); break; case UFO_GETINFO_GLYPHSTRING: *pcbNeeded = sizeof(GETINFO_GLYPHSTRING); break; case UFO_GETINFO_GLYPHBITMAP: *pcbNeeded = sizeof(GETINFO_GLYPHBITMAP); break; case UFO_GETINFO_GLYPHWIDTH: *pcbNeeded = sizeof(GETINFO_GLYPHWIDTH); break; case UFO_GETINFO_MEMORY: *pcbNeeded = sizeof(GETINFO_MEMORY); break; case UFO_GETINFO_STDVARIABLE: *pcbNeeded = sizeof(GETINFO_STDVAR); break; default: *pcbNeeded = 0; bRet = FALSE; VERBOSE(("UNIFONTOBJ_GetInfo(): Invalid dwInfoID.\n")); break; } } } else { bRet = FALSE; // // ERROR CHECK LIST // (A) Data structure size check // GETINFO_FONTOBJ // GETINFO_GLYPHYSTRING // GETINFO_GLYPHBITMAP // GETINFO_GLYPHWIDTH // GETINFO_MEORY // GETNFO_STDVARIABLE // (B) Necessary data pointer check // e.g. pI_UFObj->XXXX // switch (dwInfoID) { case UFO_GETINFO_FONTOBJ: // // Return FONTOBJ data in GETINFO_FONTOBJ // typedef struct _GETINFO_FONTOBJ { // DWORD dwSize; // Size of this structure // FONTOBJ *pFontObj; // Pointer to the FONTOBJ // } GETINFO_FONTOBJ, *PGETINFO_FONTOBJ; // // ERROR CHECK // (A) and (B) // (B) pI_UFObj->pFontObj // if (((GETINFO_FONTOBJ*)pData)->dwSize != sizeof(GETINFO_FONTOBJ) || !pI_UFObj->pFontObj) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_FONTOBJ): pData or pUFObj is invalid.\n")); break; } ((GETINFO_FONTOBJ*)pData)->pFontObj = pI_UFObj->pFontObj; bRet = TRUE; break; case UFO_GETINFO_GLYPHSTRING: // // Return glyph string // // typedef struct _GETINFO_GLYPHSTRING { // DWORD dwSize; // Size of this structure // DWORD dwCount; // Count of glyphs in pGlyphIn // DWORD dwTypeIn; // Glyph type of pGlyphIn, TYPE_GLYPHID/TYPE_HANDLE. // PVOID pGlyphIn; // Pointer to the input glyph string // DWORD dwTypeOut; // Glyph type of pGlyphOut, TYPE_UNICODE/TYPE_TRANSDATA. // PVOID pGlyphOut; // Pointer to the output glyph string // DWORD dwGlyphOutSize; // The size of pGlyphOut buffer // } GETINFO_GLYPHSTRING, *PGETINFO_GLYPHSTRING; // // // OutputGlyph callback function receives // 1. GLYPH HANLDE for Device font // 2. GLYPH ID for TrueType font // // In TYPE_GLYPHHANDLE (Device font) // Out TYPE_UNICODE // TYPE_TRANSDATA // // In TYPE_GLYPHID (TrueType font) // Out TYPE_UNICODE // Out TYPE_GLYPHHANDLE // // TYPE_TRANSDATA conversion> // TRANSDATA could have MTYPE_COMPOSE so that UNIDRV doesn't know the size of output buffer. // At the first call, a minidriver sets 0 to dwGlyphOutSize. // Then UNIDRV returns necessary buffer size in dwGlyphOutSize. // At the second call, a minidriver allocates memory, set the pointer of it to pGlyphOut, // and set the size to dwGlyphOutSize. // // pGlyphString = pData; dwCount = pGlyphString->dwCount; if (!dwCount) { // // No operation is necessary. // break; } // // ERROR CHECK (A) // pGlyphString // if ( !pGlyphString->pGlyphIn || pGlyphString->dwTypeOut != TYPE_TRANSDATA && !pGlyphString->pGlyphOut ) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_FONTOBJ): pData is invalid.\n")); break; } // // Now we support type size of GETINFO_GLYPHSTRING. // This is a bug backward compatibility. // Before beta 3 GETINFO_GLYPHSTRING didn't have dwGlyphOutSize. // Now we have new data structure but don't change the name of // structure. // if (!( (pGlyphString->dwSize == sizeof(GETINFO_GLYPHSTRING)) || (pGlyphString->dwSize == sizeof(GETINFO_GLYPHSTRING) - sizeof(DWORD)) ) ) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_FONTOBJ): pData is invalid.\n")); break; } // // ERROR CHECK (B) // pI_UFObj->pFontMap // pI_UFObj->pPDev // if (!pI_UFObj->pFontMap || !pI_UFObj->pPDev) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_FONTOBJ): pUFObj is invalid.\n")); break; } switch(pGlyphString->dwTypeIn) { case TYPE_GLYPHHANDLE: // // Device font case // if ( pI_UFObj->pFontMap->dwFontType == FMTYPE_DEVICE ) { pHGlyph = pGlyphString->pGlyphIn; pGlyphData = ((PFONTMAP_DEV)pI_UFObj->pFontMap->pSubFM)->pvNTGlyph; dwNumOfRuns = pGlyphData->dwRunCount; switch(pGlyphString->dwTypeOut) { case TYPE_UNICODE: pUnicode = pGlyphString->pGlyphOut; pGlyphRun = GET_GLYPHRUN(pGlyphData); while (dwCount--) { *pUnicode++ = WGHtoUnicode(dwNumOfRuns, pGlyphRun, *pHGlyph++); } bRet = TRUE; break; case TYPE_TRANSDATA: pTransOutStart = pTransOut = pGlyphString->pGlyphOut; pMapTable = GET_MAPTABLE(pGlyphData); pTrans = pMapTable->Trans; dwBuffSize = pGlyphString->dwGlyphOutSize; // // New version of GETINFO_GLYPYSTRING // if ( pGlyphString->dwSize == sizeof(GETINFO_GLYPHSTRING) ) { if (0 == dwBuffSize) { while (dwCount --) { if (!(pTrans[*pHGlyph - 1].ubType & MTYPE_COMPOSE)) { dwBuffSize += sizeof(TRANSDATA); } else { pbString = (PBYTE)pMapTable + pTrans[*pHGlyph - 1].uCode.sCode; dwBuffSize += sizeof(TRANSDATA) + *(PWORD)pbString + sizeof(WORD); } pHGlyph++; } pGlyphString->dwGlyphOutSize = dwBuffSize; } else { // // Initialize the MTYPE_COMPOSE buffer // pbOutput = (PBYTE)pTransOutStart + dwCount * sizeof(TRANSDATA); lBuffSize = dwBuffSize - dwCount * sizeof(TRANSDATA); if (lBuffSize < 0 || NULL == pTransOut) { break; } else { bRet = TRUE; while (dwCount --) { *pTransOut = pTrans[*pHGlyph - 1]; if (pTrans[*pHGlyph - 1].ubType & MTYPE_COMPOSE) { pbString = (PBYTE)pMapTable + pTrans[*pHGlyph - 1].uCode.sCode; if (lBuffSize >= *(PWORD)pbString) { pTransOut->uCode.sCode = (SHORT)(pbOutput - (PBYTE)pTransOutStart); CopyMemory(pbOutput, pbString, *(PWORD)pbString + sizeof(WORD)); pbOutput += *(PWORD)pbString + sizeof(WORD); lBuffSize -= *(PWORD)pbString + sizeof(WORD); } else { bRet = FALSE; break; } } pTransOut ++; pHGlyph ++; } } } } // // New version of GETINFO_GLYPYSTRING // else if ( pGlyphString->dwSize == sizeof(GETINFO_GLYPHSTRING) - sizeof(DWORD) ) { pTransOut = pGlyphString->pGlyphOut; pMapTable = GET_MAPTABLE(pGlyphData); pTrans = pMapTable->Trans; while (dwCount --) { *pTransOut++ = pTrans[*pHGlyph++ - 1]; } bRet = TRUE; } break; default: break; } } break; case TYPE_GLYPHID: // // TrueType font case // pGlyphID = (PDWORD)pGlyphString->pGlyphIn; apdlGlyph = pI_UFObj->apdlGlyph; if (!apdlGlyph) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_GLYPHSTRING): pUFObj is not correct.\n")); break; } if (pI_UFObj->pFontMap->dwFontType == FMTYPE_TTOEM) { switch (pGlyphString->dwTypeOut) { case TYPE_UNICODE: pUnicode = pGlyphString->pGlyphOut; while (dwCount--) { *pUnicode = 0; for (dwI = 0; dwI < pI_UFObj->dwNumInGlyphTbl; dwI++, apdlGlyph++) { if ((*apdlGlyph)->wDLGlyphID == (0x0ffff & *pGlyphID)) { *pUnicode = (*apdlGlyph)->wchUnicode; break; } } pGlyphID ++; pUnicode ++; } bRet = TRUE; break; case TYPE_GLYPHHANDLE: pHGlyph = pGlyphString->pGlyphOut; while (dwCount--) { *pHGlyph = 0; for (dwI = 0; dwI < pI_UFObj->dwNumInGlyphTbl; dwI++, apdlGlyph++) { if ((*apdlGlyph)->wDLGlyphID == (0x0ffff & *pGlyphID)) { *pHGlyph = (*apdlGlyph)->hTTGlyph; break; } } pGlyphID ++; pHGlyph ++; } bRet = TRUE; break; } } break; } break; case UFO_GETINFO_GLYPHBITMAP: // // Return Glyph Bitmap // // typedef struct _GETINFO_GLYPHBITMAP { // DWORD dwSize; // Size of this structure // HGLYPH hGlyph; // Glyph hangle passed in OEMDownloadCharGlyph // GLYPHDATA *pGlyphData; // Pointer to the GLYPHDATA data structure // } GETINFO_GLYPHBITMAP, *PGETINFO_GLYPHBITMAP; // pGlyphBitmap = pData; // // Error check (A) and (B) // (B) pI_UFObj->pFontObj // if (!pI_UFObj->pFontObj || pGlyphBitmap->dwSize != sizeof(GETINFO_GLYPHBITMAP)) break; if (FONTOBJ_cGetGlyphs(pI_UFObj->pFontObj, FO_GLYPHBITS, 1, &pGlyphBitmap->hGlyph, &pGlyphBitmap->pGlyphData) ) { bRet = TRUE; } break; case UFO_GETINFO_GLYPHWIDTH: // // Return glyph width. // // typedef struct _GETINFO_GLYPHWIDTH { // DWORD dwSize; // Size of this structure // DWORD dwType; // Type of glyph stirng in pGlyph, TYPE_GLYPHHANDLE/GLYPHID. // DWORD dwCount; // Count of glyph in pGlyph // PVOID pGlyph; // Pointer to a glyph string // PLONG plWidth; // Pointer to the buffer of width table. // // Minidriver has to prepare this. // } GETINFO_GLYPHWIDTH, *PGETINFO_GLYPHWIDTH; // pGlyphWidth = pData; // // Error check (A) // if ((pGlyphWidth->dwSize != sizeof(GETINFO_GLYPHWIDTH))|| !(plWidth = pGlyphWidth->plWidth) || !(pGlyphID = pGlyphWidth->pGlyph) ) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_GLYPHWIDTH): pData is not correct.\n")); break; } // // Error check (B) // pI_UFObj->pPDev // pI_UFObj->pFontObj // if (!pI_UFObj->pPDev) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_GLYPHWIDTH): pUFObj is not correct.\n")); break; } switch(pGlyphWidth->dwType) { case TYPE_GLYPHID: if (pUFObj->dwFlags & UFOFLAG_TTFONT) { HGLYPH hGlyph; if (!pI_UFObj->pFontObj) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_GLYPHWIDTH): UNIDRV needs FONTOBJ. This must be white text case!\n")); break; } for (dwI = 0, pGlyphID = pGlyphWidth->pGlyph; dwI < pGlyphWidth->dwCount; dwI ++, pGlyphID ++, plWidth++) { apdlGlyph = pI_UFObj->apdlGlyph; for (dwJ = 0; dwJ < pI_UFObj->dwNumInGlyphTbl; dwJ++ , apdlGlyph++) { if ((*apdlGlyph)->wDLGlyphID == (0x0ffff & *pGlyphID)) { hGlyph = (*apdlGlyph)->hTTGlyph; break; } } *plWidth= DwGetTTGlyphWidth(pI_UFObj->pPDev->pFontPDev, pI_UFObj->pFontObj, hGlyph); } bRet = TRUE; } break; case TYPE_GLYPHHANDLE: if (!(pUFObj->dwFlags & UFOFLAG_TTFONT)) { for (dwI = 0,pHGlyph = pGlyphWidth->pGlyph; dwI < pGlyphWidth->dwCount; dwI ++, pHGlyph++, plWidth++) { *plWidth = IGetUFMGlyphWidthJr(&pI_UFObj->ptGrxRes, pI_UFObj->pFontMap, *pHGlyph); } bRet = TRUE; } break; } break; case UFO_GETINFO_MEMORY: // // Retuen available memory on the printer. // // typedef struct _GETINFO_MEMORY { // DWORD dwSize; // DWORD dwRemainingMemory; // } GETINFO_MEMORY, PGETINFO_MEMROY; // // Error check (A) // if (((GETINFO_MEMORY*)pData)->dwSize != sizeof(GETINFO_MEMORY)) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_MEMORY): pData is not correct.\n")); break; } // // Error check (B) // pI_UFObj->pPDev // pI_UFObj->pPDev->pFontPDev // if (!pI_UFObj->pPDev || !(pFontPDev = pI_UFObj->pPDev->pFontPDev)) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_MEMORY): pUFObj is not correct.\n")); break; } ((GETINFO_MEMORY*)pData)->dwRemainingMemory = pFontPDev->dwFontMem; bRet = TRUE; break; case UFO_GETINFO_STDVARIABLE: // // Return standard variables // //typedef struct _GETINFO_STDVAR { // DWORD dwSize; // DWORD dwNumOfVariable; // struct { // DWORD dwStdVarID; // LONG lStdVariable; // } StdVar[1]; //} GETINFO_STDVAR, *PGETINFO_STDVAR; // // // FNT_INFO_PRINTDIRINCCDEGREES 0 // PrintDirInCCDegrees // FNT_INFO_GRAYPERCENTAGE 1 // GrayPercentage // FNT_INFO_NEXTFONTID 2 // NextfontID // FNT_INFO_NEXTGLYPH 3 // NextGlyph // FNT_INFO_FONTHEIGHT 4 // FontHeight // FNT_INFO_FONTWIDTH 5 // FontWidth // FNT_INFO_FONTBOLD 6 // FontBold // FNT_INFO_FONTITALIC 7 // FontItalic // FNT_INFO_FONTUNDERLINE 8 // FontUnderline // FNT_INFO_FONTSTRIKETHRU 9 // FontStrikeThru // FNT_INFO_CURRENTFONTID 10 // Current // FNT_INFO_TEXTYRES 11 // TextYRes // FNT_INFO_TEXTXRES 12 // TextXRes // FNT_INFO_FONTMAXWIDTH 13 // FontMaxWidth // pStdVar = pData; // // Error check (A) // if ( (pStdVar->dwSize != sizeof(GETINFO_STDVAR) + ((dwNumOfVar = pStdVar->dwNumOfVariable) - 1) * 2 * sizeof(DWORD)) ) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETIFNO_STDVARIABLE): pData is incorrect.\n")); break; } // // Error check (B) // pI_UFObj->pPDev // if (!pI_UFObj->pPDev) { ERR(("UNIFONTOBJ_GetInfo(UFO_GETINFO_STDVARIABLE): pUFObj is not correct.\n")); break; } bRet = TRUE; while (dwNumOfVar--) { dwSVID = FontStdVariable[pStdVar->StdVar[dwNumOfVar].dwStdVarID]; if (dwSVID > SV_MAX) { bRet = FALSE; ERR(("UFONTOBJ_GetInfo(UFO_GETIFNO_STDVARIABLE): pData is incorrect.\n")); break; } pStdVar->StdVar[dwNumOfVar].lStdVariable = *(pI_UFObj->pPDev->arStdPtrs[dwSVID]); } break; default: VERBOSE(("UNIFONTOBJ_GetInfo(): Invalid dwInfoID.\n")); break; } } return bRet; } // // Font module FONTMAP functions // DWORD DwOutputGlyphCallback( TO_DATA *pTod) /*++ Routine Description: Implementation of OEM OutpuotGlyphCallback calling routine for FONTMAP dispatch routine Arguments: pTod - a pointer to TO_DATA. Return Value: The number of glyph printed. Note: --*/ { PFN_OEMOutputCharStr pfnOEMOutputCharStr; PI_UNIFONTOBJ pUFObj; IFIMETRICS *pIFIMet; PFONTPDEV pFontPDev; PDEV *pPDev; PUNI_GLYPHSETDATA pGlyphData; PTRANSDATA pTrans; PMAPTABLE pMapTable; COMMAND *pCmd, *pCmdSingle, *pCmdDouble; FONTMAP *pFontMap; GLYPHPOS *pgp; PDLGLYPH pdlGlyph; POINTL ptlRem; DWORD dwI, dwCount; PDWORD pdwGlyph, pdwGlyphStart; INT iXInc, iYInc; BOOL bSetCursorForEachGlyph, bPrint, bNewFontSelect, bCOMInterface; bCOMInterface = FALSE; pPDev = pTod->pPDev; ASSERT(pPDev) pFontPDev = pPDev->pFontPDev; ASSERT(pFontPDev) pFontMap = pTod->pfm; pUFObj = (PI_UNIFONTOBJ)pFontPDev->pUFObj; ASSERT(pFontMap && pUFObj) pIFIMet = pFontMap->pIFIMet; ASSERT(pIFIMet) pfnOEMOutputCharStr = NULL; if ( pPDev->pOemHookInfo && (pPDev->pOemHookInfo[EP_OEMOutputCharStr].pfnHook)) { FIX_DEVOBJ(pPDev, EP_OEMOutputCharStr); if( pPDev->pOemEntry && ((POEM_PLUGIN_ENTRY)pPDev->pOemEntry)->pIntfOem ) { bCOMInterface = TRUE; } else { pfnOEMOutputCharStr = (PFN_OEMOutputCharStr)pPDev->pOemHookInfo[EP_OEMOutputCharStr].pfnHook; } } else if (pPDev->ePersonality != kPCLXL) { ERR(("DwOutputGlyphCallback: OEMOutputCharStr callback is not supported by a minidriver.")); return 0; } // // Error exit // if (pFontMap->flFlags & FM_IFIVER40 || pUFObj->pGlyph == NULL) { ERR(("DwOutputGlyphCallback: pUFObj->pGlyph is NULL.")); return 0; } // // OEMOutputCharStr passes two type of glyph string. // TYPE_GLYPHID for TrueType font // TYPE_GLYPHHANDLE for Device font // bSetCursorForEachGlyph = SET_CURSOR_FOR_EACH_GLYPH(pTod->flAccel); pdwGlyphStart = pdwGlyph = (PDWORD)pUFObj->pGlyph; pgp = pTod->pgp; pUFObj->pFontMap = pFontMap; if (pUFObj->dwFlags & UFOFLAG_TTFONT) { DWORD dwCurrGlyphIndex = pTod->dwCurrGlyph; PFONTMAP_TTOEM pFMOEM = (PFONTMAP_TTOEM) pFontMap->pSubFM; DL_MAP *pdm = pFMOEM->u.pvDLData; ASSERT(pTod->apdlGlyph); if (bSetCursorForEachGlyph) { for (dwI = 0; dwI < pTod->cGlyphsToPrint; dwI++, pgp++, dwCurrGlyphIndex++) { pdlGlyph = pTod->apdlGlyph[dwCurrGlyphIndex]; if (!pdlGlyph) { // // pFM->pfnDownloadGlyph could fail by some reason. // Eventually apdlGlyph is not initialized by download.c // ERR(("DwOutputGlyphCallback: pTod->apdlGlyph[dwCurrGlyphIndex] is NULL.")); continue; } if (GLYPH_IN_NEW_SOFTFONT(pFontPDev, pdm, pdlGlyph)) { // // Need to select the new softfont. // We do this by setting pfm->ulDLIndex // to new softfontid. // pUFObj->ulFontID = pFontMap->ulDLIndex = pdlGlyph->wDLFontId; BNewFont(pPDev, pTod->iFace, pFontMap, 0); } VSetCursor( pPDev, pgp->ptl.x, pgp->ptl.y, MOVE_ABSOLUTE, &ptlRem); HANDLE_VECTORPROCS(pPDev, VMOutputCharStr, ((PDEVOBJ)pPDev, (PUNIFONTOBJ)pUFObj, TYPE_GLYPHID, 1, &(pdlGlyph->wDLGlyphID))) else CALL_OEMOUTPUTCHARSTR(TYPE_GLYPHID, 1, &(pdlGlyph->wDLGlyphID)); // // Update position // VSetCursor( pPDev, pdlGlyph->wWidth, 0, MOVE_RELATIVE|MOVE_UPDATE, &ptlRem); } } else { VSetCursor( pPDev, pgp->ptl.x, pgp->ptl.y, MOVE_ABSOLUTE, &ptlRem); dwI = 0; dwCount = 0; bNewFontSelect = FALSE; do { for (; dwI < pTod->cGlyphsToPrint; pdwGlyph++, dwCount++, pgp++, dwI++, dwCurrGlyphIndex++) { pdlGlyph = pTod->apdlGlyph[dwCurrGlyphIndex]; if (0 == pgp->hg) { // // UNIDRV returns 1 for the first glyph handle // in FD_GLYPHSET. // However, GDI could pass zero in hg. // We need to handle this GDI error properly. continue; } if (!pdlGlyph) { // // pFM->pfnDownloadGlyph could fail by some reason. // Eventually apdlGlyph is not initialized by download.c // ERR(("DwOutputGlyphCallback: pTod->apdlGlyph[dwCurrGlyphIndex++] is NULL.")); continue; } *pdwGlyph = pdlGlyph->wDLGlyphID; if (GLYPH_IN_NEW_SOFTFONT(pFontPDev, pdm, pdlGlyph)) { // // Need to select the new softfont. // We do this by setting pfm->ulDLIndex // to new softfontid. // pFontMap->ulDLIndex = pdlGlyph->wDLFontId; bNewFontSelect = TRUE; break; } } if (dwCount > 0) { HANDLE_VECTORPROCS(pPDev, VMOutputCharStr, ((PDEVOBJ)pPDev, (PUNIFONTOBJ)pUFObj, TYPE_GLYPHID, dwCount, pdwGlyphStart)) else CALL_OEMOUTPUTCHARSTR(TYPE_GLYPHID, dwCount, pdwGlyphStart); // // Update position // pgp --; VSetCursor( pPDev, pgp->ptl.x + pdlGlyph->wWidth, pgp->ptl.y, MOVE_ABSOLUTE|MOVE_UPDATE, &ptlRem); dwCount = 0; } if (bNewFontSelect) { dwCount = 1; *pdwGlyphStart = *pdwGlyph; pdwGlyph = pdwGlyphStart + 1; pUFObj->ulFontID = pFontMap->ulDLIndex; BNewFont(pPDev, pTod->iFace, pFontMap, 0); bNewFontSelect = FALSE; } } while (dwCount > 0); } pgp --; if (NULL != pdlGlyph) { iXInc = pdlGlyph->wWidth; } else { iXInc = 0; } } else // Device Font { pGlyphData = ((PFONTMAP_DEV)pFontMap->pSubFM)->pvNTGlyph; pMapTable = GET_MAPTABLE(pGlyphData); pTrans = pMapTable->Trans; pCmdSingle = COMMANDPTR(pPDev->pDriverInfo, CMD_SELECTSINGLEBYTEMODE); pCmdDouble = COMMANDPTR(pPDev->pDriverInfo, CMD_SELECTDOUBLEBYTEMODE); if (bSetCursorForEachGlyph) { for (dwI = 0; dwI < pTod->cGlyphsToPrint; dwI ++, pgp ++) { // // UNIDRV returns 1 for the first glyph handle in FD_GLYPHSET. // However, GDI could pass zero in hg. // We need to handle this GDI error properly. // if (0 == pgp->hg) { continue; } VSetCursor( pPDev, pgp->ptl.x, pgp->ptl.y, MOVE_ABSOLUTE, &ptlRem); if ( (pCmdSingle) && (pTrans[pgp->hg - 1].ubType & MTYPE_SINGLE) && !(pFontPDev->flFlags & FDV_SINGLE_BYTE) ) { WriteChannel( pPDev, pCmdSingle ); pFontPDev->flFlags |= FDV_SINGLE_BYTE; pFontPDev->flFlags &= ~FDV_DOUBLE_BYTE; } else if ( (pCmdDouble) && (pTrans[pgp->hg - 1].ubType & MTYPE_DOUBLE) && !(pFontPDev->flFlags & FDV_DOUBLE_BYTE) ) { WriteChannel( pPDev, pCmdDouble ); pFontPDev->flFlags |= FDV_DOUBLE_BYTE; pFontPDev->flFlags &= ~FDV_SINGLE_BYTE; } HANDLE_VECTORPROCS(pPDev, VMOutputCharStr, ((PDEVOBJ)pPDev, (PUNIFONTOBJ)pUFObj, TYPE_GLYPHHANDLE, 1, &(pgp->hg))) else CALL_OEMOUTPUTCHARSTR(TYPE_GLYPHHANDLE, 1, &(pgp->hg)); // // Update position // GET_CHARWIDTH(iXInc, pFontMap, pgp->hg); VSetCursor( pPDev, iXInc, 0, MOVE_RELATIVE|MOVE_UPDATE, &ptlRem); } } else // Default Placement { bPrint = FALSE; dwCount = 0; VSetCursor( pPDev, pgp->ptl.x, pgp->ptl.y, MOVE_ABSOLUTE, &ptlRem); for (dwI = 0; dwI < pTod->cGlyphsToPrint; dwI ++, pgp ++, pdwGlyph ++, dwCount++) { *pdwGlyph = pgp->hg; // // Single/Double byte mode switch // if (pCmdSingle && (pTrans[*pdwGlyph - 1].ubType & MTYPE_SINGLE) && !(pFontPDev->flFlags & FDV_SINGLE_BYTE) ) { pFontPDev->flFlags &= ~FDV_DOUBLE_BYTE; pFontPDev->flFlags |= FDV_SINGLE_BYTE; pCmd = pCmdSingle; bPrint = TRUE; } else if (pCmdDouble && (pTrans[*pdwGlyph - 1].ubType & MTYPE_DOUBLE) && !(pFontPDev->flFlags & FDV_DOUBLE_BYTE) ) { pFontPDev->flFlags |= FDV_DOUBLE_BYTE; pFontPDev->flFlags &= ~FDV_SINGLE_BYTE; pCmd = pCmdDouble; bPrint = TRUE; } if (bPrint) { if (dwI != 0) { HANDLE_VECTORPROCS(pPDev, VMOutputCharStr, ((PDEVOBJ)pPDev, (PUNIFONTOBJ)pUFObj, TYPE_GLYPHHANDLE, dwCount, pdwGlyphStart)) else CALL_OEMOUTPUTCHARSTR(TYPE_GLYPHHANDLE, dwCount, pdwGlyphStart); // // Update position // GET_CHARWIDTH(iXInc, pFontMap, pgp->hg); VSetCursor( pPDev, iXInc, 0, MOVE_RELATIVE|MOVE_UPDATE, &ptlRem); dwCount = 0; pdwGlyphStart = pdwGlyph; } WriteChannel(pPDev, pCmd); bPrint = FALSE; } } HANDLE_VECTORPROCS(pPDev, VMOutputCharStr, ((PDEVOBJ)pPDev, (PUNIFONTOBJ)pUFObj, TYPE_GLYPHHANDLE, dwCount, pdwGlyphStart)) else CALL_OEMOUTPUTCHARSTR(TYPE_GLYPHHANDLE, dwCount, pdwGlyphStart); } // // Output may have successed, so update the position. // pgp --; GET_CHARWIDTH(iXInc, pFontMap, pgp->hg); VSetCursor( pPDev, pgp->ptl.x + iXInc, pgp->ptl.y, MOVE_ABSOLUTE|MOVE_UPDATE, &ptlRem); } return pTod->cGlyphsToPrint; } BOOL BFontCmdCallback( PDEV *pdev, PFONTMAP pFM, POINTL *pptl, BOOL bSelect) /*++ Routine Description: Implementation of OEM SendFontCmd calling sub routine for FONTMAP dispatch routine Arguments: pdev - a pointer to PDEV pFM - a pointer to FONTMAP pptl - a pointer to POINTL which has the height and with of font bSelect - Boolean to send selection/deselection command Return Value: TRUE if successful, otherwise FALSE. Note: --*/ { PFN_OEMSendFontCmd pfnOEMSendFontCmd; FONTPDEV *pFontPDev; PFONTMAP_DEV pfmdev; FINVOCATION FInv; ASSERT(pdev && pFM); if (pdev->pOemHookInfo && (pfnOEMSendFontCmd = (PFN_OEMSendFontCmd)pdev->pOemHookInfo[EP_OEMSendFontCmd].pfnHook) || (pdev->ePersonality == kPCLXL)) { pFontPDev = pdev->pFontPDev; pFontPDev->flFlags &= ~FDV_DOUBLE_BYTE | FDV_SINGLE_BYTE; if (pFM->dwFontType == FMTYPE_DEVICE) { pfmdev = pFM->pSubFM; pfmdev->ulCodepageID = (ULONG)-1; pFontPDev->pUFObj->pFontMap = pFM; if (pFM->flFlags & FM_IFIVER40) { if (bSelect) { FInv.dwCount = pfmdev->cmdFontSel.pCD->wLength; FInv.pubCommand = pfmdev->cmdFontSel.pCD->rgchCmd; } else { FInv.dwCount = pfmdev->cmdFontDesel.pCD->wLength; FInv.pubCommand = pfmdev->cmdFontDesel.pCD->rgchCmd; } } else { if (bSelect) { FInv.dwCount = pfmdev->cmdFontSel.FInv.dwCount; FInv.pubCommand = pfmdev->cmdFontSel.FInv.pubCommand; } else { FInv.dwCount = pfmdev->cmdFontDesel.FInv.dwCount; FInv.pubCommand = pfmdev->cmdFontDesel.FInv.pubCommand; } } } else if (pFM->dwFontType == FMTYPE_TTOEM) { // // Initialize UNIFONTOBJ // pFontPDev->pUFObj->ulFontID = pFM->ulDLIndex; pFontPDev->pUFObj->pFontMap = pFM; // // Initialize FInv // FInv.dwCount = sizeof(ULONG); FInv.pubCommand = (PBYTE)&(pFontPDev->pUFObj->ulFontID); } HANDLE_VECTORPROCS(pdev, VMSendFontCmd, ((PDEVOBJ)pdev, (PUNIFONTOBJ)pFontPDev->pUFObj, &FInv)) else { FIX_DEVOBJ(pdev, EP_OEMSendFontCmd); if (pdev->pOemEntry) { if(((POEM_PLUGIN_ENTRY)pdev->pOemEntry)->pIntfOem ) // OEM plug in uses COM and function is implemented. { HRESULT hr ; hr = HComSendFontCmd((POEM_PLUGIN_ENTRY)pdev->pOemEntry, &pdev->devobj, (PUNIFONTOBJ)pFontPDev->pUFObj, &FInv); if(SUCCEEDED(hr)) ; // cool ! } else { if (NULL != pfnOEMSendFontCmd) { pfnOEMSendFontCmd(&pdev->devobj, (PUNIFONTOBJ)pFontPDev->pUFObj, &FInv); } } } } } return TRUE; } BOOL BSelectFontCallback( PDEV *pdev, PFONTMAP pFM, POINTL *pptl) /*++ Routine Description: Implementation of OEM SendFontCMd calling routine for FONTMAP dispatch routine Arguments: pTod - a pointer to TO_DATA. Return Value: The number of glyph printed. Note: --*/ { return BFontCmdCallback(pdev, pFM, pptl, TRUE); } BOOL BDeselectFontCallback( PDEV *pdev, PFONTMAP pFM) /*++ Routine Description: Implementation of OEM SendFontCmd calling routine for FONTMAP dispatch routine Arguments: pTod - a pointer to TO_DATA. Return Value: The number of glyph printed. Note: --*/ { return BFontCmdCallback(pdev, pFM, NULL, FALSE); } DWORD DwDLHeaderOEMCallback( PDEV *pPDev, PFONTMAP pFM) /*++ Routine Description: Implementation of OEM SendFontCmd calling routine for FONTMAP dispatch routine Arguments: pPDev - a pointer to PDEV pFM - a pointer to FONTMAP Return Value: Note: --*/ { PFN_OEMDownloadFontHeader pfnOEMDownloadFontHeader; PFONTPDEV pFontPDev; DWORD dwMem = 0; // // Should not be NULL // ASSERT(pPDev && pFM); pFontPDev = pPDev->pFontPDev; pfnOEMDownloadFontHeader = NULL; if ( pPDev->pOemHookInfo && (pfnOEMDownloadFontHeader = (PFN_OEMDownloadFontHeader) pPDev->pOemHookInfo[EP_OEMDownloadFontHeader].pfnHook) || (pPDev->ePersonality == kPCLXL)) { HRESULT hr ; if (pFontPDev->pUFObj == NULL) { // // This should not happen. pUFObj must be initialized. // ERR(("DwDLHeaderOEMCallback: pFontPDev->pUFObj is NULL")); return 0; } pFontPDev->pUFObj->pFontMap = pFM; pFontPDev->pUFObj->ulFontID = pFM->ulDLIndex; BUpdateStandardVar(pPDev, pFM, 0, 0, STD_STD | STD_NFID); WriteChannel(pPDev, COMMANDPTR(pPDev->pDriverInfo, CMD_SETFONTID)); HANDLE_VECTORPROCS(pPDev, VMDownloadFontHeader, ((PDEVOBJ)pPDev, (PUNIFONTOBJ)pFontPDev->pUFObj, &dwMem)) else { FIX_DEVOBJ(pPDev, EP_OEMDownloadFontHeader); if (pPDev->pOemEntry) { if(((POEM_PLUGIN_ENTRY)pPDev->pOemEntry)->pIntfOem ) // OEM plug in uses COM and function is implemented. { hr = HComDownloadFontHeader((POEM_PLUGIN_ENTRY)pPDev->pOemEntry, &pPDev->devobj, (PUNIFONTOBJ)pFontPDev->pUFObj, &dwMem); if(SUCCEEDED(hr)) ; // cool ! } else if (pfnOEMDownloadFontHeader) { dwMem = pfnOEMDownloadFontHeader(&pPDev->devobj, (PUNIFONTOBJ)pFontPDev->pUFObj); } } } } return dwMem; } DWORD DwDLGlyphOEMCallback( PDEV *pPDev, PFONTMAP pFM, HGLYPH hGlyph, WORD wDLGlyphId, WORD *pwWidth) /*++ Routine Description: Implementation of OEM SendFontCmd calling routine for FONTMAP dispatch routine Arguments: pPDev - a pointer to PDEV pFM - a pointer to FONTMAP Return Value: Note: --*/ { PFN_OEMDownloadCharGlyph pfnOEMDownloadCharGlyph; PI_UNIFONTOBJ pUFObj; PFONTPDEV pFontPDev; DL_MAP *pdm; DWORD dwMem; INT iWide; // // There values have to be non-NULL. // ASSERT(pPDev && pFM); dwMem = 0; iWide = 0; pFontPDev = pPDev->pFontPDev; pUFObj = pFontPDev->pUFObj; pdm = ((PFONTMAP_TTOEM)pFM->pSubFM)->u.pvDLData; pfnOEMDownloadCharGlyph = NULL; // // There values have to be non-NULL. // ASSERT(pFontPDev && pUFObj && pdm); if ( pPDev->pOemHookInfo && (pfnOEMDownloadCharGlyph = (PFN_OEMDownloadCharGlyph) pPDev->pOemHookInfo[EP_OEMDownloadCharGlyph].pfnHook) || (pPDev->ePersonality == kPCLXL)) { HRESULT hr ; if (!(PFDV->flFlags & FDV_SET_FONTID)) { pFM->ulDLIndex = pdm->wCurrFontId; BUpdateStandardVar(pPDev, pFM, 0, 0, STD_STD | STD_NFID); WriteChannel(pPDev, COMMANDPTR(pPDev->pDriverInfo, CMD_SETFONTID)); PFDV->flFlags |= FDV_SET_FONTID; } BUpdateStandardVar(pPDev, pFM, wDLGlyphId, 0, STD_GL); WriteChannel(pPDev, COMMANDPTR(pPDev->pDriverInfo, CMD_SETCHARCODE)); pUFObj->pFontMap = pFM; pUFObj->ulFontID = pFM->ulDLIndex; HANDLE_VECTORPROCS(pPDev, VMDownloadCharGlyph, ((PDEVOBJ)pPDev, (PUNIFONTOBJ)pFontPDev->pUFObj, hGlyph, (PDWORD)&iWide, &dwMem)) else { FIX_DEVOBJ(pPDev, EP_OEMDownloadCharGlyph); if (pPDev->pOemEntry) { if(((POEM_PLUGIN_ENTRY)pPDev->pOemEntry)->pIntfOem ) // OEM plug in uses COM and function is implemented. { hr = HComDownloadCharGlyph((POEM_PLUGIN_ENTRY)pPDev->pOemEntry, &pPDev->devobj, (PUNIFONTOBJ)pFontPDev->pUFObj, hGlyph, (PDWORD)&iWide, &dwMem); if(SUCCEEDED(hr)) ; // cool ! } else if (pfnOEMDownloadCharGlyph) { dwMem = pfnOEMDownloadCharGlyph(&pPDev->devobj, (PUNIFONTOBJ)pFontPDev->pUFObj, hGlyph, (PDWORD)&iWide); } } } ((PFONTMAP_TTOEM)pFM->pSubFM)->dwDLSize += dwMem; *pwWidth = (WORD)iWide; } return dwMem; } BOOL BCheckCondOEMCallback( PDEV *pPDev, FONTOBJ *pfo, STROBJ *pso, IFIMETRICS *pifi ) /*++ Routine Description: Implementation of CheckConditon for FONTMAP dispatch routine Arguments: pPDev - a pointer to PDEV pfo - a pointer to FONTOBJ pso - a pointer to STROBJ pifi - a pointer to IFIMETRICS Return Value: Note: --*/ { PFONTPDEV pFontPDev; PI_UNIFONTOBJ pUFObj; ASSERT(pPDev); pFontPDev = pPDev->pFontPDev; pUFObj = pFontPDev->pUFObj; if (pUFObj->dwFlags & UFOFLAG_TTFONT) return TRUE; else return FALSE; } BOOL BSelectTrueTypeOutline( PDEV *pPDev, PFONTMAP pFM, POINTL *pptl) { BOOL bRet = FALSE; if( pFM->flFlags & FM_SOFTFONT ) { if (BUpdateStandardVar(pPDev, pFM, 0, 0, STD_STD | STD_CFID ) && BFontCmdCallback(pPDev, pFM, pptl, TRUE) ) bRet = TRUE; } return bRet; } BOOL BDeselectTrueTypeOutline( PDEV *pPDev, PFONTMAP pFM) { BOOL bRet = FALSE; DWORD dwFlags; PFONTPDEV pFontPDev = pPDev->pFontPDev; PFONTMAP_TTOEM pFMOEM = (PFONTMAP_TTOEM) pFM->pSubFM; // // Deselect case. We need to reinitialize UFObj // dwFlags = ((PI_UNIFONTOBJ)pFontPDev->pUFObj)->dwFlags; ((PI_UNIFONTOBJ)pFontPDev->pUFObj)->dwFlags = pFMOEM->dwFlags; if( pFM->flFlags & FM_SOFTFONT ) { if (BUpdateStandardVar(pPDev, pFM, 0, 0, STD_STD | STD_CFID ) && BFontCmdCallback(pPDev, pFM, NULL, 0) ) bRet = TRUE; } // // Restore the current dwFlags in UFOBJ // ((PI_UNIFONTOBJ)pFontPDev->pUFObj)->dwFlags = dwFlags; return bRet; } BOOL BOEMFreePFMCallback( PFONTMAP pfm) /*++ Routine Description: Implementation of PFM Free function for FONTMAP dispatch routine Arguments: pFM - a pointer to FONTMAP Return Value: Note: --*/ { ASSERT(pfm); if (pfm) { if (pfm->pIFIMet) MemFree(pfm->pIFIMet); MemFree(pfm); return TRUE; } else return FALSE; } PFONTMAP PfmInitPFMOEMCallback( PDEV *pPDev, FONTOBJ *pfo) /*++ Routine Description: Implementation of PfmInit for FONTMAP dispatch routine Arguments: pPDev - a pointer to PDEV pfo - a pointer to FONTOBJ Return Value: A pointer to FONTMAP Note: --*/ { PFONTPDEV pFontPDev; PFONTMAP pfm; DWORD dwSize; ASSERT(pPDev && pfo); pFontPDev = pPDev->pFontPDev; dwSize = sizeof(FONTMAP) + sizeof(FONTMAP_TTOEM); if (pfm = MemAlloc(dwSize)) { PFONTMAP_TTOEM pFMOEM; ZeroMemory(pfm, dwSize); pfm->dwSignature = FONTMAP_ID; pfm->dwSize = sizeof(FONTMAP); pfm->dwFontType = FMTYPE_TTOEM; pfm->pSubFM = (PVOID)(pfm+1); pfm->wFirstChar = 0; pfm->wLastChar = 0xffff; pfm->wXRes = (WORD)pPDev->ptGrxRes.x; pfm->wYRes = (WORD)pPDev->ptGrxRes.y; pfm->pIFIMet = pFontPDev->pIFI; pfm->ulDLIndex = (ULONG)-1; if (!(pFontPDev->flFlags & FDV_ALIGN_BASELINE) ) { pfm->syAdj = ((IFIMETRICS*)pfm->pIFIMet)->fwdWinAscender; } if (pPDev->pOemHookInfo && pPDev->pOemHookInfo[EP_OEMOutputCharStr].pfnHook || (pPDev->ePersonality == kPCLXL) ) pfm->pfnGlyphOut = DwOutputGlyphCallback; else pfm->pfnGlyphOut = DwTrueTypeBMPGlyphOut; if (pPDev->ePersonality == kPCLXL) { pfm->pfnSelectFont = BSelectTrueTypeOutline; pfm->pfnDeSelectFont = BDeselectTrueTypeOutline; } else if (pFontPDev->pUFObj->dwFlags & UFOFLAG_TTDOWNLOAD_TTOUTLINE) { pfm->pfnSelectFont = BSelectTrueTypeOutline; pfm->pfnDeSelectFont = BDeselectTrueTypeOutline; } else if (pFontPDev->pUFObj->dwFlags & UFOFLAG_TTDOWNLOAD_BITMAP) { pfm->pfnSelectFont = BSelectTrueTypeBMP; pfm->pfnDeSelectFont = BDeselectTrueTypeBMP; } pfm->pfnDownloadFontHeader = DwDLHeaderOEMCallback; pfm->pfnDownloadGlyph = DwDLGlyphOEMCallback; pfm->pfnCheckCondition = BCheckCondOEMCallback; pfm->pfnFreePFM = BOEMFreePFMCallback; pFMOEM = (PFONTMAP_TTOEM) pfm->pSubFM; pFMOEM->dwFlags = ((PI_UNIFONTOBJ)pFontPDev->pUFObj)->dwFlags; pFMOEM->flFontType = pfo->flFontType; if (pFontPDev->pUFObj->dwFlags & UFOFLAG_TTDOWNLOAD_TTOUTLINE) { if (pfo->flFontType & FO_SIM_BOLD) pFontPDev->pUFObj->dwFlags |= UFOFLAG_TTOUTLINE_BOLD_SIM; if (pfo->flFontType & FO_SIM_ITALIC) pFontPDev->pUFObj->dwFlags |= UFOFLAG_TTOUTLINE_ITALIC_SIM; if (NULL != pFontPDev->pIFI && '@' == *((PBYTE)pFontPDev->pIFI + pFontPDev->pIFI->dpwszFamilyName)) { pFontPDev->pUFObj->dwFlags |= UFOFLAG_TTOUTLINE_VERTICAL; } } } else { ERR(("PfmInitPFMOEMCallback: MemAlloc failed.\n")); } return pfm; } // // Misc functions // VOID VUFObjFree( IN FONTPDEV* pFontPDev) /*++ Routine Description: UFObj(UNIFONTOBJ) memory free function Arguments: pFontPDev - a pointer to FONTPDEV. Return Value: Note: --*/ { PI_UNIFONTOBJ pUFObj = pFontPDev->pUFObj; ASSERT(pFontPDev); pUFObj = pFontPDev->pUFObj; if (pUFObj && pUFObj->pGlyph) MemFree(pUFObj->pGlyph); pFontPDev->pUFObj = NULL; } WCHAR WGHtoUnicode( DWORD dwNumOfRuns, PGLYPHRUN pGlyphRun, HGLYPH hg) /*++ Routine Description: Character coversion function from HGLYPH to Unicode. Arguments: dwNumOfRuns - number of run in pGlyphRun pGlyphRun - a pointer to glyph run hd - HGLYPH Return Value: Unicode character Note: --*/ { DWORD dwI; HGLYPH hCurrent = 1; WCHAR wchChar = 0; ASSERT(pGlyphRun); for( dwI = 0; dwI < dwNumOfRuns; dwI ++, pGlyphRun ++) { if (hCurrent <= hg && hg < hCurrent + pGlyphRun->wGlyphCount) { wchChar = (WCHAR)(pGlyphRun->wcLow + hg - hCurrent); break; } hCurrent += pGlyphRun->wGlyphCount; } return wchChar; }