Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

601 lines
16 KiB

//--------------------------------------------------------------------------
//
// Module Name: PATHS.C
//
// Brief Description: This module contains the PSCRIPT driver's path
// rendering functions and related routines.
//
// Author: Kent Settle (kentse)
// Created: 02-May-1991
//
// Copyright (c) 1991 - 1992 Microsoft Corporation
//
// This Module contains the following functions:
// DrvStrokePath
// DrvFillPath
// DrvStrokeAndFillPath
//--------------------------------------------------------------------------
#include "pscript.h"
#define MAX_STROKE_POINTS 1500
VOID ps_box(PDEVDATA, PRECTL, BOOL);
BOOL DrvCommonPath(PDEVDATA, PATHOBJ *, BOOL, BOOL *, XFORMOBJ *, BRUSHOBJ *,
PPOINTL, PLINEATTRS);
//--------------------------------------------------------------------------
// BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix)
// SURFOBJ *pso;
// PATHOBJ *ppo;
// CLIPOBJ *pco;
// XFORMOBJ *pxo;
// BRUSHOBJ *pbo;
// PPOINTL pptlBrushOrg;
// PLINEATTRS plineattrs;
// MIX mix;
//
//
// Parameters:
//
// Returns:
// This function returns TRUE.
//
// History:
// 02-May-1991 -by- Kent Settle [kentse]
// Wrote it.
//--------------------------------------------------------------------------
BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix)
SURFOBJ *pso;
PATHOBJ *ppo;
CLIPOBJ *pco;
XFORMOBJ *pxo;
BRUSHOBJ *pbo;
PPOINTL pptlBrushOrg;
PLINEATTRS plineattrs;
MIX mix;
{
PDEVDATA pdev;
BOOL bClipping; // TRUE if there is a clip region.
ULONG ulColor;
BOOL bPathExists;
RECTFX rcfxBound;
RECTL rclBound;
UNREFERENCED_PARAMETER(mix);
TRACEDDIENTRY("DrvStrokePath");
// get the pointer to our DEVDATA structure and make sure it is ours.
pdev = (PDEVDATA) pso->dhpdev;
if (! bValidatePDEV(pdev) || (pdev->dwFlags & PDEV_CANCELDOC))
return FALSE;
if (pdev->dwFlags & PDEV_IGNORE_GDI)
return TRUE;
// deal with LINEATTRS.
if (!(ps_setlineattrs(pdev, plineattrs, pxo)))
return(FALSE);
// output the line color to stroke with. do this before we handle
// clipping, so the line color will remain beyond the gsave/grestore.
if (pbo->iSolidColor == NOT_SOLID_COLOR)
{
//!!! this needs to be fixed!!! -kentse.
ulColor = RGB_GRAY;
ps_setrgbcolor(pdev, (PSRGB *)&ulColor);
}
else
{
// we have a solid brush, so simply output the line color.
ps_setrgbcolor(pdev, (PSRGB *)&pbo->iSolidColor);
}
// get the bounding rectangle for the path. this is used to checked
// against the clipping for optimization.
PATHOBJ_vGetBounds(ppo, &rcfxBound);
// get a RECTL which is guaranteed to bound the path.
rclBound.left = FXTOL(rcfxBound.xLeft);
rclBound.top = FXTOL(rcfxBound.yTop);
rclBound.right = FXTOL(rcfxBound.xRight + FIX_ONE);
rclBound.bottom = FXTOL(rcfxBound.yBottom + FIX_ONE);
//
// Skip the clipping operation when inside BEGIN_PATH and END_PATH escapes
//
if (pdev->dwFlags & PDEV_INSIDE_PATHESCAPE) {
bClipping = FALSE;
if (! DrvCommonPath(pdev, ppo, FALSE, &bPathExists, pxo, pbo, pptlBrushOrg, plineattrs))
return FALSE;
} else {
bClipping = bDoClipObj(pdev, pco, NULL, &rclBound);
if (! DrvCommonPath(pdev, ppo, TRUE, &bPathExists, pxo, pbo, pptlBrushOrg, plineattrs))
return FALSE;
}
if (bPathExists)
{
// now transform for geometric lines if necessary.
if (plineattrs->fl & LA_GEOMETRIC)
ps_geolinexform(pdev, plineattrs, pxo);
// now stroke the path.
ps_stroke(pdev);
// restore the CTM if a transform for a geometric line was in effect.
if (pdev->cgs.dwFlags & CGS_GEOLINEXFORM)
{
psputs(pdev, "SM\n");
pdev->cgs.dwFlags &= ~CGS_GEOLINEXFORM;
}
}
// restore the clip path to what it was before this call.
if (bClipping)
ps_restore(pdev, TRUE, FALSE);
return(TRUE);
}
//--------------------------------------------------------------------------
// BOOL DrvFillPath(pso, ppo, pco, pbo, pptlBrushOrg, mix, flOptions)
// SURFOBJ *pso;
// PATHOBJ *ppo;
// CLIPOBJ *pco;
// BRUSHOBJ *pbo;
// PPOINTL pptlBrushOrg;
// MIX mix;
// FLONG flOptions;
//
// Parameters:
//
// Returns:
// This function returns TRUE.
//
// History:
// 03-May-1991 -by- Kent Settle [kentse]
// Wrote it.
//--------------------------------------------------------------------------
BOOL DrvFillPath(pso, ppo, pco, pbo, pptlBrushOrg, mix, flOptions)
SURFOBJ *pso;
PATHOBJ *ppo;
CLIPOBJ *pco;
BRUSHOBJ *pbo;
PPOINTL pptlBrushOrg;
MIX mix;
FLONG flOptions;
{
PDEVDATA pdev;
RECTL rclBounds;
RECTFX rcfxBounds;
BOOL gsaved, result;
TRACEDDIENTRY("DrvFillPath");
// get the pointer to our DEVDATA structure and make sure it is ours.
pdev = (PDEVDATA) pso->dhpdev;
if (! bValidatePDEV(pdev) || (pdev->dwFlags & PDEV_CANCELDOC))
return FALSE;
if (pdev->dwFlags & PDEV_IGNORE_GDI)
return TRUE;
// get the bounding rectangle of the path
PATHOBJ_vGetBounds(ppo, &rcfxBounds);
rclBounds.left = FXTOL(rcfxBounds.xLeft);
rclBounds.right = FXTOL(rcfxBounds.xRight) + 1;
rclBounds.top = FXTOL(rcfxBounds.yTop);
rclBounds.bottom = FXTOL(rcfxBounds.yBottom) + 1;
//
// Skip the clipping operation when inside BEGIN_PATH and END_PATH escapes
//
gsaved = (pdev->dwFlags & PDEV_INSIDE_PATHESCAPE) ?
FALSE :
bDoClipObj(pdev, pco, NULL, &rclBounds);
result = DrvCommonPath(pdev, ppo, FALSE, NULL, NULL, NULL, NULL, NULL) &&
ps_patfill(pdev, pso, flOptions, pbo, pptlBrushOrg, MixToRop4(mix), &rclBounds, FALSE, TRUE);
if (gsaved)
ps_restore(pdev, TRUE, FALSE);
return result;
}
//--------------------------------------------------------------------------
// BOOL DrvStrokeAndFillPath(pso, ppo, pco, pxo, pboStroke, plineattrs,
// pboFill, pptlBrushOrg, mixFill, flOptions)
// SURFOBJ *pso;
// PATHOBJ *ppo;
// CLIPOBJ *pco;
// XFORMOBJ *pxo;
// BRUSHOBJ *pboStroke;
// PLINEATTRS plineattrs;
// BRUSHOBJ *pboFill;
// PPOINTL pptlBrushOrg;
// MIX mixFill;
// FLONG flOptions;
//
// Parameters:
//
// Returns:
// This function returns TRUE.
//
// History:
// 03-May-1991 -by- Kent Settle [kentse]
// Wrote it.
//--------------------------------------------------------------------------
BOOL DrvStrokeAndFillPath(pso, ppo, pco, pxo, pboStroke, plineattrs,
pboFill, pptlBrushOrg, mixFill, flOptions)
SURFOBJ *pso;
PATHOBJ *ppo;
CLIPOBJ *pco;
XFORMOBJ *pxo;
BRUSHOBJ *pboStroke;
PLINEATTRS plineattrs;
BRUSHOBJ *pboFill;
PPOINTL pptlBrushOrg;
MIX mixFill;
FLONG flOptions;
{
PDEVDATA pdev;
RECTL rclBounds;
RECTFX rcfxBounds;
ULONG ulColor;
BOOL gsaved, result;
TRACEDDIENTRY("DrvStrokeAndFillPath");
// get the pointer to our DEVDATA structure and make sure it is ours.
pdev = (PDEVDATA) pso->dhpdev;
if (! bValidatePDEV(pdev) || (pdev->dwFlags & PDEV_CANCELDOC))
return FALSE;
if (pdev->dwFlags & PDEV_IGNORE_GDI) return TRUE;
// deal with LINEATTRS.
if (!(ps_setlineattrs(pdev, plineattrs, pxo)))
return(FALSE);
// output the line color to stroke with. do this before we handle
// clipping, so the line color will remain beyond the gsave/grestore.
if (pboStroke->iSolidColor == NOT_SOLID_COLOR)
{
//!!! this needs to be fixed!!! -kentse.
ulColor = RGB_GRAY;
ps_setrgbcolor(pdev, (PSRGB *)&ulColor);
}
else
{
// we have a solid brush, so simply output the line color.
ps_setrgbcolor(pdev, (PSRGB *)&pboStroke->iSolidColor);
}
// get the bounding rectangle of the path
PATHOBJ_vGetBounds(ppo, &rcfxBounds);
rclBounds.left = FXTOL(rcfxBounds.xLeft);
rclBounds.right = FXTOL(rcfxBounds.xRight) + 1;
rclBounds.top = FXTOL(rcfxBounds.yTop);
rclBounds.bottom = FXTOL(rcfxBounds.yBottom) + 1;
//
// Skip the clipping operation when inside BEGIN_PATH and END_PATH escapes
//
gsaved = (pdev->dwFlags & PDEV_INSIDE_PATHESCAPE) ?
FALSE :
bDoClipObj(pdev, pco, NULL, &rclBounds);
result = DrvCommonPath(pdev, ppo, FALSE, NULL, NULL, NULL, NULL, NULL);
// save the path. then fill it. then restore the path which
// was wiped out when it was filled so we can stroke it. TRUE
// means to do a gsave, not a save command.
if (result && ps_save(pdev, TRUE, FALSE)) {
if (! ps_patfill(pdev,
pso,
flOptions,
pboFill,
pptlBrushOrg,
MixToRop4(mixFill),
&rclBounds,
FALSE,
TRUE))
{
result = FALSE;
}
if (! ps_restore(pdev, TRUE, FALSE))
result = FALSE;
if (result) {
// now transform for geometric lines if necessary.
if (plineattrs->fl & LA_GEOMETRIC)
ps_geolinexform(pdev, plineattrs, pxo);
ps_stroke(pdev);
// restore the CTM if a transform for a geometric line was in effect.
if (pdev->cgs.dwFlags & CGS_GEOLINEXFORM) {
psputs(pdev, "SM\n");
pdev->cgs.dwFlags &= ~CGS_GEOLINEXFORM;
}
}
} else
result = FALSE;
if (gsaved)
ps_restore(pdev, TRUE, FALSE);
return result;
}
BOOL _isrightbox(PDEVDATA pdev, POINTFIX pptfx[])
/* draw right rectangle a la Win 3, for compatibility with WinWord 6 */
{
BOOL isbox;
isbox = pptfx[0].y == pptfx[1].y && pptfx[1].x == pptfx[2].x &&
pptfx[2].y == pptfx[3].y && pptfx[3].x == pptfx[0].x ;
if (isbox) {
RECTL r;
r.left = FXTOL(pptfx[1].x);
r.top = FXTOL(pptfx[1].y);
r.right = FXTOL(pptfx[0].x);
r.bottom = FXTOL(pptfx[2].y);
ps_box(pdev, &r, FALSE);
}
return isbox;
}
//--------------------------------------------------------------------------
// BOOL DrvCommonPath(pdev, ppo, bStrokeOnly, pbPathExists)
// PDEVDATA pdev;
// PATHOBJ *ppo;
// BOOL bStrokeOnly;
// BOOL *pbPathExists;
//
// Parameters:
//
// Returns:
// This function returns TRUE.
//
// History:
// 02-May-1991 -by- Kent Settle [kentse]
// Wrote it.
//--------------------------------------------------------------------------
BOOL DrvCommonPath(pdev, ppo, bStrokeOnly, pbPathExists, pxo, pbo,
pptlBrushOrg, plineattrs)
PDEVDATA pdev;
PATHOBJ *ppo;
BOOL bStrokeOnly;
BOOL *pbPathExists;
XFORMOBJ *pxo;
BRUSHOBJ *pbo;
PPOINTL pptlBrushOrg;
PLINEATTRS plineattrs;
{
PATHDATA pathdata;
POINTL ptl, ptl1, ptl2;
POINTFIX *pptfx;
LONG cPoints, totalPoints;
BOOL bMore;
BOOL bPathExists;
// Before we enumerate the path, let's make sure we have a clean start.
// Don't do it if we're currently inside BEGIN_PATH and END_PATH escapes.
if (! (pdev->dwFlags & PDEV_INSIDE_PATHESCAPE))
ps_newpath(pdev);
// enumerate the path, doing what needs to be done along the way.
PATHOBJ_vEnumStart(ppo);
bPathExists = FALSE;
totalPoints = 0;
do {
bMore = PATHOBJ_bEnum(ppo, &pathdata);
// get a local pointer to the array of POINTFIX's.
pptfx = pathdata.pptfx;
cPoints = (LONG) pathdata.count;
if (pathdata.flags & PD_BEGINSUBPATH) {
// the first path begins a new subpath. it is not connected
// to the previous subpath. note that if this flag is not
// set, then the starting point for the first curve to be
// drawn from this data is the last point returned in the
// previous call.
if (pathdata.flags & PD_RESETSTYLE) {
// this bit is defined only if this record begins a new
// subpath. if set, it indicates that the style state
// should be reset to zero at the beginning of the subpath.
// if not set, the style state is defined by the
// LINEATTRS, or continues from the previous path.
DBGMSG(DBG_LEVEL_VERBOSE, "PD_RESETSTYLE flag set.\n");
}
// draw right rectangle a la Win3, for compatibility with WinWord 6
if ((cPoints == 4) &&
!(pathdata.flags & PD_BEZIERS) &&
(pathdata.flags & PD_CLOSEFIGURE) &&
_isrightbox(pdev, pptfx))
{
cPoints = 0;
totalPoints += 4;
bPathExists = TRUE;
} else {
// begin subpath with a moveto command
ptl.x = FXTOL(pptfx->x);
ptl.y = FXTOL(pptfx->y);
pptfx++;
ps_moveto(pdev, &ptl);
cPoints--;
totalPoints++;
}
}
// If the path segment consists of Bezier curves, then
// the number of points must be a multiple of 3.
if ((pathdata.flags & PD_BEZIERS) && (cPoints % 3) != 0) {
SETLASTERROR(ERROR_INVALID_PARAMETER);
return FALSE;
}
while (TRUE) {
// Hack to keep complex path from blowing up the printer!!!
//
// If the current segment has more than ~500 points
// and we're only stroking the path, then output a
// stroke operator to the printer to display whatever
// we've got so far. And then start a new path.
if (bStrokeOnly && totalPoints >= MAX_STROKE_POINTS) {
// now transform for geometric lines if necessary.
if (plineattrs->fl & LA_GEOMETRIC)
ps_geolinexform(pdev, plineattrs, pxo);
// save the current position.
psputs(pdev, "a\n");
// now stroke the path.
ps_stroke(pdev);
// stroking the path blows it away.
bPathExists = FALSE;
totalPoints = 0;
// move to the save current position, so we have a
// current point to start from.
psputs(pdev, "M\n");
// restore the CTM if a transform for a geometric
// line was in effect.
if (pdev->cgs.dwFlags & CGS_GEOLINEXFORM) {
psputs(pdev, "SM\n");
pdev->cgs.dwFlags &= ~CGS_GEOLINEXFORM;
}
}
if (cPoints <= 0) break;
bPathExists = TRUE;
if (pathdata.flags & PD_BEZIERS) {
// Output a Bezier curve segment
ptl.x = FXTOL(pptfx->x);
ptl.y = FXTOL(pptfx->y);
pptfx++;
ptl1.x = FXTOL(pptfx->x);
ptl1.y = FXTOL(pptfx->y);
pptfx++;
ptl2.x = FXTOL(pptfx->x);
ptl2.y = FXTOL(pptfx->y);
pptfx++;
ps_curveto(pdev, &ptl, &ptl1, &ptl2);
cPoints -= 3;
totalPoints += 3;
} else {
// Output a straight line segment
ptl.x = FXTOL(pptfx->x);
ptl.y = FXTOL(pptfx->y);
pptfx++;
ps_lineto(pdev, &ptl);
cPoints--;
totalPoints++;
}
}
if ((pathdata.flags & PD_ENDSUBPATH) &&
(pathdata.flags & PD_CLOSEFIGURE))
{
ps_closepath(pdev);
}
} while(bMore);
if (pbPathExists)
*pbPathExists = bPathExists;
return(TRUE);
}