/*++ Copyright (c) 1996 - 1999 Microsoft Corporation Module Name: newfont.c Abstract: Implementation of the functions to use new font format. Environment: Windows NT Unidrv driver Revision History: 02/21/97 -eigos- Support Double byte font 01/24/97 -eigos- Filled in functionality 01/14/97 -ganeshp- Created --*/ #include "font.h" // // // const BYTE aubAnsi[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; // // Macro definition // #define DW_MASK (DWBITS - 1) // // Internal function prototype // BOOL BExtractGTT( PUNI_GLYPHSETDATA pGTT, WCHAR wchFirst, WCHAR wchLast, FD_GLYPHSET *pFD_GLYPHSET, PDWORD pdwFD_GLYPHSETSize); BOOL BExtractGTTwithPredefGTT( IN PUNI_GLYPHSETDATA pPreDefGTT, IN PUNI_GLYPHSETDATA pMiniDefGTT, IN WCHAR wchFirst, IN WCHAR wchLast, OUT FD_GLYPHSET **ppFD_GLYPHSET, OUT PMAPTABLE *pMapTable, IN PDWORD pdwFD_GLYPHSETSize); SHORT SGetWidth( PWIDTHTABLE pWidthTable, HGLYPH hg); BYTE ubGetAnsi( WCHAR, INT, PWCHAR, PBYTE); DWORD DwCheckTrans( PGLYPHRUN pMiniGlyphRun, PMAPTABLE pMiniMapTable, DWORD dwMiniGlyphRunCount, WORD wUnicode); WCHAR WchGetNextUnicode( PWCHAR pwchUnicode, PDWORD pdwUnicodeBits, INT iNumOfHandle); int __cdecl Comp(const void *elem1, const void *elem2); // // // Functions // // VOID* PVGetUCFD_GLYPHSET( PDEV *pPDev, FONTMAP *pFM ) /*++ Routine Description: Arguments: pPDev Pointer to PDEV Return Value: TRUE for success and FALSE for failure Note: 01/14/97 -ganeshp- Created it. --*/ { PFONTMAP_DEV pFMDev; PVOID pvFD_GLYPHSET = NULL; DWORD dwFD_GLYPHSETSize; // // Paremeter validation // ASSERT(pFM != NULL); pFMDev = pFM->pSubFM; pvFD_GLYPHSET = NULL; if (pFMDev->pvNTGlyph) { #if ENABLE_GTT_COMBINE RES_ELEM ResElem; if (((PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph)->lPredefinedID != CC_NOPRECNV) { if (BGetWinRes( &(pPDev->WinResData), ((PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph)->lPredefinedID, RC_GTT, &ResElem)) { pFMDev->pvPredefGTT = ResElem.pvResData; BExtractGTTwithPredefGTT(pFMDev->pvPredefGTT, pFMDev->pvNTGlyph, pFM->wFirstChar, pFM->wLastChar, pvFD_GLYPHSET, (PMAPTABLE*)&pFMDev->pvMapTable, &dwFD_GLYPHSETSize); } else { pFMDev->pvPredefGTT = NULL; ERR(("UniFont!PVGetUCFD_GLYPHSET: pvNTGTT is no loaded.\n")); } } #endif // // First, try to get Far East Stock FD_GLYPHSET. // #if ENABLE_STOCKGLYPHSET if (!BGetStockGlyphset( pPDev, &pvFD_GLYPHSET, (SHORT)pFMDev->sCTTid)) { if (!BExtractGTT((PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph, pFM->wFirstChar, pFM->wLastChar, (FD_GLYPHSET*)NULL, (PDWORD)&dwFD_GLYPHSETSize) || !(pvFD_GLYPHSET = MemAlloc(dwFD_GLYPHSETSize)) || !BExtractGTT((PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph, pFM->wFirstChar, pFM->wLastChar, (FD_GLYPHSET*)pvFD_GLYPHSET, (PDWORD)&dwFD_GLYPHSETSize)) { if (pvFD_GLYPHSET) { MemFree(pvFD_GLYPHSET); pvFD_GLYPHSET = NULL; ERR(("UniFont!PVGetUCFD_GLYPHSET failed\n")); } } } #else if (!BExtractGTT((PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph, pFM->wFirstChar, pFM->wLastChar, (FD_GLYPHSET*)NULL, (PDWORD)&dwFD_GLYPHSETSize) || !(pvFD_GLYPHSET = MemAlloc(dwFD_GLYPHSETSize)) || !BExtractGTT((PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph, pFM->wFirstChar, pFM->wLastChar, (FD_GLYPHSET*)pvFD_GLYPHSET, (PDWORD)&dwFD_GLYPHSETSize)) { if (pvFD_GLYPHSET) { MemFree(pvFD_GLYPHSET); pvFD_GLYPHSET = NULL; ERR(("UniFont!PVGetUCFD_GLYPHSET failed\n")); } } #endif } else { ERR(("UniFont!PVGetUCFD_GLYPHSET: pvNTGTT is no loaded.\n")); } pFMDev->pUCTree = pvFD_GLYPHSET; return pvFD_GLYPHSET; } VOID * PVUCKernPair( PDEV *pPDev, FONTMAP *pFM ) /*++ Routine Description: Arguments: pPDev Pointer to PDEV Return Value: TRUE for success and FALSE for failure Note: 01/14/97 -ganeshp- Created it. --*/ { PFONTMAP_DEV pFMDev; PKERNDATA pKerningData; PUNIFM_HDR pUFM; PVOID pvKernPair = NULL; // // Paremeter validation // ASSERT(pFM != NULL); pFMDev = pFM->pSubFM; pUFM = pFMDev->pvFontRes; if (pFM->flFlags & FM_KERNRES) { pvKernPair = pFMDev->pUCKernTree; } else if (pUFM && pUFM->loKernPair) { pKerningData = GET_KERNDATA(pUFM); pFMDev->pUCKernTree = pKerningData->KernPair; pFM->flFlags |= FM_KERNRES; } return pvKernPair; } BOOL BGetNewFontInfo( FONTMAP *pFM, BYTE *pRes) /*++ Routine Description: Arguments: pfm Pointer to FONTMAP pRes Pointer to UFM resource Return Value: TRUE for success and FALSE for failure Note: 01/14/97 -ganeshp- Created it. --*/ { PUNIFM_HDR pUFM; PUNIDRVINFO pUnidrvInfo; PIFIMETRICS pIFI; PKERNDATA pKerningData; PFONTMAP_DEV pFMDev; // // Paremeter validation // ASSERT(pFM != NULL || pRes != NULL); // // Get UFM data // pFMDev = pFM->pSubFM; pFMDev->pvFontRes = pRes; pUFM = (PUNIFM_HDR)pRes; if (pUFM == NULL || pUFM->loIFIMetrics == 0) { ERR(("UniFont!BGetNewFontInfo failed: Invalid FONTMAP.pUFMFontRes\n")); SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } // // Get data pointer of UFM // pUnidrvInfo = GET_UNIDRVINFO(pUFM); // // Fill out FONTMAP members // if (0 != pUFM->loIFIMetrics % sizeof(PVOID)) { DWORD dwSize; pIFI = GET_IFIMETRICS(pUFM); if (NULL == pIFI) { return FALSE; } dwSize = ((IFIMETRICS UNALIGNED *)(pIFI))->cjThis; if (pFM->pIFIMet = MemAlloc(dwSize)) { CopyMemory(pFM->pIFIMet, pIFI, dwSize); pIFI = pFM->pIFIMet; pFM->flFlags &= ~FM_IFIRES; } else return FALSE; } else { pIFI = GET_IFIMETRICS(pUFM); pFM->pIFIMet = pIFI; pFM->flFlags = FM_IFIRES; } if (pUnidrvInfo->SelectFont.dwCount && pUnidrvInfo->SelectFont.loOffset) { pFMDev->cmdFontSel.FInv.dwCount = pUnidrvInfo->SelectFont.dwCount; pFMDev->cmdFontSel.FInv.pubCommand = GET_SELECT_CMD(pUnidrvInfo); pFM->flFlags |= FM_FINVOC | FM_FONTCMD; } if (pUnidrvInfo->UnSelectFont.dwCount && pUnidrvInfo->UnSelectFont.loOffset) { pFMDev->cmdFontDesel.FInv.dwCount = pUnidrvInfo->UnSelectFont.dwCount; pFMDev->cmdFontDesel.FInv.pubCommand = GET_UNSELECT_CMD(pUnidrvInfo); pFM->flFlags |= FM_FINVOC | FM_FONTCMD; } if (pUFM->loExtTextMetric) { pFMDev->pETM = GET_EXTTEXTMETRIC(pUFM); } if (pUFM->loWidthTable) { pFMDev->W.pWidthTable = GET_WIDTHTABLE(pUFM); pFM->flFlags |= FM_WIDTHRES; } if (pUFM->loKernPair) { pKerningData = GET_KERNDATA(pUFM); pFMDev->pUCKernTree = pKerningData->KernPair; pFM->flFlags |= FM_KERNRES; } pFMDev->wDevFontType = pUnidrvInfo->wType; pFMDev->ulCodepage = pUFM->ulDefaultCodepage; pFM->wFirstChar = pIFI->wcFirstChar; pFM->wLastChar = pIFI->wcLastChar; pFM->wXRes = pUnidrvInfo->wXRes; pFM->wYRes = pUnidrvInfo->wYRes; pFMDev->sYAdjust = pUnidrvInfo->sYAdjust; pFMDev->sYMoved = pUnidrvInfo->sYMoved; pFMDev->sCTTid = (SHORT)pUFM->lGlyphSetDataRCID; pFMDev->fCaps = pUnidrvInfo->fCaps; return TRUE; } INT IGetUFMGlyphWidth( PDEV *pPDev, FONTMAP *pFM, HGLYPH hg ) /*++ Routine Description: Arguments: pFM Pointer to FONTMAP Return Value: Width Note: 01/14/97 -ganeshp- Created it. --*/ { return IGetUFMGlyphWidthJr(&(pPDev->ptGrxRes), pFM, hg); } INT IGetUFMGlyphWidthJr( POINT *pptGrxRes, FONTMAP *pFM, HGLYPH hg ) /*++ Routine Description: Arguments: pFM Pointer to FONTMAP Return Value: Width Note: 01/14/97 -ganeshp- Created it. --*/ { TRANSDATA *pTrans; MAPTABLE *pMapTable; FONTMAP_DEV *pFMDev; INT iGlyphWidth; // // 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 (NULL == pFM || NULL == pptGrxRes || 0 == hg) { return 0; } pFMDev = pFM->pSubFM; if ((pFM->flFlags & FM_WIDTHRES) && (iGlyphWidth = SGetWidth(pFMDev->W.pWidthTable, hg))) { iGlyphWidth = iGlyphWidth * pptGrxRes->x / pFM->wXRes; } else { pMapTable = GET_MAPTABLE(pFMDev->pvNTGlyph); pTrans = pMapTable->Trans; if (IS_DBCSCHARSET(((IFIMETRICS*)pFM->pIFIMet)->jWinCharSet)) { if (pTrans[hg - 1].ubType & MTYPE_DOUBLE) { iGlyphWidth = (INT)((PIFIMETRICS)pFM->pIFIMet)->fwdMaxCharInc; //VERBOSE(("(2)MTYPE_DOUBLE:Char=0x%x%x, ", // pTrans[hg-1].uCode.ubPairs[0], // pTrans[hg-1].uCode.ubPairs[1])); } else { iGlyphWidth = (INT)((PIFIMETRICS)pFM->pIFIMet)->fwdAveCharWidth; //VERBOSE(("(2)MTYPE_SINGLE:Char=%d, ", // pTrans[hg-1].uCode.ubCode)); } } else { iGlyphWidth = (INT)((PIFIMETRICS)pFM->pIFIMet)->fwdMaxCharInc; } } //VERBOSE(("Width=%d\n",iGlyphWidth)); return iGlyphWidth; } BOOL BGTTOutputGlyph( TO_DATA *pTod) /*++ Routine Description: Same as BRLEOutputGlyph in textout.c. Should use GTT data instead of RLE. Arguments: pTod - a pointer to TEXTOUT DATA (TO_DATA) structure Return Value: TRUE for success and FALSE for failure Note: 02/14/97 -eigos- Created it. --*/ { FONTPDEV *pFontPDev; IFIMETRICS *pIFIMetrics; PUNI_GLYPHSETDATA pGlyphSetData; PUNI_CODEPAGEINFO pCodePageInfo; PMAPTABLE pMapTable; COMMAND *pCmd; PTRANSDATA pTrans; PFONTMAP_DEV pFMDev; PDEV *pPDev; HGLYPH hg; FONTMAP *pFM; PGLYPHPOS pgp; POINTL ptlRem; PBYTE pString; DWORD dwSize, cGlyphs; INT iX, iY, iXInc, iYInc; BOOL bRet; BOOL bSetCursorForEachGlyph; pPDev = pTod->pPDev; pFontPDev = pPDev->pFontPDev; pFM = pTod->pfm; pIFIMetrics = (IFIMETRICS*)pFM->pIFIMet; pFMDev = pFM->pSubFM; pGlyphSetData = (PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph; cGlyphs = pTod->cGlyphsToPrint; pgp = pTod->pgp; bSetCursorForEachGlyph = SET_CURSOR_FOR_EACH_GLYPH(pTod->flAccel); if (!bSetCursorForEachGlyph || pFontPDev->flFlags & FDV_DISABLE_POS_OPTIMIZE) { // // If bSetCursorForEachGlyph is not set, send the first character's // position. // // FDV_DISABLE_POS_OPTIMIZE // If there is rounding error, when scaling width, // disable x position optimization // VSetCursor( pPDev, pgp->ptl.x, pgp->ptl.y, MOVE_ABSOLUTE, &ptlRem); } pTod->flFlags |= TODFL_FIRST_GLYPH_POS_SET; // // Set the cursor to the desired X position for this glyph. NOTE // that we should only use RELATIVE move commands in here, since // the LaserJet family rotates the COORDINATE AXES when text is // being rotated by multiples of 90 degrees. Using relative moves // means we can avoid trying to figure out where the printer thinks // the print positiion is located. It's almost guaranteed to be // different to what we think it is! // // DCR - should reorganise the move command code to do a better // job here. Problem is that if we are rotating the bitmap, then MV_FINE // is NOT a good idea, since it almost undoubtedly move the cursor in // the WRONG dimension! When we are rotating the bitmap, it is most // probable that the MV_FINE will move in the Y direction!!! // bRet = TRUE; iX = iY = 0; if (pGlyphSetData != NULL) { while (cGlyphs --) { // // Do nothing. GDI could pass ZERO HGLYPH. // GTT glyph handle starts from 1. GDI is not supposed to pass 0 in // HGLYPH. // if (0 == pgp->hg) continue; hg = pgp->hg; iX = pgp->ptl.x; iY = pgp->ptl.y; // // Move to the next character's position // if (bSetCursorForEachGlyph) VSetCursor( pPDev, iX, iY, MOVE_ABSOLUTE, &ptlRem); // // Minidriver defined glyph conversion // pMapTable = GET_MAPTABLE((PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph); pTrans = pMapTable->Trans; // // Send symbol set selection command // if ( pFMDev->ulCodepageID != pTrans[hg - 1].ubCodePageID ) { if (pFMDev->ulCodepageID != -1) { pCodePageInfo = GET_CODEPAGEINFO((PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph); pCodePageInfo += pFMDev->ulCodepageID; pString = (PBYTE)pCodePageInfo + pCodePageInfo->UnSelectSymbolSet.loOffset; dwSize = pCodePageInfo->UnSelectSymbolSet.dwCount; if (dwSize) { WriteSpoolBuf(pPDev, pString, dwSize); } } pFMDev->ulCodepageID = pTrans[hg - 1].ubCodePageID; pCodePageInfo = GET_CODEPAGEINFO((PUNI_GLYPHSETDATA)pFMDev->pvNTGlyph); pCodePageInfo += pFMDev->ulCodepageID; pString = (PBYTE)pCodePageInfo + pCodePageInfo->SelectSymbolSet.loOffset; dwSize = pCodePageInfo->SelectSymbolSet.dwCount; if (dwSize) { WriteSpoolBuf(pPDev, pString, dwSize); } } // // Single/Double byte mode switch // if ((pTrans[hg - 1].ubType & MTYPE_SINGLE) && !(pFontPDev->flFlags & FDV_SINGLE_BYTE) ) { if(pCmd = COMMANDPTR(pPDev->pDriverInfo, CMD_SELECTSINGLEBYTEMODE)) { pFontPDev->flFlags &= ~FDV_DOUBLE_BYTE; pFontPDev->flFlags |= FDV_SINGLE_BYTE; WriteChannel( pPDev, pCmd ); } else pFontPDev->flFlags |= FDV_SINGLE_BYTE; } else if ((pTrans[hg - 1].ubType & MTYPE_DOUBLE) && !(pFontPDev->flFlags & FDV_DOUBLE_BYTE) ) { if (pCmd = COMMANDPTR(pPDev->pDriverInfo, CMD_SELECTDOUBLEBYTEMODE)) { pFontPDev->flFlags |= FDV_DOUBLE_BYTE; pFontPDev->flFlags &= ~FDV_SINGLE_BYTE; WriteChannel( pPDev, pCmd ); } else pFontPDev->flFlags |= FDV_DOUBLE_BYTE; } // // Send string // switch(MTYPE_FORMAT_MASK & pTrans[hg - 1].ubType) { case MTYPE_DIRECT: bRet = WriteSpoolBuf(pPDev, &(pTrans[hg - 1].uCode.ubCode), 1) == 1; break; case MTYPE_PAIRED: // // First, try to use cursor push/pop escapes to // overlay the 2 characters. If they are not // available, try the backspace. If it doesn't exist // either, ignore the second character. // pCmd = COMMANDPTR(pPDev->pDriverInfo, CMD_PUSHCURSOR); pString = pTrans[hg - 1].uCode.ubPairs; if (pTrans[hg - 1].ubType & (MTYPE_SINGLE|MTYPE_DOUBLE)) { bRet = WriteSpoolBuf( pPDev, pString, 2 ) == 2; } else { if ( *(pString + 1) && (pCmd != NULL) ) { // // Pushed the position; output ch1, pop position, ch2 // bRet = WriteSpoolBuf( pPDev, pString, 1 ) == 1; WriteChannel( pPDev, pCmd ); bRet = WriteSpoolBuf( pPDev, pString + 1, 1 ) == 1; } else { pCmd = COMMANDPTR(pPDev->pDriverInfo, CMD_BACKSPACE); bRet = WriteSpoolBuf( pPDev, pString, 1 ) == 1; if( (*(pString + 1)) && (pFontPDev->flFlags & FDV_BKSP_OK) ) { WriteChannel( pPDev, pCmd ); bRet = WriteSpoolBuf( pPDev, pString + 1, 1 ) == 1; } } } break; case MTYPE_COMPOSE: pString = (PBYTE)pMapTable + pTrans[hg - 1].uCode.sCode; bRet = (WriteSpoolBuf(pPDev, pString + 2, *(WORD UNALIGNED *)pString) == *(WORD UNALIGNED *)pString); break; } pgp++; // // After drawing the character, in the printer, the cursor position // moves. Update the UNIDRV internal value to reduce the amount of // command to send. // if (bSetCursorForEachGlyph) { if( pFM->flFlags & FM_WIDTHRES) { if ((iXInc = SGetWidth(pFMDev->W.pWidthTable, hg))) iXInc = iXInc * pPDev->ptGrxRes.x / pFM->wXRes; else iXInc = pIFIMetrics->fwdAveCharWidth; } else { if (pTrans[hg - 1].ubType & MTYPE_DOUBLE) iXInc = pIFIMetrics->fwdMaxCharInc; else iXInc = pIFIMetrics->fwdAveCharWidth; } if (pFM->flFlags & FM_SCALABLE) { iXInc = LMulFloatLong(&pFontPDev->ctl.eXScale,iXInc); } if (pTod->flAccel & SO_VERTICAL) { iYInc = iXInc; iXInc = 0; } else { iYInc = 0; } VSetCursor( pPDev, iXInc, iYInc, MOVE_RELATIVE|MOVE_UPDATE, &ptlRem); } } } else { bRet = FALSE; } if (bRet && pFM) { if (!bSetCursorForEachGlyph) { // // Output may have successed, so update the position. // if (pFM->flFlags & FM_WIDTHRES) { if (!(iXInc = SGetWidth(pFMDev->W.pWidthTable, hg))) iXInc = pIFIMetrics->fwdAveCharWidth; } else { if (pTrans[hg - 1].ubType & MTYPE_DOUBLE) { iXInc = pIFIMetrics->fwdMaxCharInc; } else { iXInc = pIFIMetrics->fwdAveCharWidth; } } if (pFM->flFlags & FM_SCALABLE) { // // Need to transform the value to current size // iXInc = LMulFloatLong(&pFontPDev->ctl.eXScale,iXInc); } if (pTod->flAccel & SO_VERTICAL) { iYInc = iXInc; iXInc = 0; } else { iYInc = 0; } VSetCursor( pPDev, (iX + iXInc) - pTod->pgp->ptl.x, (iY + iYInc) - pTod->pgp->ptl.y, MOVE_RELATIVE | MOVE_UPDATE, &ptlRem); } } else { bRet = FALSE; } return bRet; } BOOL BGTTSelectFont( PDEV *pPDev, PFONTMAP pFM, POINTL *pptl) { PFONTMAP_DEV pfmdev; INT iCmdLength; PBYTE pbCmd; pfmdev = pFM->pSubFM; if ((iCmdLength = (INT)pfmdev->cmdFontSel.FInv.dwCount) && (pbCmd = pfmdev->cmdFontSel.FInv.pubCommand)) { pfmdev->pfnDevSelFont( pPDev, pbCmd, iCmdLength, pptl); } // // Reset uLCodepageID to send codepage selection command. // pfmdev->ulCodepageID = (ULONG)-1; ((PFONTPDEV)pPDev->pFontPDev)->flFlags &= ~FDV_DOUBLE_BYTE | FDV_SINGLE_BYTE; return TRUE; } BOOL BGTTDeselectFont( PDEV *pPDev, PFONTMAP pFM) { PFONTMAP_DEV pfmdev; INT iCmdLength; PBYTE pbCmd; pfmdev = pFM->pSubFM; if ((iCmdLength = (INT)pfmdev->cmdFontDesel.FInv.dwCount) && (pbCmd = pfmdev->cmdFontDesel.FInv.pubCommand) && iCmdLength != WriteSpoolBuf( pPDev, pbCmd, iCmdLength) ) { return FALSE; } return TRUE; } // // // Internal functions // // BOOL BExtractGTT( PUNI_GLYPHSETDATA pGTT, WCHAR wchFirst, WCHAR wchLast, FD_GLYPHSET *pFD_GLYPHSET, PDWORD pdwFD_GLYPHSETSize) /*++ Routine Description: Create FD_GLYPHSET from GLYPHRUN in GTT. Arguments: pGTT - GTT file resource pFD_GLYPHSET - a buffer to be filled out pdwFD_GLYPHSETSize - a pointer to the size of FD_GLYPHSET Return Value: TRUE for success and FALSE for failure Note: --*/ { PGLYPHRUN pGlyphRun; HGLYPH GlyphHandle, *pGlyphHandle; DWORD dwI, dwGlyphNum; WORD wJ; // // parameter validation // ASSERT(pGTT != NULL); if (pFD_GLYPHSET == NULL) { // // pFD_GLYPHSET == NULL case // return the necessary amount of memory // pGlyphRun = GET_GLYPHRUN(pGTT); dwGlyphNum = 0; for (dwI = 0; dwI < pGTT->dwRunCount; dwI ++, pGlyphRun ++) { dwGlyphNum += pGlyphRun->wGlyphCount; } *pdwFD_GLYPHSETSize = sizeof(FD_GLYPHSET) + (pGTT->dwRunCount - 1) * sizeof(WCRUN) + dwGlyphNum * sizeof(HGLYPH); } else { // // pFD_GLYPHSET != NULL case // Fill out pFD_GLYPHSET // pFD_GLYPHSET->cjThis = *pdwFD_GLYPHSETSize; pFD_GLYPHSET->flAccel = 0; pFD_GLYPHSET->cGlyphsSupported = 0; pFD_GLYPHSET->cRuns = pGTT->dwRunCount; pGlyphHandle = (HGLYPH*)( (PBYTE)pFD_GLYPHSET + sizeof(FD_GLYPHSET) + sizeof(WCRUN) * (pGTT->dwRunCount-1) ); pGlyphRun = GET_GLYPHRUN(pGTT); dwGlyphNum = 0; // // IMPORTANT!!!: Glyph handle in FD_GLYPHSET starts from 1 for GTT. // GlyphHandle = 1; for (dwI = 0; dwI < pGTT->dwRunCount; dwI ++, pGlyphRun ++) { dwGlyphNum += pGlyphRun->wGlyphCount; pFD_GLYPHSET->awcrun[dwI].cGlyphs = pGlyphRun->wGlyphCount; pFD_GLYPHSET->awcrun[dwI].wcLow = pGlyphRun->wcLow; pFD_GLYPHSET->awcrun[dwI].phg = pGlyphHandle; for (wJ = 0; wJ < pGlyphRun->wGlyphCount; wJ ++, pGlyphHandle ++, GlyphHandle ++) { *pGlyphHandle = GlyphHandle; } } pFD_GLYPHSET->cGlyphsSupported = dwGlyphNum; } return TRUE; } SHORT SGetWidth( PWIDTHTABLE pWidthTable, HGLYPH hg) { // Because of a problem in at least one very common font resource DLL (HPCFONT.DLL) // already out and about, it's safer and easier to access this table in an unaligned // memory location than to try move it to align it. PWIDTHRUN pWidthRun = pWidthTable->WidthRun; SHORT UNALIGNED *psWidth; DWORD dwRunCount = 0; while ( ( hg < (ULONG)(*((SHORT UNALIGNED *)&(pWidthRun->wStartGlyph)) ) || (ULONG)( *((SHORT UNALIGNED *)&(pWidthRun->wStartGlyph)) ) + ( *((SHORT UNALIGNED *)&(pWidthRun->wGlyphCount)) ) <= hg ) && dwRunCount < ( *((DWORD UNALIGNED *)&(pWidthTable->dwRunNum)) ) ) { pWidthRun ++; dwRunCount ++; } if (dwRunCount == ( *((SHORT UNALIGNED *)&(pWidthTable->dwRunNum)) )) { return 0; } else { DWORD dwOffset = *( (DWORD UNALIGNED *) (&(pWidthRun->loCharWidthOffset)) ); psWidth = ((SHORT UNALIGNED *)( (PBYTE)pWidthTable + dwOffset )); return psWidth[hg - ( *((SHORT UNALIGNED *)&(pWidthRun->wStartGlyph)) )]; } } PUNI_GLYPHSETDATA PNTGTT1To1( IN DWORD dwCodePage, IN BOOL bSymbolCharSet, IN INT iFirstChar, IN INT iLastChar) /*++ Routine Description: Generates a simple mapping format for the GTT stuff. This is typically used for a printer with a 1:1 mapping to the Windows character set. Arguments: iFirst: The lowest glyph in the range. iLast: The last glyph in the range (inclusive) Return Value: Address of GTT structure allocated from heap; NULL on failure. Note: 11-27-96: Created it -ganeshp- --*/ { PUNI_CODEPAGEINFO pCodePageInfo; PGLYPHRUN pGlyphRun, pGlyphRunOrg; TRANSDATA *pTrans; PMAPTABLE pMapTable; USHORT usAnsiCodePage, usOEMCodePage; INT iNumOfHandle, iNumOfRuns, iTotalGlyphSetDataSize, iNumOfUnsupportChar; INT iI, iJ, iK, iIndex; WCHAR awchUnicode[256]; struct { WORD wID; WCHAR Unicode; } UnicodeDst[256]; WCHAR wchChar, wchCurrent, wchTemp; PBYTE pbBase; ASSERT(iFirstChar == 0x20 && iLastChar == 0xFF); iNumOfUnsupportChar = 0; iNumOfHandle = iLastChar - iFirstChar + 1; if (iNumOfHandle > 256) { ERR(("UniFont!NTGTT1To1 failed:iNumOfHandle > 256.\n")); return NULL; } if (dwCodePage == 0) { dwCodePage = 1252; } #ifndef WINNT_40 // NT 5.0 if( -1 == (iNumOfHandle = EngMultiByteToWideChar(dwCodePage, awchUnicode, (INT)(iNumOfHandle * sizeof(WCHAR)), (PCH)aubAnsi+iFirstChar, (INT)iNumOfHandle))) { ERR(("UniFont!NTGTT1To1:EngMultiByteToWideChar failed\n")); return NULL; } #else EngMultiByteToUnicodeN(awchUnicode, iNumOfHandle * sizeof(WCHAR), NULL, (PBYTE)aubAnsi+iFirstChar, iNumOfHandle); // // Disable new symbol set character range on NT4 (F020 to F0FF) // bSymbolCharSet = FALSE; #endif // WINNT_40 wchCurrent = 0; iNumOfRuns = 0; for (iI = 0; iI < iNumOfHandle; iI ++) { UnicodeDst[iI].wID = iI+iFirstChar; UnicodeDst[iI].Unicode = awchUnicode[iI]; } qsort(UnicodeDst, iNumOfHandle, sizeof(WCHAR)+sizeof(WORD), Comp); for( iI = 0; iI < iNumOfHandle; iI ++ ) { wchTemp = UnicodeDst[iI].Unicode; if (wchTemp == EURO_CUR_SYMBOL || wchTemp == 0xFFFF) { iNumOfUnsupportChar ++; UnicodeDst[iI].Unicode = 0; continue; } else if (wchTemp == wchCurrent + 1) { wchCurrent ++; continue; } wchCurrent = wchTemp; iNumOfRuns ++; } // // Create GLYPHRUN // if (bSymbolCharSet) { iNumOfRuns ++; } if( !(pGlyphRunOrg = pGlyphRun = (PGLYPHRUN)MemAlloc( iNumOfRuns * sizeof(GLYPHRUN) )) ) { ERR(("UniFont!NTGTT1To1:MemAlloc failed\n")); return NULL; } wchCurrent = 0; for (iI = 0; iI < iNumOfHandle; iI ++) { wchTemp = UnicodeDst[iI].Unicode; if (wchTemp == 0) { continue; } else if (wchTemp == wchCurrent + 1) { pGlyphRun->wGlyphCount++; wchCurrent ++; } else { if (wchCurrent != 0) pGlyphRun ++; wchCurrent = pGlyphRun->wcLow = wchTemp; pGlyphRun->wGlyphCount = 1; } } if (bSymbolCharSet) { pGlyphRun++; pGlyphRun->wcLow = SYMBOL_START; pGlyphRun->wGlyphCount = NUM_OF_SYMBOL; } // // Calculate total size of this file. // iNumOfHandle -= iNumOfUnsupportChar; iTotalGlyphSetDataSize = sizeof(UNI_GLYPHSETDATA) + sizeof(UNI_CODEPAGEINFO) + iNumOfRuns * sizeof( GLYPHRUN ) + sizeof(MAPTABLE) + (iNumOfHandle - 1) * sizeof(TRANSDATA); if (bSymbolCharSet) { iTotalGlyphSetDataSize += sizeof(TRANSDATA) * NUM_OF_SYMBOL; } // // Allocate memory and set header, copy GLYPHRUN, CODEPAGEINFO // if( !(pbBase = MemAlloc( iTotalGlyphSetDataSize )) ) { MemFree(pGlyphRunOrg); return NULL; } ((PUNI_GLYPHSETDATA)pbBase)->dwVersion = UNI_GLYPHSETDATA_VERSION_1_0; ((PUNI_GLYPHSETDATA)pbBase)->dwFlags = 0; ((PUNI_GLYPHSETDATA)pbBase)->lPredefinedID = CC_NOPRECNV; ((PUNI_GLYPHSETDATA)pbBase)->dwGlyphCount = 0; ((PUNI_GLYPHSETDATA)pbBase)->dwCodePageCount = 1; ((PUNI_GLYPHSETDATA)pbBase)->dwRunCount = iNumOfRuns; ((PUNI_GLYPHSETDATA)pbBase)->dwSize = iTotalGlyphSetDataSize; ((PUNI_GLYPHSETDATA)pbBase)->loRunOffset = sizeof(UNI_GLYPHSETDATA); ((PUNI_GLYPHSETDATA)pbBase)->loCodePageOffset = sizeof(UNI_GLYPHSETDATA) + sizeof(GLYPHRUN) * iNumOfRuns; ((PUNI_GLYPHSETDATA)pbBase)->loMapTableOffset = sizeof(UNI_GLYPHSETDATA) + sizeof(GLYPHRUN) * iNumOfRuns + sizeof(UNI_CODEPAGEINFO); CopyMemory(pbBase + sizeof(UNI_GLYPHSETDATA), pGlyphRunOrg, sizeof(GLYPHRUN) * iNumOfRuns); // // CodePageInfo // pCodePageInfo = (PUNI_CODEPAGEINFO)(pbBase + ((PUNI_GLYPHSETDATA)pbBase)->loCodePageOffset); pCodePageInfo->dwCodePage = dwCodePage; pCodePageInfo->SelectSymbolSet.dwCount = 0; pCodePageInfo->UnSelectSymbolSet.dwCount = 0; pCodePageInfo->SelectSymbolSet.loOffset = 0; pCodePageInfo->UnSelectSymbolSet.loOffset = 0; // // MapTable // pMapTable = (PMAPTABLE)(pbBase + ((PUNI_GLYPHSETDATA)pbBase)->loMapTableOffset); pMapTable->dwSize = sizeof(MAPTABLE) + (iNumOfHandle - 1) * sizeof(TRANSDATA); pMapTable->dwGlyphNum = iNumOfHandle; pTrans = pMapTable->Trans; iIndex = 0; iK = 0; pGlyphRun = pGlyphRunOrg; if (bSymbolCharSet) { for( iI = 0; iI < iNumOfRuns; iI ++, pGlyphRun ++) { if (pGlyphRun->wcLow == SYMBOL_START) { for (iJ = SYMBOL_START; iJ <= SYMBOL_END; iJ ++) { pTrans[iIndex].ubCodePageID = 0; pTrans[iIndex].ubType = MTYPE_DIRECT; pTrans[iIndex].uCode.ubCode = (BYTE)iJ; iIndex++; } } else { for( iJ = 0; iJ < pGlyphRun->wGlyphCount; iJ ++) { while (iK < 256 && UnicodeDst[iK].Unicode == 0) { iK++; } if (iK < 256) { pTrans[iIndex].ubCodePageID = 0; pTrans[iIndex].ubType = MTYPE_DIRECT; pTrans[iIndex].uCode.ubCode = (BYTE)UnicodeDst[iK++].wID; iIndex++; } } } } } else { for( iI = 0; iI < iNumOfHandle; iI ++) { while (iK < 256 && UnicodeDst[iK].Unicode == 0) { iK++; } if (iK < 256) { pTrans[iIndex].ubCodePageID = 0; pTrans[iIndex].ubType = MTYPE_DIRECT; pTrans[iIndex].uCode.ubCode = (BYTE)UnicodeDst[iK++].wID; iIndex++; } } } MemFree(pGlyphRunOrg); VDBGDUMPGTT((PUNI_GLYPHSETDATA)pbBase); return (PUNI_GLYPHSETDATA)pbBase; } BOOL BExtractGTTwithPredefGTT( IN PUNI_GLYPHSETDATA pPreDefGTT, IN PUNI_GLYPHSETDATA pMiniDefGTT, IN WCHAR wchFirst, IN WCHAR wchLast, OUT FD_GLYPHSET **ppFD_GLYPHSET, OUT MAPTABLE **ppMapTable, IN PDWORD pdwFD_GLYPHSETSize) { PGLYPHRUN pPreDefGlyphRun, pMiniDefGlyphRun; PMAPTABLE pMiniMapTable; PTRANSDATA pMiniDefTrans, pPreDefTrans; PTRANSDATA pSrcTrans, pDstTrans, pNewTrans, pTrans; WCRUN* pWCRun; HGLYPH *pHGlyph; DWORD dwGlyphNum, dwMapTableSize, dwRunCount, dwIndex, dwI; DWORD dwAddGlyphNum, dwSubGlyphNum, dwType; WORD wJ; WCHAR wcLow, wcHigh; BOOL bInRun; // // FD_GLYPHSET creation. // // Additonal case: // case 1: the begining of predef run // Change wcLow and add cGlyphs in WCRUN. // Change cGlyphsSupported in FD_GLYPHSET. // case 2: the end of predef run // Change add cGlyphs in WCRUN. // Change cGlyphsSupported in FD_GLYPHSET. // case 3: not in the predef run // Add new WCRUN // Change cGlyphsSupported in FD_GLYPHSET. // // Disable case: // case 1: the begining of predef run // Change wcLow and cGlyphs in WCRUN. // Change cGlyphsSupported in FD_GLYPHSET. // case 2: in the middle of predef run // Divide this run into two different run. // Change cGlyphsSupported in FD_GLYPHSET. // case 3: the end of predef run // Change cGlyphs in WCRUN. // Change cGlyphsSupported in FD_GLYPHSET. // // Replace case: // Do nothing. // ASSERT(pPreDefGTT != NULL && pMiniDefGTT); // // Count glyph number in predefined GTT. // dwGlyphNum = 0; pPreDefGlyphRun = GET_GLYPHRUN(pPreDefGTT); for (dwI = 0; dwI < pPreDefGTT->dwRunCount; dwI ++, pPreDefGlyphRun ++) { dwGlyphNum += pPreDefGlyphRun->wGlyphCount; } pPreDefGlyphRun = GET_GLYPHRUN(pPreDefGTT); pMiniDefGlyphRun = GET_GLYPHRUN(pMiniDefGTT); pMiniMapTable = GET_MAPTABLE(pMiniDefGTT); dwIndex = 0; dwAddGlyphNum = 0; dwSubGlyphNum = 0; // // Count a total glyph number and glyph run number. // for (dwI = 0; dwI < pMiniDefGTT->dwRunCount; dwI ++, pMiniDefGlyphRun ++) { wcHigh = pMiniDefGlyphRun->wcLow + pMiniDefGlyphRun->wGlyphCount; for (wJ = pMiniDefGlyphRun->wcLow; wJ < wcHigh; wJ ++, dwIndex ++) { switch (pMiniMapTable->Trans[dwIndex].ubType & MTYPE_PREDEFIN_MASK) { case MTYPE_ADD: dwAddGlyphNum ++; break; case MTYPE_DISABLE: dwSubGlyphNum ++; break; case MTYPE_REPLACE: default: break; } } } dwGlyphNum += dwAddGlyphNum - dwSubGlyphNum; // // Create MAPTABLE // // Memory allocation // Creation // // ---------------- // Predefined MAPPTABLE (1 -> n glyph handle) // Minidriver's MTYPE_DISABLE is already removed. // ---------------- // Minidriver additional MAPTABLE // (n + 1 -> n + m) glyph handle // Even if some glyphs could be merged into Predefined MAPTABLE, we // separate them with minidriver's additional glyphs for a convenience. // ---------------- // dwMapTableSize = sizeof(MAPTABLE) + sizeof(TRANSDATA) * (dwGlyphNum - 1); if((*ppMapTable = MemAlloc(dwMapTableSize)) == NULL) { return FALSE; } // // Fill in MAPTABLE // (*ppMapTable)->dwSize = dwMapTableSize; (*ppMapTable)->dwGlyphNum = dwGlyphNum; pPreDefGlyphRun = GET_GLYPHRUN(pPreDefGTT); pMiniDefGlyphRun = GET_GLYPHRUN(pMiniDefGTT); pMiniMapTable = GET_MAPTABLE(pMiniDefGTT); pPreDefTrans = (GET_MAPTABLE(pPreDefGTT))->Trans; pMiniDefTrans = pMiniMapTable->Trans; pTrans = (*ppMapTable)->Trans; pNewTrans = (*ppMapTable)->Trans + dwGlyphNum - dwAddGlyphNum; dwIndex = 0; dwRunCount = 0; for (dwI = 0; dwI < pPreDefGlyphRun->wGlyphCount; dwI ++) { wcHigh = pPreDefGlyphRun->wcLow + pPreDefGlyphRun->wGlyphCount; bInRun = FALSE; for (wJ = pPreDefGlyphRun->wcLow; wJ < wcHigh; wJ ++) { dwType = DwCheckTrans(pMiniDefGlyphRun, pMiniMapTable, pMiniDefGTT->dwRunCount, wJ); if ( (dwType == 0) || (dwType == MTYPE_REPLACE) ) { if (!bInRun) { dwRunCount ++; bInRun = TRUE; } if (!dwType ) { pSrcTrans = pPreDefTrans; pDstTrans = pTrans; } else if (dwType == MTYPE_REPLACE) { pSrcTrans = pMiniDefTrans; pDstTrans = pTrans; } pDstTrans->ubCodePageID = pSrcTrans->ubCodePageID; pDstTrans->ubType = pSrcTrans->ubType; switch(pSrcTrans->ubType & MTYPE_FORMAT_MASK) { case MTYPE_COMPOSE: pDstTrans->uCode.ubCode = pSrcTrans->uCode.ubCode; break; case MTYPE_DIRECT: pDstTrans->uCode.ubPairs[0] = pSrcTrans->uCode.ubPairs[0]; pDstTrans->uCode.ubPairs[1] = pSrcTrans->uCode.ubPairs[1]; break; case MTYPE_PAIRED: pDstTrans->uCode.sCode = pSrcTrans->uCode.sCode; break; } pSrcTrans ++; pDstTrans ++; } else if (dwType == MTYPE_DISABLE) { pPreDefTrans ++; if (bInRun && wJ != wcHigh - 1) { dwRunCount ++; bInRun = FALSE; } } } } for (dwI = 0; dwI < pMiniDefGlyphRun->wGlyphCount; dwI ++) { wcHigh = pMiniDefGlyphRun->wcLow + pMiniDefGlyphRun->wGlyphCount; bInRun = FALSE; for (wJ = pMiniDefGlyphRun->wcLow; wJ < wcHigh; wJ ++, pMiniDefTrans ++) { if (pMiniDefTrans->ubType & MTYPE_ADD) { pNewTrans->ubCodePageID = pMiniDefTrans->ubCodePageID; pNewTrans->ubType = pMiniDefTrans->ubType; switch (pNewTrans->ubType & MTYPE_FORMAT_MASK) { case MTYPE_COMPOSE: pNewTrans->uCode.ubCode = pMiniDefTrans->uCode.ubCode; break; case MTYPE_DIRECT: pNewTrans->uCode.ubPairs[0] = pMiniDefTrans->uCode.ubPairs[0]; pNewTrans->uCode.ubPairs[1] = pMiniDefTrans->uCode.ubPairs[1]; break; case MTYPE_PAIRED: pNewTrans->uCode.sCode = pMiniDefTrans->uCode.sCode; break; } pNewTrans ++; if (!bInRun) { dwRunCount ++; bInRun = TRUE; } } else { if (bInRun) { bInRun = FALSE; } } } } // // Crate FD_GLYPHSET // // Memory allocation with dwGlyphNum and dwRunCount. // // ----------------- // Predefined FD_GLYPHSET // ----------------- // Minidriver additional glyph run // ---------------- // // // Now we know the number of run. Allocate memory for FD_GLYPHSET. // *pdwFD_GLYPHSETSize = sizeof(FD_GLYPHSET) + sizeof(WCRUN) * dwRunCount + sizeof(HGLYPH) * dwGlyphNum; if((*ppFD_GLYPHSET = (FD_GLYPHSET*)MemAlloc(*pdwFD_GLYPHSETSize)) == NULL) { MemFree(*ppMapTable); return FALSE; } (*ppFD_GLYPHSET)->cjThis = *pdwFD_GLYPHSETSize; (*ppFD_GLYPHSET)->cGlyphsSupported = *pdwFD_GLYPHSETSize; (*ppFD_GLYPHSET)->cRuns = dwRunCount; pWCRun = (*ppFD_GLYPHSET)->awcrun; pHGlyph = (HGLYPH*)((PBYTE)*ppFD_GLYPHSET + sizeof(FD_GLYPHSET) + sizeof(WCRUN) * dwRunCount); pPreDefGlyphRun = GET_GLYPHRUN(pPreDefGTT); pMiniDefGlyphRun = GET_GLYPHRUN(pMiniDefGTT); pMiniDefTrans = pMiniMapTable->Trans; for (dwI = 1; dwI <= dwGlyphNum; dwI ++, *pHGlyph) { *pHGlyph = dwI; } pHGlyph = (HGLYPH*)((PBYTE)*ppFD_GLYPHSET + sizeof(FD_GLYPHSET) + sizeof(WCRUN) * dwRunCount); for (dwI = 0; dwI < pPreDefGlyphRun->wGlyphCount; dwI ++) { pWCRun->wcLow = wcLow = pPreDefGlyphRun->wcLow; wcHigh = wcLow + pPreDefGlyphRun->wGlyphCount; bInRun = FALSE; for (wJ = pPreDefGlyphRun->wcLow; wJ < wcHigh; wJ ++) { if (MTYPE_DISABLE == DwCheckTrans(pMiniDefGlyphRun, pMiniMapTable, pMiniDefGTT->dwRunCount, wJ)) { if (bInRun) { pWCRun->cGlyphs = wJ - wcLow + 1; pWCRun->phg = pHGlyph; pHGlyph += pWCRun->cGlyphs; pWCRun ++; bInRun = FALSE; } } else { if (!bInRun) { pWCRun->wcLow = wcLow = wJ; wcHigh = wcLow + pPreDefGlyphRun->wGlyphCount; bInRun = TRUE; } } } pWCRun->cGlyphs = wcHigh - wcLow; pWCRun->phg = pHGlyph; pWCRun ++; } bInRun = FALSE; for (dwI = 0; dwI < pMiniDefGlyphRun->wGlyphCount; dwI ++) { for (wJ = pMiniDefGlyphRun->wcLow; wJ < wcHigh; wJ ++, pMiniDefTrans ++) { if (pMiniDefTrans->ubType & MTYPE_ADD) { if (!bInRun) { pWCRun->wcLow = wcLow = wJ; bInRun = TRUE; } } else { if (bInRun) { pWCRun->cGlyphs = wJ - wcLow + 1; pWCRun->phg = pHGlyph; pHGlyph += pWCRun->cGlyphs; bInRun = FALSE; } } } } return TRUE; } DWORD DwCheckTrans( PGLYPHRUN pMiniGlyphRun, PMAPTABLE pMiniMapTable, DWORD dwMiniGlyphRunCount, WORD wUnicode) { DWORD dwI; WORD wIndex; for (dwI = 0; dwI < dwMiniGlyphRunCount; dwI ++, pMiniGlyphRun ++) { if (wUnicode < pMiniGlyphRun->wcLow) { continue; } if (wUnicode < pMiniGlyphRun->wcLow + pMiniGlyphRun->wGlyphCount) { wIndex = wUnicode - pMiniGlyphRun->wcLow; return pMiniMapTable->Trans[wIndex].ubType & MTYPE_PREDEFIN_MASK; } else { return 0; } } return 0; } int __cdecl Comp(const void *elem1, const void *elem2) { //struct { // WORD wID; // WCHAR Unicode; //} UnicodeDst[256]; // // Compare Unicode in this data structure // return *((PWORD)elem1+1) - *((PWORD)elem2+1); }