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.
551 lines
18 KiB
551 lines
18 KiB
/******************************Module*Header***********************************\
|
|
*
|
|
* *******************
|
|
* * GDI SAMPLE CODE *
|
|
* *******************
|
|
*
|
|
* Module Name: Stroke.c
|
|
*
|
|
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
|
|
* Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
|
|
******************************************************************************/
|
|
#include "precomp.h"
|
|
#include "gdi.h"
|
|
#include "log.h"
|
|
|
|
PFNSTRIP gapfnStrip[] =
|
|
{
|
|
vSolidHorizontalLine,
|
|
vSolidVerticalLine,
|
|
vSolidDiagonalHorizontalLine,
|
|
vSolidDiagonalVerticalLine,
|
|
|
|
// Should be NUM_STRIP_DRAW_DIRECTIONS = 4 strip drawers in every group
|
|
|
|
vSolidHorizontalLine,
|
|
vSolidVerticalLine,
|
|
vSolidDiagonalHorizontalLine,
|
|
vSolidDiagonalVerticalLine,
|
|
|
|
// Should be NUM_STRIP_DRAW_STYLES = 8 strip drawers in total for doing
|
|
// solid lines, and the same number for non-solid lines:
|
|
|
|
vStyledHorizontalLine,
|
|
vStyledVerticalLine,
|
|
vStyledVerticalLine, // Diagonal goes here
|
|
vStyledVerticalLine, // Diagonal goes here
|
|
|
|
vStyledHorizontalLine,
|
|
vStyledVerticalLine,
|
|
vStyledVerticalLine, // Diagonal goes here
|
|
vStyledVerticalLine, // Diagonal goes here
|
|
};
|
|
|
|
// Style array for alternate style (alternates one pixel on, one pixel off):
|
|
|
|
STYLEPOS gaspAlternateStyle[] = { 1 };
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrush, pla, mix)
|
|
//
|
|
// DrvStrokePath strokes a path when called by GDI. If the driver has hooked the
|
|
// function, and if the appropriate GCAPs are set, GDI calls DrvStrokePath when
|
|
// GDI draws a line or curve with any set of attributes.
|
|
//
|
|
// Parameters
|
|
// pso----------Identifies the surface on which to draw.
|
|
// ppo----------Points to a PATHOBJ structure. GDI PATHOBJ_Xxx service routines
|
|
// are provided to enumerate the lines, Bezier curves, and other
|
|
// data that make up the path. This indicates what is to be drawn.
|
|
// pco----------Points to a CLIPOBJ structure. GDI CLIPOBJ_Xxx service routines
|
|
// are provided to enumerate the clip region as a set of
|
|
// rectangles. Optionally, all the lines in the path may be
|
|
// enumerated preclipped by CLIPOBJ. This means that drivers can
|
|
// have all their line clipping calculations done for them.
|
|
// pxo----------Points to a XFORMOBJ. This is only needed when a geometric wide
|
|
// line is to be drawn. It specifies the transform that maps world
|
|
// coordinates to device coordinates. This is needed because the
|
|
// path is provided in device coordinates but a geometric wide line
|
|
// is actually widened in world coordinates.
|
|
// The XFORMOBJ can be queried to find the transform.
|
|
// pbo----------Specifies the brush to be used when drawing the path.
|
|
// pptlBrushOrg-Points to the brush origin used to align the brush pattern on
|
|
// the device.
|
|
// pLineAttrs---Points to a LINEATTRS structure. Note that the elStyleState
|
|
// member must be updated as part of this function if the line is
|
|
// styled. Also note that the ptlLastPel member must be updated if
|
|
// a single pixel width cosmetic line is being drawn.
|
|
// mix----------Specifies how to combine the brush with the destination.
|
|
//
|
|
// Return Value
|
|
// The return value is TRUE if the driver is able to stroke the path. If GDI
|
|
// should stroke the path, the return value is FALSE, and an error code is not
|
|
// logged. If the driver encounters an error, the return value is DDI_ERROR,
|
|
// and an error code is reported.
|
|
//
|
|
// Comments
|
|
// If a driver supports this entry point, it should also support the drawing of
|
|
// cosmetic wide lines with arbitrary clipping. Using the provided GDI
|
|
// functions, the call can be broken down into a set of single-pixel-width
|
|
// lines with precomputed clipping.
|
|
//
|
|
// This function is required if any drawing is to be done on a device-managed
|
|
// surface.
|
|
//
|
|
// Drivers for advanced devices can optionally receive this call to draw paths
|
|
// containing Bezier curves and geometric wide lines. GDI will test the
|
|
// GCAPS_BEZIERS and GCAPS_GEOMETRICWIDE flags of the flGraphicsCaps member of
|
|
// the DEVINFO structure to decide whether it should call. (The four
|
|
// combinations of the bits determine the four levels of functionality for
|
|
// this call.) If the driver gets an advanced call containing Bezier curves or
|
|
// geometric wide lines, it can decide not to handle the call, returning FALSE.
|
|
// This might happen if the path or clipping is too complex for the device to
|
|
// process. If the call does return FALSE, GDI breaks the call down into
|
|
// simpler calls that can be handled easily.
|
|
//
|
|
// For device-managed surfaces, the function must minimally support
|
|
// single-pixel-wide solid and styled cosmetic lines using a solid-colored
|
|
// brush. The device can return FALSE if the line is geometric and the engine
|
|
// will convert those calls to DrvFillPath or DrvPaint calls.
|
|
//
|
|
// The mix mode defines how the incoming pattern should be mixed with the data
|
|
// already on the device surface. The MIX data type consists of two ROP2 values
|
|
// packed into a single ULONG. The low-order byte defines the foreground raster
|
|
// operation; the next byte defines the background raster operation. For more
|
|
// information about raster operation codes, see the Platform SDK.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
DrvStrokePath(SURFOBJ* pso,
|
|
PATHOBJ* ppo,
|
|
CLIPOBJ* pco,
|
|
XFORMOBJ* pxo,
|
|
BRUSHOBJ* pbo,
|
|
POINTL* pptlBrush,
|
|
LINEATTRS* pLineAttrs,
|
|
MIX mix)
|
|
{
|
|
STYLEPOS aspLtoR[STYLE_MAX_COUNT];
|
|
STYLEPOS aspRtoL[STYLE_MAX_COUNT];
|
|
LINESTATE lineState;
|
|
PFNSTRIP* apfn;
|
|
FLONG fl;
|
|
PDev* ppdev;
|
|
Surf* psurfDst;
|
|
RECTL arclClip[4]; // For rectangular clipping
|
|
BOOL bResetHW;
|
|
BOOL bRet;
|
|
DWORD logicOp;
|
|
|
|
DBG_GDI((6, "DrvStrokePath called with mix =%x", mix));
|
|
|
|
psurfDst = (Surf*)pso->dhsurf;
|
|
|
|
//
|
|
// Punt to engine if surface to draw is not in video memory
|
|
//
|
|
if ( psurfDst->flags & SF_SM )
|
|
{
|
|
goto puntIt;
|
|
}
|
|
|
|
ppdev = (PDev*)pso->dhpdev;
|
|
|
|
//@@BEGIN_DDKSPLIT
|
|
#if MULTITHREADED
|
|
if(ppdev->ulLockCount)
|
|
{
|
|
DBG_GDI((MT_LOG_LEVEL, "DrvStrokePath: re-entered! %d", ppdev->ulLockCount));
|
|
}
|
|
EngAcquireSemaphore(ppdev->hsemLock);
|
|
ppdev->ulLockCount++;
|
|
#endif
|
|
//@@END_DDKSPLIT
|
|
|
|
vCheckGdiContext(ppdev);
|
|
|
|
ppdev->psurf = psurfDst;
|
|
|
|
fl = 0;
|
|
|
|
//
|
|
// Look after styling initialization:
|
|
//
|
|
if ( pLineAttrs->fl & LA_ALTERNATE )
|
|
{
|
|
//
|
|
// LA_ALTERNATE: A special cosmetic line style; every other pixel is on
|
|
//
|
|
lineState.cStyle = 1;
|
|
lineState.spTotal = 1;
|
|
lineState.spTotal2 = 2;
|
|
lineState.spRemaining = 1;
|
|
lineState.aspRtoL = &gaspAlternateStyle[0];
|
|
lineState.aspLtoR = &gaspAlternateStyle[0];
|
|
lineState.spNext = HIWORD(pLineAttrs->elStyleState.l);
|
|
lineState.xyDensity = 1;
|
|
lineState.ulStartMask = 0L;
|
|
fl |= FL_ARBITRARYSTYLED;
|
|
}// Cosmetic line
|
|
else if ( pLineAttrs->pstyle != (FLOAT_LONG*)NULL )
|
|
{
|
|
//
|
|
// "pLineAttrs->pstyle" points to the style array. If this member is
|
|
// null, the line style is solid
|
|
//
|
|
PFLOAT_LONG pStyle;
|
|
STYLEPOS* pspDown;
|
|
STYLEPOS* pspUp;
|
|
|
|
//
|
|
// "pLineAttrs->cstyle" specifies the number of entries in the style
|
|
// array. So here we get the address of the last array first
|
|
//
|
|
pStyle = &pLineAttrs->pstyle[pLineAttrs->cstyle];
|
|
|
|
lineState.xyDensity = STYLE_DENSITY;
|
|
lineState.spTotal = 0;
|
|
|
|
//
|
|
// Loop through all the data array backworfds to get the sum of style
|
|
// array
|
|
//
|
|
while ( pStyle-- > pLineAttrs->pstyle )
|
|
{
|
|
lineState.spTotal += pStyle->l;
|
|
}
|
|
|
|
lineState.spTotal *= STYLE_DENSITY;
|
|
lineState.spTotal2 = 2 * lineState.spTotal;
|
|
|
|
//
|
|
// Compute starting style position (this is guaranteed not to overflow)
|
|
// Note: "pLineAttrs->elStyleState" is a pair of 16-bit values supplied
|
|
// by GDI whenever the driver calls PATHOBJ_bEnumClipLines. These two
|
|
// values, packed into a LONG, specify where in the styling array
|
|
// (at which pixel) to start the first subpath. This value must be
|
|
// updated as part of the output routine if the line is not solid.
|
|
// This member applies to cosmetic lines only.
|
|
//
|
|
lineState.spNext = HIWORD(pLineAttrs->elStyleState.l) * STYLE_DENSITY
|
|
+ LOWORD(pLineAttrs->elStyleState.l);
|
|
|
|
fl |= FL_ARBITRARYSTYLED;
|
|
lineState.cStyle = pLineAttrs->cstyle;
|
|
lineState.aspRtoL = aspRtoL;
|
|
lineState.aspLtoR = aspLtoR;
|
|
|
|
if ( pLineAttrs->fl & LA_STARTGAP )
|
|
{
|
|
//
|
|
// The first entry in the style array specifies the length of the
|
|
// first gap. set "ulStartMask" to mark it as a GAP
|
|
//
|
|
lineState.ulStartMask = 0xffffffffL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// It must be LA_GEOMETRIC which specifies a geometric wide line. Mark
|
|
// it as not a GAP
|
|
//
|
|
lineState.ulStartMask = 0L;
|
|
}
|
|
|
|
//
|
|
// Let "pStyle" points to the 1st style array, "pspDown" ponits to the
|
|
// "cStyle"th array in aspRtoL and "pspUp" points to the 1st array in
|
|
// aspLtoR
|
|
//
|
|
pStyle = pLineAttrs->pstyle;
|
|
pspDown = &lineState.aspRtoL[lineState.cStyle - 1];
|
|
pspUp = &lineState.aspLtoR[0];
|
|
|
|
//
|
|
// Move backwards to assign all the style data
|
|
//
|
|
while ( pspDown >= &lineState.aspRtoL[0] )
|
|
{
|
|
//
|
|
// Let the last style data in "pspDown" = the 1st in "pspUp", 2 to
|
|
// last in "pspDown" = 2nd in "pspUp".....
|
|
// pspDown [n][n-1]...[2][1]
|
|
// pspUp [1][2]...[n-1][n]
|
|
//
|
|
*pspDown = pStyle->l * STYLE_DENSITY;
|
|
*pspUp = *pspDown;
|
|
|
|
pspUp++;
|
|
pspDown--;
|
|
|
|
pStyle++;
|
|
}
|
|
}// Non-solid line
|
|
|
|
bRet = TRUE;
|
|
apfn = &gapfnStrip[NUM_STRIP_DRAW_STYLES *
|
|
((fl & FL_STYLE_MASK) >> FL_STYLE_SHIFT)];
|
|
|
|
//
|
|
// Set up to enumerate the path:
|
|
//
|
|
if ( pco->iDComplexity != DC_COMPLEX )
|
|
{
|
|
PATHDATA pd;
|
|
RECTL* prclClip = (RECTL*)NULL;
|
|
BOOL bMore;
|
|
ULONG lPtFix;
|
|
POINTFIX ptfxStartFigure;
|
|
POINTFIX ptfxLast;
|
|
POINTFIX* pptfxFirst;
|
|
POINTFIX* pptfxBuf;
|
|
|
|
if ( pco->iDComplexity == DC_RECT )
|
|
{
|
|
fl |= FL_SIMPLE_CLIP;
|
|
|
|
//
|
|
// This is the only clip region of importance to Permedia2
|
|
//
|
|
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;
|
|
}// if ( pco->iDComplexity == DC_RECT )
|
|
|
|
pd.flags = 0;
|
|
|
|
//
|
|
// Get the logic op and set up the flag to indicate reads from the frame
|
|
// buffer will occur.
|
|
//
|
|
logicOp = ulRop3ToLogicop(gaMix[mix & 0xff]);
|
|
DBG_GDI((7, "logicop is %d", logicOp));
|
|
|
|
if ( LogicopReadDest[logicOp] )
|
|
{
|
|
fl |= FL_READ;
|
|
}
|
|
|
|
//
|
|
// Need to set up Permedia2 modes and colors appropriately for the lines
|
|
//
|
|
bResetHW = bInitializeStrips(ppdev, pbo->iSolidColor,
|
|
logicOp, prclClip);
|
|
|
|
PATHOBJ_vEnumStart(ppo);
|
|
|
|
do
|
|
{
|
|
bMore = PATHOBJ_bEnum(ppo, &pd);
|
|
|
|
lPtFix = pd.count;
|
|
if ( lPtFix == 0 )
|
|
{
|
|
//
|
|
// If the pathdata contains no data, finish
|
|
//
|
|
break;
|
|
}
|
|
|
|
if ( pd.flags & PD_BEGINSUBPATH )
|
|
{
|
|
ptfxStartFigure = *pd.pptfx;
|
|
pptfxFirst = pd.pptfx;
|
|
pptfxBuf = pd.pptfx + 1;
|
|
lPtFix--;
|
|
}
|
|
else
|
|
{
|
|
pptfxFirst = &ptfxLast;
|
|
pptfxBuf = pd.pptfx;
|
|
}
|
|
|
|
if ( pd.flags & PD_RESETSTYLE )
|
|
{
|
|
lineState.spNext = 0;
|
|
}
|
|
|
|
if ( lPtFix > 0 )
|
|
{
|
|
if ( !bLines(ppdev,
|
|
pptfxFirst,
|
|
pptfxBuf,
|
|
(RUN*)NULL,
|
|
lPtFix,
|
|
&lineState,
|
|
prclClip,
|
|
apfn,
|
|
fl) )
|
|
{
|
|
bRet = FALSE;
|
|
goto ResetReturn;
|
|
}
|
|
}
|
|
|
|
ptfxLast = pd.pptfx[pd.count - 1];
|
|
|
|
if ( pd.flags & PD_CLOSEFIGURE )
|
|
{
|
|
if ( !bLines(ppdev,
|
|
&ptfxLast,
|
|
&ptfxStartFigure,
|
|
(RUN*)NULL,
|
|
1,
|
|
&lineState,
|
|
prclClip,
|
|
apfn,
|
|
fl) )
|
|
{
|
|
bRet = FALSE;
|
|
goto ResetReturn;
|
|
}
|
|
}
|
|
} while ( bMore );
|
|
|
|
if ( fl & FL_STYLED )
|
|
{
|
|
//
|
|
// Save the style state
|
|
//
|
|
ULONG ulHigh;
|
|
ULONG ulLow;
|
|
|
|
//
|
|
// Masked styles don't normalize the style state. It's a good thing
|
|
// to do, so let's do it now
|
|
//
|
|
if ( (ULONG)lineState.spNext >= (ULONG)lineState.spTotal2 )
|
|
{
|
|
lineState.spNext = (ULONG)lineState.spNext
|
|
% (ULONG)lineState.spTotal2;
|
|
}
|
|
|
|
ulHigh = lineState.spNext / lineState.xyDensity;
|
|
ulLow = lineState.spNext % lineState.xyDensity;
|
|
|
|
pLineAttrs->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;
|
|
|
|
//
|
|
// Need to set up hardware modes and colors appropriately for the lines.
|
|
// NOTE, with a complex clip,we can not yet use permedia2 for fast lines
|
|
//
|
|
bResetHW = bInitializeStrips(ppdev, pbo->iSolidColor,
|
|
ulRop3ToLogicop(gaMix[mix&0xff]),
|
|
NULL);
|
|
|
|
//
|
|
// We use the clip object when non-simple clipping is involved:
|
|
//
|
|
PATHOBJ_vEnumStartClipLines(ppo, pco, pso, pLineAttrs);
|
|
|
|
do
|
|
{
|
|
bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(cl), &cl.cl);
|
|
if ( cl.cl.c != 0 )
|
|
{
|
|
if ( fl & FL_STYLED )
|
|
{
|
|
lineState.spComplex = HIWORD(cl.cl.lStyleState)
|
|
* lineState.xyDensity
|
|
+ LOWORD(cl.cl.lStyleState);
|
|
}
|
|
if ( !bLines(ppdev,
|
|
&cl.cl.ptfxA,
|
|
&cl.cl.ptfxB,
|
|
&cl.cl.arun[0],
|
|
cl.cl.c,
|
|
&lineState,
|
|
(RECTL*) NULL,
|
|
apfn,
|
|
fl) )
|
|
{
|
|
bRet = FALSE;
|
|
goto ResetReturn;
|
|
}
|
|
}
|
|
} while ( bMore );
|
|
}
|
|
|
|
ResetReturn:
|
|
|
|
if ( bResetHW )
|
|
{
|
|
vResetStrips(ppdev);
|
|
}
|
|
|
|
DBG_GDI((6, "DrvStrokePath done it"));
|
|
|
|
InputBufferFlush(ppdev);
|
|
|
|
//@@BEGIN_DDKSPLIT
|
|
#if MULTITHREADED
|
|
ppdev->ulLockCount--;
|
|
EngReleaseSemaphore(ppdev->hsemLock);
|
|
#endif
|
|
//@@END_DDKSPLIT
|
|
|
|
return (bRet);
|
|
|
|
puntIt:
|
|
//@@BEGIN_DDKSPLIT
|
|
#if GDI_TEST
|
|
ULONG flags = vPuntBefore(NULL, pso);
|
|
#endif
|
|
//@@END_DDKSPLIT
|
|
|
|
bRet = EngStrokePath(pso, ppo, pco, pxo, pbo, pptlBrush,
|
|
pLineAttrs, mix);
|
|
|
|
//@@BEGIN_DDKSPLIT
|
|
#if GDI_TEST
|
|
vPuntAfter(flags, NULL, pso);
|
|
|
|
vLogPunt();
|
|
#endif
|
|
//@@END_DDKSPLIT
|
|
|
|
DBG_GDI((6, "DrvStrokePath punt it"));
|
|
return bRet;
|
|
}// DrvStrokePath()
|
|
|
|
|