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.
531 lines
13 KiB
531 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1990-2003 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
path.c
|
|
|
|
|
|
Abstract:
|
|
|
|
This module contains Functions related to drawing paths. The main stroke
|
|
drawing entry poing DrvStrokePath, is implemented in this module.
|
|
|
|
|
|
See also textout.c, bitblt.c: These two have copies of almost all the
|
|
DrvStrokePath() code.
|
|
|
|
|
|
Author:
|
|
|
|
17:30 on Wed 03 Apr 1991
|
|
Created it
|
|
|
|
8/18/92 AP
|
|
I have pretty much rewritten most of this. Some of the original
|
|
code is left in, mainly to point out things that need to be added.
|
|
|
|
15-Nov-1993 Mon 19:40:18 updated
|
|
clean up / debugging information
|
|
|
|
30-Nov-1993 Tue 22:32:12 updated
|
|
style clean up, updated
|
|
|
|
|
|
01-Feb-1994 updated
|
|
Added the ability to stroke styled lines through a complex
|
|
clipping object
|
|
|
|
[Environment:]
|
|
|
|
GDI Device Driver - Plotter.
|
|
|
|
|
|
[Notes:]
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define DBG_PLOTFILENAME DbgPath
|
|
|
|
#define DBG_STROKEPATH 0x00000001
|
|
#define DBG_SELECTCOLOR 0x00000002
|
|
#define DBG_STROKECLIPLINES 0x00000004
|
|
#define DBG_MOVEPEN 0x00000008
|
|
|
|
|
|
DEFINE_DBGVAR(0);
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DoStrokePathByEnumingClipLines(
|
|
PPDEV pPDev,
|
|
SURFOBJ *pso,
|
|
CLIPOBJ *pco,
|
|
PATHOBJ *ppo,
|
|
PPOINTL pptlBrushOrg,
|
|
BRUSHOBJ *pbo,
|
|
ROP4 rop4,
|
|
LINEATTRS *plineattrs
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Strokes a path through a complex clipping region by utilizing the
|
|
engine helper functions. This is done because there is no way to
|
|
fail a DrvStrokePath and have it come back in any simpler format by
|
|
the NT graphics engine. In general, we can fail DrvXXX calls and the
|
|
NT graphic engine will simply the object to draw, then call back into
|
|
the driver. Stroking a path however cannot be simplified any more, so
|
|
the best we can hope for is having the PATHOBJ converted to straight
|
|
line segments (removing BEZIERS if present). We then must stroke the
|
|
path ourselves, using the provided EngXXX helpers.
|
|
Since helper functions exist that allow us to to enumerate the
|
|
portions of a path as CLIPLINE segments that fall within the
|
|
clipping region, we do that here, thus stroking the segments that lie
|
|
inside of the passed CLIPOBJ.
|
|
|
|
|
|
Arguments:
|
|
|
|
pPDev Pointer to the current PDEV
|
|
|
|
pso SURFOBJ to write to
|
|
|
|
pco CLIPOBJ to use when enuming paths
|
|
|
|
ppo PATHOBJ to stroke through clip path
|
|
|
|
pptlBrushOrg BRUSH origin
|
|
|
|
pbo BRUSH to stroke with
|
|
|
|
rop4 ROP4 to use
|
|
|
|
plineattrs LINEATTRS structure that describes the styling for the line
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful FALSE if failed, If the path we are asked to stroke
|
|
contains BEZIERS, this function will fail in order to allow the
|
|
Engine to break the path down to line segments.
|
|
|
|
Author:
|
|
|
|
|
|
2/01/94 JB
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOT_CLIPLINE PlotClipLine;
|
|
CLIPLINE *pCurClipLine;
|
|
RUN *pCurRun;
|
|
POINTFIX ptsfx[2];
|
|
POINTL ptlCur;
|
|
FIX iStartInFX;
|
|
FIX iStopInFX;
|
|
LONG dx;
|
|
LONG dy;
|
|
LONG i;
|
|
BOOL bMore;
|
|
BOOL bXordered;
|
|
BOOL bFlipX;
|
|
BOOL bFlipY;
|
|
|
|
|
|
//
|
|
// First check for Beziers and if we have them fail the call since we
|
|
// want straight line segments to stroke, with the appropriate style
|
|
//
|
|
|
|
if (ppo->fl & PO_BEZIERS) {
|
|
|
|
PLOTDBG(DBG_STROKECLIPLINES,
|
|
("DoStrokePathByEnumingClipLines:Path had BEZ returning FALSE"));
|
|
return(FALSE);
|
|
}
|
|
|
|
if (NULL == pco) {
|
|
|
|
PLOTDBG(DBG_STROKECLIPLINES,
|
|
("DoStrokePathByEnumingClipLines:CLIPOBJ is NULL."));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Send out the line attributes , so the residue will be calculated
|
|
// correctly
|
|
//
|
|
|
|
DoSetupOfStrokeAttributes(pPDev, pptlBrushOrg, pbo, rop4, NULL);
|
|
|
|
//
|
|
// Initiate enumeration of the CLIPLINES by calling the Engine helper
|
|
//
|
|
|
|
PATHOBJ_vEnumStartClipLines(ppo, pco, pso, plineattrs);
|
|
|
|
//
|
|
// Start a loop to enum through all the available CLIPLINE structures
|
|
//
|
|
|
|
pCurClipLine = (CLIPLINE *)&PlotClipLine;
|
|
|
|
do {
|
|
|
|
//
|
|
// Get the first batch of CLIPLINE structures then go to work on them
|
|
//
|
|
|
|
bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(PlotClipLine), pCurClipLine);
|
|
|
|
//
|
|
// Calculate dx and dy in order to determine if the line is Xordered or
|
|
// Yordered this is needed because of the way the engine passes us RUNS
|
|
// if dx > dy then the line is said to be Xordered and thus any given
|
|
// RUN iStart and iStop values is a projection on the x axis. Given this
|
|
// informatino we can calculate the adjoining Y coordinate and draw the
|
|
// line appropriately.
|
|
//
|
|
|
|
dx = pCurClipLine->ptfxB.x - pCurClipLine->ptfxA.x;
|
|
dy = pCurClipLine->ptfxB.y - pCurClipLine->ptfxA.y;
|
|
|
|
|
|
|
|
if ( bFlipX = (dx < 0 )) {
|
|
|
|
dx = -dx;
|
|
}
|
|
|
|
if ( bFlipY = (dy < 0 )) {
|
|
|
|
dy = -dy;
|
|
}
|
|
|
|
|
|
//
|
|
// Now calculate if the line is x ordered or y ordered
|
|
//
|
|
|
|
bXordered = (dx >= dy);
|
|
|
|
PLOTDBG(DBG_STROKECLIPLINES,
|
|
("DoStrokePathByEnumingClipLines:Compute ClipLine runs=%u, xordered %d",
|
|
pCurClipLine->c, bXordered ));
|
|
|
|
//
|
|
// Enum through all the given RUNS drawing with the pen down between any
|
|
// iStart and iStop value in each RUN
|
|
//
|
|
|
|
for (i = 0, pCurRun = &(pCurClipLine->arun[0]);
|
|
i < (LONG)pCurClipLine->c;
|
|
i++, pCurRun++) {
|
|
|
|
|
|
//
|
|
// The value of iStart and iStop are always positive!! so
|
|
// we must handle it ourselves, so the correct thing happens
|
|
//
|
|
|
|
iStartInFX = LTOFX(pCurRun->iStart);
|
|
iStopInFX = LTOFX(pCurRun->iStop);
|
|
|
|
|
|
if (bFlipX ) {
|
|
|
|
ptsfx[0].x = -iStartInFX;
|
|
ptsfx[1].x = -iStopInFX;
|
|
|
|
} else {
|
|
|
|
ptsfx[0].x = iStartInFX;
|
|
ptsfx[1].x = iStopInFX;
|
|
}
|
|
|
|
if (bFlipY ) {
|
|
|
|
ptsfx[0].y = -iStartInFX;
|
|
ptsfx[1].y = -iStopInFX;
|
|
|
|
} else {
|
|
|
|
ptsfx[0].y = iStartInFX;
|
|
ptsfx[1].y = iStopInFX;
|
|
}
|
|
|
|
|
|
//
|
|
// We must output the correct line attributes structure with the
|
|
// correct calculated residue in order for this to work correctly
|
|
//
|
|
|
|
HandleLineAttributes(pPDev,
|
|
plineattrs,
|
|
&pCurClipLine->lStyleState,
|
|
pCurRun->iStart);
|
|
|
|
|
|
|
|
//
|
|
// The calculations for the opposing coordinate varies based on the
|
|
// ordering of the line. If the line is Xordered we calculate the
|
|
// Y value, if itsYordered we calculate the X value. We do this
|
|
// in order to determine the correct target coordinate. Since the
|
|
// RUN is given to us as START and STOP, we must manually determine
|
|
// what coordinate this represents inside the device coordinate
|
|
// space. If the RUN is xordered, the x-coordinate is correct, and
|
|
// the y-coordinate must be projected based on the ratio.
|
|
//
|
|
|
|
if (bXordered) {
|
|
|
|
ptsfx[0].x += pCurClipLine->ptfxA.x;
|
|
ptsfx[0].y = MulDiv( ptsfx[0].y, dy, dx) +
|
|
pCurClipLine->ptfxA.y;
|
|
ptsfx[1].x += pCurClipLine->ptfxA.x;
|
|
ptsfx[1].y = MulDiv( ptsfx[1].y, dy, dx) +
|
|
pCurClipLine->ptfxA.y;
|
|
|
|
} else {
|
|
|
|
ptsfx[0].x = MulDiv(ptsfx[0].x, dx, dy) +
|
|
pCurClipLine->ptfxA.x;
|
|
ptsfx[0].y += pCurClipLine->ptfxA.y;
|
|
ptsfx[1].x = MulDiv(ptsfx[1].x, dx, dy) +
|
|
pCurClipLine->ptfxA.x;
|
|
ptsfx[1].y += pCurClipLine->ptfxA.y;
|
|
}
|
|
|
|
|
|
//
|
|
// Do PE with pen up first, in order to move to the starting
|
|
// position.
|
|
//
|
|
|
|
OutputString(pPDev, "PE<");
|
|
|
|
if (!i) {
|
|
|
|
//
|
|
// If we are at first point then output that now.
|
|
//
|
|
|
|
ptlCur.x =
|
|
ptlCur.y = 0;
|
|
|
|
OutputString(pPDev, "=");
|
|
}
|
|
|
|
|
|
//
|
|
// Stroke the segment with the pen down.
|
|
//
|
|
|
|
OutputXYParams(pPDev,
|
|
(PPOINTL)ptsfx,
|
|
(PPOINTL)NULL,
|
|
(PPOINTL)&ptlCur,
|
|
(UINT)2,
|
|
(UINT)1,
|
|
'F');
|
|
|
|
OutputString(pPDev, ";");
|
|
}
|
|
|
|
} while (bMore); // While we need to enum again..
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DrvStrokePath(
|
|
SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
XFORMOBJ *pxo,
|
|
BRUSHOBJ *pbo,
|
|
PPOINTL pptlBrushOrg,
|
|
LINEATTRS *plineattrs,
|
|
MIX Mix
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The driver's function for the StrokePath
|
|
|
|
Arguments:
|
|
|
|
same as EngStrokePath
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful FALSE if failed
|
|
|
|
|
|
Author:
|
|
|
|
8/18/92 -- t-alip
|
|
Rewrote it.
|
|
|
|
30-Nov-1993 Tue 22:21:51 updated
|
|
updated by DC
|
|
|
|
04-Aug-1994 Thu 20:00:23 updated
|
|
bug# 22348
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
31-Jan-1994 Tue 22:21:51 updated
|
|
Fixed dopolygon to pass in ROP4 not just MIX
|
|
|
|
--*/
|
|
|
|
{
|
|
PPDEV pPDev;
|
|
BOOL bRetVal;
|
|
|
|
UNREFERENCED_PARAMETER(pxo);
|
|
|
|
|
|
|
|
PLOTDBG(DBG_STROKEPATH, ("DrvStrokePath: Mix = %x", Mix));
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(pso))) {
|
|
|
|
PLOTERR(("DrvStrokePath: Invalid pPDev"));
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!(bRetVal = DoPolygon(pPDev,
|
|
NULL,
|
|
pco,
|
|
ppo,
|
|
pptlBrushOrg,
|
|
NULL,
|
|
pbo,
|
|
MixToRop4(Mix),
|
|
plineattrs,
|
|
FPOLY_STROKE) )) {
|
|
|
|
//
|
|
// Since DoPolygon failed, it can only be because we had both a complex
|
|
// clip and a pathobj, so the thing to here is do the stroke via another
|
|
// method using some of the engine helpers.
|
|
//
|
|
// We will also failed when STYLE LINE + DC_RECT when raster plotter is
|
|
// used
|
|
//
|
|
|
|
bRetVal = DoStrokePathByEnumingClipLines( pPDev,
|
|
pso,
|
|
pco,
|
|
ppo,
|
|
pptlBrushOrg,
|
|
pbo,
|
|
MixToRop4(Mix),
|
|
plineattrs);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
return(bRetVal);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
MovePen(
|
|
PPDEV pPDev,
|
|
PPOINTFIX pPtNewPos,
|
|
PPOINTL pPtDevPos
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sends the HPGL code for the requested pen.
|
|
|
|
|
|
Arguments:
|
|
|
|
pPDev - Pointer to the PDEV data structure
|
|
|
|
pPtNewPos - The location pen will move to, this is in 28.4 fix notation
|
|
|
|
pPtDevPos - The new device coordinate device position
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful FALSE otherwise
|
|
|
|
|
|
Author:
|
|
|
|
1:04 on Tue 7 Nov 1989
|
|
Added this commentary, and area fill optimization code.
|
|
|
|
30-Nov-1993 Tue 22:05:32 updated
|
|
Update, commented and clean up style
|
|
|
|
16-Feb-1994 Wed 17:10:54 updated
|
|
Re-write to get rid of the physical position
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
POINTL ptDevPos;
|
|
|
|
|
|
ptDevPos.x = FXTODEVL(pPDev, pPtNewPos->x);
|
|
ptDevPos.y = FXTODEVL(pPDev, pPtNewPos->y);
|
|
|
|
if (pPtDevPos) {
|
|
|
|
*pPtDevPos = ptDevPos;
|
|
}
|
|
|
|
PLOTDBG( DBG_MOVEPEN,
|
|
("MovePen: Moving Absolute to FIX = [X=%d,%d] Device = [X=%d, Y=%d]",
|
|
pPtNewPos->x,
|
|
pPtNewPos->y,
|
|
ptDevPos.x,
|
|
ptDevPos.y ));
|
|
|
|
|
|
return(OutputFormatStr(pPDev, "PE<=#D#D;", ptDevPos.x, ptDevPos.y));
|
|
}
|