mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1089 lines
36 KiB
1089 lines
36 KiB
/*********************************************************************
|
|
|
|
sbit.c -- Embedded Bitmap Module
|
|
|
|
(c) Copyright 1993-95 Microsoft Corp. All rights reserved.
|
|
|
|
02/07/95 deanb Workspace pointers for GetMetrics & GetBitmap
|
|
01/31/95 deanb memset unrotated bitmap to zero
|
|
01/27/95 deanb usShaveLeft & usShaveRight added to sbit state
|
|
12/21/94 deanb rotation and vertical metrics support
|
|
08/02/94 deanb pf26DevLSB->y calculated correctly
|
|
01/05/94 deanb Bitmap scaling added
|
|
11/29/93 deanb First cut
|
|
|
|
**********************************************************************/
|
|
|
|
// added by bodind, speed optimization
|
|
|
|
#include "nt.h"
|
|
#include "ntrtl.h"
|
|
|
|
|
|
#include "fscdefs.h" /* shared data types */
|
|
#include "fserror.h" /* error codes */
|
|
#include "fontmath.h" /* for inttodot6 macro */
|
|
|
|
#include "sfntaccs.h" /* sfnt access functions */
|
|
#include "sbit.h" /* own function prototypes */
|
|
|
|
/**********************************************************************/
|
|
|
|
/* Local structure */
|
|
|
|
typedef struct
|
|
{
|
|
uint8* pbySrc; /* unrotated source bitmap (as read) */
|
|
uint8* pbyDst; /* rotated destination bitmap (as returned) */
|
|
uint16 usSrcBytesPerRow; /* source bitmap width */
|
|
uint16 usDstBytesPerRow; /* destination bitmap width */
|
|
uint16 usSrcX; /* source horiz pixel index */
|
|
uint16 usSrcY; /* destination horiz pixel index */
|
|
uint16 usDstX; /* source vert pixel index */
|
|
uint16 usDstY; /* destination vert pixel index */
|
|
}
|
|
CopyBlock;
|
|
|
|
/**********************************************************************/
|
|
|
|
/* Local prototypes */
|
|
|
|
FS_PRIVATE ErrorCode GetSbitMetrics(
|
|
sbit_State *pSbit,
|
|
sfac_ClientRec *pClientInfo
|
|
);
|
|
|
|
FS_PRIVATE ErrorCode GetSbitComponent (
|
|
sfac_ClientRec *pClientInfo,
|
|
uint32 ulStrikeOffset,
|
|
uint16 usBitmapFormat,
|
|
uint32 ulBitmapOffset,
|
|
uint32 ulBitmapLength,
|
|
uint16 usHeight,
|
|
uint16 usWidth,
|
|
uint16 usShaveLeft,
|
|
uint16 usShaveRight,
|
|
uint16 usXOffset,
|
|
uint16 usYOffset,
|
|
uint16 usRowBytes,
|
|
uint8 *pbyBitMap
|
|
);
|
|
|
|
FS_PRIVATE uint16 UScaleX(
|
|
sbit_State *pSbit,
|
|
uint16 usValue
|
|
);
|
|
|
|
FS_PRIVATE uint16 UScaleY(
|
|
sbit_State *pSbit,
|
|
uint16 usValue
|
|
);
|
|
|
|
FS_PRIVATE int16 SScaleX(
|
|
sbit_State *pSbit,
|
|
int16 sValue
|
|
);
|
|
|
|
FS_PRIVATE int16 SScaleY(
|
|
sbit_State *pSbit,
|
|
int16 sValue
|
|
);
|
|
|
|
FS_PRIVATE void ScaleVertical (
|
|
uint8 *pbyBitmap,
|
|
uint16 usBytesPerRow,
|
|
uint16 usOrgHeight,
|
|
uint16 usNewHeight
|
|
);
|
|
|
|
FS_PRIVATE void ScaleHorizontal (
|
|
uint8 *pbyBitmap,
|
|
uint16 usOrgBytesPerRow,
|
|
uint16 usNewBytesPerRow,
|
|
uint16 usOrgWidth,
|
|
uint16 usNewWidth,
|
|
uint16 usRowCount
|
|
);
|
|
|
|
FS_PRIVATE void CopyBit(
|
|
CopyBlock* pcb );
|
|
|
|
/**********************************************************************/
|
|
/*** ***/
|
|
/*** SBIT Functions ***/
|
|
/*** ***/
|
|
/**********************************************************************/
|
|
|
|
/* reset sbit state structure to default values */
|
|
|
|
FS_PUBLIC ErrorCode sbit_NewTransform(
|
|
sbit_State *pSbit )
|
|
{
|
|
pSbit->bGlyphFound = FALSE;
|
|
pSbit->usTableState = SBIT_UN_SEARCHED;
|
|
return NO_ERR;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
/* Determine whether a glyph bitmap exists */
|
|
|
|
FS_PUBLIC ErrorCode sbit_SearchForBitmap(
|
|
sbit_State *pSbit,
|
|
sfac_ClientRec *pClientInfo,
|
|
uint16 usPpemX,
|
|
uint16 usPpemY,
|
|
uint16 usRotation, /* 0 - 3 => 90 deg rotation, else not 90 */
|
|
uint16 usGlyphCode,
|
|
uint16 *pusFoundCode ) /* 0 = not found, 1 = bloc, 2 = bsca */
|
|
{
|
|
ErrorCode ReturnCode;
|
|
|
|
*pusFoundCode = 0; /* default */
|
|
if (usRotation > 3)
|
|
{
|
|
return NO_ERR; /* can't match a general rotation */
|
|
}
|
|
|
|
pSbit->usPpemX = usPpemX; /* save requested ppem */
|
|
pSbit->usPpemY = usPpemY;
|
|
pSbit->usRotation = usRotation; /* used later on */
|
|
|
|
if (pSbit->usTableState == SBIT_UN_SEARCHED) /* new trans - 1st glyph */
|
|
{
|
|
ReturnCode = sfac_SearchForStrike ( /* look for a strike */
|
|
pClientInfo,
|
|
usPpemX,
|
|
usPpemY,
|
|
&pSbit->usTableState, /* may set to BLOC or BSCA */
|
|
&pSbit->usSubPpemX, /* if BSCA us this ppem */
|
|
&pSbit->usSubPpemY,
|
|
&pSbit->ulStrikeOffset );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
}
|
|
|
|
|
|
if ((pSbit->usTableState == SBIT_BLOC_FOUND) ||
|
|
(pSbit->usTableState == SBIT_BSCA_FOUND))
|
|
{
|
|
ReturnCode = sfac_SearchForBitmap ( /* now look for this glyph */
|
|
pClientInfo,
|
|
usGlyphCode,
|
|
pSbit->ulStrikeOffset,
|
|
&pSbit->bGlyphFound, /* return values */
|
|
&pSbit->usMetricsType,
|
|
&pSbit->usMetricsTable,
|
|
&pSbit->ulMetricsOffset,
|
|
&pSbit->usBitmapFormat,
|
|
&pSbit->ulBitmapOffset,
|
|
&pSbit->ulBitmapLength );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
if (pSbit->bGlyphFound)
|
|
{
|
|
if (pSbit->usTableState == SBIT_BLOC_FOUND)
|
|
{
|
|
*pusFoundCode = 1;
|
|
}
|
|
else
|
|
{
|
|
*pusFoundCode = 2;
|
|
}
|
|
pSbit->bMetricsValid = FALSE;
|
|
}
|
|
}
|
|
return NO_ERR;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
FS_PUBLIC boolean sbit_IfBitmapFound(
|
|
sbit_State *pSbit )
|
|
{
|
|
return (pSbit->bGlyphFound);
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
FS_PUBLIC ErrorCode sbit_GetDevAdvanceWidth (
|
|
sbit_State *pSbit,
|
|
sfac_ClientRec *pClientInfo,
|
|
point *pf26DevAdvW )
|
|
{
|
|
F26Dot6 f26DevAdvWx; /* unrotated metrics */
|
|
F26Dot6 f26DevAdvWy;
|
|
ErrorCode ReturnCode;
|
|
|
|
ReturnCode = GetSbitMetrics(pSbit, pClientInfo);
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
f26DevAdvWx = INTTODOT6(UScaleX(pSbit, pSbit->usAdvance));
|
|
f26DevAdvWy = 0L; /* always zero for horizontal metrics */
|
|
|
|
switch(pSbit->usRotation) /* handle 90 degree rotations */
|
|
{
|
|
case 0: /* no rotation */
|
|
pf26DevAdvW->x = f26DevAdvWx;
|
|
pf26DevAdvW->y = f26DevAdvWy;
|
|
break;
|
|
case 1: /* 90 degree rotation */
|
|
pf26DevAdvW->x = -f26DevAdvWy;
|
|
pf26DevAdvW->y = f26DevAdvWx;
|
|
break;
|
|
case 2: /* 180 degree rotation */
|
|
pf26DevAdvW->x = -f26DevAdvWx;
|
|
pf26DevAdvW->y = -f26DevAdvWy;
|
|
break;
|
|
case 3: /* 270 degree rotation */
|
|
pf26DevAdvW->x = f26DevAdvWy;
|
|
pf26DevAdvW->y = -f26DevAdvWx;
|
|
break;
|
|
default: /* non 90 degree rotation */
|
|
return SBIT_ROTATION_ERR;
|
|
}
|
|
|
|
return NO_ERR;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PUBLIC ErrorCode sbit_GetVerticalMetrics (
|
|
sbit_State *pSbit,
|
|
sfac_ClientRec *pClientInfo,
|
|
boolean *pbMetricsFound, /* set true if Vertical metrics found */
|
|
point *pf26DevAdvH,
|
|
point *pf26DevTopSB )
|
|
{
|
|
uint16 usAdvHeight;
|
|
int16 sTSBy;
|
|
point ptDevAdvH; /* unrotated metrics */
|
|
point ptDevTopSB;
|
|
ErrorCode ReturnCode;
|
|
|
|
ReturnCode = sfac_GetSbitVertMetrics(
|
|
pClientInfo,
|
|
pSbit->usMetricsType,
|
|
pSbit->usMetricsTable,
|
|
pSbit->ulMetricsOffset,
|
|
pbMetricsFound, /* false if no sbit vert metrics */
|
|
&sTSBy,
|
|
&usAdvHeight);
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
/* set x components to zero and use -TSB.y for compatability with vmtx data */
|
|
|
|
if (*pbMetricsFound)
|
|
{
|
|
ptDevAdvH.x = 0L;
|
|
ptDevAdvH.y = INTTODOT6(UScaleY(pSbit, usAdvHeight));
|
|
ptDevTopSB.x = 0L;
|
|
ptDevTopSB.y = -INTTODOT6(SScaleY(pSbit, sTSBy)); /* note: minus sign */
|
|
|
|
switch(pSbit->usRotation) /* handle 90 degree rotations */
|
|
{
|
|
case 0: /* no rotation */
|
|
pf26DevAdvH->x = ptDevAdvH.x;
|
|
pf26DevAdvH->y = ptDevAdvH.y;
|
|
pf26DevTopSB->x = ptDevTopSB.x;
|
|
pf26DevTopSB->y = ptDevTopSB.y;
|
|
break;
|
|
case 1: /* 90 degree rotation */
|
|
pf26DevAdvH->x = -ptDevAdvH.y;
|
|
pf26DevAdvH->y = ptDevAdvH.x;
|
|
pf26DevTopSB->x = -ptDevTopSB.y;
|
|
pf26DevTopSB->y = ptDevTopSB.x;
|
|
break;
|
|
case 2: /* 180 degree rotation */
|
|
pf26DevAdvH->x = -ptDevAdvH.x;
|
|
pf26DevAdvH->y = -ptDevAdvH.y;
|
|
pf26DevTopSB->x = -ptDevTopSB.x;
|
|
pf26DevTopSB->y = -ptDevTopSB.y;
|
|
break;
|
|
case 3: /* 270 degree rotation */
|
|
pf26DevAdvH->x = ptDevAdvH.y;
|
|
pf26DevAdvH->y = -ptDevAdvH.x;
|
|
pf26DevTopSB->x = ptDevTopSB.y;
|
|
pf26DevTopSB->y = -ptDevTopSB.x;
|
|
break;
|
|
default: /* non 90 degree rotation */
|
|
return SBIT_ROTATION_ERR;
|
|
}
|
|
}
|
|
return NO_ERR;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
FS_PUBLIC ErrorCode sbit_GetMetrics (
|
|
sbit_State *pSbit,
|
|
sfac_ClientRec *pClientInfo,
|
|
point *pf26DevAdvW,
|
|
point *pf26DevLSB,
|
|
point *pf26LSB,
|
|
Rect *pRect,
|
|
uint16 *pusRowBytes,
|
|
uint32 *pulOutSize,
|
|
uint32 *pulWorkSize )
|
|
{
|
|
ErrorCode ReturnCode;
|
|
uint32 ulOrgMemSize; /* size of unscaled bitmap */
|
|
uint32 ulScaMemSize; /* size of scaled bitmap */
|
|
uint32 ulMaxMemSize; /* size of larger of scaled, unscaled */
|
|
|
|
F26Dot6 f26DevAdvWx; /* unrotated metrics */
|
|
F26Dot6 f26DevAdvWy;
|
|
F26Dot6 f26DevLSBx;
|
|
F26Dot6 f26DevLSBy;
|
|
int16 sTop; /* unrotated bounds */
|
|
int16 sLeft;
|
|
int16 sBottom;
|
|
int16 sRight;
|
|
|
|
ReturnCode = GetSbitMetrics(pSbit, pClientInfo);
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
pSbit->usScaledWidth = UScaleX(pSbit, pSbit->usWidth);
|
|
pSbit->usScaledHeight = UScaleY(pSbit, pSbit->usHeight);
|
|
|
|
sTop = SScaleY(pSbit, pSbit->sBearingY); /* calc scaled metrics */
|
|
sLeft = SScaleX(pSbit, pSbit->sBearingX);
|
|
sBottom = sTop - (int16)pSbit->usScaledHeight;
|
|
sRight = sLeft + (int16)pSbit->usScaledWidth;
|
|
|
|
f26DevAdvWx = INTTODOT6(UScaleX(pSbit, pSbit->usAdvance));
|
|
f26DevAdvWy = 0L; /* always zero for horizontal metrics */
|
|
f26DevLSBx = INTTODOT6(SScaleX(pSbit, pSbit->sBearingX));
|
|
f26DevLSBy = INTTODOT6(SScaleY(pSbit, pSbit->sBearingY));
|
|
|
|
pSbit->usRowBytes = ROWBYTESLONG(pSbit->usWidth); /* keep unscaled */
|
|
pSbit->usScaledRowBytes = ROWBYTESLONG(pSbit->usScaledWidth);
|
|
|
|
ulOrgMemSize = (uint32)pSbit->usHeight * (uint32)pSbit->usRowBytes;
|
|
ulScaMemSize = (uint32)pSbit->usScaledHeight * (uint32)pSbit->usScaledRowBytes;
|
|
if (ulOrgMemSize >= ulScaMemSize)
|
|
{
|
|
ulMaxMemSize = ulOrgMemSize;
|
|
}
|
|
else
|
|
{
|
|
ulMaxMemSize = ulScaMemSize;
|
|
}
|
|
|
|
switch(pSbit->usRotation) /* handle 90 degree rotations */
|
|
{
|
|
case 0: /* no rotation */
|
|
pRect->top = sTop; /* return scaled metrics */
|
|
pRect->left = sLeft;
|
|
pRect->bottom = sBottom;
|
|
pRect->right = sRight;
|
|
|
|
pf26DevAdvW->x = f26DevAdvWx;
|
|
pf26DevAdvW->y = f26DevAdvWy;
|
|
pf26DevLSB->x = f26DevLSBx;
|
|
pf26DevLSB->y = f26DevLSBy;
|
|
pf26LSB->x = f26DevLSBx;
|
|
pf26LSB->y = INTTODOT6(sTop);
|
|
|
|
pSbit->ulOutMemSize = ulScaMemSize;
|
|
pSbit->usOutRowBytes = pSbit->usScaledRowBytes;
|
|
if (pSbit->usTableState == SBIT_BSCA_FOUND)
|
|
{
|
|
pSbit->ulWorkMemSize = ulMaxMemSize; /* room to read & scale */
|
|
}
|
|
else
|
|
{
|
|
pSbit->ulWorkMemSize = 0L;
|
|
}
|
|
break;
|
|
case 1: /* 90 degree rotation */
|
|
pRect->top = sRight;
|
|
pRect->left = -sTop;
|
|
pRect->bottom = sLeft;
|
|
pRect->right = -sBottom;
|
|
|
|
pf26DevAdvW->x = -f26DevAdvWy;
|
|
pf26DevAdvW->y = f26DevAdvWx;
|
|
pf26DevLSB->x = -f26DevLSBy;
|
|
pf26DevLSB->y = f26DevLSBx + INTTODOT6(sRight - sLeft);
|
|
pf26LSB->x = 0L;
|
|
pf26LSB->y = INTTODOT6(sRight) - f26DevLSBx;
|
|
|
|
pSbit->ulOutMemSize = (uint32)pSbit->usScaledWidth *
|
|
ROWBYTESLONG(pSbit->usScaledHeight);
|
|
pSbit->usOutRowBytes = ROWBYTESLONG(pSbit->usScaledHeight);
|
|
pSbit->ulWorkMemSize = ulMaxMemSize; /* room to read & scale */
|
|
break;
|
|
case 2: /* 180 degree rotation */
|
|
pRect->top = -sBottom;
|
|
pRect->left = -sRight;
|
|
pRect->bottom = -sTop;
|
|
pRect->right = -sLeft;
|
|
|
|
pf26DevAdvW->x = -f26DevAdvWx;
|
|
pf26DevAdvW->y = -f26DevAdvWy;
|
|
pf26DevLSB->x = -f26DevLSBx + INTTODOT6(sLeft - sRight);
|
|
pf26DevLSB->y = -f26DevLSBy + INTTODOT6(sTop - sBottom);
|
|
pf26LSB->x = -f26DevLSBx;
|
|
pf26LSB->y = INTTODOT6(-sBottom);
|
|
|
|
pSbit->ulOutMemSize = (uint32)pSbit->usScaledHeight *
|
|
ROWBYTESLONG(pSbit->usScaledWidth);
|
|
pSbit->usOutRowBytes = pSbit->usScaledRowBytes;
|
|
pSbit->ulWorkMemSize = ulMaxMemSize; /* room to read & scale */
|
|
break;
|
|
case 3: /* 270 degree rotation */
|
|
pRect->top = -sLeft;
|
|
pRect->left = sBottom;
|
|
pRect->bottom = -sRight;
|
|
pRect->right = sTop;
|
|
|
|
pf26DevAdvW->x = f26DevAdvWy;
|
|
pf26DevAdvW->y = -f26DevAdvWx;
|
|
pf26DevLSB->x = f26DevLSBy + INTTODOT6(sBottom - sTop);
|
|
pf26DevLSB->y = -f26DevLSBx;
|
|
pf26LSB->x = 0L;
|
|
pf26LSB->y = INTTODOT6(-sLeft) + f26DevLSBx;
|
|
|
|
pSbit->ulOutMemSize = (uint32)pSbit->usScaledWidth *
|
|
ROWBYTESLONG(pSbit->usScaledHeight);
|
|
pSbit->usOutRowBytes = ROWBYTESLONG(pSbit->usScaledHeight);
|
|
pSbit->ulWorkMemSize = ulMaxMemSize; /* room to read & scale */
|
|
break;
|
|
default: /* non 90 degree rotation */
|
|
return SBIT_ROTATION_ERR;
|
|
}
|
|
|
|
*pusRowBytes = pSbit->usOutRowBytes;
|
|
*pulOutSize = pSbit->ulOutMemSize; /* return mem requirement */
|
|
*pulWorkSize = pSbit->ulWorkMemSize;
|
|
return NO_ERR;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* if scaling or rotating, read bitmap into workspace, */
|
|
/* fix it up and copy it to the output map */
|
|
|
|
FS_PUBLIC ErrorCode sbit_GetBitmap (
|
|
sbit_State *pSbit,
|
|
sfac_ClientRec *pClientInfo,
|
|
uint8 *pbyOut,
|
|
uint8 *pbyWork )
|
|
{
|
|
ErrorCode ReturnCode;
|
|
uint8 *pbyRead;
|
|
CopyBlock cb; /* for bitmap rotations */
|
|
uint16 usSrcXMax;
|
|
uint16 usSrcYMax;
|
|
|
|
MEMSET(pbyOut, 0, pSbit->ulOutMemSize); /* always clear the output map */
|
|
|
|
if ((pSbit->usRotation == 0) && /* if no rotation */
|
|
(pSbit->usTableState != SBIT_BSCA_FOUND)) /* and no scaling */
|
|
{
|
|
pbyRead = pbyOut; /* read straight to output map */
|
|
}
|
|
else /* if any rotation or scaling */
|
|
{
|
|
MEMSET(pbyWork, 0, pSbit->ulWorkMemSize);
|
|
pbyRead = pbyWork; /* read into workspace */
|
|
}
|
|
|
|
ReturnCode = GetSbitComponent ( /* fetch the bitmap */
|
|
pClientInfo,
|
|
pSbit->ulStrikeOffset,
|
|
pSbit->usBitmapFormat, /* root data only in state */
|
|
pSbit->ulBitmapOffset,
|
|
pSbit->ulBitmapLength,
|
|
pSbit->usHeight,
|
|
pSbit->usWidth,
|
|
pSbit->usShaveLeft,
|
|
pSbit->usShaveRight,
|
|
0, /* no offset for the root */
|
|
0,
|
|
pSbit->usRowBytes,
|
|
pbyRead );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
if (pSbit->usTableState == SBIT_BSCA_FOUND)
|
|
{
|
|
ScaleVertical (
|
|
pbyWork,
|
|
pSbit->usRowBytes,
|
|
pSbit->usHeight,
|
|
pSbit->usScaledHeight );
|
|
|
|
ScaleHorizontal (
|
|
pbyWork,
|
|
pSbit->usRowBytes,
|
|
pSbit->usScaledRowBytes,
|
|
pSbit->usWidth,
|
|
pSbit->usScaledWidth,
|
|
pSbit->usScaledHeight );
|
|
|
|
if (pSbit->usRotation == 0) /* if no rotation */
|
|
{
|
|
MEMCPY (pbyOut, pbyWork, pSbit->ulOutMemSize); /* keep this one */
|
|
}
|
|
}
|
|
|
|
if (pSbit->usRotation == 0) /* if no rotation */
|
|
{
|
|
return NO_ERR; /* done */
|
|
}
|
|
|
|
cb.pbySrc = pbyWork;
|
|
cb.pbyDst = pbyOut;
|
|
cb.usSrcBytesPerRow = pSbit->usScaledRowBytes;
|
|
cb.usDstBytesPerRow = pSbit->usOutRowBytes;
|
|
usSrcXMax = pSbit->usScaledWidth;
|
|
usSrcYMax = pSbit->usScaledHeight;
|
|
|
|
switch(pSbit->usRotation)
|
|
{
|
|
case 1: /* 90 degree rotation */
|
|
for (cb.usSrcY = 0; cb.usSrcY < usSrcYMax; cb.usSrcY++)
|
|
{
|
|
cb.usDstX = cb.usSrcY; /* x' = y */
|
|
for (cb.usSrcX = 0; cb.usSrcX < usSrcXMax; cb.usSrcX++)
|
|
{
|
|
cb.usDstY = usSrcXMax - cb.usSrcX - 1; /* y' = -x */
|
|
CopyBit(&cb);
|
|
}
|
|
}
|
|
break;
|
|
case 2: /* 180 degree rotation */
|
|
for (cb.usSrcY = 0; cb.usSrcY < usSrcYMax; cb.usSrcY++)
|
|
{
|
|
cb.usDstY = usSrcYMax - cb.usSrcY - 1; /* y' = -y */
|
|
for (cb.usSrcX = 0; cb.usSrcX < usSrcXMax; cb.usSrcX++)
|
|
{
|
|
cb.usDstX = usSrcXMax - cb.usSrcX - 1; /* x' = -x */
|
|
CopyBit(&cb);
|
|
}
|
|
}
|
|
break;
|
|
case 3: /* 270 degree rotation */
|
|
for (cb.usSrcY = 0; cb.usSrcY < usSrcYMax; cb.usSrcY++)
|
|
{
|
|
cb.usDstX = usSrcYMax - cb.usSrcY - 1; /* x' = -y */
|
|
for (cb.usSrcX = 0; cb.usSrcX < usSrcXMax; cb.usSrcX++)
|
|
{
|
|
cb.usDstY = cb.usSrcX; /* y' = x */
|
|
CopyBit(&cb);
|
|
}
|
|
}
|
|
break;
|
|
default: /* shouldn't happen */
|
|
return SBIT_ROTATION_ERR;
|
|
}
|
|
|
|
return NO_ERR;
|
|
}
|
|
|
|
|
|
/**********************************************************************/
|
|
|
|
/* Private Functions */
|
|
|
|
/**********************************************************************/
|
|
|
|
FS_PRIVATE ErrorCode GetSbitMetrics(
|
|
sbit_State *pSbit,
|
|
sfac_ClientRec *pClientInfo
|
|
)
|
|
{
|
|
ErrorCode ReturnCode;
|
|
|
|
if (pSbit->bMetricsValid)
|
|
{
|
|
return NO_ERR; /* already got 'em */
|
|
}
|
|
|
|
ReturnCode = sfac_GetSbitMetrics (
|
|
pClientInfo,
|
|
pSbit->usMetricsType,
|
|
pSbit->usMetricsTable,
|
|
pSbit->ulMetricsOffset,
|
|
&pSbit->usHeight,
|
|
&pSbit->usWidth,
|
|
&pSbit->sBearingX,
|
|
&pSbit->sBearingY,
|
|
&pSbit->usAdvance );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
ReturnCode = sfac_ShaveSbitMetrics (
|
|
pClientInfo,
|
|
pSbit->usBitmapFormat,
|
|
pSbit->ulBitmapOffset,
|
|
pSbit->ulBitmapLength,
|
|
pSbit->usHeight,
|
|
&pSbit->usWidth,
|
|
&pSbit->usShaveLeft,
|
|
&pSbit->usShaveRight,
|
|
&pSbit->sBearingX );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
pSbit->bMetricsValid = TRUE;
|
|
return NO_ERR;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
|
|
/* This is the recursive composite routine */
|
|
|
|
FS_PRIVATE ErrorCode GetSbitComponent (
|
|
sfac_ClientRec *pClientInfo,
|
|
uint32 ulStrikeOffset,
|
|
uint16 usBitmapFormat,
|
|
uint32 ulBitmapOffset,
|
|
uint32 ulBitmapLength,
|
|
uint16 usHeight,
|
|
uint16 usWidth,
|
|
uint16 usShaveLeft,
|
|
uint16 usShaveRight,
|
|
uint16 usXOffset,
|
|
uint16 usYOffset,
|
|
uint16 usRowBytes,
|
|
uint8 *pbyBitMap )
|
|
{
|
|
uint32 ulCompMetricsOffset; /* component params */
|
|
uint32 ulCompBitmapOffset;
|
|
uint32 ulCompBitmapLength;
|
|
uint16 usComponent; /* index counter */
|
|
uint16 usCompCount;
|
|
uint16 usCompGlyphCode;
|
|
uint16 usCompXOff;
|
|
uint16 usCompYOff;
|
|
uint16 usCompMetricsType;
|
|
uint16 usCompMetricsTable;
|
|
uint16 usCompBitmapFormat;
|
|
uint16 usCompHeight;
|
|
uint16 usCompWidth;
|
|
uint16 usCompShaveLeft;
|
|
uint16 usCompShaveRight;
|
|
uint16 usCompAdvance;
|
|
int16 sCompBearingX;
|
|
int16 sCompBearingY;
|
|
boolean bCompGlyphFound;
|
|
ErrorCode ReturnCode;
|
|
|
|
ReturnCode = sfac_GetSbitBitmap ( /* fetch the bitmap */
|
|
pClientInfo,
|
|
usBitmapFormat,
|
|
ulBitmapOffset,
|
|
ulBitmapLength,
|
|
usHeight,
|
|
usWidth,
|
|
usShaveLeft,
|
|
usShaveRight,
|
|
usXOffset,
|
|
usYOffset,
|
|
usRowBytes,
|
|
pbyBitMap,
|
|
&usCompCount ); /* zero for simple glyph */
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
if (usCompCount > 0) /* if composite glyph */
|
|
{
|
|
for (usComponent = 0; usComponent < usCompCount; usComponent++)
|
|
{
|
|
ReturnCode = sfac_GetSbitComponentInfo (
|
|
pClientInfo,
|
|
usComponent, /* component index */
|
|
ulBitmapOffset,
|
|
ulBitmapLength,
|
|
&usCompGlyphCode, /* return values */
|
|
&usCompXOff,
|
|
&usCompYOff );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
ReturnCode = sfac_SearchForBitmap ( /* look for component glyph */
|
|
pClientInfo,
|
|
usCompGlyphCode,
|
|
ulStrikeOffset, /* same strike for all */
|
|
&bCompGlyphFound, /* return values */
|
|
&usCompMetricsType,
|
|
&usCompMetricsTable,
|
|
&ulCompMetricsOffset,
|
|
&usCompBitmapFormat,
|
|
&ulCompBitmapOffset,
|
|
&ulCompBitmapLength );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
if (bCompGlyphFound == FALSE) /* should be there! */
|
|
{
|
|
return SBIT_COMPONENT_MISSING_ERR;
|
|
}
|
|
|
|
ReturnCode = sfac_GetSbitMetrics ( /* get component's metrics */
|
|
pClientInfo,
|
|
usCompMetricsType,
|
|
usCompMetricsTable,
|
|
ulCompMetricsOffset,
|
|
&usCompHeight, /* these matter */
|
|
&usCompWidth,
|
|
&sCompBearingX, /* these don't */
|
|
&sCompBearingY,
|
|
&usCompAdvance );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
ReturnCode = sfac_ShaveSbitMetrics ( /* shave white space for const metrics */
|
|
pClientInfo,
|
|
usCompBitmapFormat,
|
|
ulCompBitmapOffset,
|
|
ulCompBitmapLength,
|
|
usCompHeight,
|
|
&usCompWidth,
|
|
&usCompShaveLeft,
|
|
&usCompShaveRight,
|
|
&sCompBearingX );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
|
|
ReturnCode = GetSbitComponent ( /* recurse here */
|
|
pClientInfo,
|
|
ulStrikeOffset,
|
|
usCompBitmapFormat,
|
|
ulCompBitmapOffset,
|
|
ulCompBitmapLength,
|
|
usCompHeight,
|
|
usCompWidth,
|
|
usCompShaveLeft,
|
|
usCompShaveRight,
|
|
(uint16)(usCompXOff + usXOffset + usCompShaveLeft), /* for nesting */
|
|
(uint16)(usCompYOff + usYOffset),
|
|
usRowBytes, /* same for all */
|
|
pbyBitMap );
|
|
|
|
if (ReturnCode != NO_ERR) return ReturnCode;
|
|
}
|
|
}
|
|
return NO_ERR;
|
|
}
|
|
|
|
/********************************************************************/
|
|
|
|
/* Bitmap Scaling Routines */
|
|
|
|
/********************************************************************/
|
|
|
|
FS_PRIVATE uint16 UScaleX(
|
|
sbit_State *pSbit,
|
|
uint16 usValue
|
|
)
|
|
{
|
|
uint32 ulValue;
|
|
|
|
if (pSbit->usTableState == SBIT_BSCA_FOUND) /* if scaling needed */
|
|
{
|
|
ulValue = (uint32)usValue;
|
|
ulValue *= (uint32)pSbit->usPpemX << 1;
|
|
ulValue += (uint32)pSbit->usSubPpemX; /* for rounding */
|
|
ulValue /= (uint32)pSbit->usSubPpemX << 1;
|
|
usValue = (uint16)ulValue;
|
|
}
|
|
return usValue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
|
|
FS_PRIVATE uint16 UScaleY(
|
|
sbit_State *pSbit,
|
|
uint16 usValue
|
|
)
|
|
{
|
|
uint32 ulValue;
|
|
|
|
if (pSbit->usTableState == SBIT_BSCA_FOUND) /* if scaling needed */
|
|
{
|
|
ulValue = (uint32)usValue;
|
|
ulValue *= (uint32)pSbit->usPpemY << 1;
|
|
ulValue += (uint32)pSbit->usSubPpemY; /* for rounding */
|
|
ulValue /= (uint32)pSbit->usSubPpemY << 1;
|
|
usValue = (uint16)ulValue;
|
|
}
|
|
return usValue;
|
|
}
|
|
|
|
/********************************************************************/
|
|
|
|
FS_PRIVATE int16 SScaleX(
|
|
sbit_State *pSbit,
|
|
int16 sValue
|
|
)
|
|
{
|
|
if (pSbit->usTableState == SBIT_BSCA_FOUND)
|
|
{
|
|
if (sValue >= 0) /* positive Value */
|
|
{
|
|
return (int16)UScaleX(pSbit, (uint16)sValue);
|
|
}
|
|
else /* negative Value */
|
|
{
|
|
return -(int16)(UScaleX(pSbit, (uint16)(-sValue)));
|
|
}
|
|
}
|
|
else /* no scaling needed */
|
|
{
|
|
return sValue;
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
|
|
FS_PRIVATE int16 SScaleY(
|
|
sbit_State *pSbit,
|
|
int16 sValue
|
|
)
|
|
{
|
|
if (pSbit->usTableState == SBIT_BSCA_FOUND)
|
|
{
|
|
if (sValue >= 0) /* positive Value */
|
|
{
|
|
return (int16)UScaleY(pSbit, (uint16)sValue);
|
|
}
|
|
else /* negative Value */
|
|
{
|
|
return -(int16)(UScaleY(pSbit, (uint16)(-sValue)));
|
|
}
|
|
}
|
|
else /* no scaling needed */
|
|
{
|
|
return sValue;
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
|
|
FS_PRIVATE void ScaleVertical (
|
|
uint8 *pbyBitmap,
|
|
uint16 usBytesPerRow,
|
|
uint16 usOrgHeight,
|
|
uint16 usNewHeight
|
|
)
|
|
{
|
|
uint8 *pbyOrgRow; /* original data pointer */
|
|
uint8 *pbyNewRow; /* new data pointer */
|
|
uint16 usErrorTerm; /* for 'Bresenham' calculation */
|
|
uint16 usLine; /* loop counter */
|
|
|
|
usErrorTerm = usOrgHeight >> 1; /* used by both comp and exp */
|
|
|
|
if (usOrgHeight > usNewHeight) /* Compress Vertical */
|
|
{
|
|
pbyOrgRow = pbyBitmap;
|
|
pbyNewRow = pbyBitmap;
|
|
|
|
for (usLine = 0; usLine < usNewHeight; usLine++)
|
|
{
|
|
while (usErrorTerm >= usNewHeight)
|
|
{
|
|
pbyOrgRow += usBytesPerRow; /* skip a row */
|
|
usErrorTerm -= usNewHeight;
|
|
}
|
|
if (pbyOrgRow != pbyNewRow)
|
|
{
|
|
MEMCPY(pbyNewRow, pbyOrgRow, usBytesPerRow);
|
|
}
|
|
pbyNewRow += usBytesPerRow;
|
|
usErrorTerm += usOrgHeight;
|
|
}
|
|
for (usLine = usNewHeight; usLine < usOrgHeight; usLine++)
|
|
{
|
|
MEMSET(pbyNewRow, 0, usBytesPerRow); /* erase the leftover */
|
|
pbyNewRow += usBytesPerRow;
|
|
}
|
|
}
|
|
else if (usNewHeight > usOrgHeight) /* Expand Vertical */
|
|
{
|
|
pbyOrgRow = pbyBitmap + (usOrgHeight - 1) * usBytesPerRow;
|
|
pbyNewRow = pbyBitmap + (usNewHeight - 1) * usBytesPerRow;
|
|
|
|
for (usLine = 0; usLine < usOrgHeight; usLine++)
|
|
{
|
|
usErrorTerm += usNewHeight;
|
|
|
|
while (usErrorTerm >= usOrgHeight) /* executes at least once */
|
|
{
|
|
if (pbyOrgRow != pbyNewRow)
|
|
{
|
|
MEMCPY(pbyNewRow, pbyOrgRow, usBytesPerRow);
|
|
}
|
|
pbyNewRow -= usBytesPerRow;
|
|
usErrorTerm -= usOrgHeight;
|
|
}
|
|
pbyOrgRow -= usBytesPerRow;
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
|
|
FS_PRIVATE void ScaleHorizontal (
|
|
uint8 *pbyBitmap,
|
|
uint16 usOrgBytesPerRow,
|
|
uint16 usNewBytesPerRow,
|
|
uint16 usOrgWidth,
|
|
uint16 usNewWidth,
|
|
uint16 usRowCount
|
|
)
|
|
{
|
|
uint8 *pbyOrgRow; /* points to original row beginning */
|
|
uint8 *pbyNewRow; /* points to new row beginning */
|
|
uint8 *pbyOrg; /* original data pointer */
|
|
uint8 *pbyNew; /* new data pointer */
|
|
uint8 byOrgData; /* original data read 1 byte at a time */
|
|
uint8 byNewData; /* new data assembled bit by bit */
|
|
|
|
uint16 usErrorTerm; /* for 'Bresenham' calculation */
|
|
uint16 usByte; /* to byte counter */
|
|
uint16 usOrgBytes; /* from width rounded up in bytes */
|
|
uint16 usNewBytes; /* to width rounded up in bytes */
|
|
|
|
int16 sOrgBits; /* counts valid bits of from data */
|
|
int16 sNewBits; /* counts valid bits of to data */
|
|
int16 sOrgBitsInit; /* valid original bits at row begin */
|
|
int16 sNewBitsInit; /* valid new bits at row begin */
|
|
|
|
|
|
if (usOrgWidth > usNewWidth) /* Compress Horizontal */
|
|
{
|
|
pbyOrgRow = pbyBitmap;
|
|
pbyNewRow = pbyBitmap;
|
|
usNewBytes = (usNewWidth + 7) >> 3;
|
|
|
|
while (usRowCount > 0)
|
|
{
|
|
pbyOrg = pbyOrgRow;
|
|
pbyNew = pbyNewRow;
|
|
usErrorTerm = usOrgWidth >> 1;
|
|
|
|
sOrgBits = 0; /* start at left edge */
|
|
sNewBits = 0;
|
|
usByte = 0;
|
|
byNewData = 0;
|
|
while (usByte < usNewBytes)
|
|
{
|
|
while (usErrorTerm >= usNewWidth)
|
|
{
|
|
sOrgBits--; /* skip a bit */
|
|
usErrorTerm -= usNewWidth;
|
|
}
|
|
while (sOrgBits <= 0) /* if out of data */
|
|
{
|
|
byOrgData = *pbyOrg++; /* then get some fresh */
|
|
sOrgBits += 8;
|
|
}
|
|
byNewData <<= 1; /* new bit to lsb */
|
|
byNewData |= (byOrgData >> (sOrgBits - 1)) & 1;
|
|
|
|
sNewBits++;
|
|
if (sNewBits == 8) /* if to data byte is full */
|
|
{
|
|
*pbyNew++ = byNewData; /* then write it out */
|
|
sNewBits = 0;
|
|
usByte++; /* loop counter */
|
|
}
|
|
usErrorTerm += usOrgWidth;
|
|
}
|
|
while (usByte < usNewBytesPerRow)
|
|
{
|
|
*pbyNew++ = 0; /* blank out the rest */
|
|
usByte++;
|
|
}
|
|
pbyOrgRow += usOrgBytesPerRow;
|
|
pbyNewRow += usNewBytesPerRow;
|
|
usRowCount--;
|
|
}
|
|
}
|
|
else if (usNewWidth > usOrgWidth) /* Expand Horizontal */
|
|
{
|
|
pbyOrgRow = pbyBitmap + (usRowCount - 1) * usOrgBytesPerRow;
|
|
pbyNewRow = pbyBitmap + (usRowCount - 1) * usNewBytesPerRow;
|
|
|
|
usOrgBytes = (usOrgWidth + 7) >> 3;
|
|
sOrgBitsInit = (int16)((usOrgWidth + 7) & 0x07) - 7;
|
|
|
|
usNewBytes = (usNewWidth + 7) >> 3;
|
|
sNewBitsInit = 7 - (int16)((usNewWidth + 7) & 0x07);
|
|
|
|
while (usRowCount > 0) /* for each row */
|
|
{
|
|
pbyOrg = pbyOrgRow + usOrgBytes - 1; /* point to right edges */
|
|
pbyNew = pbyNewRow + usNewBytes - 1;
|
|
usErrorTerm = usOrgWidth >> 1;
|
|
|
|
sOrgBits = sOrgBitsInit; /* initially unaligned */
|
|
sNewBits = sNewBitsInit;
|
|
usByte = 0;
|
|
byNewData = 0;
|
|
while (usByte < usNewBytes) /* for each output byte */
|
|
{
|
|
if (sOrgBits <= 0) /* if out of data */
|
|
{
|
|
byOrgData = *pbyOrg--; /* then get some fresh */
|
|
sOrgBits += 8;
|
|
}
|
|
usErrorTerm += usNewWidth;
|
|
|
|
while (usErrorTerm >= usOrgWidth) /* executes at least once */
|
|
{
|
|
byNewData >>= 1; /* use the msb of byte */
|
|
byNewData |= (byOrgData << (sOrgBits - 1)) & 0x80;
|
|
|
|
sNewBits++;
|
|
if (sNewBits == 8) /* if to data byte is full */
|
|
{
|
|
*pbyNew-- = byNewData; /* then write it out */
|
|
sNewBits = 0;
|
|
usByte++; /* loop counter */
|
|
}
|
|
usErrorTerm -= usOrgWidth;
|
|
}
|
|
sOrgBits--; /* get next bit */
|
|
}
|
|
pbyOrgRow -= usOrgBytesPerRow;
|
|
pbyNewRow -= usNewBytesPerRow;
|
|
usRowCount--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
|
|
FS_PRIVATE void CopyBit(
|
|
CopyBlock* pcb )
|
|
{
|
|
uint16 usSrcOffset;
|
|
uint16 usSrcShift;
|
|
uint16 usDstOffset;
|
|
uint16 usDstShift;
|
|
|
|
static uint16 usByteMask[8] =
|
|
{ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
|
|
|
|
/* if speed becomes an issue, this next multiply could be moved up */
|
|
/* to the calling routined, and placed outside the 'x' loop */
|
|
|
|
usSrcOffset = (pcb->usSrcY * pcb->usSrcBytesPerRow) + (pcb->usSrcX >> 3);
|
|
usSrcShift = pcb->usSrcX & 0x0007;
|
|
|
|
if (pcb->pbySrc[usSrcOffset] & usByteMask[usSrcShift])
|
|
{
|
|
usDstOffset = (pcb->usDstY * pcb->usDstBytesPerRow) + (pcb->usDstX >> 3);
|
|
usDstShift = pcb->usDstX & 0x0007;
|
|
pcb->pbyDst[usDstOffset] |= usByteMask[usDstShift];
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|