mac-rom/Toolbox/FontMgr/embeddedBitmap.c
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

716 lines
22 KiB
C

/*
File: embeddedBitmap.c
Contains: Code to read embedded bitmaps in 'bloc' & 'bdat' tables in sfnts.
Written by: Richard Becker
Copyright: © 1991 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<1> 10/23/91 RB first checked in
*/
#if TheFuture
#include "setjmp.h"
#include "FSError.h"
#include "FSCdefs.h"
#include "FontMath.h"
#include "sfnt.h"
#include "sc.h"
#include "fnt.h"
#include "FontScaler.h"
#include "FSGlue.h"
#include "privateSFNT.h"
#include "embeddedBitmap.h"
// private prototypes
static uint8 bm_availFontBits(uint8 hPpem, uint8 vPpem, uint16 size, uint8* p, int16* jTable );
static uint8 bm_bestScalableGlyph( fsg_SplineKey* key );
static uint8 bm_calcMethod( uint8 method, uint8 bitmapPreferences, uint8 usefulOutlines );
static uint16 bm_bDatOffset1( uint16* p, uint8 shift, uint8 n, uint16 glyph, uint32* offsetP );
static uint16 bm_bDatOffset( fsg_SplineKey* key );
uint8* MAGICREED( fsg_SplineKey* key , sfnt_tableIndex n, uint32 offset, uint32 length );
static void stretchRow( uint8* sP, uint8* dP, int sWide, int dWide, Fixed r, int sOffset, int8 xSide );
/* rwb 7/19/91
* key contains a target hPpem, vPpem, ps, and glyph index
* key contains a pointer to a bloc table
* Find the best bitmap table that actually has data for that glyph.
* Fill out parameters specifying hPpem, vPpem, & ps of best match
* Also fill out offset of glyph bitmap data
* Fill out output record fields.
*/
void bm_bestMatchGlyph(fs_GlyphInputType *inputPtr, fsg_SplineKey* key, fs_GlyphInfoType *outputPtr )
{
uint8 success;
if( inputPtr->param.newglyph.bitmapMethodPreferences != key->bitmapPreferences )
{
key->bitmapPreferences = inputPtr->param.newglyph.bitmapMethodPreferences;
key->methodToBeUsed = bm_calcMethod( key->availMatchFont, key->bitmapPreferences, key->usefulOutlines );
}
else key->methodToBeUsed = key->methodToBeUsedFont;
if( key->methodToBeUsed == 2 || key->methodToBeUsed == 3)
{
key->bestHorPpemGlyph = key->bestHorPpemFont;
key->bestVerPpemGlyph = key->bestVerPpemFont;
key->bestPointSizeGlyph = key->bestPointSizeFont;
key->indexShiftGlyph = key->indexShiftFont;
key->indexNbaseGlyph = key->indexNbaseFont;
key->indexOffsetGlyph = key->indexOffsetFont;
key->lengthBitData = bm_bDatOffset( key );
if( key->lengthBitData == 0 )
{
switch( key->bitmapPreferences )
{
case 0: key->methodToBeUsed = key->usefulOutlines ? 0 : 1;
break;
case 1: key->methodToBeUsed = 1;
break;
case 2: key->methodToBeUsed = 1;
break;
// case 3 can't happen
case 4: key->methodToBeUsed = 1;
break;
case 5: key->methodToBeUsed = 4;
break;
}
}
}
if( key->methodToBeUsed == 1 )
{
success = bm_bestScalableGlyph( key );
if( success == 4 && key->bitmapPreferences == 4 ) key->methodToBeUsed = 4;
else if( success == 4 && key->usefulOutlines == 0 ) key->methodToBeUsed = 4;
else if( success == 4 ) key->methodToBeUsed = 0;
}
if( key->methodToBeUsed == 4 || key->methodToBeUsed == 0)
{
key->bestHorPpemGlyph = 0;
key->bestVerPpemGlyph = 0;
}
/* now fill out the output record */
outputPtr->bitmapMethod = key->methodToBeUsed;
outputPtr->bitmapHorizontalPPEM = key->bestHorPpemGlyph;
outputPtr->bitmapVerticalPPEM = key->bestVerPpemGlyph;
}
/* rwb 7/25/91
* Attempt to find best scalable glyph data; (assumes method == 1)
* Fill out bestHorPpemGlyph, bestVerPpemGlyph, bestPointSizeGlyph, indexShiftGlyph,
* indexNbaseGlyph, offsetBitData in key.
* Set method to 4 if unsuccessful.
*/
static uint8 bm_bestScalableGlyph( fsg_SplineKey* key )
{
uint8 avail;
uint8* pt;
int16 table;
key->bestHorPpemGlyph = key->bestHorPpemFont;
key->bestVerPpemGlyph = key->bestVerPpemFont + 1;
key->bestPointSizeGlyph = key->bestPointSizeFont;
do
{
--key->bestVerPpemGlyph;
avail = bm_availFontBits( key->bestHorPpemGlyph, key->bestVerPpemGlyph, key->desiredPointSize,
key->blocPointer, &table );
if( avail )
{
pt = key->blocPointer + 8 + (SIZESUBTABLESIZE * table); //address of size-subtable
key->bestHorPpemGlyph = *pt;
key->bestVerPpemGlyph = *(pt+1);
key->bestPointSizeGlyph = *((uint16*)(pt+2));
key->indexShiftGlyph = *(pt+14);
key->indexNbaseGlyph = *(pt+15);
key->indexOffsetGlyph = *((uint32*)(pt+16));
key->lengthBitData = bm_bDatOffset( key );
}
else return 4;
} while( key->lengthBitData == 0 );
return 1;
}
/* rwb 7/19/91
* Given a target hPpem, vPpem, & ps
* Given pointer to a bloc table. (set when new_sfnt looked for bitmaps)
* Find the best bitmap table match in this font.
* Fill out parameters specifying hPpem, vPpem, & ps of best match
* Also fill out offset of index subtable for the match.
* Fillout indicator of match quality =
* 0 - no bitmap match available
* 1 - scalable match available
* 2 - exact match available
* 3 - exact match available except for pointsize
* Fill out output record fields.
*/
void bm_bestMatchFont( fsg_SplineKey* key, fs_GlyphInfoType *outputPtr )
{
uint8* pt;
int16 table;
uint8 method = bm_availFontBits( key->desiredHorPpem, key->desiredVerPpem, key->desiredPointSize,
key->blocPointer, &table );
key->indexPtrGlyph = 0;
if( method )
{
key->availMatchFont = method;
pt = key->blocPointer;
key->numberGlyphs = *((uint16*)(pt+4));
pt += ( 8 + (SIZESUBTABLESIZE * table)); //address of size-subtable
key->bestHorPpemFont = *pt;
key->bestVerPpemFont = *(pt+1);
key->bestPointSizeFont = *((uint16*)(pt+2));
key->horAscent = *(pt+4);
key->horDescent = *(pt+5);
key->horLineGap = *(pt+6);
key->horAdvanceMax = *(pt+7);
key->verAscent = *(pt+8);
key->verDescent = *(pt+9);
key->verLineGap = *(pt+10);
key->verAdvanceMax = *(pt+11);
key->indexShiftFont = *(pt+14);
key->indexNbaseFont = *(pt+15);
key->indexOffsetFont = *((uint32*)(pt+16));
key->indexFormat = *(pt+20);
key->dataFormat = *(pt+21);
key->methodToBeUsedFont = bm_calcMethod( method, key->bitmapPreferences, key->usefulOutlines );
}
else
{
key->availMatchFont = 0;
key->methodToBeUsedFont = key->usefulOutlines ? 0 : 4;
key->bestHorPpemFont = 0;
key->bestVerPpemFont = 0;
}
/* now fill out the output record */
outputPtr->bitmapMethod = key->methodToBeUsedFont;
outputPtr->bitmapHorizontalPPEM = key->bestHorPpemFont;
outputPtr->bitmapVerticalPPEM = key->bestVerPpemFont;
}
/* rwb 7/1/91
* Given a target horiz ppem, vert ppem & point-size.
* Given a pointer to a bloc table.
* Return an indicator =
* 0 - no match available.
* 1 - exact match available.
* 2 - exact match except for point-size available.
* 3 - scalable resolution available.
* Use x res + y res as decision criteria, providing that both x & Y are smaller than target.
* If bitmap is available, set *jTable to which table provides the best match.
*/
static uint8 bm_availFontBits(uint8 hPpem, uint8 vPpem, uint16 size, uint8* p, int16* jTable )
{
int distance = 1025;
uint16 n = *((uint16*)(p+6)); // number of size-subtables
int dSize = 0;
int table = 0;
uint16 s;
int j;
p += 8; //start of subtables
for(j=0; j<n; ++j)
{
int d = (*p > hPpem) ? 512 : hPpem - *p;
d += (*(p+1) > vPpem) ? 512 : vPpem - *(p+1);
if( d < distance )
{
distance = d;
table = j;
s = *((uint16*)(p+2));
dSize = ( (s == size) || (s == 0)) ? 0 : 1;
}
p += SIZESUBTABLESIZE; //size of a size-subtable
}
if(distance > 511)
{
*jTable = 0;
return 0;
}
*jTable = table;
if(distance == 0 && dSize == 0) return 2;
if(distance == 0) return 3;
return 1;
}
/* rwb 7/23/91
* Given bitmap availability, bitmapPreferences, and outline availability
* Calculate closest match to preferences
*/
static uint8 bm_calcMethod( uint8 method, uint8 bitmapPreferences, uint8 usefulOutlines )
{
if( method == 0 )
{
if( (bitmapPreferences <= 3 && !usefulOutlines)
|| (bitmapPreferences >= 4 )) method = 4;
}
else switch( bitmapPreferences )
{
case 0: if( usefulOutlines && method == 1 ) method = 0;
break;
case 2: if( usefulOutlines ) method = 0;
break;
case 3: method = usefulOutlines ? 0 : 4;
break;
case 5: if( method == 1) method = 4;
break;
// cases 1 & 4 leave method unchanged
}
return method;
}
/* rwb 7/26/91
* Given a bitmap Method and an Offset into the bdat table.
* Read the bdat table, cache the pointer.
* Fill out the sc_BitMapData structure with metrics (may be scaled) info.
* ONLY Formats 2 & 4
*/
void bm_fillOutBMdata( sc_BitMapData* dest, metricsType* metric, fsg_SplineKey* key )
{
#define SCALE( num, den) ((ShortMulDiv( temp<<16, num, den ) + 0x8000) >> 16)
uint8 pixelWidth, pixelHeight, destWidth;
uint8 format = key->dataFormat;
uint8* source = MAGICREED( key, sfnt_bitmapData, key->offsetBitData, key->lengthBitData);
uint8* begin = source;
int scaleB = ( key->methodToBeUsed == 1 );
int16 xNum = key->desiredHorPpem;
int16 xDen = key->bestHorPpemGlyph;
int16 yNum = key->desiredVerPpem;
int16 yDen = key->bestVerPpemGlyph;
Fixed temp;
temp = key->pixHeightSource = *source++;
pixelHeight = scaleB ? (uint8)SCALE( yNum, yDen ) : temp;
temp = key->pixWidthSource = *source++;
pixelWidth = scaleB ? (uint8)SCALE( xNum, xDen ) : temp;
if( format == 1 || format == 4 || format == 6 ) // read vertical bearings & advance
{
if( format == 1 ) source += 4; // skip horizontal
else if( format == 6 ) source += 3;
temp = key->vBearingXsource = *source++;
dest->xMin = scaleB ? (uint8)SCALE( xNum, xDen ) : temp;
metric->devLeftSideBearing.x = metric->leftSideBearing.x = metric->leftSideBearingLine.x \
= metric->devLeftSideBearingLine.x = dest->xMin << 16;
temp = key->vBearingYsource = *source++;
dest->yMax = scaleB ? (uint8)SCALE( yNum, yDen ) : temp;
metric->devLeftSideBearing.y = metric->leftSideBearing.y = metric->leftSideBearingLine.y \
= metric->devLeftSideBearingLine.y = dest->yMax << 16;
if( format == 1 )
{
temp = *((int16*)source);
source += 2;
}
else temp = *source++;
key->vAdvanceSource = temp;
metric->advanceWidth.x = metric->devAdvanceWidth.x = scaleB ? (uint8)SCALE( xNum, xDen ) : *source << 16;
metric->advanceWidth.y = metric->devAdvanceWidth.y = 0;
}
if( format == 1 || format == 2 || format == 6 ) // now overwrite with horizontal stuff
{
if( format == 1 ) source -= 8; // go back to horizontal
else if( format == 6 ) source -= 6;
temp = key->hBearingXsource =*source++;
dest->xMin = scaleB ? (uint8)SCALE( xNum, xDen ) : temp;
metric->devLeftSideBearing.x = metric->leftSideBearing.x = metric->leftSideBearingLine.x \
= metric->devLeftSideBearingLine.x = dest->xMin << 16;
temp = key->hBearingYsource = *source++;
dest->yMax = scaleB ? (uint8)SCALE( yNum, yDen ) : temp;
metric->devLeftSideBearing.y = metric->leftSideBearing.y = metric->leftSideBearingLine.y \
= metric->devLeftSideBearingLine.y = dest->yMax << 16;
if( format == 1 )
{
temp = *((int16*)source);
source += 2;
}
else temp = *source++;
key->hAdvanceSource = temp;
metric->advanceWidth.x = metric->devAdvanceWidth.x = scaleB ? (uint8)SCALE( xNum, xDen ) : *source << 16;
metric->advanceWidth.y = metric->devAdvanceWidth.y = 0;
if( format == 1 ) source += 4; // skip verticals
else if( format == 6 ) source += 3;
}
if( format == 1 )
{
key->numAttachments = *source++;
key->numComponents = *source++;
source += 2; // skip attachments offset
key->bitmapPtr = begin + *((uint16*)source); // might be pointer to components
}
else
{
key->bitmapPtr = source;
key->numAttachments = 0;
key->numComponents = 0;
}
dest->high = pixelHeight;
dest->yMin = dest->yMax - pixelHeight;
destWidth = (pixelWidth + 31) & ~31; //round up to a long
if( !(pixelWidth & 31)) destWidth += 32; //to be backward compatible with outlines
dest->wide = destWidth;
dest->xMax = dest->xMin + pixelWidth;
#undef SCALE
}
/* rwb 7/29/91
* Given the client preferences in the input record
* Given the current device specifications
* Fill out key->bitmapPreferences, scalingPreference, desiredHorPpem, desiredVerPpem,
* desiredPointSize,
* Return false for bitmaps not requested, else true.
*/
boolean bm_requestForBitmaps( fsg_SplineKey* key, fs_GlyphInputType *inputPtr )
{
register Fixed xppem, yppem;
if( inputPtr->param.newtrans.bitmapMethodPreferences == 3 ) return false;
if( key->currentTMatrix.transform[0][1] != 0 ||
key->currentTMatrix.transform[1][0] != 0) return false; // don't do rotated bitmaps
key->bitmapPreferences = inputPtr->param.newtrans.bitmapMethodPreferences;
key->scalingPreference = inputPtr->param.newtrans.scalingPreference;
xppem = ShortMulDiv( key->fixedPointSize, inputPtr->param.newtrans.xResolution, POINTSPERINCH );
yppem = ShortMulDiv( key->fixedPointSize, inputPtr->param.newtrans.yResolution, POINTSPERINCH );
xppem = FixMul( xppem, key->currentTMatrix.transform[0][0] );
yppem = FixMul( yppem, key->currentTMatrix.transform[1][1] );
key->desiredPointSize = (key->fixedPointSize + 0x8000) >> 16;
key->desiredHorPpem = (xppem + 0x8000) >> 16;
key->desiredVerPpem = (yppem + 0x8000) >> 16;
}
/* rwb 7/18/91
* Given a spline-key containing a copy of the size-subtable for the best match
* for the current transformation and a desired glyph.
* If necessary, read in the index-subtable, look up the glyph.
* Set offset to the required glyph-bitmap in key.
* Return the length of the glyph-bitmap data.
*/
static uint16 bm_bDatOffset( fsg_SplineKey* key )
{
int16 length, j;
uint8 indexF = key->indexFormat;
uint16* indexP = key->indexPtrGlyph;
uint8 nbase = key->indexNbaseGlyph;
uint16 glyph = key->glyphIndex;
int32 offset1, offset2;
if( indexF == 1 ) length = 4 * key->numberGlyphs + 4;
else if( indexF == 2 ) length = 2 * key->numberGlyphs + 2 + 4*key->indexNbaseGlyph;
else return 0;
if( indexP == 0 )
key->indexPtrGlyph = indexP =
(uint16*)MAGICREED( key, sfnt_bitmapLocation, key->indexOffsetGlyph, length);
if( indexF == 1)
{
offset1 = *((uint32*)indexP + glyph );
offset2 = *((uint32*)indexP + glyph + 1);
length = offset2 - offset1;
if( length == 0 ) return 0;
}
else
{
j = glyph + nbase + nbase; // skip base addresses
offset1 = *(indexP + j);
offset2 = *(indexP + j + 1);
length = offset2 - offset1;
if( length == 0 ) return 0;
j = glyph >> key->indexShiftGlyph; // calculate base address to be added
j <<= 1; // base addresses are longs
offset1 += (*(indexP+j) << 16);
offset1 += *(indexP+j+1);
if( length < 0 ) // 16-bit offsets are reversed, must have crossed base address
{
j += 2;
offset2 += (*(indexP+j) << 16);
offset2 += *(indexP+j+1);
length = offset2 - offset1;
}
}
key->offsetBitData = offset1;
return length;
}
/* rwb 7/17/91
* source is byte aligned, destination is long aligned. sourceWide will generally
* be less than 4 bytes, so moving longs or words is not justified.
* Accomodate banding, to be consistent with outline rendering.
*/
void bm_copyExactBitMap( uint8* source, uint8 sourceWide, int16 lowBand, int16 highBand,
uint8* bitMap, uint8 destWide, uint8 destHigh )
{
uint8* destBegin = bitMap;
uint8 *destNext, *sourceNext;
int16 nRows = highBand - lowBand + 1;
while( destHigh-- > highBand )
{
destBegin += destWide;
source += sourceWide;
}
destNext = destBegin + destWide;
sourceNext = source + sourceWide;
while( nRows-- )
{
while( source < sourceNext ) *destBegin++ = *source++;
while( destBegin < destNext ) *destBegin++ = 0;
sourceNext += sourceWide;
destNext += destWide;
}
}
uint8* MAGICREED( fsg_SplineKey* key , sfnt_tableIndex n, uint32 offset, uint32 length )
{
#pragma unused( length )
uint8* p = sfnt_GetTablePtr( key, n, false );
p += offset;
return p;
}
void bm_clear( uint8* p, int32 n )
{
while( n-- ) *p++ = 0;
}
/* rwb 8/14/91
* Or a component glyph into the bitmap cache for a compound glyph.
* Read the data from the bdat table.
* Offset the component (including surrounding whitespace) by xGOff & yOff.
* If component is itself compound, call this routine recursively.
* Components only exist in data format 1.
* Component offsets are based on horizontal bearings (even if layout is vertical).
* yGoff combines component offsets and vert component of left sidebearing of dest glyph.
*/
void bm_orComponent(fsg_SplineKey* key, uint32 offSet, uint16 length,
int16 lowBand, int16 highBand,
uint8* bitMap, uint8 destWide, uint8 destHigh, int8 xGOff, int8 yGOff, int8 ySide )
{
uint8* cP = MAGICREED( key, sfnt_bitmapData, offSet, length);
uint8* subP = cP + *((int16*)(cP+14));
int nComp = *(cP + 11);
if( nComp == 0 )
{
int8 xBOff = xGOff + *(cP+2);
int8 yBOff = yGOff + *(cP+3);
bm_orSimpleBitMap( subP, *(cP+1), lowBand, highBand,
bitMap, destWide, destHigh, xBOff, yBOff, *cP, ySide );
}
else
{
while( nComp-- != 0 )
{
uint32 oj = *((uint32*)subP);
uint16 lj = *((uint16*)subP+3);
int8 ojx = xGOff + *(subP+4);
int8 ojy = yGOff + *(subP+5);
bm_orComponent(key, oj, lj, lowBand, highBand,
bitMap, destWide, destHigh, ojx, ojy, ySide );
subP += 8;
}
}
}
/* rwb 7/17/91
* OR a simple bitmap into destination cache.
* Assumes glyph format 1.
* Offset the source bitmap by xOff and yOff.
* source is byte aligned, destination is long aligned. sourceWide will generally
* be less than 4 bytes, so moving longs or words is not justified.
* Accomodate banding, to be consistent with outline rendering.
* yOff combines vertical component of left SideBearing for source glyph and vertical
* component of left SideBearing for destination glyph with any component offsets.
*/
void bm_orSimpleBitMap( uint8* source, uint8 sourceWide, int16 lowBand, int16 highBand,
uint8* bitMap, uint8 destWide, uint8 destHigh, int8 xOff, int8 yOff, uint8 sourceHigh, int8 ySide )
{
uint8* destBegin = bitMap;
uint8 *destNext = destBegin + destWide;
uint8* sourceNext = source + sourceWide;
int16 dRow = ySide;
int16 sRow = ySide + sourceHigh - yOff;
while( dRow > ySide - destHigh )
{
if( dRow <= highBand && dRow >= lowBand )
{
if( sRow <= sourceHigh && sRow >= 1)
{
int temp = *source;
int tt;
while( source++ < sourceNext )
{
temp <<= 8;
if(source < sourceNext ) temp |= *source;
tt = (xOff >= 0) ? temp >> xOff : temp << xOff;
*destBegin++ |= (tt >> 8);
}
sourceNext += sourceWide;
}
destBegin = destNext;
destNext += destWide;
}
--dRow;
--sRow;
}
}
/* rwb 8/19/91
* Stretch Or a component glyph into the bitmap cache for a compound glyph.
* Read the data from the bdat table, and stretch it by the ratio 1/r.
* Offset the component (including surrounding whitespace) by xGOff & yOff.
* If component is itself compound, call this routine recursively.
* Components only exist in data format 1.
* Component offsets are based on horizontal bearings (even if layout is vertical).
*/
void bm_orStretchComponent(fsg_SplineKey* key, uint32 offSet, uint16 length,
int16 lowBand, int16 highBand,
uint8* bitMap, uint8 destWidePix, uint8 destHigh, int8 xGOff, int8 yGOff,
Fixed r, Fixed q, int8 ySide, int8 xSide )
{
uint8* cP = MAGICREED( key, sfnt_bitmapData, offSet, length);
uint8* subP = cP + *((int16*)(cP+14));
int nComp = *(cP + 11);
if( nComp == 0 )
{
int8 xBOff = xGOff + *(cP+2);
int8 yBOff = yGOff + *(cP+3);
bm_orStretchSimpleBitMap( subP, *(cP+1), lowBand, highBand,
bitMap, destWidePix, destHigh, xBOff, yBOff, *cP, r, q, ySide, xSide );
}
else
{
while( nComp-- != 0 )
{
uint32 oj = *((uint32*)subP);
uint16 lj = *((uint16*)subP+3);
int8 ojx = xGOff + *(subP+4);
int8 ojy = yGOff + *(subP+5);
bm_orStretchComponent(key, oj, lj, lowBand, highBand,
bitMap, destWidePix, destHigh, ojx, ojy, r, q, ySide, xSide);
subP += 8;
}
}
}
/* rwb 9/14/91
* STRETCH OR a simple bitmap into destination cache.
* Assumes glyph format 1.
* Offset the source bitmap by xOff and yOff.
* source is byte aligned, destination is long aligned. sourceWide will generally
* be less than 4 bytes, so moving longs or words is not justified.
* Accomodate banding, to be consistent with outline rendering.
* 1/r is horizontal stretch factor
* 1/q is vertical stretch factor
* ySide is vertical component of left SideBearing for destination glyph
* yOff combines vertical component of left SideBearing for source glyph with any component offsets.
*/
void bm_orStretchSimpleBitMap( uint8* source, uint8 sourceWidePix,
int16 lowBand, int16 highBand, uint8* bitMap, uint8 destWidePix, uint8 destHigh,
int8 xOff, int8 yOff, uint8 sourceHigh, Fixed r, Fixed q, int8 ySide, int8 xSide )
{
uint8* destBegin = bitMap;
int16 sourceWideBytes = sourceWidePix > 0 ? ((sourceWidePix-1)>>3)+1 : 0;
int16 destWideBytes = destWidePix > 0 ? ((destWidePix-1)>>3)+1 : 0;
int16 dRow = ySide;
Fixed dr = ySide << 16;
Fixed sr = (FixMul( dr, q ) + 0x8000 ) >> 16;
int16 sRow = sr - yOff + sourceHigh;
int16 first = 1;
int16 sOld;
while( dRow > ySide-destHigh )
{
if( dRow <= highBand && dRow >= lowBand )
{
dr = dRow << 16;
sr = (FixMul( dr, q ) + 0x8000 ) >> 16;
sRow = sr -yOff + sourceHigh;
if( sRow <= sourceHigh && sRow >= 1)
{
if( first )
{
first = 0;
sOld = sRow;
}
else if( sRow != sOld )
{
sOld = sRow;
source += sourceWideBytes;
}
stretchRow( source, destBegin, sourceWidePix, destWidePix, r, xOff, xSide );
}
destBegin += destWideBytes;
}
--dRow;
}
}
/* rwb 8-9-91
* Stretch one row of a bitmap by a ratio (1/r) = (n/m)
* m is the ppem of the source bitmap.
* n is the ppem of the destination bitmap ( n >= m ).
* The source row consists of sWide pixels beginning at sP
* and sOffset pixels of left-sidebearing
* The destination row consists of dWide pixels beginning at dP
* and dOffset pixels of left-siedbearing. (Calculate dOffset).
* r is a Fixed (16.16) point number = (m/n);
* assume destination has been previously filled with zeros
*/
void stretchRow( uint8* sP, uint8* dP, int sWide, int dWide, Fixed r, int sOffset, int8 xSide)
{
uint8 mask[8] = {128,64,32,16,8,4,2,1};
int sMask, dMask, k;
Fixed valS;
int32 oldS, newS, offS;
offS = sOffset << 16;
sMask = dMask = 0;
/* first do left-sidebearing */
valS = r>>1;
for(k=0; k<xSide; ++k) valS += r;
oldS = valS & 0x7FFF0000;
/* next bump dest bitmap until component offset + source-left-sidebearing offset are covered
*/
while( oldS < offS )
{
valS += r;
oldS = valS & 0x7FFF0000;
if( ++dMask == 8 )
{
dMask = 0;
++dP;
}
}
offS += (sWide << 16);
for( k=0; k< dWide; ++k)
{
newS = valS & 0x7FFF0000;
if( newS > oldS )
{
if( newS >= offS ) break;
oldS = newS;
if( ++sMask == 8 )
{
++sP;
sMask = 0;
}
}
if( *sP & *(mask + sMask) ) *dP |= *(mask + dMask);
if( ++dMask == 8 )
{
dMask = 0;
++dP;
}
valS += r;
}
}
#endif