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.
1078 lines
22 KiB
1078 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
path.c
|
|
|
|
Abstract:
|
|
|
|
Implementation of path related DDI entry points:
|
|
DrvStrokePath
|
|
DrvFillPath
|
|
DrvStrokeAndFillPath
|
|
|
|
Environment:
|
|
|
|
PCL-XL driver, kernel mode
|
|
|
|
Revision History:
|
|
|
|
11/08/95 -davidx-
|
|
Created it.
|
|
|
|
mm/dd/yy -author-
|
|
description
|
|
|
|
--*/
|
|
|
|
#include "xldrv.h"
|
|
|
|
BOOL SelectPath(PDEVDATA, PATHOBJ *);
|
|
BOOL SelectFillMode(PDEVDATA, FLONG);
|
|
BOOL SelectPatternBrush(PDEVDATA, DEVBRUSH *);
|
|
BOOL SelectLineAttrs(PDEVDATA, LINEATTRS *, XFORMOBJ *);
|
|
|
|
|
|
|
|
BOOL
|
|
DrvStrokePath(
|
|
SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
XFORMOBJ *pxo,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrushOrg,
|
|
LINEATTRS *plineattrs,
|
|
MIX mix
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implementation of DDI entry point DrvStrokePath.
|
|
Please refer to DDK documentation for more details.
|
|
|
|
Arguments:
|
|
|
|
pso - Identifies the surface on which to draw
|
|
ppo - Defines the path to be stroked
|
|
pco - Defines the clipping path
|
|
pbo - Specifies the brush to be used when drawing the path
|
|
pptlBrushOrg - Defines the brush origin
|
|
plineattrs - Defines the line attributes
|
|
mix - Specifies how to combine the brush with the destination
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful
|
|
FALSE if driver cannot handle the path
|
|
DDI_ERROR if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVDATA pdev;
|
|
|
|
Verbose(("Entering DrvStrokePath...\n"));
|
|
|
|
//
|
|
// Validate input parameters
|
|
//
|
|
|
|
Assert(pso != NULL);
|
|
pdev = (PDEVDATA) pso->dhpdev;
|
|
|
|
if (! ValidDevData(pdev)) {
|
|
|
|
Error(("ValidDevData failed\n"));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return DDI_ERROR;
|
|
}
|
|
|
|
//
|
|
// Set up current graphics state
|
|
// clipping path
|
|
// foreground/background mix mode
|
|
// pen
|
|
// line attributes
|
|
//
|
|
// Send the path object to the printer and stroke it
|
|
//
|
|
|
|
if (! SelectClip(pdev, pco) ||
|
|
! SelectMix(pdev, mix) ||
|
|
! SelectPenBrush(pdev, pbo, pptlBrushOrg, SPB_PEN) ||
|
|
! SelectPenBrush(pdev, NULL, NULL, SPB_BRUSH) ||
|
|
! SelectLineAttrs(pdev, plineattrs, pxo) ||
|
|
! SelectPath(pdev, ppo) ||
|
|
! xl_paintpath(pdev))
|
|
{
|
|
Error(("Cannot stroke path\n"));
|
|
return DDI_ERROR;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DrvFillPath(
|
|
SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrushOrg,
|
|
MIX mix,
|
|
FLONG flOptions
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implementation of DDI entry point DrvFillPath.
|
|
Please refer to DDK documentation for more details.
|
|
|
|
Arguments:
|
|
|
|
pso - Defines the surface on which to draw.
|
|
ppo - Defines the path to be filled
|
|
pco - Defines the clipping path
|
|
pbo - Defines the pattern and colors to fill with
|
|
pptlBrushOrg - Defines the brush origin
|
|
mix - Defines the foreground and background ROPs to use for the brush
|
|
flOptions - Whether to use zero-winding or odd-even rule
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful
|
|
FALSE if driver cannot handle the path
|
|
DDI_ERROR if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVDATA pdev;
|
|
|
|
Verbose(("Entering DrvFillPath...\n"));
|
|
|
|
//
|
|
// Validate input parameters
|
|
//
|
|
|
|
Assert(pso != NULL);
|
|
pdev = (PDEVDATA) pso->dhpdev;
|
|
|
|
if (! ValidDevData(pdev)) {
|
|
|
|
Error(("ValidDevData\n"));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return DDI_ERROR;
|
|
}
|
|
|
|
//
|
|
// Determine whether we should use zero-winding or odd-even rule
|
|
//
|
|
|
|
if (! SelectFillMode(pdev, flOptions))
|
|
return DDI_ERROR;
|
|
|
|
//
|
|
// Set up current graphics state
|
|
// clipping path
|
|
// foreground/background mix mode
|
|
// brush
|
|
//
|
|
// Send the path object to the printer and fill it
|
|
//
|
|
|
|
if (! SelectClip(pdev, pco) ||
|
|
! SelectMix(pdev, mix) ||
|
|
! SelectPenBrush(pdev, NULL, NULL, SPB_PEN) ||
|
|
! SelectPenBrush(pdev, pbo, pptlBrushOrg, SPB_BRUSH) ||
|
|
! SelectPath(pdev, ppo) ||
|
|
! xl_paintpath(pdev))
|
|
{
|
|
Error(("Cannot fill path\n"));
|
|
return DDI_ERROR;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DrvStrokeAndFillPath(
|
|
SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
XFORMOBJ *pxo,
|
|
BRUSHOBJ *pboStroke,
|
|
LINEATTRS *plineattrs,
|
|
BRUSHOBJ *pboFill,
|
|
POINTL *pptlBrushOrg,
|
|
MIX mixFill,
|
|
FLONG flOptions
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implementation of DDI entry point DrvStrokeAndFillPath.
|
|
Please refer to DDK documentation for more details.
|
|
|
|
Arguments:
|
|
|
|
pso - Describes the surface on which to draw
|
|
ppo - Describes the path to be filled
|
|
pco - Defines the clipping path
|
|
pxo - Specifies the world to device coordinate transformation
|
|
pboStroke - Specifies the brush to use when stroking the path
|
|
plineattrs - Specifies the line attributes
|
|
pboFill - Specifies the brush to use when filling the path
|
|
pptlBrushOrg - Specifies the brush origin for both brushes
|
|
mixFill - Specifies the foreground and background ROPs to use
|
|
for the fill brush
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful
|
|
FALSE if driver cannot handle the path
|
|
DDI_ERROR if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVDATA pdev;
|
|
|
|
Verbose(("Entering DrvStrokeAndFillPath...\n"));
|
|
|
|
//
|
|
// Validate input parameters
|
|
//
|
|
|
|
Assert(pso != NULL);
|
|
pdev = (PDEVDATA) pso->dhpdev;
|
|
|
|
if (! ValidDevData(pdev)) {
|
|
|
|
Error(("ValidDevData\n"));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return DDI_ERROR;
|
|
}
|
|
|
|
//
|
|
// Determine whether we should use zero-winding or odd-even rule
|
|
//
|
|
|
|
if (! SelectFillMode(pdev, flOptions))
|
|
return DDI_ERROR;
|
|
|
|
//
|
|
// Set up current graphics state
|
|
// clipping path
|
|
// foreground/background mix mode
|
|
// pen
|
|
// brush
|
|
// line attributes
|
|
//
|
|
// Send the path object to the printer and fill it
|
|
//
|
|
|
|
if (! SelectClip(pdev, pco) ||
|
|
! SelectMix(pdev, mixFill) ||
|
|
! SelectPenBrush(pdev, pboStroke, pptlBrushOrg, SPB_PEN) ||
|
|
! SelectPenBrush(pdev, pboFill, pptlBrushOrg, SPB_BRUSH) ||
|
|
! SelectLineAttrs(pdev, plineattrs, pxo) ||
|
|
! SelectPath(pdev, ppo) ||
|
|
! xl_paintpath(pdev))
|
|
{
|
|
Error(("Cannot fill path\n"));
|
|
return DDI_ERROR;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
DrvPaint(
|
|
SURFOBJ *pso,
|
|
CLIPOBJ *pco,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrushOrg,
|
|
MIX mix
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Implementation of DDI entry point DrvPaint.
|
|
Please refer to DDK documentation for more details.
|
|
|
|
Arguments:
|
|
|
|
pso - Describes the surface on which to draw
|
|
pco - Describes the area to be painted
|
|
pbo - Defines the pattern and colors with which to fill
|
|
pptlBrushOrg - Defines the brush origin
|
|
mix - Defines the foreground and background ROPs to use for the brush
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVDATA pdev;
|
|
|
|
Verbose(("Entering DrvPaint...\n"));
|
|
|
|
//
|
|
// Validate input parameters
|
|
//
|
|
|
|
Assert(pso != NULL);
|
|
pdev = (PDEVDATA) pso->dhpdev;
|
|
|
|
if (! ValidDevData(pdev)) {
|
|
|
|
Error(("ValidDevData\n"));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Set up current graphics state
|
|
// clipping path
|
|
// foreground/background mix mode
|
|
// brush
|
|
//
|
|
|
|
if (! SelectClip(pdev, pco) ||
|
|
! SelectMix(pdev, mix) ||
|
|
! SelectPenBrush(pdev, NULL, NULL, SPB_PEN) ||
|
|
! SelectPenBrush(pdev, pbo, pptlBrushOrg, SPB_BRUSH))
|
|
{
|
|
Error(("Cannot setup current graphics state\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Fill the bounding box of clipping path
|
|
//
|
|
|
|
return xl_rectangle(pdev,
|
|
pco->rclBounds.left, pco->rclBounds.top,
|
|
pco->rclBounds.right, pco->rclBounds.bottom) &&
|
|
xl_paintpath(pdev);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SelectClip(
|
|
PDEVDATA pdev,
|
|
CLIPOBJ *pco
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Select the specified path as the clipping path on the printer
|
|
|
|
Arguments:
|
|
|
|
pdev - Points to our DEVDATA structure
|
|
pco - Specifies the new clipping path
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
PATHOBJ *ppo;
|
|
|
|
//
|
|
// We don't need to do anything if the clipping path was cached
|
|
//
|
|
|
|
if (pdev->cgs.clipId != 0 && pco && pco->iUniq == pdev->cgs.clipId)
|
|
return TRUE;
|
|
|
|
//
|
|
// If the clipping path is NULL, reset to page default
|
|
//
|
|
|
|
if (pco == NULL) {
|
|
|
|
Verbose(("Null clipping path.\n"));
|
|
pdev->cgs.clipId = 0;
|
|
return xl_cliptopage(pdev);
|
|
}
|
|
|
|
//
|
|
// Ask the engine for the clipping path
|
|
//
|
|
|
|
if (! (ppo = CLIPOBJ_ppoGetPath(pco))) {
|
|
|
|
Error(("CLIPOBJ_ppoGetPath\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Download the clipping path to the printer
|
|
//
|
|
|
|
if (! SelectPath(pdev, ppo)) {
|
|
|
|
Error(("SelectPath\n"));
|
|
EngDeletePath(ppo);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Clip to the current path
|
|
//
|
|
|
|
pdev->cgs.clipId = pco->iUniq;
|
|
EngDeletePath(ppo);
|
|
return xl_cliptopath(pdev);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SelectPath(
|
|
PDEVDATA pdev,
|
|
PATHOBJ *ppo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send a path to the printer
|
|
|
|
Arguments:
|
|
|
|
pdev - Points to our DEVDATA structure
|
|
ppo - Defines the path to be sent to the printer
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
--*/
|
|
|
|
#define isrightrect(p) \
|
|
((p[0].x == p[1].x && p[1].y == p[2].y && \
|
|
p[2].x == p[3].x && p[3].y == p[0].y) || \
|
|
(p[0].y == p[1].y && p[1].x == p[2].x && \
|
|
p[2].y == p[3].y && p[3].x == p[0].x))
|
|
|
|
{
|
|
BOOL moreData = TRUE;
|
|
PATHDATA pathData;
|
|
POINTFIX *pPoints;
|
|
ULONG cPoints;
|
|
LONG x, y;
|
|
|
|
//
|
|
// Get rid of any existing path
|
|
//
|
|
|
|
if (! xl_newpath(pdev))
|
|
return FALSE;
|
|
|
|
PATHOBJ_vEnumStart(ppo);
|
|
|
|
while (moreData) {
|
|
|
|
//
|
|
// Retrieve the next subpath from the engine
|
|
//
|
|
|
|
moreData = PATHOBJ_bEnum(ppo, &pathData);
|
|
|
|
if ((cPoints = pathData.count) == 0)
|
|
continue;
|
|
pPoints = pathData.pptfx;
|
|
|
|
if (pathData.flags & PD_BEGINSUBPATH) {
|
|
|
|
ErrorIf(pathData.flags & PD_RESETSTYLE, ("PD_RESETSTYLE ignored.\n"));
|
|
|
|
//
|
|
// Remember the starting cursor position
|
|
//
|
|
|
|
x = FXTOLROUND(pPoints[0].x);
|
|
y = FXTOLROUND(pPoints[0].y);
|
|
|
|
//
|
|
// If the path specifies a rectangle, handle it
|
|
// as a special case to gain performance.
|
|
//
|
|
|
|
if ((cPoints == 4) &&
|
|
!(pathData.flags & PD_BEZIERS) &&
|
|
(pathData.flags & PD_CLOSEFIGURE) &&
|
|
isrightrect(pPoints))
|
|
{
|
|
if (! xl_rectangle(pdev, x, y, FXTOLROUND(pPoints[2].x), FXTOLROUND(pPoints[2].y)))
|
|
return FALSE;
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Starting a new subpath
|
|
//
|
|
|
|
if (! xl_moveto(pdev, x, y))
|
|
return FALSE;
|
|
pPoints++;
|
|
cPoints--;
|
|
}
|
|
|
|
if (cPoints) {
|
|
|
|
//
|
|
// Send the subpath to printer
|
|
//
|
|
|
|
if (!xl_path(pdev,
|
|
(pathData.flags & PD_BEZIERS) ? PATHTYPE_BEZIER : PATHTYPE_LINE,
|
|
x, y, cPoints, pPoints))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Update the current cursor position
|
|
//
|
|
|
|
x = FXTOLROUND(pPoints[cPoints-1].x);
|
|
y = FXTOLROUND(pPoints[cPoints-1].y);
|
|
}
|
|
|
|
//
|
|
// Close the subpath if necessary
|
|
//
|
|
|
|
if ((pathData.flags & PD_ENDSUBPATH) &&
|
|
(pathData.flags & PD_CLOSEFIGURE) &&
|
|
!xl_closepath(pdev))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SelectFillMode(
|
|
PDEVDATA pdev,
|
|
FLONG flOptions
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Specify whether to use zero-winding or odd-even rule for filling
|
|
|
|
Arguments:
|
|
|
|
pdev - Points to our DEVDATA structure
|
|
flOptions - FP_WINDINGMODE or FP_ALTERNATEMODE
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
BYTE fillMode;
|
|
|
|
if (flOptions & FP_WINDINGMODE)
|
|
fillMode = eNonZeroWinding;
|
|
else if (flOptions & FP_ALTERNATEMODE)
|
|
fillMode = eEvenOdd;
|
|
else {
|
|
|
|
Error(("Unknown fill mode: %x\n", flOptions));
|
|
return FALSE;
|
|
}
|
|
|
|
if (fillMode != pdev->cgs.fillMode) {
|
|
|
|
pdev->cgs.fillMode = fillMode;
|
|
return xl_setfillmode(pdev, fillMode);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SelectMix(
|
|
PDEVDATA pdev,
|
|
MIX mix
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Select the specified mix mode into current graphics state
|
|
|
|
Arguments:
|
|
|
|
pdev - Points to our DEVDATA structure
|
|
mix - Brush mix mode
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Table to map a ROP2 to a ROP3
|
|
//
|
|
|
|
static BYTE Rop2ToRop3[] = {
|
|
0xff, // 0x10 = R2_WHITE 1
|
|
0x00, // 0x01 = R2_BLACK 0
|
|
0x05, // 0x02 = R2_NOTMERGEPEN DPon
|
|
0x0a, // 0x03 = R2_MASKNOTPEN DPna
|
|
0x0f, // 0x04 = R2_NOTCOPYPEN PN
|
|
0x50, // 0x05 = R2_MASKPENNOT PDna
|
|
0x55, // 0x06 = R2_NOT Dn
|
|
0x5a, // 0x07 = R2_XORPEN DPx
|
|
0x5f, // 0x08 = R2_NOTMASKPEN DPan
|
|
0xa0, // 0x09 = R2_MASKPEN DPa
|
|
0xa5, // 0x0A = R2_NOTXORPEN DPxn
|
|
0xaa, // 0x0B = R2_NOP D
|
|
0xaf, // 0x0C = R2_MERGENOTPEN DPno
|
|
0xf0, // 0x0D = R2_COPYPEN P
|
|
0xf5, // 0x0E = R2_MERGEPENNOT PDno
|
|
0xfa, // 0x0F = R2_MERGEPEN DPo
|
|
};
|
|
|
|
BYTE foreground, background;
|
|
|
|
//
|
|
// Bit 7-0 defines the foreground ROP2
|
|
// Bit 15-8 defines the foreground ROP2
|
|
//
|
|
|
|
foreground = Rop2ToRop3[mix & 0xf];
|
|
background = Rop2ToRop3[(mix >> 8) & 0xf];
|
|
|
|
if (background == 0xAA) {
|
|
|
|
//
|
|
// Background is transparent
|
|
//
|
|
|
|
if ((pdev->cgs.sourceTxMode != eTransparent && !xl_setsourcetxmode(pdev, eTransparent)) ||
|
|
(pdev->cgs.paintTxMode != eTransparent && !xl_setpainttxmode(pdev, eTransparent)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pdev->cgs.sourceTxMode = pdev->cgs.paintTxMode = eTransparent;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Background is opaque
|
|
//
|
|
|
|
ErrorIf(foreground != background, ("Unsupported mix mode: %x\n", mix));
|
|
|
|
if ((pdev->cgs.sourceTxMode != eOpaque && !xl_setsourcetxmode(pdev, eOpaque)) ||
|
|
(pdev->cgs.paintTxMode != eOpaque && !xl_setpainttxmode(pdev, eOpaque)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pdev->cgs.sourceTxMode = pdev->cgs.paintTxMode = eOpaque;
|
|
}
|
|
|
|
return SelectRop3(pdev, foreground);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SelectRop3(
|
|
PDEVDATA pdev,
|
|
BYTE rop3
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Select the specified raster operation code (ROP3)
|
|
into current graphics state
|
|
|
|
Arguments:
|
|
|
|
pdev - Points to our DEVDATA structure
|
|
rop3 - Specifies the raster operation code to be used
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
if (rop3 != pdev->cgs.rop3) {
|
|
|
|
pdev->cgs.rop3 = rop3;
|
|
return xl_setrop3(pdev, rop3);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SelectPenBrush(
|
|
PDEVDATA pdev,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pOrigin,
|
|
INT mode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Select a new pen or brush
|
|
|
|
Arguments:
|
|
|
|
pdev - Points to our DEVDATA structure
|
|
pbo - Points a BRUSHOBJ
|
|
pOrigin - Specifies pattern brush origin
|
|
mode - Whether the specified BRUSHOBJ is used as pen or brush
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE otherwise
|
|
|
|
--*/
|
|
|
|
{
|
|
PBRUSHINFO pboCached;
|
|
|
|
pboCached = (mode == SPB_PEN) ? &pdev->cgs.pen : &pdev->cgs.brush;
|
|
|
|
//
|
|
// Null brush case
|
|
//
|
|
|
|
if (pbo == NULL) {
|
|
|
|
if (pboCached->iSolidColor == NOT_SOLID_COLOR && pboCached->iUniq == 0)
|
|
return TRUE;
|
|
|
|
pboCached->iSolidColor = NOT_SOLID_COLOR;
|
|
pboCached->iUniq = 0;
|
|
|
|
if (! xl_nullbrush(pdev))
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If the specified brush is the same as the cached brush,
|
|
// then we don't need to do anything. Otherwise, select
|
|
// the brush into current graphics state.
|
|
//
|
|
|
|
if (pbo->iSolidColor == NOT_SOLID_COLOR) {
|
|
|
|
//
|
|
// Bitmap pattern brush
|
|
//
|
|
|
|
DEVBRUSH *pRbrush;
|
|
POINTL origin;
|
|
|
|
if (! (pRbrush = BRUSHOBJ_pvGetRbrush(pbo))) {
|
|
|
|
Error(("BRUSHOBJ_pvGetRbrush failed\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (pOrigin)
|
|
origin = *pOrigin;
|
|
else
|
|
origin.x = origin.y = 0;
|
|
|
|
if (pboCached->iSolidColor == NOT_SOLID_COLOR &&
|
|
pboCached->iUniq == pRbrush->iUniq)
|
|
{
|
|
if (pboCached->origin.x == origin.x &&
|
|
pboCached->origin.y == origin.y)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
} else {
|
|
|
|
pboCached->iSolidColor = NOT_SOLID_COLOR;
|
|
pboCached->iUniq == pRbrush->iUniq;
|
|
pboCached->origin = origin;
|
|
|
|
if (! SelectPatternBrush(pdev, pRbrush))
|
|
return FALSE;
|
|
}
|
|
|
|
if (! xl_setpatternbrush(pdev, PATTERN_BRUSH_ID, &origin))
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Solid color brush
|
|
//
|
|
|
|
if (pboCached->iSolidColor == pbo->iSolidColor)
|
|
return TRUE;
|
|
|
|
if (! xl_setrgbcolor(pdev, pboCached->iSolidColor))
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return (mode == SPB_PEN) ? xl_setpensource(pdev) : xl_setbrushsource(pdev);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SelectPatternBrush(
|
|
PDEVDATA pdev,
|
|
DEVBRUSH *pRbrush
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Send a bitmap pattern brush to the printer
|
|
|
|
Arguments:
|
|
|
|
pdev - Points to our DEVDATA structure
|
|
pRbrush - Specifies a realized bitmap pattern brush
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Prepare to define raster pattern
|
|
//
|
|
|
|
if (! xl_beginrastpattern(pdev,
|
|
eDirectPixel,
|
|
(pRbrush->type == BMF_1BPP) ? e1Bit : e8Bit,
|
|
&pRbrush->size,
|
|
&pRbrush->size,
|
|
PATTERN_BRUSH_ID,
|
|
eTempPattern) ||
|
|
! xl_readrastpattern(pdev, 0, pRbrush->size.cy))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Send pattern bitmap
|
|
//
|
|
|
|
return splwrite(pdev, pRbrush->pBits, pRbrush->lDelta * pRbrush->size.cy) &&
|
|
xl_endrastpattern(pdev);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SelectLineAttrs(
|
|
PDEVDATA pdev,
|
|
LINEATTRS *pLineAttrs,
|
|
XFORMOBJ *pxo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Setup line attributes in the current graphics state
|
|
|
|
Arguments:
|
|
|
|
pdev - Points to our DEVDATA structure
|
|
pLineAttrs - Specifies the line attributes to be selected
|
|
pxo - Specifies a XFORMOBJ for geometric wide lines
|
|
|
|
Return Value:
|
|
|
|
TRUE if successful, FALSE if there is an error
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG cDashs, index;
|
|
WORD dashLength;
|
|
BOOL dashChanged;
|
|
BYTE lineCap;
|
|
BYTE lineJoin;
|
|
LONG miterLimit;
|
|
LONG lineWidth;
|
|
PGSTATE pgs;
|
|
|
|
ErrorIf(pLineAttrs->fl & LA_STARTGAP, ("LA_STARTGAP line style ignored\n"));
|
|
ErrorIf((pLineAttrs->fl & LA_ALTERNATE) && (pLineAttrs->cstyle != 2 || !pLineAttrs->pstyle),
|
|
("Invalid LA_ALTERNATE line style\n"));
|
|
|
|
//
|
|
// Check if we're dealing with dashed lines
|
|
//
|
|
|
|
pgs = &pdev->cgs;
|
|
cDashs = (pLineAttrs->pstyle == NULL) ? 0 : pLineAttrs->cstyle;
|
|
|
|
if (cDashs != pgs->cDashs) {
|
|
|
|
MemFree(pgs->pDashs);
|
|
pgs->pDashs = NULL;
|
|
|
|
if (cDashs > 0 && !(pgs->pDashs = MemAlloc(sizeof(WORD) * cDashs))) {
|
|
|
|
Error(("MemAlloc\n"));
|
|
cDashs = 0;
|
|
}
|
|
}
|
|
|
|
dashChanged = (cDashs != pgs->cDashs);
|
|
|
|
if (pLineAttrs->fl & LA_GEOMETRIC) {
|
|
|
|
FLOATOBJ fo;
|
|
|
|
// Deal with geometric wide lines
|
|
|
|
switch (pLineAttrs->iJoin) {
|
|
|
|
case JOIN_ROUND:
|
|
lineJoin = eRoundJoin;
|
|
break;
|
|
|
|
case JOIN_BEVEL:
|
|
lineJoin = eBevelJoin;
|
|
break;
|
|
|
|
default:
|
|
lineJoin = eMiterJoin;
|
|
break;
|
|
}
|
|
|
|
switch (pLineAttrs->iEndCap) {
|
|
|
|
case ENDCAP_ROUND:
|
|
lineCap = eRoundCap;
|
|
break;
|
|
|
|
case ENDCAP_SQUARE:
|
|
lineCap = eSquareCap;
|
|
break;
|
|
|
|
default:
|
|
lineCap = eButtCap;
|
|
break;
|
|
}
|
|
|
|
Assert(sizeof(LONG) == sizeof(FLOAT));
|
|
miterLimit = *((PLONG) &pLineAttrs->eMiterLimit);
|
|
|
|
//
|
|
// Calcuate line width and optionally line dash
|
|
//
|
|
|
|
// How to we use the specified XFORMOBJ?
|
|
|
|
NOT_IMPLEMENTED();
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Deal with cosmetic lines
|
|
//
|
|
|
|
lineCap = eButtCap;
|
|
lineJoin = eNoJoin;
|
|
miterLimit = pgs->miterLimit;
|
|
lineWidth = pLineAttrs->elWidth.l;
|
|
|
|
for (index=0; index < cDashs; index++) {
|
|
|
|
if (pLineAttrs->pstyle[index].l > MAX_WORD) {
|
|
|
|
Error(("Dash element too long: %d\n", pLineAttrs->pstyle[index].l));
|
|
dashLength = MAX_WORD;
|
|
} else
|
|
dashLength = (WORD) pLineAttrs->pstyle[index].l;
|
|
|
|
if (pgs->pDashs[index] != dashLength) {
|
|
|
|
pgs->pDashs[index] = dashLength;
|
|
dashChanged = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Send any changed line attributes to printer
|
|
//
|
|
|
|
return
|
|
(lineCap == pgs->lineCap || xl_setlinecap(pdev, pgs->lineCap = lineCap)) &&
|
|
(lineJoin == pgs->lineJoin || xl_setlinejoin(pdev, pgs->lineJoin = lineJoin)) &&
|
|
(lineWidth == pgs->lineWidth || xl_setpenwidth(pdev, pgs->lineWidth = lineWidth)) &&
|
|
(miterLimit == pgs->miterLimit || xl_setmiterlimit(pdev, pgs->miterLimit = miterLimit)) &&
|
|
(!dashChanged || xl_setlinedash(pdev, pgs->cDashs = cDashs, pgs->pDashs));
|
|
}
|
|
|