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.
395 lines
12 KiB
395 lines
12 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: Stroke.c
|
|
*
|
|
* DrvStrokePath for VGA driver
|
|
*
|
|
* Copyright (c) 1992 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "driver.h"
|
|
#include "lines.h"
|
|
|
|
// Style array for alternate style (alternates one pixel on, one pixel off):
|
|
|
|
STYLEPOS gaspAlternateStyle[] = { 1 };
|
|
|
|
// Array to compute ROP masks:
|
|
|
|
LONG gaiLineMix[] = {
|
|
AND_ZERO | XOR_ONE,
|
|
AND_ZERO | XOR_ZERO,
|
|
AND_NOTPEN | XOR_NOTPEN,
|
|
AND_NOTPEN | XOR_ZERO,
|
|
AND_ZERO | XOR_NOTPEN,
|
|
AND_PEN | XOR_PEN,
|
|
AND_ONE | XOR_ONE,
|
|
AND_ONE | XOR_PEN,
|
|
AND_PEN | XOR_ONE,
|
|
AND_PEN | XOR_ZERO,
|
|
AND_ONE | XOR_NOTPEN,
|
|
AND_ONE | XOR_ZERO,
|
|
AND_PEN | XOR_NOTPEN,
|
|
AND_ZERO | XOR_PEN,
|
|
AND_NOTPEN | XOR_ONE,
|
|
AND_NOTPEN | XOR_PEN
|
|
};
|
|
|
|
// We have 4 basic strip drawers, one for every semi-octant. The near-
|
|
// horizontal semi-octant is number 0, and the rest are numbered
|
|
// consecutively.
|
|
|
|
// Prototypes to go to the screen and handle any ROPs:
|
|
|
|
VOID vStripSolid0(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolid1(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolid2(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolid3(STRIP*, LINESTATE*, LONG*);
|
|
|
|
VOID vStripStyled0(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripStyled123(STRIP*, LINESTATE*, LONG*);
|
|
|
|
// Prototypes to go to the screen and handle only set-style ROPs:
|
|
|
|
VOID vStripSolidSet0(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolidSet1(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolidSet2(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripSolidSet3(STRIP*, LINESTATE*, LONG*);
|
|
|
|
VOID vStripStyledSet0(STRIP*, LINESTATE*, LONG*);
|
|
VOID vStripStyledSet123(STRIP*, LINESTATE*, LONG*);
|
|
|
|
PFNSTRIP gapfnStrip[] = {
|
|
vStripSolid0,
|
|
vStripSolid3,
|
|
vStripSolid1,
|
|
vStripSolid2,
|
|
|
|
vStripStyled0,
|
|
vStripStyled123,
|
|
vStripStyled123,
|
|
vStripStyled123,
|
|
|
|
vStripSolidSet0,
|
|
vStripSolidSet3,
|
|
vStripSolidSet1,
|
|
vStripSolidSet2,
|
|
|
|
vStripStyledSet0,
|
|
vStripStyledSet123,
|
|
vStripStyledSet123,
|
|
vStripStyledSet123,
|
|
};
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrushOrg, pla, mix)
|
|
*
|
|
* Strokes the path.
|
|
\**************************************************************************/
|
|
|
|
BOOL DrvStrokePath(
|
|
SURFOBJ* pso,
|
|
PATHOBJ* ppo,
|
|
CLIPOBJ* pco,
|
|
XFORMOBJ* pxo,
|
|
BRUSHOBJ* pbo,
|
|
POINTL* pptlBrushOrg,
|
|
LINEATTRS* pla,
|
|
MIX mix)
|
|
{
|
|
STYLEPOS aspLtoR[STYLE_MAX_COUNT];
|
|
STYLEPOS aspRtoL[STYLE_MAX_COUNT];
|
|
LINESTATE ls;
|
|
PFNSTRIP* apfn;
|
|
FLONG fl;
|
|
PPDEV ppdev = (PPDEV) pso->dhsurf;
|
|
|
|
UNREFERENCED_PARAMETER(pxo);
|
|
UNREFERENCED_PARAMETER(pptlBrushOrg);
|
|
|
|
// Fast lines can't handle trivial clipping, ROPs other than R2_COPYPEN, or
|
|
// styles:
|
|
|
|
mix &= 0xf;
|
|
if ((mix == 0x0d) &&
|
|
(pco->iDComplexity == DC_TRIVIAL) &&
|
|
(pla->pstyle == NULL) && !(pla->fl & LA_ALTERNATE))
|
|
{
|
|
vFastLine(ppdev, ppo, ppdev->lNextScan,
|
|
(pbo->iSolidColor << 8) | (pbo->iSolidColor & 0xff));
|
|
return(TRUE);
|
|
}
|
|
|
|
fl = 0;
|
|
|
|
// Look after styling initialization:
|
|
|
|
if (pla->fl & LA_ALTERNATE)
|
|
{
|
|
ASSERTVGA(pla->pstyle == (FLOAT_LONG*) NULL && pla->cstyle == 0,
|
|
"Non-empty style array for PS_ALTERNATE");
|
|
|
|
ls.bStartIsGap = 0; // First pel is a dash
|
|
ls.cStyle = 1; // Size of style array
|
|
ls.spTotal = 1; // Sum of style array
|
|
ls.spTotal2 = 2; // Twice the sum
|
|
ls.aspRtoL = &gaspAlternateStyle[0]; // Right-to-left array
|
|
ls.aspLtoR = &gaspAlternateStyle[0]; // Left-to-right array
|
|
ls.spNext = HIWORD(pla->elStyleState.l) & 1;
|
|
// Light first pixel if
|
|
// a multiple of 2
|
|
ls.xyDensity = 1; // Each 'dot' is one
|
|
// pixel long
|
|
fl |= FL_ARBITRARYSTYLED;
|
|
}
|
|
else if (pla->pstyle != (FLOAT_LONG*) NULL)
|
|
{
|
|
FLOAT_LONG* pstyle;
|
|
STYLEPOS* pspDown;
|
|
STYLEPOS* pspUp;
|
|
|
|
ASSERTVGA(pla->cstyle <= STYLE_MAX_COUNT, "Style array too large");
|
|
|
|
// Compute length of style array:
|
|
|
|
pstyle = &pla->pstyle[pla->cstyle];
|
|
|
|
ls.xyDensity = STYLE_DENSITY;
|
|
ls.spTotal = 0;
|
|
while (pstyle-- > pla->pstyle)
|
|
{
|
|
ls.spTotal += pstyle->l;
|
|
}
|
|
|
|
// The style array is given in 'style' units. Since we're going to
|
|
// assign each unit to be STYLE_DENSITY (3) pixels long, multiply:
|
|
|
|
ls.spTotal *= STYLE_DENSITY;
|
|
ls.spTotal2 = 2 * ls.spTotal;
|
|
|
|
// Compute starting style position (this is guaranteed not to overflow).
|
|
// Note that since the array repeats infinitely, this number might
|
|
// actually be more than ls.spTotal2, but we take care of that later
|
|
// in our code:
|
|
|
|
ls.spNext = HIWORD(pla->elStyleState.l) * STYLE_DENSITY +
|
|
LOWORD(pla->elStyleState.l);
|
|
|
|
fl |= FL_ARBITRARYSTYLED;
|
|
ls.cStyle = pla->cstyle;
|
|
ls.aspRtoL = aspRtoL; // Style array in right-to-left order
|
|
ls.aspLtoR = aspLtoR; // Style array in left-to-right order
|
|
|
|
// ulStartMask determines if the first entry in the style array is for
|
|
// a dash or a gap:
|
|
|
|
ls.bStartIsGap = (pla->fl & LA_STARTGAP) ? -1L : 0L;
|
|
|
|
pstyle = pla->pstyle;
|
|
pspDown = &ls.aspRtoL[ls.cStyle - 1];
|
|
pspUp = &ls.aspLtoR[0];
|
|
|
|
// We always draw strips left-to-right, but styles have to be laid
|
|
// down in the direction of the original line. This means that in
|
|
// the strip code we have to traverse the style array in the
|
|
// opposite direction;
|
|
|
|
while (pspDown >= &ls.aspRtoL[0])
|
|
{
|
|
ASSERTVGA(pstyle->l > 0 && pstyle->l <= STYLE_MAX_VALUE,
|
|
"Illegal style array value");
|
|
|
|
*pspDown = pstyle->l * STYLE_DENSITY;
|
|
*pspUp = *pspDown;
|
|
|
|
pspUp++;
|
|
pspDown--;
|
|
pstyle++;
|
|
}
|
|
}
|
|
|
|
{
|
|
// All ROPs are handled in a single pass:
|
|
|
|
ULONG achColor[4];
|
|
LONG iIndex;
|
|
ULONG iColor = (pbo->iSolidColor & 0xff);
|
|
|
|
achColor[AND_ZERO] = 0;
|
|
achColor[AND_PEN] = pbo->iSolidColor;
|
|
achColor[AND_NOTPEN] = ~pbo->iSolidColor;
|
|
achColor[AND_ONE] = (ULONG) -1L;
|
|
|
|
iIndex = gaiLineMix[mix];
|
|
|
|
// We have special strip drawers for set-style ROPs (where we don't
|
|
// have to read video memory):
|
|
|
|
if ((iIndex & 0xff) == AND_ZERO)
|
|
fl |= FL_SET;
|
|
|
|
// Put the AND index in the low byte, and the XOR index in the next:
|
|
|
|
*((BYTE*) &ls.chAndXor) = (BYTE) achColor[iIndex & 0xff];
|
|
*((BYTE*) &ls.chAndXor + 1) = (BYTE) achColor[iIndex >> MIX_XOR_OFFSET];
|
|
}
|
|
|
|
apfn = &gapfnStrip[4 * ((fl & FL_STRIP_ARRAY_MASK) >> FL_STRIP_ARRAY_SHIFT)];
|
|
|
|
// Set up to enumerate the path:
|
|
|
|
if (pco->iDComplexity != DC_COMPLEX)
|
|
{
|
|
RECTL arclClip[4]; // For rectangular clipping
|
|
PATHDATA pd;
|
|
RECTL* prclClip = (RECTL*) NULL;
|
|
BOOL bMore;
|
|
ULONG cptfx;
|
|
POINTFIX ptfxStartFigure;
|
|
POINTFIX ptfxLast;
|
|
POINTFIX* pptfxFirst;
|
|
POINTFIX* pptfxBuf;
|
|
|
|
if (pco->iDComplexity == DC_RECT)
|
|
{
|
|
fl |= FL_SIMPLE_CLIP;
|
|
|
|
arclClip[0] = pco->rclBounds;
|
|
|
|
// FL_FLIP_D:
|
|
|
|
arclClip[1].top = pco->rclBounds.left;
|
|
arclClip[1].left = pco->rclBounds.top;
|
|
arclClip[1].bottom = pco->rclBounds.right;
|
|
arclClip[1].right = pco->rclBounds.bottom;
|
|
|
|
// FL_FLIP_V:
|
|
|
|
arclClip[2].top = -pco->rclBounds.bottom + 1;
|
|
arclClip[2].left = pco->rclBounds.left;
|
|
arclClip[2].bottom = -pco->rclBounds.top + 1;
|
|
arclClip[2].right = pco->rclBounds.right;
|
|
|
|
// FL_FLIP_V | FL_FLIP_D:
|
|
|
|
arclClip[3].top = pco->rclBounds.left;
|
|
arclClip[3].left = -pco->rclBounds.bottom + 1;
|
|
arclClip[3].bottom = pco->rclBounds.right;
|
|
arclClip[3].right = -pco->rclBounds.top + 1;
|
|
|
|
prclClip = arclClip;
|
|
}
|
|
|
|
do {
|
|
bMore = PATHOBJ_bEnum(ppo, &pd);
|
|
|
|
cptfx = pd.count;
|
|
if (cptfx == 0)
|
|
{
|
|
ASSERTVGA(!bMore, "Empty path record in non-empty path");
|
|
break;
|
|
}
|
|
|
|
if (pd.flags & PD_BEGINSUBPATH)
|
|
{
|
|
ptfxStartFigure = *pd.pptfx;
|
|
pptfxFirst = pd.pptfx;
|
|
pptfxBuf = pd.pptfx + 1;
|
|
cptfx--;
|
|
}
|
|
else
|
|
{
|
|
pptfxFirst = &ptfxLast;
|
|
pptfxBuf = pd.pptfx;
|
|
}
|
|
|
|
if (pd.flags & PD_RESETSTYLE)
|
|
ls.spNext = 0;
|
|
|
|
// We have to check for cptfx == 0 because the only point in the
|
|
// subpath may have been the StartFigure point:
|
|
|
|
if (cptfx > 0)
|
|
{
|
|
if (!bLines(ppdev,
|
|
pptfxFirst,
|
|
pptfxBuf,
|
|
(RUN*) NULL,
|
|
cptfx,
|
|
&ls,
|
|
prclClip,
|
|
apfn,
|
|
fl))
|
|
return(FALSE);
|
|
}
|
|
|
|
ptfxLast = pd.pptfx[pd.count - 1];
|
|
|
|
if (pd.flags & PD_CLOSEFIGURE)
|
|
{
|
|
if (!bLines(ppdev,
|
|
&ptfxLast,
|
|
&ptfxStartFigure,
|
|
(RUN*) NULL,
|
|
1,
|
|
&ls,
|
|
prclClip,
|
|
apfn,
|
|
fl))
|
|
return(FALSE);
|
|
}
|
|
} while (bMore);
|
|
|
|
if (fl & FL_STYLED)
|
|
{
|
|
// Save the style state:
|
|
|
|
ULONG ulHigh;
|
|
ULONG ulLow;
|
|
|
|
ulHigh = ls.spNext / ls.xyDensity;
|
|
ulLow = ls.spNext % ls.xyDensity;
|
|
|
|
pla->elStyleState.l = MAKELONG(ulLow, ulHigh);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Local state for path enumeration:
|
|
|
|
BOOL bMore;
|
|
union {
|
|
BYTE aj[offsetof(CLIPLINE, arun) + RUN_MAX * sizeof(RUN)];
|
|
CLIPLINE cl;
|
|
} cl;
|
|
|
|
fl |= FL_COMPLEX_CLIP;
|
|
|
|
// We use the clip object when non-simple clipping is involved:
|
|
|
|
PATHOBJ_vEnumStartClipLines(ppo, pco, pso, pla);
|
|
|
|
do {
|
|
bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(cl), &cl.cl);
|
|
if (cl.cl.c != 0)
|
|
{
|
|
if (fl & FL_STYLED)
|
|
{
|
|
ls.spComplex = HIWORD(cl.cl.lStyleState) * ls.xyDensity
|
|
+ LOWORD(cl.cl.lStyleState);
|
|
}
|
|
if (!bLines(ppdev,
|
|
&cl.cl.ptfxA,
|
|
&cl.cl.ptfxB,
|
|
&cl.cl.arun[0],
|
|
cl.cl.c,
|
|
&ls,
|
|
(RECTL*) NULL,
|
|
apfn,
|
|
fl))
|
|
return(FALSE);
|
|
}
|
|
} while (bMore);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|