Leaked source code of windows server 2003
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.
 
 
 
 
 
 

645 lines
20 KiB

/******************************Module*Header*******************************\
* Module Name: pathwide.hxx
*
* Path widening defines.
*
* CLASS HIERARCHY
*
* In constructing the wide-line, we keep track of 4 paths:
*
* 1) The original path.
* 2) The path holding the vertices of the polygonized pen.
* 3) The 'left' side of the wide-line outline.
* 4) The 'right' side of the wide-line outline.
*
* To keep track of the latter 3 paths, we use:
*
* PATHMEMOBJ // Regular path
* |
* v
* WIDEPATHOBJ // Path object to keep track of one side of the
* | // wide-line. Adds methods for easily adding
* | // one point at a time.
* v
* WIDEPENOBJ // Path object to keep the pen shape. A pen is
* // composed of an arbitrary number of points,
* // like a path, so we make it a path. Plus we
* // add some pen functionality.
*
* It was useful to compartmentalize the task of the widener into separate
* base classes:
*
* READER // Reads the original path a point at a time
* |
* v
* LINER // Reads the path a line at a time (flattening
* | // Beziers and generating close-figure lines as
* | // it goes).
* v
* STYLER // Handles styling by hacking the lines into
* | // itty bitty pieces.
* v
* WIDENER // Widens the path by generating the points at
* // every line-join and end-cap.
*
* Created: 9-Oct-1991
* Author: J. Andrew Goossen [andrewgo]
*
* Copyright (c) 1991-1999 Microsoft Corporation
\**************************************************************************/
#if DBG
// #define DEBUG_WIDE
#endif
class WIDENER;
#define SQUARE(x) ((x) * (x))
#define LPLUSHALFTOFX(x) (LTOFX(x) + (LTOFX(1) >> 1))
/***********************************Struct*********************************\
* struct HOBBY
*
* Structure used for containing half a Hobby pen.
*
* History:
* 9-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
typedef struct _HOBBY
{
PPOINTFIX pptfx;
COUNT cptfx;
} HOBBY, *PHOBBY; /* hob, phob */
/*********************************class************************************\
* class EVECTORFLEXT
*
* Can use VECTORFX's.
*
* History:
* 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
class EVECTORFLEXT : public EVECTORFL /* evecfl */
{
public:
EVECTORFLEXT(VECTORFX& vec)
{
x.vFxToEf(vec.x);
y.vFxToEf(vec.y);
}
BOOL bToVECTORFX(VECTORFX& vec)
{
return(x.bEfToFx(vec.x) && y.bEfToFx(vec.y));
}
};
/*********************************class************************************\
* class LINEDATA
*
* Keeps track of useful stuff about the current line in the original
* path that we're processing.
*
* History:
* 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
// LINEDATA flags:
#define LDF_INVERT 0x0001L
#define LDF_VECSQUARECOMPUTED 0x0002L
#define LDF_VECPERPCOMPUTED 0x0004L
#define LDF_VECDRAWCOMPUTED 0x0008L
#define LDF_NORMALIZEDCOMPUTED 0x0010L
class LINEDATA /* ld */
{
public:
FLONG fl; // LINEDATA flags, as above
PPATHREC ppr; // Pathrecord containing point
PPOINTFIX pptfx; // *pptfx == -ptfx if bInvert is TRUE
LONGLONG fxCrossStart;
LONGLONG fxCrossEnd;
EVECTORFX vecLine; // Actual line vector
EVECTORFX vecTangent; // True tangent to current point. Direction
// only -- to be used for calculating perps
// Cached values:
EVECTORFX vecSquare; // Vector to offset to square cap start
EVECTORFX vecPerp; // Perpendicular vector to line
EVECTORFX vecDraw; // Drawing vector for line
POINTFL ptflNormalized; // Normalized version of line vector
BOOL bInvert() { return(fl & LDF_INVERT); }
VOID vSetInvert() { fl |= LDF_INVERT; }
VOID vClearInvert() { fl &= ~LDF_INVERT; }
VOID vSetVecSquareComputed() { fl |= LDF_VECSQUARECOMPUTED; }
VOID vSetVecPerpComputed() { fl |= LDF_VECPERPCOMPUTED; }
VOID vSetVecDrawComputed() { fl |= LDF_VECDRAWCOMPUTED; }
VOID vSetNormalizedComputed() { fl |= LDF_NORMALIZEDCOMPUTED; }
BOOL bVecSquareComputed() { return(fl & LDF_VECSQUARECOMPUTED); }
BOOL bVecPerpComputed() { return(fl & LDF_VECPERPCOMPUTED); }
BOOL bVecDrawComputed() { return(fl & LDF_VECDRAWCOMPUTED); }
BOOL bNormalizedComputed() { return(fl & LDF_NORMALIZEDCOMPUTED); }
VOID vInit() { fl = 0; }
VOID vInit(POINTFIX& ptfxEnd, POINTFIX& ptfxStart)
{ fl = 0;
vecLine = ptfxEnd;
vecLine -= ptfxStart;
vecTangent = vecLine; }
// bToLeftSide() returns true if the perpendicular for the line
// falls to the left of the draw vector:
BOOL bToLeftSide() { return(fxCrossStart > fxCrossEnd); }
// bSamePenSection() returns true if the two lines have perpendicular
// vectors in the same area:
BOOL bSamePenSection(LINEDATA& ld)
{
return((pptfx == ld.pptfx) && (bToLeftSide() == ld.bToLeftSide()));
}
};
typedef LINEDATA *PLINEDATA;
/*********************************Class************************************\
* class WIDEPATHOBJ
*
* History:
* 12-Sep-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
class WIDEPATHOBJ : public PATHMEMOBJ /* wpath */
{
private:
#ifdef DEBUG_WIDE
BOOL bOpenPath;
#endif
protected:
BOOL bOutOfMemory;
PPOINTFIX pptfxPathRecCurrent;
PPOINTFIX pptfxPathRecEnd;
PPATHREC pprFigureStart;
BOOL bGrowPath();
VOID vGrowPathAndAddPoint(
PPOINTFIX, PEVECTORFX = (PEVECTORFX) NULL, BOOL = FALSE);
public:
WIDEPATHOBJ()
{
bOutOfMemory = FALSE;
#ifdef DEBUG_WIDE
bOpenPath = FALSE;
#endif
}
~WIDEPATHOBJ() {}
VOID vAddPoint(PPOINTFIX pptfx, BOOL bAddRecordIfNeeded = TRUE)
{
#ifdef DEBUG_WIDE
ASSERTGDI(bOpenPath, "vAddPoint path not open!");
#endif
if (pptfxPathRecCurrent >= pptfxPathRecEnd)
{
#ifdef DEBUG_WIDE
ASSERTGDI(pptfxPathRecCurrent == pptfxPathRecEnd,
"vAddPoint out of bounds!");
#endif
if (bAddRecordIfNeeded)
vGrowPathAndAddPoint(pptfx);
}
else
{
#ifdef DEBUG_WIDE
ASSERTGDI((PBYTE) pptfxPathRecCurrent - (PBYTE) ppath->ppachain
< (LONG) ppath->ppachain->siztPathAlloc, "vAddPoint out of bounds.");
#endif
*pptfxPathRecCurrent++ = *pptfx;
}
}
VOID vAddPoint(PPOINTFIX pptfx, PEVECTORFX pvec, BOOL bInvert)
{
#ifdef DEBUG_WIDE
ASSERTGDI(bOpenPath, "vAddPoint2 path not open!");
#endif
if (pptfxPathRecCurrent >= pptfxPathRecEnd)
{
#ifdef DEBUG_WIDE
ASSERTGDI(pptfxPathRecCurrent == pptfxPathRecEnd,
"vAddPoint2 out of bounds!");
#endif
vGrowPathAndAddPoint(pptfx, pvec, bInvert);
}
else
{
#ifdef DEBUG_WIDE
ASSERTGDI((PBYTE) pptfxPathRecCurrent - (PBYTE) ppath->ppachain
< (LONG) ppath->ppachain->siztPathAlloc, "vAddPoint2 out of bounds.");
#endif
// 'bInvert' will usually be constant, and so one of these code
// paths will optimize away:
if (bInvert)
{
pptfxPathRecCurrent->x = pptfx->x - pvec->x;
pptfxPathRecCurrent->y = pptfx->y - pvec->y;
}
else
{
pptfxPathRecCurrent->x = pptfx->x + pvec->x;
pptfxPathRecCurrent->y = pptfx->y + pvec->y;
}
pptfxPathRecCurrent++;
}
}
VOID vReverseConcatenate(WIDEPATHOBJ&);
VOID vPrependBeforeFigure();
VOID vPrependBeforeSubpath();
VOID vMarkFigureStart() { pprFigureStart = ppath->pprlast; }
BOOL bBeginFigure();
VOID vEndFigure();
VOID vCloseFigure() { ppath->pprlast->flags |= PD_CLOSEFIGURE; }
BOOL bValid() { return(PATHMEMOBJ::bValid() && !bOutOfMemory); }
VOID vSetError() { bOutOfMemory = TRUE; }
};
/******************************Public*Routine******************************\
* WIDEPATHOBJ::vAddPoint(pptfx, pvec, bInvert)
*
* Adds a single point to the path. The added point is the given point
* plus the specified vector (minus the vector if bInvert is TRUE).
*
* History:
* 1-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
/*********************************Class************************************\
* class WIDEPENOBJ
*
* History:
* 12-Sep-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
class WIDEPENOBJ : public WIDEPATHOBJ /* wpen */
{
private:
// Pre-computed look-up tables containing points of circular Hobby pens
// for widths 1 through 6:
#define HOBBY_TABLE_SIZE 6L
static POINTFIX aptfxHobby1[4];
static POINTFIX aptfxHobby2[5];
static POINTFIX aptfxHobby3[6];
static POINTFIX aptfxHobby4[8];
static POINTFIX aptfxHobby5[10];
static POINTFIX aptfxHobby6[10];
static HOBBY ahob[HOBBY_TABLE_SIZE];
BOOL bHobby; // TRUE if this is a Hobby pen
BOOL bThicken(PPOINTFIX pptfx); // Thickens pen if need-be
BOOL bHobbyize(EVECTORFX avec[]);// Makes a Hobby pen if need-be
BOOL bPenFlatten(PPOINTFIX); // Converts Beziers to lines
VOID vAddPenPoint(PPOINTFIX); // Adds a point to the end of our path
public:
WIDEPENOBJ() { bHobby = FALSE; }
BOOL bIsHobby() { return(bHobby); }
BOOL bIsHobby(BOOL b) { return(bHobby = b); }
BOOL bPolygonizePen(EXFORMOBJ&, LONG);
VOID vDetermineDrawVertex(EVECTORFX&, LINEDATA&);
COUNT cptAddRound(WIDENER&, LINEDATA&, LINEDATA&,
BOOL, BOOL, BOOL);
VOID vAddRoundEndCap(WIDENER&, LINEDATA&, BOOL, BOOL);
};
/*********************************class************************************\
* class READER
*
* Reads the path.
*
* History:
* 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
// Path widening flags:
#define FW_MORETOENUM 0x00000001L
#define FW_DOINGSTYLES 0x00000002L
#define FW_STYLENEXT 0x00000004L
#define FW_FIGURESTYLED 0x00000008L
#define FW_ALLROUND 0x00000010L
class READER
{
private:
EPATHOBJ* pepoSpine;
PATHDATA pd;
VOID vMoreToEnum(BOOL b) { vSetFlag(b, FW_MORETOENUM); }
BOOL bMoreToEnum() { return(fl & FW_MORETOENUM); }
PPOINTFIX pptfxRead;
PPOINTFIX pptfxEnd;
protected:
FLONG fl; // For widening flags, as above
VOID vSetFlag(BOOL b, FLONG flBit)
{
if (b)
fl |= flBit;
else
fl &= ~flBit;
}
READER(EPATHOBJ& epo) { pepoSpine = &epo;
pepoSpine->vEnumStart();
vMoreToEnum(TRUE); }
BOOL bIsBezier() { return(pd.flags & PD_BEZIERS); }
BOOL bNextFigure();
BOOL bNextPoint(POINTFIX& ptfx);
// Only valid when !bNextPoint():
BOOL bIsClosedFigure() { return(pd.flags & PD_CLOSEFIGURE); }
};
/*********************************class************************************\
* class LINER
*
* Cracks Beziers and handles CloseFigures.
*
* History:
* 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
enum WIDENEVENT { WE_STARTFIGURE, // Figure starts at 'ptfxThis'
WE_ENDFIGURE, // Figure ends at 'ptfxThis'
WE_CLOSEFIGURE, // Do a close figure join at 'ptfxThis'
WE_JOIN, // Do a join at 'ptfxThis'
WE_BEZIERJOIN, // Do a Bezier join at 'ptfxThis'
WE_STOPDASH, // Stop a styling dash at 'ptfxThis'
WE_STARTDASH, // Start a styling dash at 'ptfxThis'
WE_ZEROFIGURE, // Figure has zero length at 'ptfxThis'
WE_FINISHFIGURE, // Do start-cap of figure at 'ptfxThis'
WE_DONEPATH };
enum LINESTATE { LS_READPATH, // Next point in figure comes from path
LS_STARTFIGURE, // Next point in path is the start of
// a figure
LS_FINISHFIGURE, // Go back to first point in figure
LS_READBEZIER, // Next point comes from current Bezier
LS_DONEPATH };
class LINER : public READER
{
private:
BEZIER bez;
BOOL bReadLine(LINEDATA& ld);
POINTFIX ptfxNext; // Next point in path after 'ptfxThis' (see below)
POINTFIX ptfxStartFigure; // Keep around for later
LINEDATA ldStartFigure; // Start point for current figure
LINEDATA ldBuf[2]; // Line vector data buffer for current lines
LINESTATE ls; // Reading path state
VOID vNextPoint();
VOID vZeroFigure(); // Sets up for a zero-length figure
protected:
LINEDATA ldEndTangent; // Line vector data for last line in figure
LINEDATA ldStartTangent; // Line vector data for first line in figure
public:
LINER(EPATHOBJ& epo) : READER(epo)
{
if (!bNextFigure())
ls = LS_DONEPATH;
else
{
bNextPoint(ptfxNext);
ptfxStartFigure = ptfxNext;
ls = LS_STARTFIGURE;
}
}
VOID vNextEvent();
// Keeps track of all the info needed to add a join, start-cap or end-cap:
WIDENEVENT we; // Flag to indicate start-cap, end-cap, etc.
POINTFIX ptfxThis; // Point at which to add cap or join
PLINEDATA pldIn; // Vector of line entering 'ptfxThis' (used for
// end-caps and joins)
PLINEDATA pldOut; // Vector of line exiting 'ptfxThis' (used for
// start-caps and joins)
};
/*********************************class************************************\
* class STYLER
*
* Hacks up the path into itty bitty pieces to feed to the widener.
*
* History:
* 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
class STYLER : public LINER
{
private:
VOID vStyleNext(BOOL b) { vSetFlag(b, FW_STYLENEXT); }
VOID vDoingStyles(BOOL b) { vSetFlag(b, FW_DOINGSTYLES); }
BOOL bStyleNext() { return(fl & FW_STYLENEXT); }
BOOL bDoingStyles() { return(fl & FW_DOINGSTYLES); }
PFLOAT_LONG pstyleStart;
PFLOAT_LONG pstyleCurrent;
PFLOAT_LONG pstyleEnd;
EFLOAT efRemainingLength;// Length remaining in current line
EFLOAT efStyleLength; // Length of current dash or gap
EFLOAT efDoneLength; // Length of current line done
EFLOAT efLineLength; // efLineLength = efDoneLength + efRemainingLength
POINTFIX ptfxLineStart; // Start point of line
protected:
EFLOAT efWorldLength(EVECTORFX);
EFLOAT efNextStyleLength();
VOID vResetStyles() { pstyleCurrent = pstyleStart; }
// These two actually get initialized by the derived class because it's
// a bit of work, and it will know if we'll need them:
MATRIX mxDeviceToWorld;
EXFORMOBJ exoDeviceToWorld;
public:
STYLER(EPATHOBJ&, PLINEATTRS);
VOID vNextStyleEvent();
};
// Prototype used in WIDENER:
VOID vAddNice(WIDEPATHOBJ&, PPOINTFIX, PEVECTORFX, BOOL);
/*********************************class************************************\
* class WIDENER
*
* Widens the path.
*
* History:
* 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/
class WIDENER : public STYLER
{
friend VOID WIDEPENOBJ::vAddRoundEndCap(WIDENER&, LINEDATA&, BOOL, BOOL);
friend COUNT WIDEPENOBJ::cptAddRound(WIDENER&, LINEDATA&, LINEDATA&,
BOOL, BOOL, BOOL);
private:
WIDEPENOBJ wpen;
WIDEPATHOBJ wpathLeft;
WIDEPATHOBJ wpathRight;
ULONG iJoin;
ULONG iEndCap;
VOID vFigureStyled(BOOL b) { vSetFlag(b, FW_FIGURESTYLED); }
VOID vAllRound(BOOL b) { vSetFlag(b, FW_ALLROUND); }
BOOL bFigureStyled() { return(fl & FW_FIGURESTYLED); }
BOOL bAllRound() { return(fl & FW_ALLROUND); }
EFLOAT efHalfWidthMiterLimitSquared;
EFLOAT efHalfWidth;
VOID vVecPerpCompute(LINEDATA&);
VOID vVecSquareCompute(LINEDATA&);
VOID vVecDrawCompute(LINEDATA&);
protected:
BOOL bMiterInLimit(EVECTORFX);
EVECTORFX vecInDraw() { if (!pldIn->bVecDrawComputed())
vVecDrawCompute(*pldIn);
return(pldIn->vecDraw); }
EVECTORFX vecInPerp() { if (!pldIn->bVecPerpComputed())
vVecPerpCompute(*pldIn);
return(pldIn->vecPerp); }
EVECTORFX vecInSquare() { if (!pldIn->bVecSquareComputed())
vVecSquareCompute(*pldIn);
return(pldIn->vecSquare); }
EVECTORFX vecOutDraw() { if (!pldOut->bVecDrawComputed())
vVecDrawCompute(*pldOut);
return(pldOut->vecDraw); }
EVECTORFX vecOutPerp() { if (!pldOut->bVecPerpComputed())
vVecPerpCompute(*pldOut);
return(pldOut->vecPerp); }
EVECTORFX vecOutSquare() { if (!pldOut->bVecSquareComputed())
vVecSquareCompute(*pldOut);
return(pldOut->vecSquare); }
VOID vAddLeft(EVECTORFX& vec, BOOL bInvert = FALSE)
{ wpathLeft.vAddPoint(&ptfxThis, &vec, !bInvert); }
VOID vAddLeft(PEVECTORFX pvec, BOOL bInvert)
{ wpathLeft.vAddPoint(&ptfxThis, pvec, !bInvert); }
VOID vAddLeft() { wpathLeft.vAddPoint(&ptfxThis); }
VOID vAddLeftNice(PEVECTORFX pvec, BOOL bInvert)
{ vAddNice(wpathLeft, &ptfxThis, pvec, !bInvert); }
VOID vAddRight(EVECTORFX& vec, BOOL bInvert = FALSE)
{ wpathRight.vAddPoint(&ptfxThis, &vec, bInvert); }
VOID vAddRight(PEVECTORFX pvec, BOOL bInvert)
{ wpathRight.vAddPoint(&ptfxThis, pvec, bInvert); }
VOID vAddRight() { wpathRight.vAddPoint(&ptfxThis); }
VOID vAddRightNice(PEVECTORFX pvec, BOOL bInvert)
{ vAddNice(wpathRight, &ptfxThis, pvec, bInvert); }
VOID vAddJoin(BOOL);
VOID vAddRoundJoin(BOOL);
VOID vAddEndCap();
VOID vAddStartCap();
BOOL bWiden();
VOID vSetError() { wpathRight.vSetError(); }
public:
WIDENER(EPATHOBJ&, EXFORMOBJ&, PLINEATTRS);
BOOL bValid() { return(wpathRight.bValid() &&
wpathLeft.bValid() &&
wpen.bValid()); }
VOID vMakeItWide(EPATHOBJ&);
};