/******************************Module*Header*******************************\ * Module Name: stretch.c * * Routines to stretch a glyph bitmap up to five times in the x direction * and an arbitrary number of times in the y direction. These limits are * the ones imposed by windows. * * Created: 7-Dec-1992 16:00:00 * Author: Gerrit van Wingerden * * Copyright (c) 1992 Microsoft Corporation \**************************************************************************/ #include "fd.h" // Since there are only four ways we can stretch in the x direction we use // tables to do our stretching. The tables index 2 to 3 bit quantities to // bytes or words that correspond to the stretched values of those quantities. // This is much faster than doing all the shifting neccesary to stretch those // quantities. BYTE ajStretch2[16] = { 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF }; BYTE ajStretch3B1[8] = { 0x00, 0x03, 0x1C, 0x1F, 0xE0, 0xE3, 0xFC, 0xFF }; BYTE ajStretch3B2[16] = { 0x00, 0x01, 0x0E, 0x0F, 0x70, 0x71, 0x7E, 0x7F, 0x80, 0x81, 0x8E, 0x8F, 0xF0, 0xF1, 0xFE, 0xFF }; BYTE ajStretch3B3[8] = { 0x00, 0x07, 0x38, 0x3F, 0xC0, 0xC7, 0xF8, 0xFF }; WORD awStretch4[16] = { 0x0000, 0x0F00, 0xF000, 0xFF00, 0x000F, 0x0F0F, 0xF00F, 0xFF0F, 0x00F0, 0x0FF0, 0xF0F0, 0xFFF0, 0x00FF, 0x0FFF, 0xF0FF, 0xFFFF }; WORD awStretch5W1[16] = { 0x0000, 0x0100, 0x3E00, 0x3F00, 0xC007, 0xC107, 0xFE07, 0xFF07, 0x00F8, 0x01F8, 0x3EF8, 0x3FF8, 0xC0FF, 0xC1FF, 0xFEFF, 0xFFFF }; WORD awStretch5W2[16] = { 0x0000, 0x0300, 0x7C00, 0x7F00, 0x800F, 0x830F, 0xFC0F, 0xFF0F, 0x00F0, 0x03F0, 0x7CF0, 0x7FF0, 0x80FF, 0x83FF, 0xFCFF, 0xFFFF }; BYTE ajStretch5B1[4] = { 0x00, 0x1F, 0xE0, 0xFF }; /**************************************************************************\ * void vEmboldenItalicizeLine * * Emboldens and italicizes a scan line. * * Created: 7-Dec-1992 16:00:00 * Author: Gerrit van Wingerden * * Copyright (c) 1992 Microsoft Corporation \**************************************************************************/ void vEmboldenItalicizeLine( BYTE *pjDst, // Destitnation scan line BYTE *pjSrc, // Source scan line BYTE *pjEnd, // End of source scan line LONG lShift, // Amount by which to shift UINT uiPixelWidth // Width of scan line in pixels ) { BYTE jSrcItalic; BYTE jCarry = (BYTE) 0; BYTE jCarryBold = (BYTE) 0; for( ; pjSrc < pjEnd; pjDst++, pjSrc++ ) { jSrcItalic = (BYTE) ( (*pjSrc >> lShift) | jCarry ); *pjDst = (BYTE) ( jSrcItalic | ( jSrcItalic >> 1 ) | jCarryBold ); // remember the lShift rightmost and mve them over to the left jCarry = (BYTE) ( *pjSrc << ( 8 - lShift )); jCarryBold = (BYTE) ( jSrcItalic << 7 ); } if( ( (long) ( 8 - ( uiPixelWidth & 7l )) & 7l ) < lShift ) { jSrcItalic = jCarry; *pjDst = (BYTE) ( jSrcItalic | ( jSrcItalic >> 1 ) | jCarryBold ); jCarryBold = (BYTE) (jSrcItalic << 7 ); if( ( uiPixelWidth & 0x7l ) == 0l ) { *(++pjDst) = jCarryBold; } } } /**************************************************************************\ * void vEmboldenLine * * Emboldens a scan line. * * Created: 7-Dec-1992 16:00:00 * Author: Gerrit van Wingerden * * Copyright (c) 1992 Microsoft Corporation \**************************************************************************/ void vEmboldenLine( BYTE *pjDst, // Destination scan line BYTE *pjSrc, // Source scan line BYTE *pjEnd, // End of dest scan line UINT uiPixelWidth // Width of scan line in pixels ) { BYTE jCarry = (BYTE) 0; for( ; pjDst < pjEnd; pjDst++, pjSrc++ ) { *pjDst = ( *pjSrc | (( *pjSrc >> 1 ) | jCarry )); jCarry = ( *pjSrc << 7); } if( (( uiPixelWidth << 1 ) & 7l ) == 0l ) *pjDst = jCarry; } /**************************************************************************\ * void vItalicizeLine * * Italicizes a scan line. * * Created: 7-Dec-1992 16:00:00 * Author: Gerrit van Wingerden * * Copyright (c) 1992 Microsoft Corporation \**************************************************************************/ void vItalicizeLine( BYTE *pjDst, // Destitnation scan line BYTE *pjSrc, // Source scan line BYTE *pjEnd, // End of source scan line LONG lShift, // Amount by which to shift UINT uiPixelWidth // Width of scan line in pixels ) { BYTE jCarry = (BYTE) 0; for( ; pjSrc < pjEnd; pjDst++, pjSrc++ ) { *pjDst = (( *pjSrc >> lShift ) | jCarry ); jCarry = ( *pjSrc << ( 8 - lShift) ); } if( ( (long) ( 8 - ( uiPixelWidth & 7l )) & 7l ) < lShift ) *pjDst = jCarry; } /*************************************************************************\ * VOID vStretchGlyphBitmap * * Stretches a bitmap in fontfile format ( collumns ) to a row format and * performs bold and italic simulations. This routine could be faster * by spliting it up into several special case routines to handle simulations * and or different widths or by inlining the italicizing or emboldening * routines. However, we hardly ever need to stretch bitmap fonts so it * was deemed better to have one, nice neat routine that takes up less * code than several routines that are overall faster. * * * Created: 7-Dec-1992 16:00:00 * Author: Gerrit van Wingerden [gerritv] * * Copyright (c) 1992 Microsoft Corporation \**************************************************************************/ VOID vStretchGlyphBitmap( BYTE *pjTarget, // Target bitmap BYTE *pjSourceBitmap, // Source bitmap BYTE *pjLineBuffer, // Scan line buffer UINT uiPixelWidth, // Width of bitmap in pixels UINT uiHeight, // Height of bitmap in bits UINT uiVertScale, // Vertical scaling factor UINT uiHorzScale, // Horizontal scaling factor UINT flSim ) // Simulation flags { BYTE *pjSource, *pjBufferBase, *pjScanEnd, *pjSimEnd; UINT uiScanDelta, uiNewWidth, uiNewWidthSim, cjEmpty, uiCurScan; LONG lShift; BYTE *pjDone = pjSourceBitmap + uiHeight; uiNewWidth = ( ( uiPixelWidth * uiHorzScale ) + 7 ) >> 3; pjSimEnd = pjLineBuffer + uiNewWidth; cjEmpty = 0; switch( flSim ) { case (FO_SIM_ITALIC | FO_SIM_BOLD): // fall through to the italic case with one added to cxOffset case FO_SIM_ITALIC: { UINT cxOffset = ( uiHeight * uiVertScale - 1 ) / 2; if( flSim & FO_SIM_BOLD ) cxOffset += 1; uiNewWidthSim = ( ( uiPixelWidth * uiHorzScale ) + cxOffset + 7 ) >> 3; uiCurScan = 0; lShift = cxOffset & (UINT) 7; cjEmpty = cxOffset >> 3; break; } case FO_SIM_BOLD: uiNewWidthSim = ( ( uiPixelWidth *uiHorzScale ) + 8 ) >> 3; break; default: uiNewWidthSim = uiNewWidth; break; } // output bytes generated per new scan line uiScanDelta = uiNewWidthSim * uiVertScale; for( ; pjSourceBitmap < pjDone; pjSourceBitmap += 1 ) { // first stretch one scan line for( pjSource = pjSourceBitmap, pjBufferBase = pjLineBuffer; pjBufferBase < pjLineBuffer + uiNewWidth; pjSource += uiHeight ) { switch( uiHorzScale ) { case 1: // don't stretch just copy *pjBufferBase++ = *pjSource; break; case 2: // stretch first nibble *pjBufferBase++ = ajStretch2[ *pjSource >> 4]; //stretch second nibble *pjBufferBase++ = ajStretch2[ *pjSource & 0xf]; break; case 3: // first byte *pjBufferBase++ = ajStretch3B1[ *pjSource >> 5]; // second byte *pjBufferBase++ = ajStretch3B2[ (*pjSource >> 2) & 0xf]; // third byte *pjBufferBase++ = ajStretch3B3[ *pjSource &0x7]; break; case 4: // I know this is strange but I didn't think about alignment // errors when I used word sized tables. So i had to hack it. // !!! later these tables should be writen to be byte tables. // [gerritv] // first nibble *pjBufferBase++ = ((BYTE*)(&awStretch4[ *pjSource >> 4]))[0]; *pjBufferBase++ = ((BYTE*)(&awStretch4[ *pjSource >> 4]))[1]; // second nibble *pjBufferBase++ = ((BYTE*)(&awStretch4[ *pjSource & 0xf]))[0]; *pjBufferBase++ = ((BYTE*)(&awStretch4[ *pjSource & 0xf]))[1]; break; case 5: // first word *pjBufferBase++ = ((BYTE*)(&awStretch5W1[ *pjSource >> 4]))[0]; *pjBufferBase++ = ((BYTE*)(&awStretch5W1[ *pjSource >> 4]))[1]; // second byte *pjBufferBase++ = ((BYTE*)(&awStretch5W2[ (*pjSource >> 1) & 0xf]))[0]; *pjBufferBase++ = ((BYTE*)(&awStretch5W2[ (*pjSource >> 1) & 0xf]))[1]; // third byte *pjBufferBase++ = ajStretch5B1[ *pjSource &0x3]; break; } } // now copy stretched scan line uiVertScale times while making the bitmap byte aligned pjScanEnd = pjTarget + uiScanDelta; switch( flSim ) { case FO_SIM_ITALIC: for( ; pjTarget < pjScanEnd; pjTarget += uiNewWidthSim ) { vItalicizeLine( pjTarget + cjEmpty, pjLineBuffer, pjLineBuffer + uiNewWidth, lShift, uiPixelWidth * uiHorzScale ); lShift -= ( uiCurScan++ & 0x1 ); if( lShift < 0 ) { lShift = 7; cjEmpty--; } } break; case ( FO_SIM_ITALIC | FO_SIM_BOLD ): for( ; pjTarget < pjScanEnd; pjTarget += uiNewWidthSim ) { vEmboldenItalicizeLine( pjTarget + cjEmpty, pjLineBuffer, pjLineBuffer + uiNewWidth, lShift, uiPixelWidth * uiHorzScale ); lShift -= ( uiCurScan++ & 0x1 ); if( lShift < 0 ) { lShift = 7; cjEmpty--; } } break; case FO_SIM_BOLD: // first embolden this scan line vEmboldenLine( pjTarget, pjLineBuffer, pjTarget + uiNewWidth, uiPixelWidth * uiHorzScale ); pjBufferBase = pjTarget; pjTarget += uiNewWidthSim; for( ; pjTarget < pjScanEnd; pjTarget += uiNewWidthSim ) memcpy( (PVOID) pjTarget, (PVOID) pjBufferBase, (size_t) uiNewWidthSim ); break; case 0: // just copy the scan line uiVertScale times for( ; pjTarget < pjScanEnd; pjTarget += uiNewWidthSim ) memcpy( (PVOID) pjTarget, (PVOID) pjLineBuffer, (size_t) uiNewWidthSim ); break; } } } /***************************************************************************\ * VOID vStretchCvtToBitmap * * Stretches a bitmap and performs bold and italic simulations. * * Created: 7-Dec-1992 16:00:00 * Author: Gerrit van Wingerden * * Copyright (c) 1992 Microsoft Corporation \**************************************************************************/ VOID vStretchCvtToBitmap ( GLYPHBITS *pgb, PBYTE pjBitmap, // bitmap in *.fnt form ULONG cx, // unscaled width ULONG cy, // unscaled height ULONG yBaseline, // baseline from font file PBYTE pjLineBuffer, // preallocated buffer for use by stretch routines ULONG cxScale, // horizontal scaling factor ULONG cyScale, // vertical scaling factor ULONG flSim // simulation flags ) { ULONG cxNew, cyNew, yBaselineNew; // compute new height, width, and baseline cxNew = cx * cxScale; cyNew = cy * cyScale; yBaselineNew = yBaseline * cyScale; switch( flSim ) { case ( FO_SIM_ITALIC | FO_SIM_BOLD ): cxNew = cxNew + ( cyNew + 1 ) / 2; break; case FO_SIM_ITALIC: cxNew = cxNew + ( cyNew - 1 ) / 2; break; case FO_SIM_BOLD: cxNew += 1; break; case 0: break; } // glyphbits data pgb->sizlBitmap.cx = cxNew; pgb->sizlBitmap.cy = cyNew; pgb->ptlOrigin.x = 0l; pgb->ptlOrigin.y = -(LONG) yBaselineNew; RtlZeroMemory( pgb->aj, ( CJ_SCAN( cxNew )) * cyNew ); vStretchGlyphBitmap( pgb->aj, pjBitmap, pjLineBuffer, cx, cy, cyScale, cxScale, flSim ); }