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.
752 lines
21 KiB
752 lines
21 KiB
/*************************************************************************\
|
|
* Module Name: EngStroke.c
|
|
*
|
|
* EngStrokePath for bitmap simulations, plus its kith.
|
|
*
|
|
* Created: 5-Apr-91
|
|
* Author: Paul Butzi
|
|
*
|
|
* Copyright (c) 1990-1999 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
#include "solline.hxx"
|
|
#include "engline.hxx"
|
|
|
|
// #define DEBUG_ENGSTROK
|
|
|
|
// Style array for alternate style (alternates one pixel on, one pixel off):
|
|
|
|
STYLEPOS gaspAlternateStyle[] = { 1 };
|
|
|
|
// Array to compute ROP masks:
|
|
|
|
LONG aiLineMix[] = {
|
|
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
|
|
};
|
|
|
|
static CHUNK mask1[] = {
|
|
0xffffffff, 0xffffff7f, 0xffffff3f, 0xffffff1f,
|
|
0xffffff0f, 0xffffff07, 0xffffff03, 0xffffff01,
|
|
0xffffff00, 0xffff7f00, 0xffff3f00, 0xffff1f00,
|
|
0xffff0f00, 0xffff0700, 0xffff0300, 0xffff0100,
|
|
0xffff0000, 0xff7f0000, 0xff3f0000, 0xff1f0000,
|
|
0xff0f0000, 0xff070000, 0xff030000, 0xff010000,
|
|
0xff000000, 0x7f000000, 0x3f000000, 0x1f000000,
|
|
0x0f000000, 0x07000000, 0x03000000, 0x01000000,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK mask4[] = {
|
|
0xffffffff,
|
|
0xffffff0f,
|
|
0xffffff00,
|
|
0xffff0f00,
|
|
0xffff0000,
|
|
0xff0f0000,
|
|
0xff000000,
|
|
0x0f000000,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK mask8[] = {
|
|
0xffffffff,
|
|
0xffffff00,
|
|
0xffff0000,
|
|
0xff000000,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK mask16[] = {
|
|
0xffffffff,
|
|
0xffff0000,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK mask24[] = {
|
|
0xffffff00,
|
|
0x00ffffff,
|
|
0x0000ffff,
|
|
0x000000ff,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK mask32[] = {
|
|
0xffffffff,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK maskpel1[] = {
|
|
0x00000080, 0x00000040, 0x00000020, 0x00000010,
|
|
0x00000008, 0x00000004, 0x00000002, 0x00000001,
|
|
0x00008000, 0x00004000, 0x00002000, 0x00001000,
|
|
0x00000800, 0x00000400, 0x00000200, 0x00000100,
|
|
0x00800000, 0x00400000, 0x00200000, 0x00100000,
|
|
0x00080000, 0x00040000, 0x00020000, 0x00010000,
|
|
0x80000000, 0x40000000, 0x20000000, 0x10000000,
|
|
0x08000000, 0x04000000, 0x02000000, 0x01000000,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK maskpel4[] = {
|
|
0x000000f0,
|
|
0x0000000f,
|
|
0x0000f000,
|
|
0x00000f00,
|
|
0x00f00000,
|
|
0x000f0000,
|
|
0xf0000000,
|
|
0x0f000000,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK maskpel8[] = {
|
|
0x000000ff,
|
|
0x0000ff00,
|
|
0x00ff0000,
|
|
0xff000000,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK maskpel16[] = {
|
|
0x0000ffff,
|
|
0xffff0000,
|
|
0x00000000,
|
|
};
|
|
|
|
static CHUNK maskpel24[] = {
|
|
0x00000000,
|
|
0x00000000,
|
|
0xff000000,
|
|
0xffff0000,
|
|
};
|
|
|
|
static CHUNK maskpel32[] = {
|
|
0xffffffff,
|
|
0x00000000,
|
|
};
|
|
|
|
// { Pointer to array of start masks,
|
|
// Pointer to array of pixel masks,
|
|
// # of pels per chunk (power of 2)
|
|
// # of bits per pel
|
|
// log2(pels per chunk)
|
|
// pels per chunk - 1 }
|
|
|
|
BMINFO gabminfo[] = {
|
|
{ NULL, NULL, 0, 0, 0, 0 }, // BMF_DEVICE
|
|
{ mask1, maskpel1, 32, 1, 5, 31 }, // BMF_1BPP
|
|
{ mask4, maskpel4, 8, 4, 3, 7 }, // BMF_4BPP
|
|
{ mask8, maskpel8, 4, 8, 2, 3 }, // BMF_8BPP
|
|
{ mask16, maskpel16, 2, 16, 1, 1 }, // BMF_16BPP
|
|
{ mask24, maskpel24, 0, 0, -1, 0 }, // BMF_24BPP
|
|
{ mask32, maskpel32, 1, 32, 0, 0 }, // BMF_32BPP
|
|
};
|
|
|
|
#if (BMF_1BPP != 1L)
|
|
error Invalid value for BMF_1BPP
|
|
#endif
|
|
|
|
#if (BMF_4BPP != 2L)
|
|
error Invalid value for BMF_4BPP
|
|
#endif
|
|
|
|
#if (BMF_8BPP != 3L)
|
|
error Invalid value for BMF_8BPP
|
|
#endif
|
|
|
|
#if (BMF_16BPP != 4L)
|
|
error Invalid value for BMF_16BPP
|
|
#endif
|
|
|
|
#if (BMF_24BPP != 5L)
|
|
error Invalid value for BMF_24BPP
|
|
#endif
|
|
|
|
#if (BMF_32BPP != 6L)
|
|
error Invalid value for BMF_32BPP
|
|
#endif
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bStrokeCosmetic(pso, ppo, eco, pbo, pla, mix)
|
|
*
|
|
* Strokes the path.
|
|
*
|
|
* History:
|
|
* 20-Mar-1991 -by- Paul Butzi
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bStrokeCosmetic(
|
|
SURFACE* pSurf,
|
|
PATHOBJ* ppo,
|
|
CLIPOBJ* pco,
|
|
BRUSHOBJ* pbo,
|
|
LINEATTRS* pla,
|
|
MIX mix)
|
|
{
|
|
STYLEPOS aspLeftToRight[STYLE_MAX_COUNT];
|
|
STYLEPOS aspRightToLeft[STYLE_MAX_COUNT];
|
|
LINESTATE ls;
|
|
|
|
// Verify that things are as they should be:
|
|
|
|
ASSERTGDI(pbo->iSolidColor != 0xFFFFFFFF, "Expect solid cosmetic pen");
|
|
ASSERTGDI(!(pla->fl & LA_GEOMETRIC) && !(ppo->fl & PO_BEZIERS),
|
|
"Unprocessable path");
|
|
|
|
FLONG fl = 0;
|
|
|
|
// Look after styling initialization:
|
|
|
|
if (pla->fl & LA_ALTERNATE)
|
|
{
|
|
ls.bStartGap = 0; // First pel is a dash
|
|
ls.cStyle = 1; // Size of style array
|
|
ls.xStep = 1; // x-styled step size
|
|
ls.yStep = 1; // y-styled step size
|
|
ls.spTotal = 1; // Sum of style array
|
|
ls.spTotal2 = 2; // Twice the sum
|
|
ls.aspRightToLeft = &gaspAlternateStyle[0]; // Right-to-left array
|
|
ls.aspLeftToRight = &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_STYLED;
|
|
}
|
|
else if (pla->pstyle != (FLOAT_LONG*) NULL)
|
|
{
|
|
ASSERTGDI(pla->cstyle <= STYLE_MAX_COUNT, "Style array too large");
|
|
|
|
{
|
|
HDEV hdev = ((SURFACE *)pSurf)->hdev();
|
|
|
|
if (hdev == 0)
|
|
{
|
|
// It is a pretty common mistake made by driver writers
|
|
// (I've made it several times myself) to call EngStrokePath
|
|
// on a temporary bitmap that it forgot to EngAssociateSurface.
|
|
|
|
WARNING("Can't get at the physical device information!\n");
|
|
WARNING("I'll bet the display/printer driver forgot to call");
|
|
WARNING("EngAssociateSurface for a bitmap it created, and");
|
|
WARNING("is now asking us to draw styled lines on it (we");
|
|
WARNING("need the device's style information).\n");
|
|
RIP("Please call EngAssociateSurface on the bitmap.");
|
|
|
|
// Assume some defaults:
|
|
|
|
ls.xStep = 1;
|
|
ls.yStep = 1;
|
|
ls.xyDensity = 3;
|
|
}
|
|
else
|
|
{
|
|
// We need the PDEV style information so that we can draw
|
|
// the styles with the correct length dashes:
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
ls.xStep = po.xStyleStep();
|
|
ls.yStep = po.yStyleStep();
|
|
ls.xyDensity = po.denStyleStep();
|
|
|
|
ASSERTGDI(ls.xyDensity != 0,
|
|
"Invalid denStyleStep supplied by the device!");
|
|
}
|
|
}
|
|
|
|
fl |= FL_STYLED;
|
|
ls.cStyle = pla->cstyle;
|
|
ls.bStartGap = (pla->fl & LA_STARTGAP) > 0;
|
|
ls.aspRightToLeft = aspRightToLeft;
|
|
ls.aspLeftToRight = aspLeftToRight;
|
|
|
|
FLOAT_LONG* pstyle = pla->pstyle;
|
|
STYLEPOS* pspDown = &ls.aspRightToLeft[ls.cStyle - 1];
|
|
STYLEPOS* pspUp = &ls.aspLeftToRight[0];
|
|
|
|
ls.spTotal = 0;
|
|
|
|
while (pspDown >= &ls.aspRightToLeft[0])
|
|
{
|
|
ASSERTGDI(pstyle->l > 0 && pstyle->l <= STYLE_MAX_VALUE,
|
|
"Illegal style array value");
|
|
|
|
*pspDown = pstyle->l * ls.xyDensity;
|
|
*pspUp = *pspDown;
|
|
ls.spTotal += *pspDown;
|
|
|
|
pspUp++;
|
|
pspDown--;
|
|
pstyle++;
|
|
}
|
|
|
|
ls.spTotal2 = 2 * ls.spTotal;
|
|
|
|
// Compute starting style position (this is guaranteed not to overflow):
|
|
|
|
ls.spNext = HIWORD(pla->elStyleState.l) * ls.xyDensity +
|
|
LOWORD(pla->elStyleState.l);
|
|
|
|
// Do some normalizing:
|
|
|
|
if (ls.spNext < 0)
|
|
{
|
|
RIP("Someone left style state negative");
|
|
ls.spNext = 0;
|
|
}
|
|
|
|
if (ls.spNext >= ls.spTotal2)
|
|
ls.spNext %= ls.spTotal2;
|
|
}
|
|
|
|
// Get device all warmed up and ready to go
|
|
|
|
LONG lOldStyleState = pla->elStyleState.l;
|
|
ULONG ulFormat = pSurf->iFormat();
|
|
LONG lDelta = pSurf->lDelta() / (LONG)sizeof(CHUNK);
|
|
CHUNK* pchBits = (CHUNK*)pSurf->pvScan0();
|
|
|
|
BMINFO* pbmi = &gabminfo[ulFormat];
|
|
CHUNK chOriginalColor = pbo->iSolidColor;
|
|
|
|
switch (ulFormat)
|
|
{
|
|
case BMF_1BPP:
|
|
chOriginalColor |= (chOriginalColor << 1);
|
|
chOriginalColor |= (chOriginalColor << 2);
|
|
// fall thru
|
|
case BMF_4BPP:
|
|
chOriginalColor |= (chOriginalColor << 4);
|
|
// fall thru
|
|
case BMF_8BPP:
|
|
chOriginalColor |= (chOriginalColor << 8);
|
|
// fall thru
|
|
case BMF_16BPP:
|
|
chOriginalColor |= (chOriginalColor << 16);
|
|
// fall thru
|
|
case BMF_24BPP:
|
|
case BMF_32BPP:
|
|
break;
|
|
default:
|
|
RIP("Invalid bitmap format");
|
|
}
|
|
|
|
{
|
|
// All ROPs are handled in a single pass.
|
|
|
|
CHUNK achColor[4];
|
|
|
|
achColor[AND_ZERO] = 0;
|
|
achColor[AND_PEN] = chOriginalColor;
|
|
achColor[AND_NOTPEN] = ~chOriginalColor;
|
|
achColor[AND_ONE] = 0xffffffff;
|
|
|
|
LONG iIndex = aiLineMix[mix & 0xf];
|
|
|
|
ls.chAnd = achColor[(iIndex & 0xff)];
|
|
ls.chXor = achColor[iIndex >> MIX_XOR_OFFSET];
|
|
}
|
|
|
|
// Figure out which set of strippers to use:
|
|
|
|
LONG iStrip = (ulFormat == BMF_24BPP) ? 8 : 0;
|
|
iStrip |= (fl & FL_STYLED) ? 4 : 0;
|
|
|
|
PFNSTRIP* apfn = &gapfnStrip[iStrip];
|
|
|
|
if ((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL))
|
|
{
|
|
// Handle complex clipping!
|
|
|
|
BOOL bMore;
|
|
union {
|
|
BYTE aj[sizeof(CLIPLINE) + (RUN_MAX - 1) * sizeof(RUN)];
|
|
CLIPLINE cl;
|
|
} cl;
|
|
|
|
fl |= FL_COMPLEX_CLIP;
|
|
|
|
((ECLIPOBJ*) pco)->vEnumPathStart(ppo, pSurf, pla);
|
|
|
|
do {
|
|
bMore = ((ECLIPOBJ*) ((EPATHOBJ*)ppo)->pco)->bEnumPath(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(pbmi,
|
|
&cl.cl.ptfxA,
|
|
&cl.cl.ptfxB,
|
|
&cl.cl.arun[0],
|
|
cl.cl.c,
|
|
&ls,
|
|
(RECTL*) NULL,
|
|
apfn,
|
|
fl,
|
|
pchBits,
|
|
lDelta))
|
|
return(FALSE);
|
|
}
|
|
} while (bMore);
|
|
}
|
|
else
|
|
{
|
|
// Handle simple or trivial clipping!
|
|
|
|
PATHDATA pd;
|
|
BOOL bMore;
|
|
ULONG cptfx;
|
|
POINTFIX ptfxStartFigure;
|
|
POINTFIX ptfxLast;
|
|
POINTFIX* pptfxFirst;
|
|
POINTFIX* pptfxBuf;
|
|
|
|
pd.flags = 0;
|
|
((EPATHOBJ*) ppo)->vEnumStart();
|
|
|
|
do {
|
|
bMore = ((EPATHOBJ*) ppo)->bEnum(&pd);
|
|
|
|
cptfx = pd.count;
|
|
if (cptfx == 0)
|
|
{
|
|
ASSERTGDI(!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(pbmi,
|
|
pptfxFirst,
|
|
pptfxBuf,
|
|
(RUN*) NULL,
|
|
cptfx,
|
|
&ls,
|
|
NULL,
|
|
apfn,
|
|
fl,
|
|
pchBits,
|
|
lDelta))
|
|
return(FALSE);
|
|
}
|
|
|
|
ptfxLast = pd.pptfx[pd.count - 1];
|
|
|
|
if (pd.flags & PD_CLOSEFIGURE)
|
|
{
|
|
if (!bLines(pbmi,
|
|
&ptfxLast,
|
|
&ptfxStartFigure,
|
|
(RUN*) NULL,
|
|
1,
|
|
&ls,
|
|
NULL,
|
|
apfn,
|
|
fl,
|
|
pchBits,
|
|
lDelta))
|
|
return(FALSE);
|
|
}
|
|
} while (bMore);
|
|
|
|
if (fl & FL_STYLED)
|
|
{
|
|
// Save the style state:
|
|
|
|
ULONG ulHigh = ls.spNext / ls.xyDensity;
|
|
ULONG ulLow = ls.spNext % ls.xyDensity;
|
|
|
|
pla->elStyleState.l = MAKELONG(ulLow, ulHigh);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL EngStrokePath(pso, ppo, pco, pxo, pbo, pptlBrushOrg, pla, mix)
|
|
*
|
|
* Strokes the path.
|
|
*
|
|
* History:
|
|
* 5-Apr-1992 -by- J. Andrew Goossen
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL EngStrokePath(
|
|
SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
XFORMOBJ *pxo,
|
|
BRUSHOBJ *pbo,
|
|
PPOINTL pptlBrushOrg,
|
|
PLINEATTRS pla,
|
|
MIX mix)
|
|
{
|
|
ASSERTGDI(pso != (SURFOBJ *) NULL, "EngStrokePath: surface\n");
|
|
ASSERTGDI(ppo != (PATHOBJ *) NULL, "EngStrokePath: path\n");
|
|
ASSERTGDI(pbo != (BRUSHOBJ *) NULL, "EngStrokePath: brushobj\n");
|
|
|
|
PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso);
|
|
|
|
if (pla->fl & LA_GEOMETRIC)
|
|
{
|
|
// Handle wide lines, remembering that the widened bounds have
|
|
// already been computed:
|
|
|
|
if (!((EPATHOBJ*) ppo)->bWiden(pxo, pla))
|
|
return(FALSE);
|
|
|
|
return(EngFillPath(pSurf->pSurfobj(),
|
|
ppo,
|
|
pco,
|
|
pbo,
|
|
pptlBrushOrg,
|
|
mix,
|
|
WINDING));
|
|
}
|
|
|
|
if (ppo->fl & PO_BEZIERS)
|
|
if (!((EPATHOBJ*) ppo)->bFlatten())
|
|
return(FALSE);
|
|
|
|
if (pSurf->iType() != STYPE_BITMAP)
|
|
{
|
|
// It's a cosmetic line to a device-managed surface. The DDI
|
|
// requires that the driver support DrvStrokePath for cosmetic
|
|
// lines if it has any device-managed surfaces:
|
|
|
|
PDEVOBJ po(pSurf->hdev());
|
|
|
|
ASSERTGDI(PPFNVALID(po, StrokePath),
|
|
"Driver must hook DrvStrokePath if it supports device-managed surfaces");
|
|
|
|
return((*PPFNDRV(po, StrokePath))(pSurf->pSurfobj(),
|
|
ppo,
|
|
pco,
|
|
pxo,
|
|
pbo,
|
|
pptlBrushOrg,
|
|
pla,
|
|
mix));
|
|
}
|
|
|
|
// Before we touch any bits, make sure the device is happy about it.
|
|
{
|
|
PDEVOBJ po(pSurf->hdev());
|
|
po.vSync(pso,NULL, 0);
|
|
}
|
|
|
|
// If this is a single pixel wide solid color line
|
|
// with trivial or simple clipping then call solid line routine:
|
|
|
|
if (((mix & 0xFF) == R2_COPYPEN) &&
|
|
((pco == NULL) || (pco->iDComplexity != DC_COMPLEX)) &&
|
|
(pla->pstyle == NULL) &&
|
|
!(pla->fl & LA_ALTERNATE))
|
|
{
|
|
vSolidLine(pSurf,
|
|
ppo,
|
|
NULL,
|
|
pco,
|
|
pbo->iSolidColor);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
return(bStrokeCosmetic(pSurf, ppo, pco, pbo, pla, mix));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL EngLineTo(pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix)
|
|
*
|
|
* Draws a single solid integer-only cosmetic line.
|
|
*
|
|
* History:
|
|
*
|
|
* 12-Sept-1996 -by- Tom Zakrajsek
|
|
* Made it work for device managed surfaces.
|
|
*
|
|
* 4-June-1995 -by- J. Andrew Goossen
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL EngLineTo(
|
|
SURFOBJ *pso,
|
|
CLIPOBJ *pco,
|
|
BRUSHOBJ *pbo,
|
|
LONG x1,
|
|
LONG y1,
|
|
LONG x2,
|
|
LONG y2,
|
|
RECTL *prclBounds,
|
|
MIX mix)
|
|
{
|
|
GDIFunctionID(EngLineTo);
|
|
ASSERTGDI(pso != (SURFOBJ *) NULL, "pso is NULL\n");
|
|
|
|
BOOL bReturn;
|
|
PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso);
|
|
LINEATTRS la;
|
|
PATHOBJ* ppo;
|
|
POINTFIX aptfx[2];
|
|
|
|
bReturn = FALSE;
|
|
|
|
aptfx[0].x = x1 << 4;
|
|
aptfx[0].y = y1 << 4;
|
|
aptfx[1].x = x2 << 4;
|
|
aptfx[1].y = y2 << 4;
|
|
|
|
if (pSurf->iType() != STYPE_BITMAP)
|
|
{
|
|
// Device managed surface
|
|
|
|
{
|
|
// Solid cosmetic lines have everything zeroed in the LINEATTRS:
|
|
|
|
memset(&la, 0, sizeof(LINEATTRS));
|
|
la.elWidth.l = 1;
|
|
|
|
// Create a path that describes the line:
|
|
|
|
ppo = EngCreatePath();
|
|
if (ppo != NULL)
|
|
{
|
|
if (PATHOBJ_bMoveTo(ppo, aptfx[0]) &&
|
|
PATHOBJ_bPolyLineTo(ppo, &aptfx[1], 1))
|
|
{
|
|
PDEVOBJ pdo(pSurf->hdev());
|
|
ECLIPOBJ eco;
|
|
RGNMEMOBJTMP rmoTmp;
|
|
|
|
// StrokePath is guaranteed not to get a NULL clip
|
|
// object, so construct a temporary one:
|
|
|
|
if (pco == NULL)
|
|
{
|
|
if (rmoTmp.bValid())
|
|
{
|
|
rmoTmp.vSet(prclBounds);
|
|
eco.vSetup(rmoTmp.prgnGet(),
|
|
*(ERECTL *) prclBounds);
|
|
|
|
pco = &eco;
|
|
}
|
|
}
|
|
|
|
// Clip may still be NULL if RGNMEMOBJTMP constructor
|
|
// failed, so need to check:
|
|
|
|
if (pco)
|
|
{
|
|
bReturn = (*PPFNGET(pdo,StrokePath,pSurf->flags())) (
|
|
pso,
|
|
ppo,
|
|
pco,
|
|
NULL, // pxo
|
|
pbo,
|
|
NULL, // pptlBrush
|
|
&la,
|
|
mix);
|
|
}
|
|
}
|
|
|
|
EngDeletePath(ppo);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Engine managed surface
|
|
|
|
// Before we touch any bits, make sure the device is happy about it.
|
|
{
|
|
PDEVOBJ po(pSurf->hdev());
|
|
po.vSync(pso,NULL,0);
|
|
}
|
|
|
|
if (((pco == NULL) || (pco->iDComplexity != DC_COMPLEX)) &&
|
|
(mix == 0x0d0d))
|
|
{
|
|
// If this is a single pixel wide solid color line
|
|
// with trivial or simple clipping then call solid line routine:
|
|
|
|
vSolidLine(pSurf,
|
|
NULL,
|
|
aptfx,
|
|
pco,
|
|
pbo->iSolidColor);
|
|
|
|
bReturn = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Solid cosmetic lines have everything zeroed in the LINEATTRS:
|
|
|
|
memset(&la, 0, sizeof(LINEATTRS));
|
|
|
|
// Create a path that describes the line:
|
|
|
|
ppo = EngCreatePath();
|
|
if (ppo != NULL)
|
|
{
|
|
if (PATHOBJ_bMoveTo(ppo, aptfx[0]) &&
|
|
PATHOBJ_bPolyLineTo(ppo, &aptfx[1], 1))
|
|
{
|
|
bReturn = bStrokeCosmetic(pSurf, ppo, pco, pbo, &la, mix);
|
|
}
|
|
|
|
EngDeletePath(ppo);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(bReturn);
|
|
}
|