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