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.
 
 
 
 
 
 

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()