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.
1284 lines
43 KiB
1284 lines
43 KiB
/*********************************************************************
|
|
|
|
scentry.c -- New Scan Converter NewScan Module
|
|
|
|
(c) Copyright 1992 Microsoft Corp. All rights reserved.
|
|
|
|
1/31/95 deanb added fsc_GetCoords function
|
|
8/04/94 deanb State initialized to more it out of bss
|
|
8/24/93 deanb flatcount fix to reversal detection
|
|
8/10/93 deanb gray scale support routines added
|
|
6/22/93 deanb all black bounding box, (0,0) for null glyph
|
|
6/11/93 gregh Removed ONCURVE definition
|
|
6/11/93 deanb if HiBand <= LoBand do entire bitmap
|
|
6/10/93 deanb fsc_Initialize added, stdio & assert gone
|
|
4/06/92 deanb CheckContour removed
|
|
3/19/92 deanb ScanArrays rather than lists
|
|
12/22/92 deanb MultDivide -> LongMulDiv; Rectangle -> Rect
|
|
12/21/92 deanb interface types aligned with rasterizer
|
|
12/11/92 deanb fserror.h imported, new error codes
|
|
11/30/92 deanb WorkSpace renamed WorkScan
|
|
11/04/92 deanb remove duplicate points function added
|
|
10/28/92 deanb memory requirement calculation reworked
|
|
10/19/92 deanb bad contours ignored rather than error'd
|
|
10/16/92 deanb first contour point off curve fix
|
|
10/13/92 deanb rect.bounds correction
|
|
10/12/92 deanb reentrant State implemented
|
|
10/08/92 deanb reworked for split workspace
|
|
10/05/92 deanb global ListMemory replace with stListSize
|
|
9/25/92 deanb scankind included in line/spline/endpoint calls
|
|
9/10/92 deanb dropout coding begun
|
|
9/08/92 deanb MAXSPLINELENGTH now imported from scspline.h
|
|
8/18/92 deanb New i/f for dropout control, contour elems
|
|
7/28/92 deanb Recursive calls for up/down & left/right
|
|
7/23/92 deanb EvaluateSpline included
|
|
7/17/92 deanb Included EvaluateLine
|
|
7/13/92 deanb Start/End point made SHORT
|
|
6/01/92 deanb fsc_FillBitMap debug switch added
|
|
5/08/92 deanb reordered includes for precompiled headers
|
|
4/27/92 deanb Splines coded
|
|
4/09/92 deanb New types
|
|
4/06/92 deanb rectBounds calc corrected
|
|
3/30/92 deanb MinMax calc added to MeasureContour
|
|
3/24/92 deanb GetWorkspaceSize coded
|
|
3/23/92 deanb First cut
|
|
|
|
**********************************************************************/
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Imports */
|
|
|
|
/*********************************************************************/
|
|
|
|
#include "fscdefs.h" /* shared data types */
|
|
#include "fserror.h" /* error codes */
|
|
#include "fsconfig.h" /* configuration def's */
|
|
#include "fontmath.h" /* for LongMulDiv */
|
|
|
|
#include "scglobal.h" /* structures & constants */
|
|
#include "scgray.h" /* gray scale param block */
|
|
#include "scspline.h" /* spline evaluation */
|
|
#include "scline.h" /* line evaluation */
|
|
#include "scendpt.h" /* for init and contour list */
|
|
#include "scanlist.h" /* for init and bitmap */
|
|
#include "scmemory.h" /* for setup mem */
|
|
#include "scentry.h" /* for own function prototypes */
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Global state structure */
|
|
|
|
/*********************************************************************/
|
|
|
|
#ifndef FSCFG_REENTRANT
|
|
|
|
FS_PUBLIC StateVars State = {0}; /* global static: available to all */
|
|
|
|
#endif
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Local Prototypes */
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PRIVATE int32 FindExtrema(ContourList*, GlyphBitMap*);
|
|
|
|
FS_PRIVATE int32 EvaluateSpline(PSTATE F26Dot6, F26Dot6, F26Dot6, F26Dot6, F26Dot6, F26Dot6, uint16 );
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Function Exports */
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Initialization Functions */
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PUBLIC void fsc_Initialize()
|
|
{
|
|
fsc_InitializeScanlist(); /* scanlist calls to bitmap */
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Remove duplicated points from contour data */
|
|
|
|
/* This was previously done in sc_FindExtrema of sc.c, */
|
|
/* but was pulled out to avoid having fsc_MeasureGlyph */
|
|
/* make changes to the contour list data structure. */
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PUBLIC int32 fsc_RemoveDups(
|
|
ContourList* pclContour ) /* glyph outline */
|
|
{
|
|
uint16 usContour; /* contour limit */
|
|
int16 sStartPt, sEndPt; /* coutour index limits */
|
|
int16 sPt; /* point index */
|
|
int16 s; /* index for list collapse */
|
|
F26Dot6 *pfxX1, *pfxY1; /* leading point */
|
|
F26Dot6 fxX2, fxY2; /* trailing point */
|
|
|
|
for (usContour = 0; usContour < pclContour->usContourCount; usContour++)
|
|
{
|
|
sStartPt = pclContour->asStartPoint[usContour];
|
|
sEndPt = pclContour->asEndPoint[usContour];
|
|
|
|
pfxX1 = &(pclContour->afxXCoord[sStartPt]);
|
|
pfxY1 = &(pclContour->afxYCoord[sStartPt]);
|
|
|
|
for (sPt = sStartPt; sPt < sEndPt; ++sPt)
|
|
{
|
|
fxX2 = *pfxX1; /* check next pair */
|
|
pfxX1++;
|
|
fxY2 = *pfxY1;
|
|
pfxY1++;
|
|
|
|
if ((*pfxX1 == fxX2) && (*pfxY1 == fxY2)) /* if duplicate */
|
|
{
|
|
for(s = sPt; s > sStartPt; s--) /* s = index of point to be removed */
|
|
{
|
|
pclContour->afxXCoord[s] = pclContour->afxXCoord[s - 1];
|
|
pclContour->afxYCoord[s] = pclContour->afxYCoord[s - 1];
|
|
pclContour->abyOnCurve[s] = pclContour->abyOnCurve[s - 1];
|
|
}
|
|
sStartPt++; /* advance start past dup */
|
|
pclContour->asStartPoint[usContour] = sStartPt;
|
|
pclContour->abyOnCurve[sPt + 1] |= ONCURVE; /* dup'd pt must be on curve */
|
|
}
|
|
}
|
|
|
|
/* now pfxX1 and pfxY1 point to end point coordinates */
|
|
|
|
if (sStartPt != sEndPt) /* finished if single point */
|
|
{
|
|
fxX2 = pclContour->afxXCoord[sStartPt];
|
|
fxY2 = pclContour->afxYCoord[sStartPt];
|
|
|
|
if ((*pfxX1 == fxX2) && (*pfxY1 == fxY2)) /* if start = end */
|
|
{
|
|
pclContour->asStartPoint[usContour]++;
|
|
pclContour->abyOnCurve[sEndPt] |= ONCURVE; /* dup'd pt must be on curve */
|
|
}
|
|
}
|
|
}
|
|
return NO_ERR;
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Calculate the amount of workspace needed to scan convert */
|
|
/* a given glyph into a given bitmap. Get per intersection and */
|
|
/* per scanline size info from ScanList module. */
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PUBLIC int32 fsc_MeasureGlyph(
|
|
ContourList* pclContour, /* glyph outline */
|
|
GlyphBitMap* pbmpBitMap, /* to return bounds */
|
|
WorkScan* pwsWork, /* to return values */
|
|
uint16 usScanKind, /* dropout control value */
|
|
uint16 usRoundXMin /* for gray scale alignment */
|
|
)
|
|
{
|
|
uint16 usCont; /* contour index */
|
|
int16 sPt; /* point index */
|
|
int16 sStart, sEnd; /* start and end point of contours */
|
|
int16 sOrgDir; /* original contour direction */
|
|
int16 sDir; /* current contour direction */
|
|
int16 sFlatCount; /* for contours starting flat */
|
|
int32 lVScanCount; /* total vertical scan lines */
|
|
int32 lHScanCount; /* total horizontal scan lines */
|
|
int32 lTotalHIx;
|
|
int32 lTotalVIx;
|
|
int32 lElementCount; /* total element point estimate */
|
|
int32 lDivide; /* spline element point counter */
|
|
int32 lErrCode;
|
|
|
|
F26Dot6 fxX1, fxX2; /* x coord endpoints */
|
|
F26Dot6 fxY1, fxY2; /* y coord endpoints */
|
|
F26Dot6 *pfxXCoord, *pfxYCoord; /* for fast point array access */
|
|
F26Dot6 fxAbsDelta; /* for element count check */
|
|
uint8 byF1, byF2; /* oncurve flag values */
|
|
uint8 *pbyFlags; /* for element count check */
|
|
|
|
PRevRoot prrRoots; /* reversal list roots structure */
|
|
|
|
|
|
lErrCode = FindExtrema(pclContour, pbmpBitMap); /* calc bounding box */
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
pbmpBitMap->rectBounds.left &= -((int32)usRoundXMin); /* mask off low n bits */
|
|
|
|
prrRoots = fsc_SetupRevRoots(pwsWork->pchRBuffer, pwsWork->lRMemSize);
|
|
lElementCount = 0; /* smart point counter */
|
|
|
|
for (usCont = 0; usCont < pclContour->usContourCount; usCont++)
|
|
{
|
|
sStart = pclContour->asStartPoint[usCont];
|
|
sEnd = pclContour->asEndPoint[usCont];
|
|
if (sStart == sEnd)
|
|
{
|
|
continue; /* for anchor points */
|
|
}
|
|
|
|
/* check contour Y values for direction reversals */
|
|
|
|
fxY1 = pclContour->afxYCoord[sEnd]; /* start by closing */
|
|
pfxYCoord = &pclContour->afxYCoord[sStart];
|
|
|
|
sPt = sStart;
|
|
sDir = 0; /* starting dir unknown */
|
|
sFlatCount = 0;
|
|
while ((sDir == 0) && (sPt <= sEnd))
|
|
{
|
|
fxY2 = *pfxYCoord++;
|
|
if (fxY2 > fxY1) /* find first up or down */
|
|
{
|
|
sDir = 1;
|
|
}
|
|
else if (fxY2 < fxY1)
|
|
{
|
|
sDir = -1;
|
|
}
|
|
else
|
|
{
|
|
sFlatCount++; /* countour starts flat */
|
|
}
|
|
fxY1 = fxY2;
|
|
sPt++;
|
|
}
|
|
sOrgDir = sDir; /* save original ep check */
|
|
|
|
while (sPt <= sEnd)
|
|
{
|
|
fxY2 = *pfxYCoord++;
|
|
if (sDir == 1)
|
|
{
|
|
if (fxY2 <= fxY1) /* = is for endpoint cases */
|
|
{
|
|
fsc_AddYReversal (prrRoots, fxY1, 1);
|
|
sDir = -1;
|
|
}
|
|
}
|
|
else /* if sDir == -1 */
|
|
{
|
|
if (fxY2 >= fxY1) /* = is for endpoint cases */
|
|
{
|
|
fsc_AddYReversal (prrRoots, fxY1, -1);
|
|
sDir = 1;
|
|
}
|
|
}
|
|
fxY1 = fxY2; /* next segment */
|
|
sPt++;
|
|
}
|
|
|
|
while (sFlatCount > 0) /* if contour started flat */
|
|
{
|
|
if (sDir == 0) /* if completely flat */
|
|
{
|
|
sDir = 1; /* then pick a direction */
|
|
sOrgDir = 1;
|
|
}
|
|
fsc_AddYReversal (prrRoots, fxY1, sDir); /* add one per point */
|
|
sDir = -sDir;
|
|
sFlatCount--;
|
|
}
|
|
if (sOrgDir != sDir) /* if endpoint reverses */
|
|
{
|
|
fsc_AddYReversal (prrRoots, fxY1, sDir); /* then balance up/down */
|
|
}
|
|
|
|
/* if doing dropout control, check contour X values for direction reversals */
|
|
|
|
if (!(usScanKind & SK_NODROPOUT)) /* if any kind of dropout */
|
|
{
|
|
fxX1 = pclContour->afxXCoord[sEnd]; /* start by closing */
|
|
pfxXCoord = &pclContour->afxXCoord[sStart];
|
|
|
|
sPt = sStart;
|
|
sDir = 0; /* starting dir unknown */
|
|
sFlatCount = 0;
|
|
while ((sDir == 0) && (sPt <= sEnd))
|
|
{
|
|
fxX2 = *pfxXCoord++;
|
|
if (fxX2 > fxX1) /* find first up or down */
|
|
{
|
|
sDir = 1;
|
|
}
|
|
else if (fxX2 < fxX1)
|
|
{
|
|
sDir = -1;
|
|
}
|
|
else
|
|
{
|
|
sFlatCount++; /* countour starts flat */
|
|
}
|
|
fxX1 = fxX2;
|
|
sPt++;
|
|
}
|
|
sOrgDir = sDir; /* save original ep check */
|
|
|
|
while (sPt <= sEnd)
|
|
{
|
|
fxX2 = *pfxXCoord++;
|
|
if (sDir == 1)
|
|
{
|
|
if (fxX2 <= fxX1) /* = is for endpoint cases */
|
|
{
|
|
fsc_AddXReversal (prrRoots, fxX1, 1);
|
|
sDir = -1;
|
|
}
|
|
}
|
|
else /* if sDir == -1 */
|
|
{
|
|
if (fxX2 >= fxX1) /* = is for endpoint cases */
|
|
{
|
|
fsc_AddXReversal (prrRoots, fxX1, -1);
|
|
sDir = 1;
|
|
}
|
|
}
|
|
fxX1 = fxX2; /* next segment */
|
|
sPt++;
|
|
}
|
|
|
|
while (sFlatCount > 0) /* if contour started flat */
|
|
{
|
|
if (sDir == 0) /* if completely flat */
|
|
{
|
|
sDir = 1; /* then pick a direction */
|
|
sOrgDir = 1;
|
|
}
|
|
fsc_AddXReversal (prrRoots, fxX1, sDir); /* add one per point */
|
|
sDir = -sDir;
|
|
sFlatCount--;
|
|
}
|
|
if (sOrgDir != sDir) /* if endpoint reverses */
|
|
{
|
|
fsc_AddXReversal (prrRoots, fxX1, sDir); /* then balance up/down */
|
|
}
|
|
|
|
if (usScanKind & SK_SMART) /* if smart dropout control */
|
|
{ /* estimate the elem point count */
|
|
fxX1 = pclContour->afxXCoord[sEnd];
|
|
fxY1 = pclContour->afxYCoord[sEnd];
|
|
byF1 = pclContour->abyOnCurve[sEnd];
|
|
pfxXCoord = &pclContour->afxXCoord[sStart];
|
|
pfxYCoord = &pclContour->afxYCoord[sStart];
|
|
pbyFlags = &pclContour->abyOnCurve[sStart];
|
|
|
|
lElementCount += (uint32)(sEnd - sStart) + 2L; /* 1/pt + 1/contour */
|
|
|
|
for (sPt = sStart; sPt <= sEnd; sPt++)
|
|
{
|
|
fxX2 = *pfxXCoord++;
|
|
fxY2 = *pfxYCoord++;
|
|
byF2 = *pbyFlags++;
|
|
|
|
if (((byF1 & byF2) & ONCURVE) == 0) /* if this is a spline */
|
|
{
|
|
if (((byF1 | byF2) & ONCURVE) == 0)
|
|
{
|
|
lElementCount++; /* +1 for midpoint */
|
|
}
|
|
|
|
if (FXABS(fxX2 - fxX1) > FXABS(fxY2 - fxY1))
|
|
{
|
|
fxAbsDelta = FXABS(fxX2 - fxX1);
|
|
}
|
|
else
|
|
{
|
|
fxAbsDelta = FXABS(fxY2 - fxY1);
|
|
}
|
|
lDivide = 0;
|
|
while (fxAbsDelta > (MAXSPLINELENGTH / 2))
|
|
{
|
|
lDivide++;
|
|
lDivide <<= 1;
|
|
fxAbsDelta >>= 1;
|
|
}
|
|
lElementCount += lDivide; /* for subdivision */
|
|
}
|
|
fxX1 = fxX2;
|
|
fxY1 = fxY2;
|
|
byF1 = byF2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!(usScanKind & SK_NODROPOUT) && (usScanKind & SK_SMART)) /* if smart dropout */
|
|
{
|
|
lElementCount += fsc_GetReversalCount(prrRoots) << 1; /* add in 2 * reversals */
|
|
}
|
|
|
|
/* set horiz workspace return values */
|
|
|
|
lHScanCount = (int32)(pbmpBitMap->rectBounds.top - pbmpBitMap->rectBounds.bottom);
|
|
lVScanCount = (int32)(pbmpBitMap->rectBounds.right - pbmpBitMap->rectBounds.left);
|
|
|
|
pbmpBitMap->sRowBytes = (int16)ROWBYTESLONG(lVScanCount);
|
|
pbmpBitMap->lMMemSize = (lHScanCount * (int32)pbmpBitMap->sRowBytes);
|
|
|
|
lTotalHIx = fsc_GetHIxEstimate(prrRoots); /* intersection count */
|
|
pwsWork->lHMemSize = fsc_GetScanHMem(usScanKind, lHScanCount, lTotalHIx);
|
|
|
|
/* set vertical workspace return values */
|
|
|
|
if (usScanKind & SK_NODROPOUT) /* if no dropout */
|
|
{
|
|
pwsWork->lVMemSize = 0L;
|
|
}
|
|
else
|
|
{
|
|
lTotalVIx = fsc_GetVIxEstimate(prrRoots); /* estimate intersection count */
|
|
pwsWork->lVMemSize = fsc_GetScanVMem(usScanKind, lVScanCount, lTotalVIx, lElementCount);
|
|
}
|
|
|
|
pwsWork->lHInterCount = lTotalHIx; /* save for SetupScan */
|
|
pwsWork->lVInterCount = lTotalVIx;
|
|
pwsWork->lElementCount = lElementCount;
|
|
pwsWork->lRMemSize = fsc_GetRevMemSize(prrRoots);
|
|
|
|
#ifdef FSCFG_REENTRANT
|
|
|
|
pwsWork->lHMemSize += sizeof(StateVars); /* reentrant state space */
|
|
|
|
#endif
|
|
|
|
return NO_ERR;
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Calculate the amount of workspace needed to scan convert */
|
|
/* a given band into a given bitmap. Get per intersection and */
|
|
/* per scanline size info from ScanList module. */
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PUBLIC int32 fsc_MeasureBand(
|
|
GlyphBitMap* pbmpBitMap, /* computed by MeasureGlyph */
|
|
WorkScan* pwsWork, /* to return new values */
|
|
uint16 usBandType, /* small or fast */
|
|
uint16 usBandWidth, /* scanline count */
|
|
uint16 usScanKind ) /* dropout control value */
|
|
{
|
|
int32 lBandWidth; /* max scanline count */
|
|
int32 lTotalHIx; /* est of horiz intersections in band */
|
|
int32 lVScanCount; /* total vertical scan lines */
|
|
int32 lHScanCount; /* total horizontal scan lines */
|
|
|
|
lBandWidth = (int32)usBandWidth;
|
|
pbmpBitMap->lMMemSize = (lBandWidth * (int32)pbmpBitMap->sRowBytes);
|
|
|
|
if (usBandType == FS_BANDINGSMALL)
|
|
{
|
|
lTotalHIx = fsc_GetHIxBandEst((PRevRoot)pwsWork->pchRBuffer, &pbmpBitMap->rectBounds, lBandWidth);
|
|
pwsWork->lHInterCount = lTotalHIx; /* save for SetupScan */
|
|
pwsWork->lHMemSize = fsc_GetScanHMem(usScanKind, lBandWidth, lTotalHIx);
|
|
pwsWork->lVMemSize = 0L; /* force dropout control off */
|
|
}
|
|
else if (usBandType == FS_BANDINGFAST)
|
|
{
|
|
lTotalHIx = fsc_GetHIxEstimate((PRevRoot)pwsWork->pchRBuffer); /* intersection count */
|
|
pwsWork->lHInterCount = lTotalHIx; /* save for SetupScan */
|
|
|
|
lHScanCount = (int32)(pbmpBitMap->rectBounds.top - pbmpBitMap->rectBounds.bottom);
|
|
pwsWork->lHMemSize = fsc_GetScanHMem(usScanKind, lHScanCount, lTotalHIx);
|
|
|
|
if (usScanKind & SK_NODROPOUT) /* if no dropout */
|
|
{
|
|
pwsWork->lVMemSize = 0L;
|
|
}
|
|
else /* if any kind of dropout */
|
|
{
|
|
pbmpBitMap->lMMemSize += (int32)pbmpBitMap->sRowBytes; /* to save below row */
|
|
|
|
lVScanCount = (int32)(pbmpBitMap->rectBounds.right - pbmpBitMap->rectBounds.left);
|
|
pwsWork->lVMemSize = fsc_GetScanVMem(usScanKind, lVScanCount, pwsWork->lVInterCount, pwsWork->lElementCount);
|
|
pwsWork->lVMemSize += (int32)pbmpBitMap->sRowBytes; /* to save above row */
|
|
}
|
|
}
|
|
|
|
#ifdef FSCFG_REENTRANT
|
|
|
|
pwsWork->lHMemSize += sizeof(StateVars); /* reentrant state space */
|
|
|
|
#endif
|
|
|
|
return NO_ERR;
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Scan Conversion Routine */
|
|
/* Trace the contour, passing out lines and splines, */
|
|
/* then call ScanList to fill the bitmap */
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PUBLIC int32 fsc_FillGlyph(
|
|
ContourList* pclContour, /* glyph outline */
|
|
GlyphBitMap* pgbBitMap, /* target */
|
|
WorkScan* pwsWork, /* for scan array */
|
|
uint16 usBandType, /* old, small, fast or faster */
|
|
uint16 usScanKind ) /* dropout control value */
|
|
{
|
|
uint16 usCont; /* contour index */
|
|
int16 sStart, sEnd; /* start and end point of contours */
|
|
int32 lStateSpace; /* HMem used by state structure */
|
|
int32 lErrCode; /* function return code */
|
|
F26Dot6 *pfxXCoord; /* next x coord ptr */
|
|
F26Dot6 *pfxYCoord; /* next y coord ptr */
|
|
uint8 *pbyOnCurve; /* next flag ptr */
|
|
F26Dot6 *pfxXStop; /* contour trace end condition */
|
|
F26Dot6 fxX1, fxX2, fxX3; /* x coord endpoints */
|
|
F26Dot6 fxY1, fxY2, fxY3; /* y coord endpoints */
|
|
uint8 byOnCurve; /* point 2 flag variable */
|
|
int32 lHiScanBand; /* top scan limit */
|
|
int32 lLoScanBand; /* bottom scan limit */
|
|
int32 lHiBitBand; /* top bitmap limit */
|
|
int32 lLoBitBand; /* bottom bitmap limit */
|
|
int32 lOrgLoBand; /* save for overscan fill check */
|
|
F26Dot6 fxYHiBand, fxYLoBand; /* limits in f26.6 */
|
|
boolean bSaveRow; /* for dropout over scanning */
|
|
boolean bBandCheck; /* eliminate out of band elements */
|
|
|
|
#ifdef FSCFG_REENTRANT
|
|
|
|
StateVars *pState; /* reentrant State is accessed via pointer */
|
|
|
|
pState = (StateVars*)pwsWork->pchHBuffer; /* and lives in HMem (memoryBase[6]) */
|
|
lStateSpace = sizeof(StateVars);
|
|
|
|
#else
|
|
|
|
lStateSpace = 0L; /* no HMem needed if not reentrant */
|
|
|
|
#endif
|
|
|
|
if (pgbBitMap->rectBounds.top <= pgbBitMap->rectBounds.bottom)
|
|
{
|
|
return NO_ERR; /* quick out for null glyph */
|
|
}
|
|
|
|
if (pgbBitMap->bZeroDimension) /* if no height or width */
|
|
{
|
|
usScanKind &= (~SK_STUBS); /* force no-stub dropout */
|
|
}
|
|
|
|
lHiBitBand = (int32)pgbBitMap->sHiBand,
|
|
lLoBitBand = (int32)pgbBitMap->sLoBand;
|
|
lOrgLoBand = lLoBitBand; /* save for fill call */
|
|
|
|
Assert (lHiBitBand > lLoBitBand); /* should be handled above */
|
|
|
|
if (!(usScanKind & SK_NODROPOUT)) /* if any kind of dropout */
|
|
{
|
|
lLoBitBand--; /* leave room below line */
|
|
}
|
|
if (lHiBitBand > pgbBitMap->rectBounds.top)
|
|
{
|
|
lHiBitBand = pgbBitMap->rectBounds.top; /* clip to top */
|
|
}
|
|
if (lLoBitBand < pgbBitMap->rectBounds.bottom)
|
|
{
|
|
lLoBitBand = pgbBitMap->rectBounds.bottom; /* clip to bottom */
|
|
}
|
|
if (usBandType == FS_BANDINGFAST) /* if fast banding */
|
|
{
|
|
lHiScanBand = pgbBitMap->rectBounds.top; /* render everything */
|
|
lLoScanBand = pgbBitMap->rectBounds.bottom;
|
|
bSaveRow = TRUE; /* keep last row for dropout */
|
|
}
|
|
else /* if old or small banding */
|
|
{
|
|
lHiScanBand = lHiBitBand; /* just take the band */
|
|
lLoScanBand = lLoBitBand;
|
|
bSaveRow = FALSE; /* last row not needed */
|
|
}
|
|
|
|
/* if fast banding has already renderend elements, skip to FillBitMap */
|
|
|
|
if (usBandType != FS_BANDINGFASTER) /* if rendering required */
|
|
{
|
|
fsc_SetupMem(ASTATE /* init workspace */
|
|
pwsWork->pchHBuffer + lStateSpace,
|
|
pwsWork->lHMemSize - lStateSpace,
|
|
pwsWork->pchVBuffer,
|
|
pwsWork->lVMemSize);
|
|
|
|
fsc_SetupLine(ASTATE0); /* passes line callback to scanlist */
|
|
fsc_SetupSpline(ASTATE0); /* passes spline callback to scanlist */
|
|
fsc_SetupEndPt(ASTATE0); /* passes endpoint callback to scanlist */
|
|
|
|
/* Eliminate out of band lines and splines, unless fast banding */
|
|
|
|
bBandCheck = ((lHiScanBand < pgbBitMap->rectBounds.top) || (lLoScanBand > pgbBitMap->rectBounds.bottom));
|
|
|
|
fxYHiBand = (F26Dot6)((lHiScanBand << SUBSHFT) - SUBHALF); /* may be too wide */
|
|
fxYLoBand = (F26Dot6)((lLoScanBand << SUBSHFT) + SUBHALF);
|
|
|
|
lErrCode = fsc_SetupScan(ASTATE &(pgbBitMap->rectBounds), usScanKind,
|
|
lHiScanBand, lLoScanBand, bSaveRow, (int32)pgbBitMap->sRowBytes,
|
|
pwsWork->lHInterCount, pwsWork->lVInterCount,
|
|
pwsWork->lElementCount, (PRevRoot)pwsWork->pchRBuffer );
|
|
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
for (usCont = 0; usCont < pclContour->usContourCount; usCont++)
|
|
{
|
|
sStart = pclContour->asStartPoint[usCont];
|
|
sEnd = pclContour->asEndPoint[usCont];
|
|
|
|
if (sStart == sEnd)
|
|
{
|
|
continue; /* for compatibilty */
|
|
}
|
|
/*
|
|
For efficiency in tracing the contour, we start by assigning (x1,y1)
|
|
to the last oncurve point. This is found by starting with the End
|
|
point and backing up if necessary. The pfxCoord pointers can then
|
|
be used to trace the entire contour without being reset across the
|
|
Start/End gap.
|
|
*/
|
|
pfxXCoord = &pclContour->afxXCoord[sStart];
|
|
pfxYCoord = &pclContour->afxYCoord[sStart];
|
|
pbyOnCurve = &pclContour->abyOnCurve[sStart];
|
|
pfxXStop = &pclContour->afxXCoord[sEnd];
|
|
|
|
if (pclContour->abyOnCurve[sEnd] & ONCURVE) /* if endpoint oncurve */
|
|
{
|
|
fxX1 = pclContour->afxXCoord[sEnd];
|
|
fxY1 = pclContour->afxYCoord[sEnd];
|
|
fxX2 = *pfxXCoord;
|
|
fxY2 = *pfxYCoord;
|
|
byOnCurve = *pbyOnCurve; /* 1st pt might be off */
|
|
pfxXStop++; /* stops at endpoint */
|
|
}
|
|
else /* if endpoint offcurve */
|
|
{
|
|
fxX1 = pclContour->afxXCoord[sEnd - 1];
|
|
fxY1 = pclContour->afxYCoord[sEnd - 1];
|
|
fxX2 = pclContour->afxXCoord[sEnd];
|
|
fxY2 = pclContour->afxYCoord[sEnd];
|
|
if ((pclContour->abyOnCurve[sEnd - 1] & ONCURVE) == 0)
|
|
{
|
|
fxX1 = (fxX1 + fxX2 + 1) >> 1; /* offcurve midpoint */
|
|
fxY1 = (fxY1 + fxY2 + 1) >> 1;
|
|
}
|
|
byOnCurve = 0;
|
|
pfxXCoord--; /* pre decrement */
|
|
pfxYCoord--;
|
|
pbyOnCurve--;
|
|
}
|
|
fsc_BeginContourEndpoint(ASTATE fxX1, fxY1); /* 1st oncurve pt -> ep module */
|
|
fsc_BeginContourScan(ASTATE usScanKind, fxX1, fxY1); /* to scanlist module too */
|
|
/*
|
|
At this point, (x1,y1) is the last oncurve point; (x2,y2) is the next
|
|
point (on or off); and the pointers are ready to be incremented to the
|
|
point following (x2,y2).
|
|
|
|
Throughout this loop (x1,y1) is always an oncurve point (it may be the
|
|
midpoint between two offcurve points). If (x2,y2) is oncurve, then we
|
|
have a line; if offcurve, we have a spline, and (x3,y3) will be the
|
|
next oncurve point.
|
|
*/
|
|
if (!bBandCheck)
|
|
{
|
|
while (pfxXCoord < pfxXStop)
|
|
{
|
|
if (byOnCurve & ONCURVE) /* if next point oncurve */
|
|
{
|
|
lErrCode = fsc_CheckEndPoint(ASTATE fxX2, fxY2, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
lErrCode = fsc_CalcLine(ASTATE fxX1, fxY1, fxX2, fxY2, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
fxX1 = fxX2; /* next oncurve point */
|
|
fxY1 = fxY2;
|
|
|
|
pfxXCoord++;
|
|
pfxYCoord++;
|
|
pbyOnCurve++;
|
|
}
|
|
else
|
|
{
|
|
pfxXCoord++; /* check next point */
|
|
fxX3 = *pfxXCoord;
|
|
pfxYCoord++;
|
|
fxY3 = *pfxYCoord;
|
|
pbyOnCurve++;
|
|
|
|
if (*pbyOnCurve & ONCURVE) /* if it's on, use it */
|
|
{
|
|
pfxXCoord++;
|
|
pfxYCoord++;
|
|
pbyOnCurve++;
|
|
}
|
|
else /* if not, calc next on */
|
|
{
|
|
fxX3 = (fxX2 + fxX3 + 1) >> 1; /* offcurve midpoint */
|
|
fxY3 = (fxY2 + fxY3 + 1) >> 1;
|
|
}
|
|
lErrCode = EvaluateSpline(ASTATE fxX1, fxY1, fxX2, fxY2, fxX3, fxY3, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
fxX1 = fxX3; /* next oncurve point */
|
|
fxY1 = fxY3;
|
|
}
|
|
fxX2 = *pfxXCoord; /* next contour point */
|
|
fxY2 = *pfxYCoord;
|
|
byOnCurve = *pbyOnCurve;
|
|
}
|
|
}
|
|
else /* if band checking */
|
|
{
|
|
while (pfxXCoord < pfxXStop)
|
|
{
|
|
if (byOnCurve & ONCURVE) /* if next point oncurve */
|
|
{
|
|
lErrCode = fsc_CheckEndPoint(ASTATE fxX2, fxY2, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
if (!(((fxY1 > fxYHiBand) && (fxY2 > fxYHiBand)) ||
|
|
((fxY1 < fxYLoBand) && (fxY2 < fxYLoBand))))
|
|
{
|
|
lErrCode = fsc_CalcLine(ASTATE fxX1, fxY1, fxX2, fxY2, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
}
|
|
|
|
fxX1 = fxX2; /* next oncurve point */
|
|
fxY1 = fxY2;
|
|
|
|
pfxXCoord++;
|
|
pfxYCoord++;
|
|
pbyOnCurve++;
|
|
}
|
|
else
|
|
{
|
|
pfxXCoord++; /* check next point */
|
|
fxX3 = *pfxXCoord;
|
|
pfxYCoord++;
|
|
fxY3 = *pfxYCoord;
|
|
pbyOnCurve++;
|
|
|
|
if (*pbyOnCurve & ONCURVE) /* if it's on, use it */
|
|
{
|
|
pfxXCoord++;
|
|
pfxYCoord++;
|
|
pbyOnCurve++;
|
|
}
|
|
else /* if not, calc next on */
|
|
{
|
|
fxX3 = (fxX2 + fxX3 + 1) >> 1; /* offcurve midpoint */
|
|
fxY3 = (fxY2 + fxY3 + 1) >> 1;
|
|
}
|
|
|
|
if (!(((fxY1 > fxYHiBand) && (fxY2 > fxYHiBand) && (fxY3 > fxYHiBand)) ||
|
|
((fxY1 < fxYLoBand) && (fxY2 < fxYLoBand) && (fxY3 < fxYLoBand))))
|
|
{
|
|
lErrCode = EvaluateSpline(ASTATE fxX1, fxY1, fxX2, fxY2, fxX3, fxY3, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
}
|
|
else /* if entirely outside of the band */
|
|
{
|
|
lErrCode = fsc_CheckEndPoint(ASTATE fxX3, fxY3, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
}
|
|
|
|
fxX1 = fxX3; /* next oncurve point */
|
|
fxY1 = fxY3;
|
|
}
|
|
fxX2 = *pfxXCoord; /* next contour point */
|
|
fxY2 = *pfxYCoord;
|
|
byOnCurve = *pbyOnCurve;
|
|
}
|
|
}
|
|
lErrCode = fsc_EndContourEndpoint(ASTATE usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
}
|
|
}
|
|
|
|
lErrCode = fsc_FillBitMap(
|
|
ASTATE
|
|
pgbBitMap->pchBitMap,
|
|
lHiBitBand,
|
|
lLoBitBand,
|
|
(int32)pgbBitMap->sRowBytes,
|
|
lOrgLoBand,
|
|
usScanKind
|
|
);
|
|
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
return NO_ERR;
|
|
}
|
|
|
|
|
|
#ifndef FSCFG_DISABLE_GRAYSCALE
|
|
|
|
/*********************************************************************/
|
|
|
|
/* This routine scales up an outline for gray scale scan conversion */
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PUBLIC int32 fsc_OverScaleOutline(
|
|
ContourList* pclContour, /* glyph outline */
|
|
uint16 usOverScale /* over scale factor */
|
|
)
|
|
{
|
|
uint16 usCont; /* contour index */
|
|
int16 sPt; /* point index */
|
|
int16 sStart, sEnd; /* start and end point of contours */
|
|
int16 sShift; /* for power of two multiply */
|
|
F26Dot6 *pfxXCoord, *pfxYCoord; /* for fast point array access */
|
|
|
|
|
|
switch (usOverScale) /* look for power of two */
|
|
{
|
|
case 1:
|
|
sShift = 0;
|
|
break;
|
|
case 2:
|
|
sShift = 1;
|
|
break;
|
|
case 4:
|
|
sShift = 2;
|
|
break;
|
|
case 8:
|
|
sShift = 3;
|
|
break;
|
|
default:
|
|
sShift = -1;
|
|
break;
|
|
}
|
|
|
|
for (usCont = 0; usCont < pclContour->usContourCount; usCont++)
|
|
{
|
|
sStart = pclContour->asStartPoint[usCont];
|
|
sEnd = pclContour->asEndPoint[usCont];
|
|
|
|
pfxXCoord = &pclContour->afxXCoord[sStart];
|
|
pfxYCoord = &pclContour->afxYCoord[sStart];
|
|
|
|
if (sShift >= 0) /* if power of two */
|
|
{
|
|
for (sPt = sStart; sPt <= sEnd; sPt++)
|
|
{
|
|
*pfxXCoord <<= sShift;
|
|
pfxXCoord++;
|
|
*pfxYCoord <<= sShift;
|
|
pfxYCoord++;
|
|
}
|
|
}
|
|
else /* if not a power of two */
|
|
{
|
|
for (sPt = sStart; sPt <= sEnd; sPt++)
|
|
{
|
|
*pfxXCoord *= (int32)usOverScale;
|
|
pfxXCoord++;
|
|
*pfxYCoord *= (int32)usOverScale;
|
|
pfxYCoord++;
|
|
}
|
|
}
|
|
}
|
|
return NO_ERR;
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Gray scale bitmap calculation */
|
|
/* Count over scale pixels into gray scale byte array */
|
|
/* Be sure that Hi/LoBand are set correctly for both Over & Gray! */
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PUBLIC int32 fsc_CalcGrayMap(
|
|
GlyphBitMap* pOverGBMap, /* over scaled source */
|
|
GlyphBitMap* pGrayGBMap, /* gray scale target */
|
|
uint16 usOverScale /* over scale factor */
|
|
)
|
|
{
|
|
char *pchOverRow; /* over scaled bitmap row pointer */
|
|
char *pchGrayRow; /* gray scale bitmap row pointer */
|
|
|
|
int16 sVOffset; /* over scaled rows to skip */
|
|
int16 sRightPix; /* right edge of used over pix's */
|
|
|
|
int16 sGrayRow; /* gray scale row loop counter */
|
|
uint16 usOverRowCount; /* over scaled row loop counter */
|
|
int16 sTotalRowCount; /* over scaled whole band counter */
|
|
|
|
uint32 ulBytes; /* gray scale count for clear */
|
|
int32 lErrCode; /* function return code */
|
|
|
|
GrayScaleParam GSP; /* param block for CalcGrayRow */
|
|
|
|
|
|
Assert ((usOverScale == 1) || (usOverScale == 2) || (usOverScale == 4) || (usOverScale == 8));
|
|
|
|
ulBytes = (uint32)pGrayGBMap->sRowBytes * (uint32)(pGrayGBMap->sHiBand - pGrayGBMap->sLoBand);
|
|
Assert(((ulBytes >> 2) << 2) == ulBytes);
|
|
fsc_ScanClearBitMap (ulBytes >> 2, (uint32*)pGrayGBMap->pchBitMap);
|
|
|
|
GSP.usOverScale = usOverScale;
|
|
GSP.pchOverLo = pOverGBMap->pchBitMap; /* set pointer limits */
|
|
GSP.pchOverHi = pOverGBMap->pchBitMap + pOverGBMap->lMMemSize;
|
|
GSP.pchGrayLo = pGrayGBMap->pchBitMap; /* set pointer limits */
|
|
GSP.pchGrayHi = pGrayGBMap->pchBitMap + pGrayGBMap->lMMemSize;
|
|
|
|
pchOverRow = pOverGBMap->pchBitMap;
|
|
usOverRowCount = usOverScale;
|
|
sTotalRowCount = pOverGBMap->sHiBand - pOverGBMap->sLoBand;
|
|
sVOffset = pOverGBMap->sHiBand - usOverScale * pGrayGBMap->sHiBand;
|
|
if (sVOffset < 0) /* if mapped above over's bitmap */
|
|
{
|
|
usOverRowCount -= (uint16)(-sVOffset); /* correct first band count */
|
|
}
|
|
else
|
|
{
|
|
pchOverRow += sVOffset * pOverGBMap->sRowBytes; /* point into bitmap */
|
|
sTotalRowCount -= sVOffset; /* adjust for skipped rows */
|
|
}
|
|
|
|
sRightPix = pGrayGBMap->rectBounds.right * (int16)usOverScale - pOverGBMap->rectBounds.left;
|
|
pchOverRow += (sRightPix - 1) >> 3;
|
|
GSP.usFirstShift = (uint16)(7 - ((sRightPix-1) & 0x0007));
|
|
|
|
GSP.sGrayCol = pGrayGBMap->rectBounds.right - pGrayGBMap->rectBounds.left;
|
|
pchGrayRow = pGrayGBMap->pchBitMap + (GSP.sGrayCol - 1);
|
|
|
|
for (sGrayRow = pGrayGBMap->sHiBand - 1; sGrayRow >= pGrayGBMap->sLoBand; sGrayRow--)
|
|
{
|
|
GSP.pchGray = pchGrayRow;
|
|
while ((usOverRowCount > 0) && (sTotalRowCount > 0))
|
|
{
|
|
GSP.pchOver = pchOverRow;
|
|
lErrCode = fsc_ScanCalcGrayRow( &GSP );
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
pchOverRow += pOverGBMap->sRowBytes;
|
|
usOverRowCount--;
|
|
sTotalRowCount--;
|
|
}
|
|
pchGrayRow += pGrayGBMap->sRowBytes;
|
|
usOverRowCount = usOverScale;
|
|
}
|
|
return NO_ERR;
|
|
}
|
|
|
|
#else /* if grayscale is disabled */
|
|
|
|
FS_PUBLIC int32 fsc_OverScaleOutline(
|
|
ContourList* pclContour, /* glyph outline */
|
|
uint16 usOverScale /* over scale factor */
|
|
)
|
|
{
|
|
FS_UNUSED_PARAMETER(pclContour);
|
|
FS_UNUSED_PARAMETER(usOverScale);
|
|
|
|
return BAD_GRAY_LEVEL_ERR;
|
|
}
|
|
|
|
|
|
FS_PUBLIC int32 fsc_CalcGrayMap(
|
|
GlyphBitMap* pOverGBMap, /* over scaled source */
|
|
GlyphBitMap* pGrayGBMap, /* gray scale target */
|
|
uint16 usOverScale /* over scale factor */
|
|
)
|
|
{
|
|
FS_UNUSED_PARAMETER(pOverGBMap);
|
|
FS_UNUSED_PARAMETER(pGrayGBMap);
|
|
FS_UNUSED_PARAMETER(usOverScale);
|
|
|
|
return BAD_GRAY_LEVEL_ERR;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Local Functions */
|
|
|
|
/*********************************************************************/
|
|
|
|
/*********************************************************************/
|
|
|
|
/* This routine examines a glyph contour by contour and calculates */
|
|
/* its bounding box. */
|
|
|
|
/*********************************************************************/
|
|
|
|
FS_PRIVATE int32 FindExtrema(
|
|
ContourList* pclContour, /* glyph outline */
|
|
GlyphBitMap* pbmpBitMap /* to return bounds */
|
|
)
|
|
{
|
|
uint16 usCont; /* contour index */
|
|
int16 sPt; /* point index */
|
|
int16 sStart, sEnd; /* start and end point of contours */
|
|
int32 lMaxX, lMinX; /* for bounding box left, right */
|
|
int32 lMaxY, lMinY; /* for bounding box top, bottom */
|
|
|
|
F26Dot6 *pfxXCoord, *pfxYCoord; /* for fast point array access */
|
|
F26Dot6 fxMaxX, fxMinX; /* for bounding box left, right */
|
|
F26Dot6 fxMaxY, fxMinY; /* for bounding box top, bottom */
|
|
boolean bFirstContour; /* set false after min/max set */
|
|
|
|
|
|
fxMaxX = 0L; /* default bounds limits */
|
|
fxMinX = 0L;
|
|
fxMaxY = 0L;
|
|
fxMinY = 0L;
|
|
bFirstContour = TRUE; /* first time only */
|
|
|
|
for (usCont = 0; usCont < pclContour->usContourCount; usCont++)
|
|
{
|
|
sStart = pclContour->asStartPoint[usCont];
|
|
sEnd = pclContour->asEndPoint[usCont];
|
|
if (sStart == sEnd)
|
|
{
|
|
continue; /* for anchor points */
|
|
}
|
|
|
|
pfxXCoord = &pclContour->afxXCoord[sStart];
|
|
pfxYCoord = &pclContour->afxYCoord[sStart];
|
|
|
|
if (bFirstContour)
|
|
{
|
|
fxMaxX = *pfxXCoord; /* init bounds limits */
|
|
fxMinX = *pfxXCoord;
|
|
fxMaxY = *pfxYCoord;
|
|
fxMinY = *pfxYCoord;
|
|
bFirstContour = FALSE; /* just once */
|
|
}
|
|
|
|
for (sPt = sStart; sPt <= sEnd; sPt++) /* find the min & max */
|
|
{
|
|
if (*pfxXCoord > fxMaxX)
|
|
fxMaxX = *pfxXCoord;
|
|
if (*pfxXCoord < fxMinX)
|
|
fxMinX = *pfxXCoord;
|
|
|
|
if (*pfxYCoord > fxMaxY)
|
|
fxMaxY = *pfxYCoord;
|
|
if (*pfxYCoord < fxMinY)
|
|
fxMinY = *pfxYCoord;
|
|
|
|
pfxXCoord++;
|
|
pfxYCoord++;
|
|
}
|
|
}
|
|
|
|
pbmpBitMap->fxMinX = fxMinX; /* save full precision bounds */
|
|
pbmpBitMap->fxMinY = fxMinY;
|
|
pbmpBitMap->fxMaxX = fxMaxX; /* save full precision bounds */
|
|
pbmpBitMap->fxMaxY = fxMaxY;
|
|
|
|
lMinX = (fxMinX + SUBHALF - 1) >> SUBSHFT; /* pixel black box */
|
|
lMinY = (fxMinY + SUBHALF - 1) >> SUBSHFT;
|
|
lMaxX = (fxMaxX + SUBHALF) >> SUBSHFT;
|
|
lMaxY = (fxMaxY + SUBHALF) >> SUBSHFT;
|
|
|
|
if ((F26Dot6)(int16)lMinX != lMinX || /* check overflow */
|
|
(F26Dot6)(int16)lMinY != lMinY ||
|
|
(F26Dot6)(int16)lMaxX != lMaxX ||
|
|
(F26Dot6)(int16)lMaxY != lMaxY )
|
|
{
|
|
return POINT_MIGRATION_ERR;
|
|
}
|
|
|
|
pbmpBitMap->bZeroDimension = FALSE; /* assume some size */
|
|
|
|
if (bFirstContour == FALSE) /* if contours present */
|
|
{ /* then force a non-zero bitmap */
|
|
if (lMinX == lMaxX)
|
|
{
|
|
lMaxX++; /* force 1 pixel wide */
|
|
pbmpBitMap->bZeroDimension = TRUE; /* flag for filling */
|
|
}
|
|
if (lMinY == lMaxY)
|
|
{
|
|
lMaxY++; /* force 1 pixel high */
|
|
pbmpBitMap->bZeroDimension = TRUE; /* flag for filling */
|
|
}
|
|
}
|
|
|
|
/* set bitmap structure return values */
|
|
|
|
pbmpBitMap->rectBounds.left = (int16)lMinX;
|
|
pbmpBitMap->rectBounds.right = (int16)lMaxX;
|
|
pbmpBitMap->rectBounds.bottom = (int16)lMinY;
|
|
pbmpBitMap->rectBounds.top = (int16)lMaxY;
|
|
|
|
return NO_ERR;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
/* This recursive routine subdivides splines that are non-monotonic or */
|
|
/* too big into splines that fsc_CalcSpline can handle. It also */
|
|
/* filters out degenerate (linear) splines, passing off to fsc_CalcLine. */
|
|
|
|
|
|
FS_PRIVATE int32 EvaluateSpline(
|
|
PSTATE /* pointer to state vars */
|
|
F26Dot6 fxX1, /* start point x coordinate */
|
|
F26Dot6 fxY1, /* start point y coordinate */
|
|
F26Dot6 fxX2, /* control point x coordinate */
|
|
F26Dot6 fxY2, /* control point y coordinate */
|
|
F26Dot6 fxX3, /* ending x coordinate */
|
|
F26Dot6 fxY3, /* ending y coordinate */
|
|
uint16 usScanKind /* scan control type */
|
|
)
|
|
{
|
|
F26Dot6 fxDX21, fxDX32, fxDX31; /* delta x's */
|
|
F26Dot6 fxDY21, fxDY32, fxDY31; /* delta y's */
|
|
|
|
F26Dot6 fxDenom; /* ratio denominator */
|
|
F26Dot6 fxX4, fxY4; /* first mid point */
|
|
F26Dot6 fxX5, fxY5; /* mid mid point */
|
|
F26Dot6 fxX6, fxY6; /* second mid point */
|
|
F26Dot6 fxX456, fxY456; /* for monotonic subdivision */
|
|
F26Dot6 fxAbsDX, fxAbsDY; /* abs of DX31, DY31 */
|
|
|
|
int32 lErrCode;
|
|
|
|
|
|
fxDX21 = fxX2 - fxX1; /* get all four deltas */
|
|
fxDX32 = fxX3 - fxX2;
|
|
fxDY21 = fxY2 - fxY1;
|
|
fxDY32 = fxY3 - fxY2;
|
|
|
|
/* If spline goes up and down, then subdivide it */
|
|
|
|
if (((fxDY21 > 0L) && (fxDY32 < 0L)) || ((fxDY21 < 0L) && (fxDY32 > 0L)))
|
|
{
|
|
fxDenom = fxDY21 - fxDY32; /* total y span */
|
|
fxX4 = fxX1 + LongMulDiv(fxDX21, fxDY21, fxDenom);
|
|
fxX6 = fxX2 + LongMulDiv(fxDX32, fxDY21, fxDenom);
|
|
fxX5 = fxX4 + LongMulDiv(fxX6 - fxX4, fxDY21, fxDenom);
|
|
fxY456 = fxY1 + LongMulDiv(fxDY21, fxDY21, fxDenom);
|
|
|
|
lErrCode = EvaluateSpline(ASTATE fxX1, fxY1, fxX4, fxY456, fxX5, fxY456, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
return EvaluateSpline(ASTATE fxX5, fxY456, fxX6, fxY456, fxX3, fxY3, usScanKind);
|
|
}
|
|
|
|
/* If spline goes left and right, then subdivide it */
|
|
|
|
if (((fxDX21 > 0L) && (fxDX32 < 0L)) || ((fxDX21 < 0L) && (fxDX32 > 0L)))
|
|
{
|
|
fxDenom = fxDX21 - fxDX32; /* total x span */
|
|
fxY4 = fxY1 + LongMulDiv(fxDY21, fxDX21, fxDenom);
|
|
fxY6 = fxY2 + LongMulDiv(fxDY32, fxDX21, fxDenom);
|
|
fxY5 = fxY4 + LongMulDiv(fxY6 - fxY4, fxDX21, fxDenom);
|
|
fxX456 = fxX1 + LongMulDiv(fxDX21, fxDX21, fxDenom);
|
|
|
|
lErrCode = EvaluateSpline(ASTATE fxX1, fxY1, fxX456, fxY4, fxX456, fxY5, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
return EvaluateSpline(ASTATE fxX456, fxY5, fxX456, fxY6, fxX3, fxY3, usScanKind);
|
|
}
|
|
|
|
/* By now the spline must be monotonic */
|
|
|
|
fxDX31 = fxX3 - fxX1; /* check overall size */
|
|
fxDY31 = fxY3 - fxY1;
|
|
fxAbsDX = FXABS(fxDX31);
|
|
fxAbsDY = FXABS(fxDY31);
|
|
|
|
/* If spline is too big to calculate, then subdivide it */
|
|
|
|
if ((fxAbsDX > MAXSPLINELENGTH) || (fxAbsDY > MAXSPLINELENGTH))
|
|
{
|
|
fxX4 = (fxX1 + fxX2) >> 1; /* first segment mid point */
|
|
fxY4 = (fxY1 + fxY2) >> 1;
|
|
fxX6 = (fxX2 + fxX3) >> 1; /* second segment mid point */
|
|
fxY6 = (fxY2 + fxY3) >> 1;
|
|
fxX5 = (fxX4 + fxX6) >> 1; /* mid segment mid point */
|
|
fxY5 = (fxY4 + fxY6) >> 1;
|
|
|
|
lErrCode = EvaluateSpline(ASTATE fxX1, fxY1, fxX4, fxY4, fxX5, fxY5, usScanKind);
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
return EvaluateSpline(ASTATE fxX5, fxY5, fxX6, fxY6, fxX3, fxY3, usScanKind);
|
|
}
|
|
|
|
/* The spline is now montonic and small enough */
|
|
|
|
lErrCode = fsc_CheckEndPoint(ASTATE fxX3, fxY3, usScanKind); /* first check endpoint */
|
|
if (lErrCode != NO_ERR) return lErrCode;
|
|
|
|
if (fxDX21 * fxDY32 == fxDY21 * fxDX32) /* if spline is degenerate (linear) */
|
|
{ /* treat as a line */
|
|
return fsc_CalcLine(ASTATE fxX1, fxY1, fxX3, fxY3, usScanKind);
|
|
}
|
|
else
|
|
{
|
|
return fsc_CalcSpline(ASTATE fxX1, fxY1, fxX2, fxY2, fxX3, fxY3, usScanKind);
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
/* Return an array of coordinates for outline points */
|
|
|
|
FS_PUBLIC int32 fsc_GetCoords(
|
|
ContourList* pclContour, /* glyph outline */
|
|
uint16 usPointCount, /* point count */
|
|
uint16* pusPointIndex, /* point indices */
|
|
PixCoord* ppcCoordinate /* point coordinates */
|
|
)
|
|
{
|
|
uint16 usMaxIndex; /* last defined point */
|
|
int32 lX; /* integer x coord */
|
|
int32 lY; /* integer y coord */
|
|
|
|
if (pclContour->usContourCount == 0)
|
|
{
|
|
return BAD_POINT_INDEX_ERR; /* can't have a point without a contour */
|
|
}
|
|
|
|
usMaxIndex = pclContour->asEndPoint[pclContour->usContourCount - 1] + 2; /* allow 2 phantoms */
|
|
|
|
while (usPointCount > 0)
|
|
{
|
|
if (*pusPointIndex > usMaxIndex)
|
|
{
|
|
return BAD_POINT_INDEX_ERR; /* beyond the last contour */
|
|
}
|
|
|
|
lX = (pclContour->afxXCoord[*pusPointIndex] + SUBHALF) >> SUBSHFT;
|
|
lY = (pclContour->afxYCoord[*pusPointIndex] + SUBHALF) >> SUBSHFT;
|
|
|
|
if ( ((int32)(int16)lX != lX) || ((int32)(int16)lY != lY) )
|
|
{
|
|
return POINT_MIGRATION_ERR; /* catch overflow */
|
|
}
|
|
|
|
ppcCoordinate->x = (int16)lX;
|
|
ppcCoordinate->y = (int16)lY;
|
|
|
|
pusPointIndex++;
|
|
ppcCoordinate++;
|
|
usPointCount--; /* loop through all points */
|
|
}
|
|
return NO_ERR;
|
|
}
|
|
|
|
/*********************************************************************/
|