/*++ Copyright (c) 1996 - 1999 Microsoft Corporation Module Name: ctt2rle.c Abstract: Convert Win 3.1 CTT CTT_WTYPE_DIRECT format tables to NT 4.0 RLE spec. Environment: Windows NT Unidrv driver Revision History: 01/10/97 -ganeshp- Created --*/ #include "font.h" /* * Some useful definitions for memory sizes and masks. */ #define DW_MASK (DWBITS - 1) #define OVERFLOW_SZ sizeof( WORD ) NT_RLE * PNTRLE1To1( IN BOOL bSymbolCharSet, int iFirst, int iLast ) /*++ Routine Description: Generates a simple mapping format for the RLE 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 NT_RLE structure allocated from heap; NULL on failure. Note: 2/10/1997 -ganeshp- Created it. --*/ { /* * Operation is simple. We create a dummy CTT that is a 1:1 mapping, * then call the conversion function to generate the correct values. */ int iI; /* Loop index */ int iMax; /* Find the longest data length for CTT_WTYPE_COMPOSE */ int cHandles; /* The number of handles we need */ int cjExtra; /* Extra storage needed for offset modes */ int cjTotal; /* Total amount of storage to be requested */ int iIndex; /* Index we install in the HGLYPH for widths etc */ int cRuns; /* Number of runs we create */ NT_RLE *pntrle; /* Allocated memory, and returned to caller */ UHG uhg; /* Clearer (?) access to HGLYPH contents */ HGLYPH *phg; /* For working through the array of HGLYPHS */ BYTE *pb; /* Current address in overflow area */ BYTE *pbBase; /* Start of overflow area containing data */ WCRUN *pwcr; /* Scanning the run data */ DWORD *pdwBits; /* For figuring out runs */ DWORD cdwBits; /* Size of this area */ DWORD cbWch; BOOL bInRun; /* For processing run accumulations */ BYTE ajAnsi[ 256 ]; WCHAR wchMin; /* Find the first unicode value */ WCHAR wchMax; /* Find the last unicode value */ WCHAR awch[ 512 ]; /* Converted array of points */ ASSERT(iFirst == 0x20 && iLast == 0xFF); cHandles = iLast - iFirst + 1; if( cHandles > 256 ) return NULL; /* This code does not handle that situation */ cjExtra = 0; /* Presume no extra storage required */ /* * We need to figure out how many runs are required to describe * this font. First obtain the correct Unicode encoding of these * values, then examine them to find the number of runs, and * hence much extra storage is required. */ ZeroMemory(awch, sizeof(awch)); for( iI = 0; iI < cHandles; ++iI ) ajAnsi[ iI ] = (BYTE)(iI + iFirst); #ifndef WINNT_40 //NT 5.0 // // force Windows ANSI codepage // if( -1 == (cbWch = EngMultiByteToWideChar(1252, awch, (ULONG)(cHandles * sizeof(WCHAR)), (PCH) ajAnsi, (ULONG) cHandles))) { #if DBG DbgPrint( "EngMultiByteToWideChar failed \n"); #endif return NULL; } cHandles = cbWch; #else // NT 4.0 EngMultiByteToUnicodeN(awch,cHandles * sizeof(WCHAR),NULL,ajAnsi,cHandles); #endif //!WINNT_40 /* * Find the largest Unicode value, then allocate storage to allow us * to create a bit array of valid unicode points. Then we can * examine this to determine the number of runs. */ if (bSymbolCharSet) { for (iI = 0; iI < NUM_OF_SYMBOL; iI ++) { awch[cHandles + iI] = SYMBOL_START + iI; } cHandles += NUM_OF_SYMBOL; } for( wchMax = 0, wchMin = 0xffff, iI = 0; iI < cHandles; ++iI ) { // // Bugfix: Euro currency symbol doesn't print. // Euro currency symbols Unicode is U+20AC. NLS Unicode to Multibyte // table converts 0x80 (Multi byte) to U+20AC. We have to exclude // 0x80 from ASCII table. So that we don't substitute U+20AC with // device font 0x80. // if (awch[ iI ] == 0x20ac) continue; if( awch[ iI ] > wchMax ) wchMax = awch[ iI ]; if( awch[ iI ] < wchMin ) wchMin = awch[ iI ]; } /* * Note that the expression 1 + wchMax IS correct. This comes about * from using these values as indices into the bit array, and that * this is essentially 1 based. */ cdwBits = (1 + wchMax + DWBITS - 1) / DWBITS * sizeof( DWORD ); if( !(pdwBits = (DWORD *)MemAllocZ(cdwBits )) ) { return NULL; /* Nothing going */ } /* * Set bits in this array corresponding to Unicode code points */ for( iI = 0; iI < cHandles; ++iI ) { if (awch[ iI ] == 0x20ac) continue; pdwBits[ awch[ iI ] / DWBITS ] |= (1 << (awch[ iI ] & DW_MASK)); } /* * Now we can examine the number of runs required. For starters, * we stop a run whenever a hole is discovered in the array of 1 * bits we just created. Later we MIGHT consider being a little * less pedantic. */ bInRun = FALSE; cRuns = 0; /* None so far */ for( iI = 1; iI <= (int)wchMax; ++iI ) { if( pdwBits[ iI / DWBITS ] & (1 << (iI & DW_MASK)) ) { /* * Not in a run: is this the end of one? */ if( !bInRun ) { /* * It's time to start one */ bInRun = TRUE; ++cRuns; } } else { if( bInRun ) { /* Not any more! */ bInRun = FALSE; } } } cjTotal = sizeof( NT_RLE ) + (cRuns - 1) * sizeof( WCRUN ) + cHandles * sizeof( HGLYPH ) + cjExtra; // // Allocate Real NTRLE // if( !(pntrle = (NT_RLE *)MemAllocZ( cjTotal )) ) { MemFree((LPSTR)pdwBits ); return pntrle; } // // For calculating offsets, we need these addresses // pbBase = (BYTE *)pntrle; // // FD_GLYPHSET contains the first WCRUN data structure, // so that cRun - 1 is correct. // phg = (HGLYPH *)(pbBase + sizeof( NT_RLE ) + (cRuns - 1) * sizeof( WCRUN )); pb = (BYTE *)phg + cHandles * sizeof( HGLYPH ); pntrle->wType = RLE_DIRECT; pntrle->bMagic0 = RLE_MAGIC0; pntrle->bMagic1 = RLE_MAGIC1; pntrle->cjThis = cjTotal; pntrle->wchFirst = wchMin; /* Lowest unicode code point */ pntrle->wchLast = wchMax; /* Highest unicode code point */ pntrle->fdg.cjThis = sizeof( FD_GLYPHSET ) + (cRuns - 1) * sizeof( WCRUN ); pntrle->fdg.cGlyphsSupported = cHandles; pntrle->fdg.cRuns = cRuns; pntrle->fdg.awcrun[ 0 ].wcLow = pntrle->wchFirst; pntrle->fdg.awcrun[ 0 ].cGlyphs = (WORD)cHandles; pntrle->fdg.awcrun[ 0 ].phg = (HGLYPH*)((BYTE *)phg - pbBase); /* * We now wish to fill in the awcrun data. Filling it in now * simplifies operations later on. Now we can scan the bit array * data, and so easily figure out how large the runs are and * where abouts a particular HGLYPH is located. */ bInRun = FALSE; cRuns = 0; /* None so far */ iMax = 0; /* Count glyphs for address arithmetic */ for( iI = 1; iI <= (int)wchMax; ++iI ) { if( pdwBits[ iI / DWBITS ] & (1 << (iI & DW_MASK)) ) { /* * Not in a run: is this the end of one? */ if( !bInRun ) { /* * It's time to start one */ bInRun = TRUE; pntrle->fdg.awcrun[ cRuns ].wcLow = (WCHAR)iI; pntrle->fdg.awcrun[ cRuns ].cGlyphs = 0; pntrle->fdg.awcrun[ cRuns ].phg = (HGLYPH*)((PBYTE)(phg + iMax) - pbBase); } pntrle->fdg.awcrun[ cRuns ].cGlyphs++; /* One more */ ++iMax; } else { if( bInRun ) { /* Not any more! */ bInRun = FALSE; ++cRuns; /* Onto the next structure */ } } } if( bInRun ) ++cRuns; /* It has finished now */ /* * Now go fill in the array of HGLYPHS. The actual format varies * depending upon the range of glyphs, and upon the CTT format. */ for( iIndex = 0, iI = iFirst; iI <= iLast; ++iI, ++iIndex ) { WCHAR wchTemp; /* For Unicode mapping */ /* * Need to map this BYTE value into the appropriate WCHAR * value, then look for the location of the phg that fits. */ wchTemp = awch[ iIndex ]; if (wchTemp == 0x20ac) continue; phg = NULL; /* Flag that we failed */ pwcr = pntrle->fdg.awcrun; for( iMax = 0; iMax < cRuns; ++iMax ) { if( pwcr->wcLow <= wchTemp && (pwcr->wcLow + pwcr->cGlyphs) > wchTemp ) { /* * Found the range, so now select the slot */ if (pwcr->phg) phg = (HGLYPH*)((ULONG_PTR)pbBase + (ULONG_PTR)pwcr->phg) + wchTemp - pwcr->wcLow; else phg = NULL; break; } ++pwcr; } if( phg == NULL ) continue; /* Should not happen */ uhg.rd.b0 = *((PBYTE)&iI); uhg.rd.b1 = 0; uhg.rd.wIndex = (WORD)iIndex; *phg = uhg.hg; } if (bSymbolCharSet) { pwcr = pntrle->fdg.awcrun; phg = NULL; for ( iMax = 0; iMax < cRuns; ++iMax) { if (SYMBOL_START == pwcr->wcLow) { /* * Found the range, so now select the slot */ if (pwcr->phg) phg = (HGLYPH*)((ULONG_PTR)pbBase + (ULONG_PTR)pwcr->phg); else phg = NULL; break; } ++pwcr; } if (phg) { for (iI = SYMBOL_START; iI <= SYMBOL_END; iI ++, iIndex++, phg++) { uhg.rd.b0 = *((PBYTE)&iI); uhg.rd.b1 = 0; uhg.rd.wIndex = (WORD)iIndex; *phg = uhg.hg; } } } // // Error check // if( (pb - pbBase) > cjTotal ) { ERR(( "Rasdd!ctt2rle: overflow of data area: alloc %ld, used %ld\n", cjTotal, pb - pbBase )); } MemFree( (LPSTR)pdwBits ); return pntrle; }