mirror of https://github.com/lianthony/NT4.0
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.
2275 lines
59 KiB
2275 lines
59 KiB
/*++
|
|
|
|
Copyright (c) 1990-1993 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
polygon.c
|
|
|
|
|
|
Abstract:
|
|
|
|
This module contain major polygon drawing funtion which used by other
|
|
functions like DrvPaint, DrvStrokePath, DrvStrokeAndFillPath
|
|
and DrvFillPath.
|
|
|
|
Author:
|
|
|
|
15:30 on Wed 09 Mar 1993 -by- Kenneth Leung [t-kenl]
|
|
Created it
|
|
|
|
15-Nov-1993 Mon 19:42:05 updated -by- Daniel Chou (danielc), v-jimbr
|
|
clean up / fixed / add debugging information
|
|
|
|
27-Jan-1994 Thu 23:40:57 updated -by- Daniel Chou (danielc)
|
|
Add user defined pattern caching
|
|
|
|
16-Mar-1994 Wed 11:21:02 updated -by- Daniel Chou (danielc)
|
|
Add SetBrushOrigin() so we can aligned brush origin for the fill
|
|
correctly
|
|
|
|
|
|
[Environment:]
|
|
|
|
GDI Device Driver - Plotter.
|
|
|
|
|
|
[Notes:]
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define DBG_PLOTFILENAME DbgPolygon
|
|
|
|
#define DBG_GENPOLYGON 0x00000001
|
|
#define DBG_GENPOLYPATH 0x00000002
|
|
#define DBG_BEZIER 0x00000004
|
|
#define DBG_DORECT 0x00000008
|
|
#define DBG_FILL_CLIP 0x00000010
|
|
#define DBG_CHECK_FOR_WHITE 0x00000020
|
|
#define DBG_USERPAT 0x00000040
|
|
#define DBG_FILL_LOGIC 0x00000080
|
|
#define DBG_HANDLELINEATTR 0x00000100
|
|
|
|
DEFINE_DBGVAR(0);
|
|
|
|
|
|
#define POLY_GEN_RECTFIX(dest, src, offset) { dest.x = src->x + offset.x; \
|
|
dest.y = src->y + offset.y; }
|
|
|
|
|
|
static BYTE __ER[] = { 'E', 'R' };
|
|
static BYTE __RR[] = { 'R', 'R' };
|
|
static BYTE __EP[] = { 'E', 'P' };
|
|
static BYTE __FP[] = { 'F', 'P' };
|
|
static BYTE __PM0[] = { 'P', 'M', '0' };
|
|
static BYTE __PM1[] = { 'P', 'M', '1' };
|
|
static BYTE __PM2[] = { 'P', 'M', '2' };
|
|
static BYTE __TR0[] = { 'T', 'R', '0' };
|
|
static BYTE __TR1[] = { 'T', 'R', '1' };
|
|
static BYTE __SEMI[] = { ';' };
|
|
static BYTE __1SEMI[] = { '1', ';' };
|
|
static BYTE __BR[] = { 'B', 'R' };
|
|
static BYTE __BZ[] = { 'B', 'Z' };
|
|
static BYTE __PE[] = { 'P', 'E' };
|
|
static BYTE __PD[] = { 'P', 'D' };
|
|
static BYTE __COMMA[] = { ',' };
|
|
|
|
#define SEND_ER(pPDev) OutputBytes(pPDev, __ER , sizeof(__ER ) );
|
|
#define SEND_RR(pPDev) OutputBytes(pPDev, __RR , sizeof(__RR ) );
|
|
#define SEND_EP(pPDev) OutputBytes(pPDev, __EP , sizeof(__EP ) );
|
|
#define SEND_FP(pPDev) OutputBytes(pPDev, __FP , sizeof(__FP ) );
|
|
#define SEND_PM0(pPDev) OutputBytes(pPDev, __PM0 , sizeof(__PM0 ) );
|
|
#define SEND_PM1(pPDev) OutputBytes(pPDev, __PM1 , sizeof(__PM1 ) );
|
|
#define SEND_PM2(pPDev) OutputBytes(pPDev, __PM2 , sizeof(__PM2 ) );
|
|
#define SEND_TR0(pPDev) OutputBytes(pPDev, __TR0 , sizeof(__TR0 ) );
|
|
#define SEND_TR1(pPDev) OutputBytes(pPDev, __TR1 , sizeof(__TR1 ) );
|
|
#define SEND_SEMI(pPDev) OutputBytes(pPDev, __SEMI , sizeof(__SEMI ) );
|
|
#define SEND_1SEMI(pPDev) OutputBytes(pPDev, __1SEMI , sizeof(__1SEMI) );
|
|
#define SEND_BR(pPDev) OutputBytes(pPDev, __BR , sizeof(__BR ) );
|
|
#define SEND_BZ(pPDev) OutputBytes(pPDev, __BZ , sizeof(__BZ ) );
|
|
#define SEND_PE(pPDev) OutputBytes(pPDev, __PE , sizeof(__PE ) );
|
|
#define SEND_PD(pPDev) OutputBytes(pPDev, __PD , sizeof(__PD ) );
|
|
#define SEND_COMMA(pPDev) OutputBytes(pPDev, __COMMA , sizeof(__COMMA) );
|
|
|
|
|
|
#define TERM_PE_MODE(pPDev, Mode) \
|
|
{ \
|
|
if (Mode == 'PE') { \
|
|
\
|
|
SEND_SEMI(pPDev); \
|
|
Mode = 0; \
|
|
} \
|
|
}
|
|
|
|
#define SWITCH_TO_PE(pPDev, Mode, PenIsDown) \
|
|
{ \
|
|
if (Mode != 'PE') { \
|
|
\
|
|
SEND_PE(pPDev); \
|
|
Mode = 'PE'; \
|
|
PenIsDown = TRUE; \
|
|
} \
|
|
}
|
|
|
|
|
|
#define SWITCH_TO_BR(pPDev, Mode, PenIsDown) \
|
|
{ \
|
|
TERM_PE_MODE(pPDev, Mode) \
|
|
\
|
|
if (Mode != 'BR') { \
|
|
\
|
|
if (!PenIsDown) { \
|
|
\
|
|
SEND_PD(pPDev); \
|
|
PenIsDown = TRUE; \
|
|
} \
|
|
\
|
|
SEND_BR(pPDev); \
|
|
Mode = 'BR'; \
|
|
\
|
|
} else { \
|
|
\
|
|
SEND_COMMA(pPDev); \
|
|
} \
|
|
}
|
|
|
|
|
|
#define PLOT_IS_WHITE(pdev, ulCol) (ulCol == WHITE_INDEX)
|
|
#define TOGGLE_DASH(x) ((x) ? FALSE : TRUE)
|
|
|
|
#define ROP4_USE_DEST(Rop4) ((Rop4 & 0x5555) != ((Rop4 & 0xAAAA) >> 1))
|
|
#define SET_PP_WITH_ROP4(pPDev, Rop4) \
|
|
SetPixelPlacement(pPDev, (ROP4_USE_DEST(Rop4)) ? SPP_MODE_EDGE : \
|
|
SPP_MODE_CENTER)
|
|
|
|
|
|
|
|
VOID
|
|
SetBrushOrigin(
|
|
PPDEV pPDev,
|
|
PPOINTL pptlBrushOrg
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function set the brush origin onto the device for the next bursh
|
|
fill
|
|
|
|
|
|
Arguments:
|
|
|
|
pPDev - Pointer to our PDEV
|
|
|
|
pptlBrushOrg - Pointer to the brush origin to be set
|
|
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
Author:
|
|
|
|
16-Mar-1994 Wed 10:56:46 created -by- Daniel Chou (danielc)
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
POINTL ptlAC;
|
|
|
|
|
|
if (pptlBrushOrg) {
|
|
|
|
ptlAC = *pptlBrushOrg;
|
|
|
|
} else {
|
|
|
|
ptlAC.x =
|
|
ptlAC.y = 0;
|
|
}
|
|
|
|
if ((ptlAC.x != pPDev->ptlAnchorCorner.x) ||
|
|
(ptlAC.y != pPDev->ptlAnchorCorner.y)) {
|
|
|
|
OutputString(pPDev, "AC");
|
|
|
|
if ((ptlAC.x) || (ptlAC.y)) {
|
|
|
|
OutputLONGParams(pPDev, (PLONG)&ptlAC, 2, 'd');
|
|
}
|
|
|
|
//
|
|
// Save the current setting
|
|
//
|
|
|
|
pPDev->ptlAnchorCorner = ptlAC;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DoRect(
|
|
PPDEV pPDev,
|
|
RECTL *pRectl,
|
|
BRUSHOBJ *pBrushFill,
|
|
BRUSHOBJ *pBrushStroke,
|
|
POINTL *pptlBrush,
|
|
ROP4 rop4,
|
|
LINEATTRS *plineattrs,
|
|
ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This fucntion draw and/or fill rectangle
|
|
|
|
Arguments:
|
|
|
|
pPDev - Pointer to our PDEV
|
|
|
|
pRectl - rectangle area interested
|
|
|
|
pBrushFill - Brush used to fill the rectangle
|
|
|
|
pBrushStroke - Brush used to stroke the rectangle
|
|
|
|
pptlBrush - brush origin
|
|
|
|
rop4 - rop to be used
|
|
|
|
plineattrs - Pointer to the line attributes
|
|
|
|
ulFlags - FPOLY_xxxx flags
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessful and false if not
|
|
|
|
|
|
Author:
|
|
|
|
15-Feb-1994 Tue 11:59:52 updated -by- Daniel Chou (danielc)
|
|
We will do RR or RA now
|
|
|
|
24-Mar-1994 Thu 19:37:05 updated -by- Daniel Chou (danielc)
|
|
Do local MovePen and make sure we at least output ONE RASTER PEL
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
POINTL ptlPlot;
|
|
SIZEL szlRect;
|
|
|
|
//
|
|
// Check to see if we can short cut some of our work if its a pen plotter
|
|
//
|
|
|
|
if (PlotCheckForWhiteIfPenPlotter(pPDev,
|
|
pBrushFill,
|
|
pBrushStroke,
|
|
rop4,
|
|
&ulFlags)) {
|
|
return(TRUE);
|
|
}
|
|
|
|
PLOTDBG(DBG_DORECT,
|
|
("DoRect: Passed In RECTL=(%ld, %ld)-(%ld, %ld)=%ld x %ld",
|
|
pRectl->left, pRectl->top,
|
|
pRectl->right, pRectl->bottom,
|
|
pRectl->right - pRectl->left,
|
|
pRectl->bottom - pRectl->top));
|
|
|
|
ptlPlot.x = LTODEVL(pPDev, pRectl->left);
|
|
ptlPlot.y = LTODEVL(pPDev, pRectl->top);
|
|
szlRect.cx = LTODEVL(pPDev, pRectl->right) - ptlPlot.x;
|
|
szlRect.cy = LTODEVL(pPDev, pRectl->bottom) - ptlPlot.y;
|
|
|
|
if ((szlRect.cx) && (szlRect.cy)) {
|
|
|
|
SET_PP_WITH_ROP4(pPDev, rop4);
|
|
|
|
if (szlRect.cx < (LONG)pPDev->MinLToDevL) {
|
|
|
|
PLOTWARN(("DoRect: cxRect=%ld < MIN=%ld, Make it as MIN",
|
|
szlRect.cx, (LONG)pPDev->MinLToDevL));
|
|
|
|
szlRect.cx = (LONG)pPDev->MinLToDevL;
|
|
}
|
|
|
|
if (szlRect.cy < (LONG)pPDev->MinLToDevL) {
|
|
|
|
PLOTWARN(("DoRect: cyRect=%ld < MIN=%ld, Make it as MIN",
|
|
szlRect.cy, (LONG)pPDev->MinLToDevL));
|
|
|
|
szlRect.cy = (LONG)pPDev->MinLToDevL;
|
|
}
|
|
|
|
//
|
|
// WATCH OUT: Do the MOVE PEN ourself at here
|
|
//
|
|
|
|
OutputFormatStr(pPDev, "PE<=#D#D;", ptlPlot.x, ptlPlot.y);
|
|
|
|
PLOTDBG(DBG_DORECT,
|
|
("DoRect: PLOTUNIT=%ld, MovePen=(%ld, %ld), RR=%ld x %ld",
|
|
pPDev->pPlotGPC->PlotXDPI,
|
|
ptlPlot.x, ptlPlot.y, szlRect.cx, szlRect.cy));
|
|
|
|
DoFillLogic(pPDev,
|
|
pptlBrush,
|
|
pBrushFill,
|
|
pBrushStroke,
|
|
rop4,
|
|
plineattrs,
|
|
&szlRect,
|
|
ulFlags);
|
|
|
|
} else {
|
|
|
|
PLOTDBG(DBG_DORECT, ("DoRect: Pass a NULL Rectl, Do NOTHING"));
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DoFillByEnumingClipRects(
|
|
PPDEV pPDev,
|
|
POINTL *ppointlOffset,
|
|
CLIPOBJ *pco,
|
|
POINTL *pPointlBrushOrg,
|
|
BRUSHOBJ *pBrushFill,
|
|
ROP4 Rop4,
|
|
LINEATTRS *plineattrs,
|
|
ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add comment!
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
BOOL TRUE - Function succeded
|
|
FALSE - Function failed. TODO more here
|
|
|
|
Author:
|
|
|
|
28-Nov-1993 created -by- James Bratsanos (v-jimbr)
|
|
|
|
18-Dec-1993 Sat 10:35:24 updated -by- Daniel Chou (danielc)
|
|
use PRECTL rather RECTL *, and use INT rater than int, removed compiler
|
|
warning which has unreferenced local variable
|
|
|
|
16-Feb-1994 Wed 16:12:53 updated -by- Daniel Chou (danielc)
|
|
Re-structure and make it Polyline encoded
|
|
|
|
09-Apr-1994 Sat 16:38:16 updated -by- Daniel Chou (danielc)
|
|
Fixed the ptlCur++ twice typo which make us Do the RECT crazy.
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
{
|
|
PRECTL prclCur;
|
|
POINTFIX ptsFix[4];
|
|
HTENUMRCL EnumRects;
|
|
POINTL ptlCur;
|
|
DWORD MaxRects;
|
|
DWORD cRects;
|
|
BOOL bMore;
|
|
BOOL NeedSendPM0;
|
|
|
|
|
|
|
|
PLOTDBG(DBG_FILL_CLIP,
|
|
("DoFillByEnumingRects: Maximum polygon points = %d",
|
|
pPDev->pPlotGPC->MaxPolygonPts));
|
|
|
|
PLOTASSERT(1, "DoFillByEnumingRects: Minimum must be 5 points [%ld]",
|
|
pPDev->pPlotGPC->MaxPolygonPts >= 5,
|
|
pPDev->pPlotGPC->MaxPolygonPts);
|
|
|
|
//
|
|
// In this mode we will enter polygon mode and try to batch based on the
|
|
// number of points the device can handle in its polygon buffer.
|
|
//
|
|
|
|
bMore = FALSE;
|
|
EnumRects.c = 1;
|
|
|
|
if ((!pco) || (pco->iDComplexity == DC_TRIVIAL)) {
|
|
|
|
PLOTASSERT(1, "DoFillByEnumingClipRects: Invalid pco TRIVIAL passed (%08lx)",
|
|
(pco) && (pco->iDComplexity != DC_TRIVIAL), pco);
|
|
|
|
return(FALSE);
|
|
|
|
} else if (pco->iDComplexity == DC_RECT) {
|
|
|
|
//
|
|
// The visible area is one rectangle intersect with the destinaiton
|
|
//
|
|
|
|
PLOTDBG(DBG_FILL_CLIP, ("DoFillByEnumingClipRects: pco=DC_RECT"));
|
|
|
|
EnumRects.rcl[0] = pco->rclBounds;
|
|
|
|
} else {
|
|
|
|
//
|
|
// We have complex clipping region to be computed, call engine to start
|
|
// enumerate the rectangles and set More = TRUE so we can get the first
|
|
// batch of rectangles.
|
|
//
|
|
|
|
PLOTDBG(DBG_FILL_CLIP, ("DoFillByEnumingClipRects: pco=DC_COMPLEX, EnumRects now"));
|
|
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
|
|
bMore = TRUE;
|
|
}
|
|
|
|
if (!(MaxRects = (DWORD)pPDev->pPlotGPC->MaxPolygonPts / 7)) {
|
|
|
|
MaxRects = 1;
|
|
}
|
|
|
|
cRects = MaxRects;
|
|
NeedSendPM0 = TRUE;
|
|
|
|
do {
|
|
|
|
if (PLOT_CANCEL_JOB(pPDev)) {
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// If More is true then we need to get next batch of rectangles
|
|
//
|
|
|
|
if (bMore) {
|
|
|
|
bMore = CLIPOBJ_bEnum(pco, sizeof(EnumRects), (ULONG *)&EnumRects);
|
|
|
|
if (!EnumRects.c) {
|
|
|
|
PLOTWARN(("DoFillByEnumingClipRects: MORE CLIPOBJ_bEnum BUT Count=0"));
|
|
}
|
|
}
|
|
|
|
|
|
PLOTDBG( DBG_FILL_CLIP,
|
|
("DoFillByEnumingClipRects: Doing batch of %ld clip rects",
|
|
EnumRects.c));
|
|
|
|
|
|
//
|
|
// prclCur will point to the first enumerated rectangle
|
|
//
|
|
|
|
prclCur = (PRECTL)&EnumRects.rcl[0];
|
|
|
|
while (EnumRects.c--) {
|
|
|
|
ptsFix[3].x = LTOFX(prclCur->left);
|
|
ptsFix[3].y = LTOFX(prclCur->top);
|
|
|
|
MovePen(pPDev, &ptsFix[3], &ptlCur);
|
|
|
|
if (NeedSendPM0) {
|
|
|
|
SEND_PM0(pPDev);
|
|
|
|
NeedSendPM0 = FALSE;
|
|
}
|
|
|
|
ptsFix[0].x = LTOFX(prclCur->right);
|
|
ptsFix[0].y = ptsFix[3].y;
|
|
|
|
ptsFix[1].x = ptsFix[0].x;
|
|
ptsFix[1].y = LTOFX(prclCur->bottom);;
|
|
|
|
ptsFix[2].x = ptsFix[3].x;
|
|
ptsFix[2].y = ptsFix[1].y;
|
|
|
|
SEND_PE(pPDev);
|
|
|
|
OutputXYParams(pPDev,
|
|
(PPOINTL)ptsFix,
|
|
(PPOINTL)NULL,
|
|
(PPOINTL)&ptlCur,
|
|
(UINT)4,
|
|
(UINT)1,
|
|
'F');
|
|
|
|
|
|
PLOTDBG(DBG_FILL_CLIP,
|
|
("DoFillByEnumingRects: Rect = (%ld, %ld) - (%ld, %ld)",
|
|
FXTOL(ptsFix[3].x), FXTOL( ptsFix[3].y),
|
|
FXTOL(ptsFix[1].x), FXTOL( ptsFix[1].y) ));
|
|
|
|
#if DBG
|
|
if ((FXTODEVL(pPdev, ptsFix[1].x - ptsFix[3].x) >= (1016 * 34)) ||
|
|
(FXTODEVL(pPdev, ptsFix[1].y - ptsFix[3].y) >= (1016 * 34))) {
|
|
|
|
PLOTWARN(("DoFillByEnumingClipRect: *** BIG RECT (%ld x %ld) *****",
|
|
FXTODEVL( pPDev, ptsFix[1].x - ptsFix[3].x),
|
|
FXTODEVL( pPDev, ptsFix[1].y - ptsFix[3].y)));
|
|
}
|
|
#endif
|
|
|
|
SEND_SEMI(pPDev);
|
|
SEND_PM1(pPDev);
|
|
SEND_SEMI(pPDev);
|
|
|
|
//
|
|
// 5 points per RECT polygon, so if we hit the limit then batch
|
|
// it out first. we also calling the DoFillLogic when we at very
|
|
// last enumeration of clipping rectangle.
|
|
//
|
|
|
|
--cRects;
|
|
++prclCur;
|
|
|
|
if ((!cRects) ||
|
|
((!EnumRects.c) && (!bMore))) {
|
|
|
|
PLOTDBG(DBG_FILL_CLIP,
|
|
("DoFillByEnumingRects: Hit MaxPolyPts limit"));
|
|
|
|
//
|
|
// We have hit the limit so close the polygon and do the fill
|
|
// logic then continue till were done
|
|
|
|
SEND_PM2(pPDev);
|
|
SETLINETYPESOLID(pPDev);
|
|
|
|
DoFillLogic(pPDev,
|
|
pPointlBrushOrg,
|
|
pBrushFill,
|
|
NULL,
|
|
Rop4,
|
|
plineattrs,
|
|
NULL,
|
|
ulFlags);
|
|
|
|
//
|
|
// Reset the count of points generated thus far, and set the
|
|
// flag to init polygon mode
|
|
//
|
|
|
|
cRects = MaxRects;
|
|
NeedSendPM0 = TRUE;
|
|
}
|
|
}
|
|
|
|
} while (bMore);
|
|
|
|
if (cRects != MaxRects) {
|
|
|
|
PLOTWARN(("DoFillByEnumingRects: Why We here?? Send Last Batch of =%ld",
|
|
MaxRects - cRects));
|
|
|
|
SEND_PM2(pPDev);
|
|
SETLINETYPESOLID(pPDev);
|
|
|
|
DoFillLogic(pPDev,
|
|
pPointlBrushOrg,
|
|
pBrushFill,
|
|
NULL,
|
|
Rop4,
|
|
plineattrs,
|
|
NULL,
|
|
ulFlags);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
PlotCheckForWhiteIfPenPlotter(
|
|
PPDEV pPDev,
|
|
BRUSHOBJ *pBrushFill,
|
|
BRUSHOBJ *pBrushStroke,
|
|
ROP4 rop4,
|
|
PULONG pulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
BOOL TRUE - Bypass future operations
|
|
FALSE - Operation needs to be completed
|
|
|
|
Author:
|
|
|
|
28-Nov-1993 created -by- James Bratsanos (v-jimbr)
|
|
|
|
15-Jan-1994 Sat 04:57:55 updated -by- Daniel Chou (danielc)
|
|
Change GetColor() and make it tab 5
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
{
|
|
|
|
ULONG StrokeColor;
|
|
ULONG FillColor;
|
|
|
|
|
|
//
|
|
// Initially we do a quick check if were a PEN plotter to get rid of
|
|
// either filling or stroking white.
|
|
//
|
|
|
|
if (!IS_RASTER(pPDev)) {
|
|
|
|
//
|
|
// TODO this might need adjusting based on ROPS
|
|
//
|
|
//
|
|
// Check to see if filling is enabled and if it is undo the fill flag
|
|
// if the fill color is white...
|
|
//
|
|
|
|
if (*pulFlags & FPOLY_FILL ) {
|
|
|
|
//
|
|
// Get the fill color so we can look at it and decide if its a NOOP on
|
|
// Pen plotters
|
|
//
|
|
|
|
GetColor(pPDev, pBrushFill, &FillColor, NULL, rop4);
|
|
|
|
if (PLOT_IS_WHITE( pPDev, FillColor)) {
|
|
|
|
*pulFlags &= ~FPOLY_FILL;
|
|
}
|
|
}
|
|
|
|
|
|
if (*pulFlags & FPOLY_STROKE) {
|
|
|
|
//
|
|
// Get the Stroke color so we can look at it and decide it its a NOOP
|
|
// on Pen plotters
|
|
//
|
|
|
|
GetColor(pPDev, pBrushStroke, &StrokeColor, NULL, rop4);
|
|
|
|
if (PLOT_IS_WHITE(pPDev, StrokeColor)) {
|
|
|
|
*pulFlags &= ~FPOLY_STROKE;
|
|
}
|
|
}
|
|
|
|
if (!(*pulFlags & (FPOLY_STROKE | FPOLY_FILL))) {
|
|
|
|
//
|
|
// Nothing left to do so simply return success
|
|
//
|
|
|
|
PLOTDBG(DBG_CHECK_FOR_WHITE,
|
|
("PlotCheckForWhiteIfPen: ALL WHITE detected"));
|
|
return(TRUE);
|
|
}
|
|
|
|
PLOTDBG(DBG_CHECK_FOR_WHITE,
|
|
("PlotCheckForWhiteIfPen: Painting required!"));
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DoPolygon(
|
|
PPDEV pPDev,
|
|
POINTL *ppointlOffset,
|
|
CLIPOBJ *pClipObj,
|
|
PATHOBJ *pPathObj,
|
|
POINTL *pPointlBrushOrg,
|
|
BRUSHOBJ *pBrushFill,
|
|
BRUSHOBJ *pBrushStroke,
|
|
ROP4 rop4,
|
|
LINEATTRS *plineattrs,
|
|
ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function draw/fill the polygon from either pathobj or a clipobj
|
|
|
|
Arguments:
|
|
|
|
pPDev - Pointer to our PDEV
|
|
|
|
ppointlOffset - Extra offset to the output polygon
|
|
|
|
pClipObj - clip object
|
|
|
|
pPathObj - The path object to be used
|
|
|
|
pPointlBrushOrg - brush origin in the brush to be fill or stroke
|
|
|
|
pBrushFill - brush object to be used in the FILL
|
|
|
|
pBrushStroke - brush object to be used in the STROKE
|
|
|
|
rop4 - Rop4 used in the fill
|
|
|
|
plineattrs - LINEATTRS for style lines stroke
|
|
|
|
ulFlags - polygon flags for stroke or fill
|
|
|
|
|
|
Return Value:
|
|
|
|
BOOL TRUE - Function succeded
|
|
FALSE - Function failed. TODO more here
|
|
|
|
Author:
|
|
|
|
28-Nov-1993 created -by- James Bratsanos (v-jimbr)
|
|
|
|
28-Jan-1994 Fri 00:58:25 updated -by- Daniel Chou (danielc)
|
|
Style, commented, re-structre the loop and reduced code size.
|
|
|
|
04-Aug-1994 Thu 20:00:23 updated -by- Daniel Chou (danielc)
|
|
bug# 22348 which actually is a HP raster plotter firmware bug
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
{
|
|
PRECTL prclClip = NULL;
|
|
POINTFIX *pptfx;
|
|
POINTFIX ptOffsetFix;
|
|
POINTFIX ptStart;
|
|
POINTL ptlCur;
|
|
PATHDATA pd;
|
|
DWORD cptfx;
|
|
DWORD cptExtra;
|
|
UINT cCurPosSkips;
|
|
WORD PolyMode;
|
|
BOOL bPathCameFromClip = FALSE;
|
|
BOOL bStrokeOnTheFly = FALSE;
|
|
BOOL bFirstSubPath;
|
|
BOOL bMore;
|
|
BOOL bRet;
|
|
BOOL PenIsDown;
|
|
BYTE NumType;
|
|
|
|
|
|
//
|
|
// Check to see if we can short cut some of our work if its a pen plotter
|
|
//
|
|
|
|
if (PlotCheckForWhiteIfPenPlotter(pPDev,
|
|
pBrushFill,
|
|
pBrushStroke,
|
|
rop4,
|
|
&ulFlags)) {
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// There are a few different scenarios to deal with here where the
|
|
// item in question is too complex and we need to fail they are are
|
|
// catagorized as follows
|
|
//
|
|
// 1) The fill mode is unsupported, in which case we fail the call
|
|
// and it should come back in in a simpler format
|
|
//
|
|
// 2) We have a CLIPOBJ thats more complicated than a RECT and a
|
|
// PATHOBJ, if we only have a clipobj we can enum it as a path
|
|
//
|
|
//
|
|
|
|
if ((ulFlags & FPOLY_WINDING) &&
|
|
(!IS_WINDINGFILL(pPDev))) {
|
|
|
|
//
|
|
// The plotter cannot support WINDING Mode fills, all we can do
|
|
// is fail the call and have it come back in a mode we can support
|
|
//
|
|
|
|
PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: Can't do WINDING, return(FALSE)"));
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pClipObj != NULL) {
|
|
|
|
//
|
|
// We have a clipobj so decide what to do
|
|
//
|
|
|
|
if (pClipObj->iDComplexity == DC_COMPLEX) {
|
|
|
|
//
|
|
// Since the clipobj is complex we have two choices, either there is
|
|
// no pathobj in which case we will enum the clipobj as a path, or
|
|
// if there is a pathobj we must fail the call
|
|
//
|
|
|
|
if (pPathObj != NULL) {
|
|
|
|
//
|
|
// We have a complex clip and a path?? we cannot handle this so
|
|
// fail the call
|
|
//
|
|
|
|
PLOTDBG(DBG_GENPOLYGON,
|
|
("DoPolygon: pco=COMPLEX, pPath != NULL, can handle, FALSE"));
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// We have gotten this far so we must have a clipobj that is complex
|
|
// and we will go ahead and enum it as a path.
|
|
//
|
|
|
|
if ((pPathObj = CLIPOBJ_ppoGetPath(pClipObj)) == NULL) {
|
|
|
|
PLOTRIP(("Engine path from clipobj returns NULL"));
|
|
return(FALSE);
|
|
}
|
|
|
|
bPathCameFromClip = TRUE;
|
|
|
|
} else if (pClipObj->iDComplexity == DC_RECT) {
|
|
|
|
//
|
|
// We have a RECT clip object, if we have no pathobj we simply fill
|
|
// the cliprect, if we do have a pathobj we need to set the clip
|
|
// window before enuming the path
|
|
//
|
|
|
|
if (pPathObj != NULL) {
|
|
|
|
//
|
|
// The HP 650c and other like has a firmware bug with clip
|
|
// window when using style line (must 2 pixels larger on each
|
|
// side of clip window before it will render the sytle line
|
|
//
|
|
// WE GET AROUND by return false at here from DrvStrokePath()
|
|
// where it will call DoStrokePathByEnumingClipLines() instead
|
|
//
|
|
|
|
if ((IS_RASTER(pPDev)) &&
|
|
(ulFlags & FPOLY_STROKE) &&
|
|
(plineattrs) &&
|
|
((plineattrs->fl & LA_ALTERNATE) ||
|
|
((plineattrs->cstyle) &&
|
|
(plineattrs->pstyle)))) {
|
|
|
|
PLOTWARN(("DoPolygon: RASTER/Stroke/DC_RECT/PathObj/StyleLine: (Firmware BUG) FAILED and using EnumClipLine()"));
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
prclClip = &pClipObj->rclBounds;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Simply call the fill rect code and return, we are DONE
|
|
//
|
|
|
|
return(DoRect(pPDev,
|
|
&pClipObj->rclBounds,
|
|
pBrushFill,
|
|
pBrushStroke,
|
|
pPointlBrushOrg,
|
|
rop4,
|
|
plineattrs,
|
|
ulFlags));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// CLIPOBJ is trivial so we simply ignore it and fill using the
|
|
// passed PATHOBJ
|
|
//
|
|
|
|
NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// No CLIPOBJ so use the PATHOBJ passed in
|
|
//
|
|
|
|
NULL;
|
|
}
|
|
|
|
//
|
|
// Setup the offset coordinate data, in case were coming from
|
|
// DrvTextOut
|
|
//
|
|
|
|
if (ppointlOffset) {
|
|
|
|
ptOffsetFix.x = LTOFX(ppointlOffset->x);
|
|
ptOffsetFix.y = LTOFX(ppointlOffset->y);
|
|
|
|
} else {
|
|
|
|
ptOffsetFix.x =
|
|
ptOffsetFix.y = 0;
|
|
}
|
|
|
|
//
|
|
// First we need to verify that we dont have more points than will fit
|
|
// in our polygon buffer for this device. If this is the case we have two
|
|
// choises, if the path did not come from a clip obj we fail this call,
|
|
// if it did we handle this based on enuming the clipobj as rects and filling
|
|
// the only problem is if we were also asked to stroke we need to this by
|
|
// enuming the path yet anonther time. messy but it should work.
|
|
//
|
|
|
|
cptfx = 0;
|
|
cptExtra = 1;
|
|
|
|
PATHOBJ_vEnumStart(pPathObj);
|
|
|
|
do {
|
|
|
|
bRet = PATHOBJ_bEnum(pPathObj, &pd);
|
|
|
|
cptfx += pd.count;
|
|
|
|
if ( pd.flags & PD_ENDSUBPATH ) {
|
|
|
|
//
|
|
// Count both the ENDSUBPATH and the PM1 as taking space...
|
|
//
|
|
|
|
cptExtra++;
|
|
|
|
if (!(pd.flags & PD_CLOSEFIGURE)) {
|
|
|
|
//
|
|
// Since we were not asked to close the figure, we will generate
|
|
// a move back to our starting point with the pen up, in order
|
|
// eliminate problems with HPGL/2 closing the polygon for
|
|
// us when we send the PM2
|
|
|
|
cptExtra++;
|
|
}
|
|
}
|
|
|
|
|
|
} while (bRet);
|
|
|
|
|
|
PLOTDBG(DBG_GENPOLYGON,
|
|
("DoPolygon: Total points = %d, Extra %d",
|
|
cptfx, cptExtra ));
|
|
|
|
//
|
|
// We will only do this if we have any points to do, first set bRet to
|
|
// true in case we did not ask to do anything
|
|
//
|
|
|
|
bRet = TRUE;
|
|
|
|
if (cptfx) {
|
|
|
|
SET_PP_WITH_ROP4(pPDev, rop4);
|
|
|
|
//
|
|
// Now add in the extra points that account for the PM0 and PM1
|
|
// since we have some REAL points in the path.
|
|
//
|
|
|
|
cptfx += cptExtra;
|
|
|
|
|
|
if (cptfx > pPDev->pPlotGPC->MaxPolygonPts) {
|
|
|
|
PLOTWARN(("DoPolygon: Too many polygon points = %ld > PCD=%ld",
|
|
cptfx, pPDev->pPlotGPC->MaxPolygonPts));
|
|
|
|
if (bPathCameFromClip) {
|
|
|
|
PLOTWARN(("DoPolygon: Using DoFillByEnumingClipRects()"));
|
|
|
|
//
|
|
// The path the engine created for us to enum must be freed.
|
|
//
|
|
|
|
EngDeletePath(pPathObj);
|
|
|
|
//
|
|
// TODO we are not clearing the clip window altough i dont see how
|
|
// we could get here in that case?
|
|
//
|
|
|
|
return(DoFillByEnumingClipRects(pPDev,
|
|
ppointlOffset,
|
|
pClipObj,
|
|
pPointlBrushOrg,
|
|
pBrushFill,
|
|
rop4,
|
|
plineattrs,
|
|
ulFlags));
|
|
|
|
} else {
|
|
|
|
//
|
|
// If were dealing with a REAL path AND there are too many points
|
|
// in the polygon and were being asked to FILL all we can do is fail
|
|
//
|
|
|
|
if (ulFlags & FPOLY_FILL) {
|
|
|
|
//
|
|
// TODO clear clip window?
|
|
//
|
|
|
|
PLOTERR(("DoPolygon: Too many POINTS, return FALSE"));
|
|
return(FALSE);
|
|
|
|
} else if (ulFlags & FPOLY_STROKE) {
|
|
|
|
//
|
|
// Since were stroking we can go ahead and do it on the
|
|
// fly... Polygon mode is not even required
|
|
//
|
|
|
|
PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: Is stroking manually"));
|
|
|
|
DoSetupOfStrokeAttributes( pPDev,
|
|
pPointlBrushOrg,
|
|
pBrushStroke,
|
|
rop4,
|
|
plineattrs );
|
|
|
|
//
|
|
// At this point were ONLY being asked to stroke so we simply
|
|
// setup up the stroke color and set a flag to keep us from
|
|
// going into polygon mode.
|
|
//
|
|
|
|
bStrokeOnTheFly = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// At this point were sure to actually do some real RENDERING so set
|
|
// the clip window if were going to
|
|
//
|
|
|
|
if (prclClip) {
|
|
|
|
PLOTDBG(DBG_GENPOLYGON,
|
|
("DoPolygon: Setting Clip Window to: (%ld, %ld)-(%ld, %ld)=%ld x %ld",
|
|
prclClip->left, prclClip->top,
|
|
prclClip->right, prclClip->bottom,
|
|
prclClip->right - prclClip->left,
|
|
prclClip->bottom - prclClip->top));
|
|
|
|
|
|
SetClipWindow( pPDev, prclClip);
|
|
}
|
|
|
|
//
|
|
// Now setup to enum the path and output the points, at here we are
|
|
// real sure we will have the points to do, and set the bFirstSubPath
|
|
// to TRUE so that we will output PM0
|
|
//
|
|
|
|
PATHOBJ_vEnumStart(pPathObj);
|
|
|
|
PenIsDown = FALSE;
|
|
PolyMode = 0;
|
|
bFirstSubPath = TRUE;
|
|
|
|
do {
|
|
|
|
if (PLOT_CANCEL_JOB(pPDev)) {
|
|
|
|
break;
|
|
}
|
|
|
|
bMore = PATHOBJ_bEnum(pPathObj, &pd);
|
|
cptfx = pd.count;
|
|
pptfx = pd.pptfx;
|
|
|
|
//
|
|
// Check the BEGINSUBPATH or if we are at here first time
|
|
//
|
|
|
|
if ((pd.flags & PD_BEGINSUBPATH) || (bFirstSubPath)) {
|
|
|
|
PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: Getting PD_BEGINSUBPATH"));
|
|
|
|
TERM_PE_MODE(pPDev, PolyMode);
|
|
|
|
ptStart.x = pptfx->x + ptOffsetFix.x;
|
|
ptStart.y = pptfx->y + ptOffsetFix.y;
|
|
|
|
MovePen(pPDev, &ptStart, &ptlCur);
|
|
PenIsDown = FALSE;
|
|
|
|
pptfx++;
|
|
cptfx--;
|
|
|
|
if ((!bStrokeOnTheFly) && (bFirstSubPath)) {
|
|
|
|
SEND_PM0(pPDev);
|
|
}
|
|
|
|
bFirstSubPath = FALSE;
|
|
}
|
|
|
|
//
|
|
// Now check if we need to do BEZIER or not
|
|
//
|
|
|
|
if (pd.flags & PD_BEZIERS) {
|
|
|
|
PLOTASSERT(1, "DoPolygon: PD_BEZIERS (count % 3) != 0 (%ld)",
|
|
(cptfx % 3) == 0, cptfx);
|
|
|
|
SWITCH_TO_BR(pPDev, PolyMode, PenIsDown);
|
|
|
|
NumType = 'f';
|
|
cCurPosSkips = 3;
|
|
|
|
} else {
|
|
|
|
SWITCH_TO_PE(pPDev, PolyMode, PenIsDown);
|
|
|
|
NumType = 'F';
|
|
cCurPosSkips = 1;
|
|
}
|
|
|
|
PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: OutputXYParam(%ld pts=%hs)",
|
|
cptfx, (pd.flags & PD_BEZIERS) ? "BEZIER" : "POLYGON"));
|
|
|
|
OutputXYParams(pPDev,
|
|
(PPOINTL)pptfx,
|
|
(PPOINTL)&ptOffsetFix,
|
|
(PPOINTL)&ptlCur,
|
|
(UINT)cptfx,
|
|
(UINT)cCurPosSkips,
|
|
NumType);
|
|
|
|
//
|
|
// So if we ending the sub path
|
|
//
|
|
|
|
if (pd.flags & PD_ENDSUBPATH) {
|
|
|
|
PLOTDBG(DBG_GENPOLYGON,
|
|
("DoPolygon: Getting PD_ENDSUBPATH %hs",
|
|
(pd.flags & PD_CLOSEFIGURE) ? "PD_CLOSEFIGURE" : ""));
|
|
|
|
//
|
|
// If we are not closing the figure then move the pen to the
|
|
// starting position so we do not have plotter to automatically
|
|
// close the sub-polygon
|
|
//
|
|
|
|
if (pd.flags & PD_CLOSEFIGURE) {
|
|
|
|
PLOTDBG(DBG_GENPOLYGON,
|
|
("DoPolygon: OutputXYParam(1) to ptStart=(%ld, %ld)",
|
|
ptStart.x, ptStart.y));
|
|
|
|
//
|
|
// We must not passed ptOffsetFix because we already add
|
|
// that into the ptStart at BEGSUBPATH.
|
|
//
|
|
|
|
SWITCH_TO_PE(pPDev, PolyMode, PenIsDown);
|
|
|
|
OutputXYParams(pPDev,
|
|
(PPOINTL)&ptStart,
|
|
(PPOINTL)NULL,
|
|
(PPOINTL)&ptlCur,
|
|
(UINT)1,
|
|
(UINT)1,
|
|
'F');
|
|
}
|
|
|
|
TERM_PE_MODE(pPDev, PolyMode);
|
|
|
|
if (!(pd.flags & PD_CLOSEFIGURE)) {
|
|
|
|
MovePen(pPDev, &ptStart, &ptlCur);
|
|
PenIsDown = FALSE;
|
|
}
|
|
|
|
if (!bStrokeOnTheFly) {
|
|
|
|
SEND_PM1(pPDev);
|
|
}
|
|
}
|
|
|
|
} while (bMore);
|
|
|
|
TERM_PE_MODE(pPDev, PolyMode);
|
|
|
|
//
|
|
// Now end polygon mode
|
|
//
|
|
|
|
if ((bRet) &&
|
|
(!bStrokeOnTheFly) &&
|
|
(!PLOT_CANCEL_JOB(pPDev))) {
|
|
|
|
SEND_PM2(pPDev);
|
|
SETLINETYPESOLID(pPDev);
|
|
|
|
//
|
|
// Now fill and/or stroke the current polygon
|
|
//
|
|
|
|
DoFillLogic(pPDev,
|
|
pPointlBrushOrg,
|
|
pBrushFill,
|
|
pBrushStroke,
|
|
rop4,
|
|
plineattrs,
|
|
NULL,
|
|
ulFlags);
|
|
}
|
|
|
|
//
|
|
// If we do this then undo the clip window
|
|
//
|
|
|
|
if (prclClip) {
|
|
|
|
ClearClipWindow(pPDev);
|
|
}
|
|
|
|
} else {
|
|
|
|
PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: PATHOBJ_bEnum=NO POINT"));
|
|
}
|
|
|
|
//
|
|
// If the path was constructed from a complex clip object we need to
|
|
// delete that path now.
|
|
//
|
|
|
|
if (bPathCameFromClip) {
|
|
|
|
EngDeletePath(pPathObj);
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
HandleLineAttributes(
|
|
PPDEV pPDev,
|
|
LINEATTRS *plineattrs,
|
|
PLONG pStyleToUse,
|
|
LONG lExtraStyle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function does any setup necessary to correctly handle stroking of
|
|
a path. It does this by looking at the LINEATTRS structure passed in
|
|
and setting up the HPGL2 plotter with the appropriate style info
|
|
|
|
Arguments:
|
|
|
|
pPDev - Pointer to our PDEV
|
|
|
|
plineattrs - LINEATTRS for style lines stroke
|
|
|
|
pStyleToUse - The starting style offset to use, if this is NULL then
|
|
we use the starting member in plineatts.
|
|
|
|
lExtraStyle - Any extra style to use based on the current run
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
Author:
|
|
|
|
01-Feb-1994 created -by- James Bratsanos (v-jimbr)
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
{
|
|
LONG lTotLen = 0L;
|
|
INT i;
|
|
LONG lScaleVal;
|
|
INT iCount;
|
|
PFLOAT_LONG pStartStyle;
|
|
FLOAT_LONG aAlternate[2];
|
|
BOOL bSolid = TRUE;
|
|
LONG lStyleState;
|
|
PLONG pArrayToUse;
|
|
|
|
|
|
PLOTDBG( DBG_HANDLELINEATTR,
|
|
("HandleLineAttr: plineattrs = %hs",
|
|
(plineattrs) ? "Exists" : "NULL" ));
|
|
|
|
if (plineattrs) {
|
|
|
|
PLOTASSERT(1,
|
|
"HandleLineAttrs: Getting a LA_GEOMETRIC and cannot handle %u",
|
|
(!(plineattrs->fl & LA_GEOMETRIC)),
|
|
plineattrs->fl);
|
|
|
|
//
|
|
// Set up the correct lStyleState to use, the passed one has precedence
|
|
// over the one imbedded in the lineattributes structure.
|
|
//
|
|
|
|
if (pStyleToUse) {
|
|
|
|
lStyleState = *pStyleToUse;
|
|
|
|
} else {
|
|
|
|
lStyleState = plineattrs->elStyleState.l;
|
|
}
|
|
|
|
if (plineattrs->fl & LA_ALTERNATE) {
|
|
|
|
PLOTDBG( DBG_HANDLELINEATTR,
|
|
("HandleLineAttr: plineattrs has LA_ALTERNATE bit set!"));
|
|
//
|
|
// This is a special case where every other pixel is on...
|
|
//
|
|
|
|
pStartStyle = &aAlternate[0];
|
|
iCount = sizeof(aAlternate) / sizeof(aAlternate[0]);
|
|
|
|
aAlternate[0].l = 1;
|
|
aAlternate[1].l = 1;
|
|
|
|
} else if ((plineattrs->cstyle != 0) &&
|
|
(plineattrs->pstyle != (PFLOAT_LONG)NULL)) {
|
|
|
|
//
|
|
// There is a user defined style passed in so set up for it
|
|
//
|
|
|
|
iCount = plineattrs->cstyle;
|
|
pStartStyle = plineattrs->pstyle;
|
|
|
|
PLOTDBG(DBG_HANDLELINEATTR, ("HandleLineAttr: Count = %ld",
|
|
plineattrs->cstyle));
|
|
|
|
} else {
|
|
|
|
//
|
|
// This is a SOLID line, so simply set the number of points to 0
|
|
//
|
|
|
|
iCount = 0;
|
|
}
|
|
|
|
if (iCount) {
|
|
|
|
PFLOAT_LONG pCurStyle;
|
|
INT idx;
|
|
LONG lTempValue;
|
|
LONG lValueToEnd;
|
|
BOOL bInDash;
|
|
LONG convArray[MAX_USER_POINTS];
|
|
PLONG pConverted;
|
|
LONG newArray[MAX_USER_POINTS+2];
|
|
PLONG pNewArray;
|
|
|
|
|
|
PLOTASSERT(0,
|
|
"HandleLineAttributes: Getting more than 18 points (%ld)",
|
|
(iCount <= MAX_STYLE_ENTRIES) ,
|
|
iCount);
|
|
|
|
//
|
|
// Record our current DASH state, ie the line either starts with
|
|
// a gap or a dash.
|
|
//
|
|
|
|
if (plineattrs->fl & LA_STARTGAP) {
|
|
|
|
bInDash = FALSE;
|
|
|
|
} else {
|
|
|
|
bInDash = TRUE;
|
|
}
|
|
|
|
//
|
|
// Since we know we cant handle more than 20 points sent to HPGL2
|
|
// we limit it now to 18 in order to compensate for the upto 2
|
|
// additional points we may add.
|
|
//
|
|
|
|
iCount = min(MAX_STYLE_ENTRIES, iCount);
|
|
|
|
//
|
|
// Get our scaling value, so we can convert style units to
|
|
// our units.
|
|
//
|
|
|
|
lScaleVal = PLOT_STYLE_STEP(pPDev);
|
|
|
|
//
|
|
// Now convert to the new units, and store the result in the
|
|
// new array. Also keep track of the total length of the style
|
|
//
|
|
|
|
for (i = 0, pConverted = &convArray[0], lTotLen = 0,
|
|
pCurStyle = pStartStyle;
|
|
i < iCount ;
|
|
i++, pCurStyle++, pConverted++) {
|
|
|
|
*pConverted = pCurStyle->l * lScaleVal;
|
|
|
|
PLOTDBG( DBG_HANDLELINEATTR,
|
|
("HandleLineAttr: Orig Array [%ld]= %ld becomes %ld",
|
|
i, pCurStyle->l, *pConverted ));
|
|
|
|
lTotLen += *pConverted;
|
|
}
|
|
|
|
//
|
|
// Now convert the passed style state and extra info into the
|
|
// real final style state to use, we do this by taking the value of
|
|
// interest which is packed into the hiword and loword of lstylestate
|
|
// based on the ddi spec, then we must add on any additional distance
|
|
// (which may have come from enuming a CLIPLINE structure)
|
|
//
|
|
|
|
lStyleState = (HIWORD(lStyleState) * PLOT_STYLE_STEP(pPDev) +
|
|
LOWORD(lStyleState) + lExtraStyle) % lTotLen ;
|
|
|
|
PLOTDBG(DBG_HANDLELINEATTR,
|
|
("HandleLineAttributes: Computed Style state = %ld, extra = %ld",
|
|
lStyleState, lExtraStyle));
|
|
|
|
//
|
|
// Set up our final pointer to the new array, since we may be done
|
|
// based on the final computed stylestate being 0
|
|
//
|
|
|
|
pNewArray = &newArray[0];
|
|
|
|
//
|
|
// TODO limit new array
|
|
//
|
|
|
|
if (lStyleState != 0) {
|
|
|
|
lTempValue = 0;
|
|
|
|
//
|
|
// Since lStyleState has a value other than zero we must
|
|
// construct a new style array to pass to hpgl2 that has been
|
|
// rotated in order to take into account the style state.
|
|
// the code below constructs the new array
|
|
//
|
|
|
|
for (i=0, pConverted = &convArray[0];
|
|
i < iCount ;
|
|
i++, pConverted++) {
|
|
|
|
//
|
|
// At this point were looking for the entry which partially
|
|
// encompasses the style state derived. Based on this
|
|
// we can create a new array that is a transformation of the
|
|
// original array rotated the correct amount
|
|
//
|
|
|
|
if (lStyleState < lTempValue + *pConverted) {
|
|
|
|
//
|
|
// Here is the transition point.
|
|
//
|
|
|
|
*pNewArray++ = *pConverted - (lStyleState - lTempValue);
|
|
|
|
//
|
|
// Record the value that needs to be appended to the end
|
|
// of the array
|
|
//
|
|
|
|
lValueToEnd = lStyleState - lTempValue;
|
|
|
|
|
|
idx = i;
|
|
|
|
idx++;
|
|
pConverted++;
|
|
|
|
//
|
|
// Fill up the end
|
|
//
|
|
|
|
while (idx++ < iCount) {
|
|
|
|
*pNewArray++ = *pConverted++;
|
|
}
|
|
|
|
//
|
|
// Now fill up the begining...
|
|
//
|
|
|
|
idx = 0;
|
|
pConverted = &convArray[0];
|
|
|
|
//
|
|
// If there was an odd number we can add together
|
|
// the starting and ending one since they have the
|
|
// same state
|
|
//
|
|
|
|
if ((iCount % 2) == 1 ) {
|
|
|
|
pNewArray--;
|
|
*pNewArray += *pConverted++;
|
|
|
|
idx++;
|
|
pNewArray++;
|
|
}
|
|
|
|
while (idx++ < i) {
|
|
|
|
*pNewArray++ = *pConverted++;
|
|
}
|
|
|
|
*pNewArray++ = lValueToEnd;
|
|
|
|
break;
|
|
}
|
|
|
|
lTempValue += *pConverted;
|
|
|
|
bInDash = TOGGLE_DASH(bInDash);
|
|
}
|
|
|
|
pArrayToUse = &newArray[0];
|
|
iCount = pNewArray - &newArray[0];
|
|
|
|
} else {
|
|
|
|
pArrayToUse = &convArray[0];
|
|
}
|
|
|
|
PLOTASSERT(0,
|
|
"HandleLineAttributes: Getting more than 20 points (%ld)",
|
|
(iCount <= MAX_USER_POINTS) ,
|
|
iCount);
|
|
//
|
|
// There is a style patter so set up for it.
|
|
//
|
|
|
|
bSolid = FALSE;
|
|
|
|
//
|
|
// Begin the HPGL2 line command to define a custom style type
|
|
//
|
|
|
|
OutputString(pPDev, "UL1");
|
|
|
|
//
|
|
// If this flag is set, the first len is a gap NOT a dash so we trick
|
|
// HPGL2 into doing the right thing by having a zero length dash
|
|
//
|
|
|
|
if (!bInDash) {
|
|
|
|
OutputString(pPDev, ",0");
|
|
}
|
|
|
|
//
|
|
// Since we output the 0 len dash at the begin if the line starts
|
|
// with a gap the most additional points we send out is decremented
|
|
// by one
|
|
//
|
|
|
|
iCount = min((bInDash ? MAX_USER_POINTS : MAX_USER_POINTS - 1) ,
|
|
iCount);
|
|
|
|
//
|
|
// Enum through the points in the style array, converting to our
|
|
// Graphics units and send them to the plotter
|
|
//
|
|
|
|
for (i = 0; i < iCount; i++, pArrayToUse++) {
|
|
|
|
PLOTDBG(DBG_HANDLELINEATTR,
|
|
("HandleLineAttr: New Array [%ld]= %ld",
|
|
i, *pArrayToUse));
|
|
|
|
OutputFormatStr(pPDev, ",#l", *pArrayToUse);
|
|
}
|
|
|
|
//
|
|
// Now output the linetype and specify the total lenght of the pattern
|
|
//
|
|
|
|
OutputFormatStr(pPDev, "LT1,#d,1",
|
|
((lTotLen * 254) / pPDev->lCurResolution ) / 10 );
|
|
|
|
//
|
|
// Update our linetype in the pdev since we ALWAYS send out this
|
|
// line type
|
|
//
|
|
|
|
pPDev->LastLineType = PLOT_LT_USERDEFINED;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If it was SOLID just send out the SOLID (default command)
|
|
//
|
|
|
|
if (bSolid) {
|
|
|
|
PLOTDBG(DBG_HANDLELINEATTR, ("HandleLineAttr: Line type is SOLID"));
|
|
|
|
//
|
|
// Send out the correct commands to the plotter
|
|
//
|
|
|
|
SETLINETYPESOLID(pPDev);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
DoFillLogic(
|
|
PPDEV pPDev,
|
|
POINTL *pPointlBrushOrg,
|
|
BRUSHOBJ *pBrushFill,
|
|
BRUSHOBJ *pBrushStroke,
|
|
ROP4 Rop4,
|
|
LINEATTRS *plineattrs,
|
|
SIZEL *pszlRect,
|
|
ULONG ulFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
Author:
|
|
|
|
30-Nov-1993 created -by- James Bratsanos (v-jimbr)
|
|
|
|
15-Jan-1994 Sat 05:02:42 updated -by- Daniel Chou (danielc)
|
|
Change GetColor() and tabify
|
|
|
|
18-Jan-1994 Sat 05:02:42 updated -by- James Bratsanos (v-jimbr)
|
|
|
|
16-Feb-1994 Wed 09:34:06 updated -by- Daniel Chou (danielc)
|
|
Update for the rectangle polygon case to use RR/ER commands
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
{
|
|
INTDECIW PenWidth;
|
|
|
|
|
|
//
|
|
// Since a polygon must already be defined this code simply
|
|
// looks at the passed data and sends out the appropriate codes to
|
|
// fill this polygon correctly.
|
|
//
|
|
|
|
PenWidth.Integer =
|
|
PenWidth.Decimal = 0;
|
|
|
|
|
|
if (ulFlags & FPOLY_FILL) {
|
|
|
|
DEVBRUSH *pDevFill;
|
|
DWORD FillForeColor;
|
|
LONG HSType;
|
|
LONG HSParam;
|
|
BOOL bSetTransparent = FALSE;
|
|
|
|
|
|
if (!GetColor(pPDev, pBrushFill, &FillForeColor, &pDevFill, Rop4)) {
|
|
|
|
PLOTERR(("DoFillLogic: GetColor()=FALSE"));
|
|
return;
|
|
}
|
|
|
|
HSType = -1;
|
|
HSParam = (LONG)((pDevFill) ? pDevFill->LineSpacing : 0);
|
|
|
|
//
|
|
// If the plotter cannot support tranparent mode there is no need
|
|
// to wory about backgrounds. we will only ever care about foreground
|
|
//
|
|
|
|
if (((IS_TRANSPARENT(pPDev)) || (!IS_RASTER(pPDev))) &&
|
|
(pDevFill)) {
|
|
|
|
switch(pDevFill->PatIndex) {
|
|
|
|
case HS_HORIZONTAL:
|
|
case HS_VERTICAL:
|
|
case HS_BDIAGONAL:
|
|
case HS_FDIAGONAL:
|
|
case HS_CROSS:
|
|
case HS_DIAGCROSS:
|
|
|
|
PenWidth.Integer = PW_HATCH_INT;
|
|
PenWidth.Decimal = PW_HATCH_DECI;
|
|
bSetTransparent = (BOOL)IS_TRANSPARENT(pPDev);
|
|
|
|
if ((Rop4 & 0xFF00) != 0xAA00) {
|
|
|
|
if (IS_RASTER(pPDev)) {
|
|
|
|
//
|
|
// Send out the Bck Rop
|
|
//
|
|
|
|
SetRopMode(pPDev, ROP4_BG_ROP(Rop4));
|
|
|
|
PLOTDBG(DBG_FILL_LOGIC,
|
|
("DoFillLogic: BCK = MC=%02lx", ROP4_BG_ROP(Rop4)));
|
|
}
|
|
|
|
//
|
|
// We need to select the background color fill then
|
|
// select the foreground color back... ONLY if NON-WHITE
|
|
//
|
|
|
|
if ((IS_RASTER(pPDev)) ||
|
|
(!PLOT_IS_WHITE(pPDev, pDevFill->ColorBG))) {
|
|
|
|
HSType = HS_DDI_MAX;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// If we are pen plotter and has user defined pattern then we
|
|
// will do horizontal hatch for background color and vertical
|
|
// hatch for the foreground color
|
|
//
|
|
|
|
if ((!IS_RASTER(pPDev)) &&
|
|
(pDevFill->PatIndex >= HS_DDI_MAX)) {
|
|
|
|
PLOTWARN(("DoFillLogic: PEN+USER PAT, Do HS_FDIAGONAL for BG [%ld]",
|
|
pDevFill->ColorBG));
|
|
|
|
HSParam <<= 1;
|
|
|
|
if (!PLOT_IS_WHITE(pPDev, pDevFill->ColorBG)) {
|
|
|
|
HSType = HS_FDIAGONAL;
|
|
|
|
} else {
|
|
|
|
PLOTWARN(("DoFillLogic: PEN+USER PAT, Skip WHITE COLOR"));
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (HSType != -1) {
|
|
|
|
PLOTDBG(DBG_FILL_LOGIC, ("DoFillLogic: Fill BGColor = %08lx", pDevFill->ColorBG));
|
|
|
|
SelectColor(pPDev, pDevFill->ColorBG, PenWidth);
|
|
SetHSFillType(pPDev, (DWORD)HSType, HSParam);
|
|
SetBrushOrigin(pPDev, pPointlBrushOrg);
|
|
|
|
if (pszlRect) {
|
|
|
|
SEND_RR(pPDev);
|
|
OutputLONGParams(pPDev, (PLONG)pszlRect, 2, 'd');
|
|
pszlRect = NULL;
|
|
|
|
} else {
|
|
|
|
SEND_FP(pPDev);
|
|
|
|
if (ulFlags & FPOLY_WINDING) {
|
|
|
|
SEND_1SEMI(pPDev);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Send out the foreground Rop
|
|
//
|
|
|
|
if (IS_RASTER(pPDev)) {
|
|
|
|
SetRopMode(pPDev, ROP4_FG_ROP(Rop4));
|
|
}
|
|
|
|
//
|
|
// Now select the fore color
|
|
//
|
|
|
|
SelectColor(pPDev, FillForeColor, PenWidth);
|
|
|
|
if (bSetTransparent) {
|
|
|
|
PLOTDBG(DBG_FILL_LOGIC, ("DoFillLogic: TRANSPARENT MODE"));
|
|
|
|
//
|
|
// Set up for transperant
|
|
//
|
|
|
|
SEND_TR1(pPDev);
|
|
}
|
|
|
|
if (pDevFill) {
|
|
|
|
if (pDevFill->PatIndex >= HS_DDI_MAX) {
|
|
|
|
if (IS_RASTER(pPDev)) {
|
|
|
|
DownloadUserDefinedPattern(pPDev, pDevFill);
|
|
|
|
} else {
|
|
|
|
PLOTWARN(("DoFillLogic: PEN+USER PAT, Do HS_BDIAGONAL for FG [%ld]",
|
|
FillForeColor));
|
|
|
|
SetHSFillType(pPDev, HS_BDIAGONAL, HSParam);
|
|
}
|
|
|
|
} else {
|
|
|
|
SetHSFillType(pPDev, pDevFill->PatIndex, pDevFill->LineSpacing);
|
|
}
|
|
|
|
//
|
|
// Set the origin and teill plotter to fill in the polygon!
|
|
//
|
|
|
|
SetBrushOrigin(pPDev, pPointlBrushOrg);
|
|
|
|
} else {
|
|
|
|
SetHSFillType(pPDev, HS_DDI_MAX, 0);
|
|
}
|
|
|
|
if (pszlRect) {
|
|
|
|
SEND_RR(pPDev);
|
|
OutputLONGParams(pPDev, (PLONG)pszlRect, 2, 'd');
|
|
pszlRect = NULL;
|
|
|
|
} else {
|
|
|
|
SEND_FP(pPDev);
|
|
|
|
if (ulFlags & FPOLY_WINDING) {
|
|
|
|
SEND_1SEMI(pPDev);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we used tranparent mode put it back
|
|
//
|
|
|
|
if (bSetTransparent) {
|
|
|
|
SEND_TR0(pPDev);
|
|
}
|
|
}
|
|
|
|
if (ulFlags & FPOLY_STROKE) {
|
|
|
|
DoSetupOfStrokeAttributes(pPDev,
|
|
pPointlBrushOrg,
|
|
pBrushStroke,
|
|
Rop4,
|
|
plineattrs);
|
|
|
|
//
|
|
// give the plotter the command to stroke the polygon outline!
|
|
//
|
|
|
|
if (pszlRect) {
|
|
|
|
SEND_ER(pPDev);
|
|
OutputLONGParams(pPDev, (PLONG)pszlRect, 2, 'd');
|
|
|
|
} else {
|
|
|
|
SEND_EP(pPDev);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
DoSetupOfStrokeAttributes(
|
|
PPDEV pPDev,
|
|
POINTL *pPointlBrushOrg,
|
|
BRUSHOBJ *pBrushStroke,
|
|
ROP4 Rop4,
|
|
LINEATTRS *plineattrs
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets up the plotter in order to correctly handle stroking,
|
|
based on the past brush and lineattributes structure.
|
|
|
|
Arguments:
|
|
|
|
pPDev Pointer to our current PDEV with state info about driver
|
|
pPointlBrushOrg Brush origin
|
|
pBrushStroke BRUSHOBJ to stroke with (should only be solid color)
|
|
Rop4 The rop to use when stroking
|
|
plineattrs LINEATTRS structure with the specified line styles
|
|
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
Author:
|
|
|
|
01-Feb-1994 Tue 05:02:42 created -by- James Bratsanos (v-jimbr)
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
{
|
|
INTDECIW PenWidth;
|
|
DWORD StrokeColor;
|
|
|
|
|
|
GetColor(pPDev, pBrushStroke, &StrokeColor, NULL, Rop4);
|
|
|
|
PenWidth.Integer =
|
|
PenWidth.Decimal = 0;
|
|
|
|
SelectColor(pPDev, StrokeColor, PenWidth);
|
|
|
|
//
|
|
// Send out the foreground Rop, if we are RASTER
|
|
//
|
|
|
|
if (IS_RASTER(pPDev)) {
|
|
|
|
SetRopMode(pPDev, ROP4_FG_ROP(Rop4));
|
|
}
|
|
|
|
//
|
|
// Handle the line attributes
|
|
//
|
|
|
|
HandleLineAttributes(pPDev, plineattrs, NULL, 0);
|
|
}
|
|
|
|
|
|
|
|
|
|
LONG
|
|
DownloadUserDefinedPattern(
|
|
PPDEV pPDev,
|
|
PDEVBRUSH pBrush
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function defined a user pattern to the HPGL/2 device
|
|
|
|
|
|
Arguments:
|
|
|
|
pPDev - Pointer to the PDEV
|
|
|
|
pBrush - Pointer to the cached device brush
|
|
|
|
|
|
Return Value:
|
|
|
|
INT to indicate a pattern number downloaed/defined
|
|
|
|
Author:
|
|
|
|
09-Feb-1994 Wed 13:11:01 updated -by- Daniel Chou (danielc)
|
|
Remove 4bpp/1bpp things, it always must have pbgr24
|
|
|
|
08-Feb-1994 Tue 01:49:53 updated -by- Daniel Chou (danielc)
|
|
make PalEntry.B = *pbgr++ as first color, since the order we have
|
|
is PALENTRY and first color is B in the structure.
|
|
|
|
27-Jan-1994 Thu 21:20:30 updated -by- Daniel Chou (danielc)
|
|
Add the RF cache codes
|
|
|
|
14-Jan-1994 Fri 15:23:40 updated -by- Daniel Chou (danielc)
|
|
Added assert for compatible device pattern
|
|
Added so it will take device compatible pattern (8x8,16x16,32x32,64x64)
|
|
|
|
13-Jan-1994 Thu 19:04:04 created -by- Daniel Chou (danielc)
|
|
Re-write
|
|
|
|
16-Feb-1994 Wed 11:00:19 updated -by- Daniel Chou (danielc)
|
|
Change return value to return the HSFillType, and fixed the bugs which
|
|
if we found the cached but we do not set the fill type again
|
|
|
|
05-Aug-1994 Fri 18:35:45 updated -by- Daniel Chou (danielc)
|
|
Bug# 22381, we do FindCachedPen() for durning the pattern downloading
|
|
and this causing the problem if the pen is not in the cache then we
|
|
will send the PEN DEFINITION at middle of pattern downloading. If this
|
|
happened then downloading sequence is broken. We fixes this by
|
|
|
|
1) Cache the pen indices if we have enough memory
|
|
2) Run through FindCachePen() for all the RGB color in the pattern
|
|
3) Download cached pen indices if we have memory OR run through
|
|
FindCachedPen() again to download the pen indices
|
|
|
|
This may still have problem if we have
|
|
|
|
1) No pen indices caching memory
|
|
2) more color in the pattern then the max pens in the device
|
|
|
|
BUT if this happened then we have no choice to have wrong output
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG HSFillType;
|
|
LONG RFIndex;
|
|
|
|
//
|
|
// Firstable we must find the RFIndex
|
|
//
|
|
//
|
|
|
|
HSFillType = HS_FT_USER_DEFINED;
|
|
|
|
if ((RFIndex = FindDBCache(pPDev, pBrush->Uniq)) < 0) {
|
|
|
|
LPBYTE pbgr24;
|
|
|
|
|
|
RFIndex = -RFIndex;
|
|
|
|
//
|
|
// We must download new pattern to the plotter now, make it positive
|
|
//
|
|
|
|
if (pbgr24 = pBrush->pbgr24) {
|
|
|
|
PALENTRY PalEntry;
|
|
LPWORD pwIdx;
|
|
UINT Idx;
|
|
UINT Size;
|
|
|
|
|
|
Size = (UINT)pBrush->cxbgr24 * (UINT)pBrush->cybgr24;
|
|
|
|
PLOTDBG(DBG_USERPAT,
|
|
("PlotGenUserDefinedPattern: DOWNLOAD %ld x %ld=%ld USER PAT #%ld",
|
|
(LONG)pBrush->cxbgr24, (LONG)pBrush->cybgr24, Size, RFIndex));
|
|
|
|
if (!(pwIdx = (LPWORD)LocalAlloc(LPTR, Size * sizeof(WORD)))) {
|
|
|
|
//
|
|
// Do not have memory to do it foget it
|
|
//
|
|
|
|
PLOTWARN(("Download User defined pattern NO Memory so REAL TIME RUN"));
|
|
}
|
|
|
|
//
|
|
// We must first get all the pen cached so we have the indxe to
|
|
// used, otherwise we will download the pen color durning the
|
|
// pen color is defined
|
|
//
|
|
|
|
PalEntry.Flags = 0;
|
|
|
|
for (Idx = 0; Idx < Size; Idx++) {
|
|
|
|
WORD PenIdx;
|
|
|
|
|
|
PalEntry.B = *pbgr24++;
|
|
PalEntry.G = *pbgr24++;
|
|
PalEntry.R = *pbgr24++;
|
|
|
|
PenIdx = (WORD)FindCachedPen(pPDev, &PalEntry);
|
|
|
|
if (pwIdx) {
|
|
|
|
pwIdx[Idx] = PenIdx;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now output the download header/size first
|
|
//
|
|
|
|
OutputFormatStr(pPDev, "RF#d,#d,#d", RFIndex,
|
|
(LONG)pBrush->cxbgr24, (LONG)pBrush->cybgr24);
|
|
|
|
//
|
|
// If we cahced the indices then use it otherwise, find the cache
|
|
// again
|
|
//
|
|
|
|
if (pwIdx) {
|
|
|
|
for (Idx = 0; Idx < Size; Idx++) {
|
|
|
|
OutputFormatStr(pPDev, ",#d", pwIdx[Idx]);
|
|
}
|
|
|
|
//
|
|
// Free the indices memory if we have one
|
|
//
|
|
|
|
LocalFree((HLOCAL)pwIdx);
|
|
|
|
} else {
|
|
|
|
//
|
|
// We do not have cached indices, so run through again
|
|
//
|
|
|
|
pbgr24 = pBrush->pbgr24;
|
|
|
|
for (Idx = 0; Idx < Size; Idx++) {
|
|
|
|
PalEntry.B = *pbgr24++;
|
|
PalEntry.G = *pbgr24++;
|
|
PalEntry.R = *pbgr24++;
|
|
|
|
OutputFormatStr(pPDev, ",#d", FindCachedPen(pPDev, &PalEntry));
|
|
}
|
|
}
|
|
|
|
SEND_SEMI(pPDev);
|
|
|
|
} else {
|
|
|
|
PLOTERR(("PlotGenUserDefinedPattern: NO pbgr24??, set SOLID"));
|
|
|
|
HSFillType = HS_DDI_MAX;
|
|
RFIndex = 0;
|
|
}
|
|
|
|
} else {
|
|
|
|
PLOTDBG(DBG_USERPAT,
|
|
("PlotGenUserDefinedPattern: We have CACHED RFIndex=%ld",
|
|
RFIndex));
|
|
}
|
|
|
|
SetHSFillType(pPDev, (DWORD)HSFillType, RFIndex);
|
|
|
|
return(RFIndex);
|
|
}
|