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.
2493 lines
76 KiB
2493 lines
76 KiB
/*++
|
|
|
|
Copyright (c) 1990-2003 Microsoft Corporation
|
|
|
|
|
|
Module Name:
|
|
|
|
bitblt.c
|
|
|
|
|
|
Abstract:
|
|
|
|
This module contains functions which implement bitmap handling for the
|
|
plotter driver.
|
|
|
|
Author:
|
|
|
|
19:15 on Mon 15 Apr 1991
|
|
Created it
|
|
|
|
15-Nov-1993 Mon 19:24:36 updated
|
|
fixed, clean up
|
|
|
|
18-Dec-1993 Sat 10:52:07 updated
|
|
Move some functions from bitbltp.c and move others to htblt.c and
|
|
bitmap.c. This file mainly has DrvXXXXX() which related to the
|
|
bitblt or drawing.
|
|
|
|
27-Jan-1994 Thu 23:41:23 updated
|
|
Revised bitblt so it will handle better ROP3/Rop4 support, also it
|
|
will check the PCD file's ROP caps
|
|
|
|
[Environment:]
|
|
|
|
GDI Device Driver - Plotter.
|
|
|
|
|
|
[Notes:]
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
#define DBG_PLOTFILENAME DbgBitBlt
|
|
|
|
|
|
#define DBG_COPYBITS 0x00000001
|
|
#define DBG_BITBLT 0x00000002
|
|
#define DBG_DRVPAINT 0x00000004
|
|
#define DBG_DRVFILLPATH 0x00000008
|
|
#define DBG_DRVSTROKEANDFILL 0x00000010
|
|
#define DBG_MIXTOROP4 0x00000020
|
|
#define DBG_TEMPSRC 0x00000040
|
|
#define DBG_STRETCHBLT 0x00000080
|
|
#define DBG_BANDINGHTBLT 0x00000100
|
|
#define DBG_DOFILL 0x00000200
|
|
#define DBG_CSI 0x00000400
|
|
|
|
|
|
DEFINE_DBGVAR(0);
|
|
|
|
|
|
//
|
|
// This is the default BANDING size (2MB) for the DrvStretchBlt()
|
|
//
|
|
|
|
#if DBG
|
|
|
|
LPSTR pCSIName[] = { "SRC", "PAT", "TMP" };
|
|
|
|
|
|
DWORD MAX_STRETCH_BLT_SIZE = (2 * 1024 * 1024);
|
|
#else
|
|
#define MAX_STRETCH_BLT_SIZE (2 * 1024 * 1024)
|
|
#endif
|
|
|
|
//
|
|
// This table converts MIX-1 to ROP3 value
|
|
//
|
|
static BYTE amixToRop4[] = {
|
|
0x00, // R2_BLACK 0
|
|
0x05, // R2_NOTMERGEPEN DPon
|
|
0x0a, // R2_MASKNOTPEN DPna
|
|
0x0f, // R2_NOTCOPYPEN PN
|
|
0x50, // R2_MASKPENNOT PDna
|
|
0x55, // R2_NOT Dn
|
|
0x5a, // R2_XORPEN DPx
|
|
0x5f, // R2_NOTMASKPEN DPan
|
|
0xa0, // R2_MASKPEN DPa
|
|
0xa5, // R2_NOTXORPEN DPxn
|
|
0xaa, // R2_NOP D
|
|
0xaf, // R2_MERGENOTPEN DPno
|
|
0xf0, // R2_COPYPEN P
|
|
0xf5, // R2_MERGEPENNOT PDno
|
|
0xfa, // R2_MERGEPEN DPo
|
|
0xff, // R2_WHITE 1
|
|
};
|
|
|
|
extern const POINTL ptlZeroOrigin;
|
|
|
|
|
|
|
|
|
|
|
|
ROP4
|
|
MixToRop4(
|
|
MIX mix
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function converts a MIX value to a ROP4 value
|
|
|
|
Arguments:
|
|
|
|
mix - MIX value to convert, this is defined in wingdi.h and represents
|
|
one of 16 different ROP2 values
|
|
Return Value:
|
|
|
|
ROP4 - the converted value
|
|
|
|
|
|
Author:
|
|
|
|
18-Dec-1993 Sat 09:34:06 created
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
{
|
|
ROP4 rop4Return;
|
|
|
|
//
|
|
// Now pack the two new values by looking up the correct rop codes in our
|
|
// table.
|
|
//
|
|
|
|
|
|
rop4Return = amixToRop4[((mix & 0xff) - 1)];
|
|
|
|
rop4Return |= ( amixToRop4[((( mix >> 8) & 0xff ) - 1 )] << 8 );
|
|
|
|
|
|
PLOTDBG(DBG_MIXTOROP4, ("MixToRop4 before %x after %x", (int) mix,(int) rop4Return));
|
|
|
|
return(rop4Return);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
BandingHTBlt(
|
|
PPDEV pPDev,
|
|
SURFOBJ *psoDst,
|
|
SURFOBJ *psoSrc,
|
|
SURFOBJ *psoMask,
|
|
CLIPOBJ *pco,
|
|
XLATEOBJ *pxlo,
|
|
COLORADJUSTMENT *pca,
|
|
POINTL *pptlBrushOrg,
|
|
PRECTL prclDst,
|
|
PRECTL prclSrc,
|
|
PPOINTL pptlMask,
|
|
WORD HTRop3,
|
|
BOOL InvertMask
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is our internal version of StretchBlt() which always does halftoning
|
|
and banding if the destination bitmap is too large. Since the target
|
|
surface can pottentially be 3 feet by 3 feet, we don't want to
|
|
have a bitmap created that large because of memory requirements. So
|
|
we review the memory requirements and if they are too large we simply
|
|
band, by setting a clip region that moves down the page via a loop. This
|
|
effectively has the halftoning engine simply working on much smaller
|
|
more manageable bitmaps, and we end up sending out virtually the same
|
|
number of bytes.
|
|
|
|
Arguments:
|
|
|
|
pPDev - Pointer to our PDEV
|
|
|
|
psoDst - This is a pointer to a SURFOBJ. It identifies the surface
|
|
on which to draw.
|
|
|
|
psoSrc - This SURFOBJ defines the source for the Blt operation. The
|
|
driver must call GDI Services to find out if this is a device
|
|
managed surface or a bitmap managed by GDI.
|
|
|
|
psoMask - This optional surface provides a mask for the source. It is
|
|
defined by a logic map, i.e. a bitmap with one bit per pel.
|
|
|
|
The mask is used to limit the area of the source that is
|
|
copied. When a mask is provided there is an implicit rop4 of
|
|
0xCCAA, which means that the source should be copied wherever
|
|
the mask is 1, but the destination should be left alone
|
|
wherever the mask is 0.
|
|
|
|
When this argument is NULL there is an implicit rop4 of
|
|
0xCCCC, which means that the source should be copied
|
|
everywhere in the source rectangle.
|
|
|
|
The mask will always be large enough to contain the source
|
|
rectangle, tiling does not need to be done.
|
|
|
|
pco - This is a pointer to a CLIPOBJ. GDI Services are provided
|
|
to enumerate the clipping region as a set of rectangles or
|
|
trapezoids. This limits the area of the destination that will
|
|
be modified.
|
|
|
|
Whenever possible, GDI will simplify the clipping involved.
|
|
However, unlike DrvBitBlt, DrvStretchBlt may be called with a
|
|
single clipping rectangle. This is necessary to prevent
|
|
roundoff errors in clipping the output.
|
|
|
|
pxlo - This is a pointer to an XLATEOBJ. It tells how color indices
|
|
should be translated between the source and target surfaces.
|
|
|
|
The XLATEOBJ can also be queried to find the RGB color for
|
|
any source index. A high quality stretching Blt will need
|
|
to interpolate colors in some cases.
|
|
|
|
pca - This is a pointer to COLORADJUSTMENT structure, if NULL it
|
|
specifies that appiclation did not set any color adjustment
|
|
for this DC, and it is up to the driver to provide a default
|
|
adjustment
|
|
|
|
pptlBrushOrg- Pointer to the POINT structure which specifies the location
|
|
where the halftone brush should alignment to, if this pointer
|
|
is NULL, then we assume that (0, 0) is the brush origin.
|
|
|
|
prclDst - This RECTL defines the area in the coordinate system of the
|
|
destination surface that should be modified.
|
|
|
|
The rectangle is defined by two points. These points are
|
|
not well ordered, i.e. the coordinates of the second point
|
|
are not necessarily larger than those of the first point.
|
|
The rectangle they describe does not include the lower and
|
|
right edges. DrvStretchBlt will never be called with an
|
|
empty destination rectangle.
|
|
|
|
DrvStretchBlt can do inversions in both x and y, this happens
|
|
when the destination rectangle is not well ordered.
|
|
|
|
prclSrc - This RECTL defines the area in the coordinate system of the
|
|
source surface that will be copied. The rectangle is defined
|
|
by two points, and will map onto the rectangle defined by
|
|
prclDst. The points of the source rectangle are well
|
|
ordered. DrvStretch will never be given an empty source
|
|
rectangle.
|
|
|
|
Note that the mapping to be done is defined by prclSrc and
|
|
prclDsst. To be precise, the given points in prclDst and
|
|
prclSrc lie on integer coordinates, which we consider to
|
|
correspond to pel centers. A rectangle defined by two such
|
|
points should be considered a geometric rectangle with two
|
|
vertices whose coordinates are the given points, but with 0.5
|
|
subtracted from each coordinate. (The POINTLs should just be
|
|
considered a shorthand notation for specifying these
|
|
fractional coordinate vertices.) Note thate the edges of any
|
|
such rectangle never intersect a pel, but go around a set of
|
|
pels. Note also that the pels that are inside the rectangle
|
|
are just what you would expect for a "bottom-right exclusive"
|
|
rectangle. The mapping to be done by DrvStretchBlt will map
|
|
the geometric source rectangle exactly onto the geometric
|
|
destination rectangle.
|
|
|
|
pptlMask - This POINTL specifies which pel in the given mask corresponds
|
|
to the upper left pel in the source rectangle. Ignore this
|
|
argument if there is no mask.
|
|
|
|
HTRop3 - HIBYTE(HTRop3) when psoMask is not NULL and
|
|
LOBYTE(HTRop3) when psoMask is NULL
|
|
|
|
InvertMask - TRUE if the mask must be inverted
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if sucessful FALSE if failed
|
|
|
|
Author:
|
|
|
|
07-Mar-1994 Mon 12:52:41 created
|
|
|
|
Revision History:
|
|
|
|
16-Mar-1994 Wed 15:20:42 updated
|
|
Updated for banding the mask so it will works correcly for the engine
|
|
problem.
|
|
|
|
04-May-1994 Wed 11:27:39 updated
|
|
Make rotate type (landscape mode) banding from right to left rather
|
|
than top to bottom
|
|
|
|
29-Nov-1995 Wed 13:00:30 updated
|
|
Mark not reentratable for the same PDEV, this is signal that called to
|
|
the EngStretchBlt(HALFTONE) is failing for some reason
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
CLIPOBJ *pcoNew;
|
|
CLIPOBJ coSave;
|
|
RECTL rclMask;
|
|
RECTL rclBounds;
|
|
DWORD MaskRop3;
|
|
UINT Loop;
|
|
BOOL DoRotate;
|
|
BOOL Ok;
|
|
|
|
|
|
|
|
if (!IS_RASTER(pPDev)) {
|
|
|
|
PLOTDBG(DBG_BANDINGHTBLT, ("BandingHTBlt: Pen Plotter: IGNORE and return OK"));
|
|
return(TRUE);
|
|
}
|
|
|
|
if (pPDev->pPlotGPC->ROPLevel < ROP_LEVEL_1) {
|
|
|
|
PLOTDBG(DBG_BITBLT, ("BandingHTBlt: RopLevel < 1, Cannot Do it"));
|
|
return(TRUE);
|
|
}
|
|
|
|
if (pPDev->Flags & PDEVF_IN_BANDHTBLT) {
|
|
|
|
//
|
|
// Something is wrong here
|
|
//
|
|
|
|
PLOTERR(("BandingHTBlt: Recursive is not allowed, FAILED"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Turn on the flag now
|
|
//
|
|
|
|
pPDev->Flags |= PDEVF_IN_BANDHTBLT;
|
|
|
|
if ((!pca) || (pca->caFlags & ~(CA_NEGATIVE | CA_LOG_FILTER))) {
|
|
|
|
//
|
|
// If we have a NULL or invalid flag then use the default one
|
|
//
|
|
|
|
PLOTWARN(("DrvStretchBlt: INVALID ColorAdjustment Flags=%04lx, USE DEFAULT",
|
|
(pca) ? pca->caFlags : 0));
|
|
|
|
pca = &(pPDev->PlotDM.ca);
|
|
}
|
|
|
|
if (!pptlBrushOrg) {
|
|
|
|
pptlBrushOrg = (PPOINTL)&(ptlZeroOrigin);
|
|
}
|
|
|
|
if (pPDev->PlotDM.Flags & PDMF_PLOT_ON_THE_FLY) {
|
|
|
|
if (psoMask) {
|
|
|
|
PLOTWARN(("BandingHTBlt: PosterMode -> Ignored MASK"));
|
|
psoMask = NULL;
|
|
}
|
|
}
|
|
|
|
if (psoMask) {
|
|
|
|
//
|
|
// If we have a source mask then we will first do (S|D)=0xEE or
|
|
// (~S|D)=0xBB to white out the mask area then use (S&D)=0x88 to AND
|
|
// in the halftoned bitmap. This is done to simulate the desired ROP
|
|
// since the target device can't handle this on its own.
|
|
//
|
|
|
|
rclMask.left = pptlMask->x;
|
|
rclMask.top = pptlMask->y;
|
|
rclMask.right = rclMask.left + (prclSrc->right - prclSrc->left);
|
|
rclMask.bottom = rclMask.top + (prclSrc->bottom - prclSrc->top);
|
|
HTRop3 = (WORD)HIBYTE(HTRop3);
|
|
MaskRop3 = (DWORD)((InvertMask) ? 0xBB : 0xEE);
|
|
Loop = 2;
|
|
|
|
//
|
|
// We must call this function to set up the xlate table correctly
|
|
//
|
|
|
|
IsHTCompatibleSurfObj(pPDev,
|
|
psoMask,
|
|
NULL,
|
|
ISHTF_ALTFMT | ISHTF_HTXB | ISHTF_DSTPRIM_OK);
|
|
|
|
} else {
|
|
|
|
HTRop3 = (WORD)LOBYTE(HTRop3);
|
|
Loop = 1;
|
|
}
|
|
|
|
if (!HTRop3) {
|
|
|
|
HTRop3 = 0xCC;
|
|
}
|
|
|
|
//
|
|
// Now look at how we can modify the clipping rect, in case we need
|
|
// to band.
|
|
//
|
|
|
|
if (pco) {
|
|
|
|
//
|
|
// Save the original clipping object so we can restore it before exiting
|
|
//
|
|
|
|
pcoNew = NULL;
|
|
coSave = *pco;
|
|
|
|
} else {
|
|
|
|
PLOTDBG(DBG_BANDINGHTBLT, ("BandingHTBlt: Create NEW EMPTY pco"));
|
|
|
|
if (!(pcoNew = pco = EngCreateClip())) {
|
|
|
|
PLOTERR(("BandingHTBlt: EngCreateClip() FAILED, got NO CLIP"));
|
|
|
|
pPDev->Flags &= ~PDEVF_IN_BANDHTBLT;
|
|
return(FALSE);
|
|
}
|
|
|
|
pco->iDComplexity = DC_TRIVIAL;
|
|
}
|
|
|
|
PLOTDBG(DBG_BANDINGHTBLT, ("BandingHTBlt: The pco->iDComplexity=%ld",
|
|
pco->iDComplexity));
|
|
|
|
if (pco->iDComplexity == DC_TRIVIAL) {
|
|
|
|
//
|
|
// Since it is trivial, we just draw the whole destination
|
|
//
|
|
|
|
pco->iDComplexity = DC_RECT;
|
|
pco->rclBounds = *prclDst;
|
|
}
|
|
|
|
//
|
|
// Now make sure our bounds will not go outside of the surface
|
|
//
|
|
|
|
rclBounds.left =
|
|
rclBounds.top = 0;
|
|
rclBounds.right = psoDst->sizlBitmap.cx;
|
|
rclBounds.bottom = psoDst->sizlBitmap.cy;
|
|
|
|
if (IntersectRECTL(&rclBounds, &(pco->rclBounds))) {
|
|
|
|
PLOTDBG(DBG_BANDINGHTBLT,
|
|
("BandingHTBlt: rclBounds=(%ld, %ld)-(%ld, %ld), %ld x %ld, ROP=%02lx",
|
|
rclBounds.left, rclBounds.top,
|
|
rclBounds.right, rclBounds.bottom,
|
|
rclBounds.right - rclBounds.left,
|
|
rclBounds.bottom - rclBounds.top, (DWORD)HTRop3));
|
|
|
|
} else {
|
|
|
|
PLOTDBG(DBG_BANDINGHTBLT, ("BandingHTBlt: rclBounds=NULL, NOTHING TO DO"));
|
|
Loop = 0;
|
|
}
|
|
|
|
//
|
|
// Now let's band it through
|
|
//
|
|
|
|
DoRotate = (BOOL)(pPDev->PlotForm.BmpRotMode == BMP_ROT_RIGHT_90);
|
|
Ok = TRUE;
|
|
|
|
while ((Ok) && (Loop--) && (!PLOT_CANCEL_JOB(pPDev))) {
|
|
|
|
RECTL rclDst;
|
|
SIZEL szlDst;
|
|
LONG cScan;
|
|
DWORD BmpFormat;
|
|
DWORD OHTFlags;
|
|
|
|
//
|
|
// When Loop = 1 then we are doing the MASK
|
|
// When Loop = 0 then we are doing the SOURCE
|
|
//
|
|
// We will band only MAX_STRETCH_BLT_SIZE at once
|
|
//
|
|
|
|
rclDst = *prclDst;
|
|
szlDst.cx = rclDst.right - rclDst.left;
|
|
szlDst.cy = rclDst.bottom - rclDst.top;
|
|
BmpFormat = (DWORD)((Loop) ? BMF_1BPP : HTBMPFORMAT(pPDev));
|
|
|
|
cScan = (LONG)(MAX_STRETCH_BLT_SIZE /
|
|
GetBmpDelta(BmpFormat, (DoRotate) ? szlDst.cy :
|
|
szlDst.cx));
|
|
|
|
|
|
//
|
|
// We always want at least 8 scan lines and also a multiple of 8.
|
|
//
|
|
|
|
|
|
if (!cScan) {
|
|
|
|
cScan = 8;
|
|
|
|
} else if (cScan & 0x07) {
|
|
|
|
cScan = (LONG)((cScan + 7) & ~(DWORD)0x07);
|
|
}
|
|
|
|
|
|
PLOTDBG(DBG_BANDINGHTBLT, ("BandingHTBlt: cScan=%ld, Total=%ld",
|
|
cScan, (DoRotate) ? szlDst.cx : szlDst.cy));
|
|
|
|
OHTFlags = 0;
|
|
|
|
while ((Ok) &&
|
|
(!PLOT_CANCEL_JOB(pPDev)) &&
|
|
(rclDst.top < prclDst->bottom) &&
|
|
(rclDst.right > prclDst->left)) {
|
|
|
|
if (DoRotate) {
|
|
|
|
if ((rclDst.left = rclDst.right - cScan) < prclDst->left) {
|
|
|
|
rclDst.left = prclDst->left;
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((rclDst.bottom = rclDst.top + cScan) > prclDst->bottom) {
|
|
|
|
rclDst.bottom = prclDst->bottom;
|
|
}
|
|
}
|
|
|
|
pco->rclBounds = rclBounds;
|
|
|
|
if (IntersectRECTL(&(pco->rclBounds), &rclDst)) {
|
|
|
|
PLOTDBG(DBG_BANDINGHTBLT,
|
|
("BandingHTBlt: Banding RECTL=(%ld, %ld)-(%ld, %ld), %ld x %ld",
|
|
pco->rclBounds.left, pco->rclBounds.top,
|
|
pco->rclBounds.right, pco->rclBounds.bottom,
|
|
pco->rclBounds.right - pco->rclBounds.left,
|
|
pco->rclBounds.bottom - pco->rclBounds.top));
|
|
|
|
if (Loop) {
|
|
|
|
SURFOBJ *psoNew;
|
|
HBITMAP hNewBmp;
|
|
RECTL rclNew;
|
|
|
|
//
|
|
// We have a mask, so create a 1BPP bitmap, and stretch it
|
|
// to the new destination size, then output it using
|
|
// MaskRop3
|
|
//
|
|
|
|
Ok = FALSE;
|
|
|
|
PLOTDBG(DBG_CSI, ("BandingHTBlt: CreateBitmapSURFOBJ(MASK)"));
|
|
|
|
if (psoNew = CreateBitmapSURFOBJ(pPDev,
|
|
&hNewBmp,
|
|
pco->rclBounds.right -
|
|
pco->rclBounds.left,
|
|
pco->rclBounds.bottom -
|
|
pco->rclBounds.top,
|
|
BMF_1BPP,
|
|
NULL)) {
|
|
|
|
rclNew.left = prclDst->left - pco->rclBounds.left;
|
|
rclNew.top = prclDst->top - pco->rclBounds.top;
|
|
rclNew.right = rclNew.left + szlDst.cx;
|
|
rclNew.bottom = rclNew.top + szlDst.cy;
|
|
|
|
PLOTDBG(DBG_BANDINGHTBLT,
|
|
("BandingHTBlt: Banding MASK RECTL=(%ld, %ld)-(%ld, %ld), %ld x %ld",
|
|
rclNew.left, rclNew.top,
|
|
rclNew.right, rclNew.bottom,
|
|
psoNew->sizlBitmap.cx,
|
|
psoNew->sizlBitmap.cy));
|
|
|
|
if (EngStretchBlt(psoNew, // psoDst
|
|
psoMask, // psoSrc
|
|
NULL, // psoMask,
|
|
NULL, // pco
|
|
NULL, // pxlo
|
|
NULL, // pca
|
|
pptlBrushOrg, // pptlHTOrg
|
|
&rclNew, // prclDst
|
|
&rclMask, // prclSrc
|
|
NULL, // pptlMask
|
|
BLACKONWHITE)) {
|
|
|
|
|
|
if (!(Ok = OutputHTBitmap(pPDev,
|
|
psoNew,
|
|
NULL,
|
|
(PPOINTL)&rclDst,
|
|
NULL,
|
|
MaskRop3,
|
|
&OHTFlags))) {
|
|
|
|
PLOTERR(("BandingHTBlt: OutputHTBitmap(M|D) FAILED"));
|
|
}
|
|
|
|
} else {
|
|
|
|
PLOTERR(("BandingHTBlt: EngStretchBlt(MASK B/W) FAILED"));
|
|
}
|
|
|
|
//
|
|
// Delete this band of the mask bitmap
|
|
//
|
|
|
|
EngUnlockSurface(psoNew);
|
|
|
|
PLOTDBG(DBG_CSI, ("BandingHTBlt: EngDeleteSuface(MASK)"));
|
|
|
|
if (!EngDeleteSurface((HSURF)hNewBmp)) {
|
|
|
|
PLOTERR(("PLOTTER: BandingHTBlt, EngDeleteSurface(%p) FAILED",
|
|
(DWORD_PTR)hNewBmp));
|
|
}
|
|
|
|
} else {
|
|
|
|
PLOTERR(("BandingHTBlt: Create MASK SURFOBJ (%ld x %ld) failed",
|
|
pco->rclBounds.right - pco->rclBounds.left,
|
|
pco->rclBounds.bottom - pco->rclBounds.top));
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
//
|
|
// We must pass the psoMask/pptlMask so the haltone
|
|
// operations will not overwrite the non masked
|
|
// area (erasing it).
|
|
//
|
|
|
|
pPDev->Rop3CopyBits = HTRop3;
|
|
|
|
if (!(Ok = EngStretchBlt(psoDst, // psoDst
|
|
psoSrc, // psoSrc
|
|
psoMask, // psoMask,
|
|
pco, // pco
|
|
pxlo, // pxlo
|
|
pca, // pca
|
|
pptlBrushOrg, // pptlHTOrg
|
|
prclDst, // prclDst
|
|
prclSrc, // prclSrc
|
|
pptlMask, // pptlMask
|
|
HALFTONE))) {
|
|
|
|
PLOTERR(("BandingHTBlt: EngStretchBlt(Halftone:S&D) FAILED"));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DoRotate) {
|
|
|
|
rclDst.right = rclDst.left;
|
|
|
|
} else {
|
|
|
|
rclDst.top = rclDst.bottom;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// We must do this in order to exit HPGL/2 mode. This is because the
|
|
// next call for the source will go through EngStrecthBlt(HALFTONE)
|
|
// which will re-enter RTL mode again.
|
|
//
|
|
|
|
if (OHTFlags & OHTF_MASK) {
|
|
|
|
OHTFlags |= OHTF_EXIT_TO_HPGL2;
|
|
|
|
OutputHTBitmap(pPDev, NULL, NULL, NULL, NULL, 0xAA, &OHTFlags);
|
|
}
|
|
}
|
|
|
|
if (pcoNew) {
|
|
|
|
EngDeleteClip(pcoNew);
|
|
|
|
} else {
|
|
|
|
*pco = coSave;
|
|
}
|
|
|
|
pPDev->Flags &= ~PDEVF_IN_BANDHTBLT;
|
|
|
|
return(Ok);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DoFill(
|
|
SURFOBJ *psoDst,
|
|
SURFOBJ *psoSrc,
|
|
CLIPOBJ *pco,
|
|
XLATEOBJ *pxlo,
|
|
PRECTL prclDst,
|
|
PPOINTL pptlSrc,
|
|
BRUSHOBJ *pbo,
|
|
PPOINTL pptlBrush,
|
|
ROP4 Rop4
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function fills a RECT area with a brush and takes clipping into
|
|
consideration
|
|
|
|
Arguments:
|
|
|
|
psoDst - Destination surface obj
|
|
|
|
psoSrc - source surface obj
|
|
|
|
pco - Clip obj
|
|
|
|
pxlo - translate obj
|
|
|
|
prclDst - destination rect area
|
|
|
|
pptlSrc - point where source starts
|
|
|
|
pbo - Brush obj to fill with
|
|
|
|
pptlBrush - Brush alignment origin
|
|
|
|
Rop4 - ROP4 to use
|
|
|
|
Return Value:
|
|
|
|
TRUE if ok, FALSE if failed
|
|
|
|
|
|
Author:
|
|
|
|
Created -
|
|
|
|
18-Dec-1993 Sat 09:34:06 created
|
|
Clean up formal argumeneted, commented
|
|
|
|
15-Jan-1994 Sat 01:41:48 updated
|
|
added rclDst to DoFill() in case pco is NULL
|
|
|
|
10-Mar-1994 Thu 00:35:06 updated
|
|
Fixed so when we call DoPolygon it will take prclDst (if not NULL)
|
|
into account by intersect it with the rclBounds in the pco first
|
|
|
|
25-Mar-1994 update
|
|
Modified function to enumerate clipping region if destination
|
|
rectangle exists.
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PPDEV pPDev;
|
|
RECTL rclDst;
|
|
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(psoDst))) {
|
|
|
|
PLOTERR(("DoFill: Invalid pPDev in psoDst"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Here we have to see if the clip obj is trivial or non existant, in which
|
|
// case we pass this directly to fill rect.
|
|
//
|
|
|
|
if ((!pco) ||
|
|
(pco->iDComplexity == DC_RECT) ||
|
|
(pco->iDComplexity == DC_TRIVIAL)) {
|
|
|
|
if ((pco) && (pco->iDComplexity == DC_RECT)) {
|
|
|
|
PLOTDBG(DBG_DOFILL,
|
|
("DoFill: pco = RECT %s", (prclDst) ? ", WITH dest rect" : "" ));
|
|
|
|
//
|
|
// First grab the destination as the bounding rect since,
|
|
// we have a RECT clipping region
|
|
//
|
|
|
|
rclDst = pco->rclBounds;
|
|
|
|
//
|
|
// Now if we also had a destination rect passed in as well,
|
|
// intersect down to the final rect
|
|
//
|
|
|
|
if (prclDst) {
|
|
|
|
if ( !IntersectRECTL(&rclDst, prclDst)) {
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// And finally point to the new rect for the fill
|
|
//
|
|
|
|
prclDst = &rclDst;
|
|
|
|
} else if (!prclDst) {
|
|
|
|
|
|
PLOTWARN(
|
|
("DoFill: No destination rectange and NULL or TRIVIAL pco!"));
|
|
|
|
//
|
|
// We don't have any clipping so fill the target rect
|
|
//
|
|
|
|
rclDst.left =
|
|
rclDst.top = 0;
|
|
rclDst.right = psoDst->sizlBitmap.cx;
|
|
rclDst.bottom = psoDst->sizlBitmap.cy;
|
|
prclDst = &rclDst;
|
|
}
|
|
|
|
return(DoRect(pPDev,
|
|
prclDst,
|
|
pbo,
|
|
NULL,
|
|
pptlBrush,
|
|
Rop4,
|
|
NULL,
|
|
FPOLY_FILL));
|
|
|
|
} else {
|
|
|
|
BOOL Ok = TRUE;
|
|
BOOL bMore;
|
|
HTENUMRCL EnumRects;
|
|
PRECTL pCurClipRect;
|
|
|
|
//
|
|
// We have complex clipping but we also have a destination rect to
|
|
// fill, this means we have to enum the clipping region as rects
|
|
// so we can intersect each one with the target rect..
|
|
//
|
|
|
|
PLOTDBG(DBG_DOFILL,
|
|
("DoFill: pco = COMPLEX %s", (prclDst) ? ", WITH dest rect" : "" ));
|
|
|
|
if (prclDst) {
|
|
|
|
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
|
|
bMore = TRUE;
|
|
|
|
do {
|
|
|
|
//
|
|
// See if the job has been aborted
|
|
//
|
|
|
|
if (PLOT_CANCEL_JOB(pPDev)) {
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Grab the next batch of rectangles
|
|
//
|
|
|
|
if (bMore) {
|
|
|
|
bMore = CLIPOBJ_bEnum(pco, sizeof(EnumRects), (ULONG *)&EnumRects);
|
|
}
|
|
|
|
if (bMore == DDI_ERROR)
|
|
{
|
|
bMore = FALSE;
|
|
Ok = FALSE;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
/// Set up for enuming the clip rectangles
|
|
//
|
|
|
|
pCurClipRect = (PRECTL)&EnumRects.rcl[0];
|
|
|
|
|
|
while ((Ok) && (EnumRects.c--)) {
|
|
|
|
rclDst = *pCurClipRect;
|
|
|
|
//
|
|
// Make sure we have something left to fill after the
|
|
// intersect
|
|
//
|
|
|
|
if( IntersectRECTL(&rclDst, prclDst) ) {
|
|
|
|
Ok = DoRect( pPDev,
|
|
&rclDst,
|
|
pbo,
|
|
NULL,
|
|
pptlBrush,
|
|
Rop4,
|
|
NULL,
|
|
FPOLY_FILL );
|
|
|
|
}
|
|
pCurClipRect++;
|
|
}
|
|
|
|
|
|
} while ( bMore );
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Ok = DoPolygon(pPDev,
|
|
NULL,
|
|
pco,
|
|
NULL,
|
|
pptlBrush,
|
|
pbo,
|
|
NULL,
|
|
Rop4,
|
|
NULL,
|
|
FPOLY_FILL);
|
|
|
|
|
|
}
|
|
|
|
return(Ok);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DrvPaint(
|
|
SURFOBJ *psoDst,
|
|
CLIPOBJ *pco,
|
|
BRUSHOBJ *pbo,
|
|
PPOINTL pptlBrushOrg,
|
|
MIX Mix
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is the most basic drawing function in the driver. As graphic
|
|
calls get failed, the NT graphics engine will reduce those other calls
|
|
(if we fail them) down to DrvPaint. We cannot fail DrvPaint as the engine
|
|
has nowhere else to go.
|
|
|
|
Arguments:
|
|
|
|
Per DDI Spec.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE of OK, FALSE if falied
|
|
|
|
Author:
|
|
|
|
Created
|
|
|
|
18-Dec-1993 Sat 09:27:29 updated
|
|
Updated, commented, change to correct formal header
|
|
|
|
15-Jan-1994 Sat 00:38:41 updated
|
|
Re-arranged and call DrvBitBlt() if can do a damm thing.
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PPDEV pPDev;
|
|
RECTL rclDst;
|
|
DWORD Rop4;
|
|
|
|
//
|
|
// get our PDEV from the SURFOBJ
|
|
//
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(psoDst))) {
|
|
|
|
PLOTERR(("DrvPaint: Invalid pPDev in pso"));
|
|
return(FALSE);
|
|
}
|
|
|
|
PLOTASSERT(0, "DrvPaint: WARNING: pco [%08lx] is NULL or DC_TRIVIAL???",
|
|
(pco) && (pco->iDComplexity != DC_TRIVIAL), pco);
|
|
|
|
if ((pco) &&
|
|
(pco->iDComplexity == DC_TRIVIAL) &&
|
|
(pco->iFComplexity == FC_RECT)) {
|
|
|
|
PLOTWARN(("DrvPaint: <pco> DC_TRIVIAL but NOT FC_RECT, make DC_RECT ??? (%ld,%ld)-(%ld,%ld)",
|
|
pco->rclBounds.left,
|
|
pco->rclBounds.top,
|
|
pco->rclBounds.right,
|
|
pco->rclBounds.bottom));
|
|
|
|
pco->iDComplexity = DC_RECT;
|
|
}
|
|
|
|
//
|
|
// Make sure we don't pass a NULL rect.
|
|
//
|
|
|
|
if ((pco) && (pco->iDComplexity != DC_TRIVIAL)) {
|
|
|
|
rclDst = pco->rclBounds;
|
|
|
|
} else {
|
|
|
|
rclDst.left =
|
|
rclDst.top = 0;
|
|
rclDst.right = psoDst->sizlBitmap.cx;
|
|
rclDst.bottom = psoDst->sizlBitmap.cy;
|
|
}
|
|
|
|
Rop4 = MixToRop4(Mix);
|
|
|
|
//
|
|
// If we can actually draw the passed object with device brushes (etc)
|
|
// then do it now. Otherwise, we will have to simulate it via DrvBitBlt
|
|
//
|
|
|
|
if (GetColor(pPDev, pbo, NULL, NULL, Rop4) > 0) {
|
|
|
|
PLOTDBG(DBG_DRVPAINT, ("DrvPAINT: Calling DoFill()"));
|
|
|
|
return(DoFill(psoDst, // psoDst
|
|
NULL, // psoSrc
|
|
pco, // pco
|
|
NULL, // pxlo
|
|
NULL, // prclDest only fill based on pco
|
|
NULL, // prclSrc
|
|
pbo, // pbo
|
|
pptlBrushOrg, // pptlBrushOrg
|
|
Rop4)); // Rop4
|
|
|
|
} else {
|
|
|
|
PLOTDBG(DBG_DRVPAINT, ("DrvPAINT: Can't do it Calling DrvBitBlt()"));
|
|
|
|
return(DrvBitBlt(psoDst, // psoDst
|
|
NULL, // psoSrc
|
|
NULL, // psoMask
|
|
pco, // pco
|
|
NULL, // pxlo
|
|
&rclDst, // prclDst
|
|
(PPOINTL)&rclDst, // pptlSrc
|
|
NULL, // pptlMask
|
|
pbo, // pbo,
|
|
pptlBrushOrg, // pptlBrushOrg,
|
|
Rop4)); // Rop4
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DrvFillPath(
|
|
SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
BRUSHOBJ *pbo,
|
|
POINTL *pptlBrushOrg,
|
|
MIX Mix,
|
|
FLONG flOptions
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will take a PATHOBJ as a parameter and fill in
|
|
the closed region with the specified brush.
|
|
|
|
Arguments:
|
|
|
|
Per DDI spec.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if ok, FALSE if error
|
|
|
|
Author:
|
|
|
|
18-Dec-1993 Sat 09:27:29 created
|
|
Updated, commented
|
|
|
|
|
|
Created
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PPDEV pPDev;
|
|
ULONG ulOptions;
|
|
ROP4 rop4;
|
|
BOOL bRetVal;
|
|
|
|
|
|
|
|
//
|
|
// Convert the mix to a rop since we use it more than once
|
|
//
|
|
|
|
rop4 = MixToRop4(Mix);
|
|
|
|
PLOTDBG(DBG_DRVFILLPATH, ("DrvFillPath: Mix = %x, Rop4 = %x", Mix, rop4));
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(pso))) {
|
|
|
|
PLOTERR(("DrvFillPath: Invalid pPDev in pso"));
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// Get color will tell us if the requested op can be done in HPGL2 mode
|
|
// if it cant, we have to simulate via DrvBitBlt
|
|
//
|
|
|
|
if (GetColor(pPDev, pbo, NULL, NULL, rop4) > 0 ) {
|
|
|
|
ulOptions = FPOLY_FILL;
|
|
|
|
if (flOptions & FP_WINDINGMODE) {
|
|
|
|
//
|
|
// Set the flag to notify the generic path code about the fill type
|
|
//
|
|
|
|
ulOptions |= FPOLY_WINDING;
|
|
}
|
|
|
|
bRetVal = DoPolygon(pPDev,
|
|
NULL,
|
|
pco,
|
|
ppo,
|
|
pptlBrushOrg,
|
|
pbo,
|
|
NULL,
|
|
rop4,
|
|
NULL,
|
|
ulOptions);
|
|
} else {
|
|
|
|
bRetVal = FALSE;
|
|
|
|
PLOTDBG(DBG_DRVFILLPATH, ("DrvFillPath: Failing because GetColor <= 0 "));
|
|
|
|
}
|
|
|
|
return( bRetVal );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DrvStrokeAndFillPath(
|
|
SURFOBJ *pso,
|
|
PATHOBJ *ppo,
|
|
CLIPOBJ *pco,
|
|
XFORMOBJ *pxo,
|
|
BRUSHOBJ *pboStroke,
|
|
LINEATTRS *plineattrs,
|
|
BRUSHOBJ *pboFill,
|
|
POINTL *pptlBrushOrg,
|
|
MIX MixFill,
|
|
FLONG flOptions
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will take a PATHOBJ as a parameter, fill in
|
|
the closed region with the FILL brush, and stroke the path with
|
|
the STROKE brush.
|
|
|
|
|
|
Arguments:
|
|
|
|
Per DDI
|
|
|
|
Return Value:
|
|
|
|
TRUE if ok, FALSE if error
|
|
|
|
|
|
Author:
|
|
|
|
18-Dec-1993 Sat 09:27:29 created
|
|
Updated, commented
|
|
|
|
|
|
Created by
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PPDEV pPDev;
|
|
ULONG ulOptions;
|
|
BOOL bRetVal;
|
|
ROP4 rop4;
|
|
|
|
|
|
//
|
|
// Convert the mix to a rop since we use it more than once
|
|
//
|
|
|
|
rop4 = MixToRop4(MixFill);
|
|
|
|
|
|
PLOTDBG(DBG_DRVSTROKEANDFILL, ("DrvStrokeAndFillPath: Mix = %x, Rop4 = %x", MixFill, rop4));
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(pso))) {
|
|
|
|
PLOTERR(("DrvStrokeAndFillPath: Invalid pPDev in pso"));
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GetColor(pPDev, pboFill, NULL, NULL, rop4) > 0 ) {
|
|
|
|
|
|
ulOptions = FPOLY_STROKE | FPOLY_FILL;
|
|
|
|
if (flOptions & FP_WINDINGMODE) {
|
|
|
|
ulOptions |= FPOLY_WINDING;
|
|
}
|
|
|
|
bRetVal = DoPolygon(pPDev,
|
|
NULL,
|
|
pco,
|
|
ppo,
|
|
pptlBrushOrg,
|
|
pboFill,
|
|
pboStroke,
|
|
rop4,
|
|
plineattrs,
|
|
ulOptions);
|
|
} else {
|
|
|
|
|
|
bRetVal = FALSE;
|
|
|
|
PLOTDBG(DBG_DRVSTROKEANDFILL,
|
|
("DrvStrokeAndFillPath: Failing because GetColor is <= 0",
|
|
MixFill, rop4));
|
|
|
|
}
|
|
|
|
return(bRetVal);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DrvCopyBits(
|
|
SURFOBJ *psoDst,
|
|
SURFOBJ *psoSrc,
|
|
CLIPOBJ *pco,
|
|
XLATEOBJ *pxlo,
|
|
RECTL *prclDst,
|
|
POINTL *pptlSrc
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert between two bitmap formats
|
|
|
|
Arguments:
|
|
|
|
Per Engine spec.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN
|
|
|
|
|
|
Author:
|
|
|
|
11-Feb-1993 Thu 21:00:43 created
|
|
|
|
09-Feb-1994 Wed 16:49:17 updated
|
|
Adding rclHTBlt to have psoHTBlt correctly tiled, also check if the
|
|
pco is passed.
|
|
|
|
19-Jan-1994 Wed 14:28:45 updated
|
|
Adding hack to handle EngStretchBlt() to our own temp surfobj
|
|
|
|
06-Jan-1994 Thu 04:34:37 updated
|
|
Make sure we do not do this for pen plotter
|
|
|
|
01-Mar-1994 Tue 10:51:58 updated
|
|
Make the call to BandingHTBlt() rather to EngStretchBlt()
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
SURFOBJ *psoHTBlt;
|
|
PPDEV pPDev;
|
|
RECTL rclDst;
|
|
|
|
|
|
//
|
|
// Copy down the destination rectangle
|
|
//
|
|
|
|
rclDst = *prclDst;
|
|
|
|
PLOTDBG(DBG_COPYBITS, ("DrvCopyBits: Dst=(%ld, %ld)-(%ld-%ld) [%ld x %ld]",
|
|
rclDst.left, rclDst.top, rclDst.right, rclDst.bottom,
|
|
rclDst.right - rclDst.left,
|
|
rclDst.bottom - rclDst.top));
|
|
|
|
//
|
|
// The DrvCopyBits() function lets applicatiosn convert between bitmap and
|
|
// device formats.
|
|
//
|
|
// BUT... for our plotter device we cannot read the printer surface
|
|
// bitmap back, so tell the caller that we cannot do it if they
|
|
// really called us with that sort of request.
|
|
//
|
|
|
|
if (psoSrc->iType != STYPE_BITMAP) {
|
|
|
|
DWORD Color = 0xFFFFFF;
|
|
|
|
PLOTASSERT(1, "DrvCopyBits: psoSrc->iType not STYPE_DEVICE",
|
|
psoSrc->iType == STYPE_DEVICE, psoSrc->iType);
|
|
|
|
//
|
|
// Someone tried to copy from a non-bitmap surface, ie STYPE_DEVICE
|
|
//
|
|
|
|
if (pxlo) {
|
|
|
|
Color = XLATEOBJ_iXlate(pxlo, Color);
|
|
}
|
|
|
|
//
|
|
// If we doing XOR then we want to have all area = 0 first
|
|
//
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(psoSrc))) {
|
|
|
|
PLOTERR(("DrvCopyBits: invalid pPDev"));
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pPDev->Rop3CopyBits == 0x66) {
|
|
|
|
PLOTWARN(("DrvCopyBits: Rop3CopyBits = 0x66, Color = 0x0"));
|
|
Color = 0;
|
|
}
|
|
|
|
PLOTWARN(("DrvCopyBits: Cannot copy from DEVICE, Do EngErase=(%ld,%ld)-(%ld, %ld), COLOR=%08lx)",
|
|
rclDst.left, rclDst.top, rclDst.right, rclDst.bottom, Color));
|
|
|
|
return(EngEraseSurface(psoDst, prclDst, Color));
|
|
}
|
|
|
|
if (psoDst->iType != STYPE_DEVICE) {
|
|
|
|
//
|
|
// Someone tried to copy to bitmap surface, ie STYPE_BITMAP
|
|
//
|
|
|
|
PLOTWARN(("DrvCopyBits: Cannot copy to NON-DEVICE destination"));
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(psoDst))) {
|
|
|
|
PLOTERR(("DrvCopyBits: invalid pPDev"));
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// If this is us calling ourselves during bitmap handling do it now.
|
|
//
|
|
|
|
if (psoHTBlt = pPDev->psoHTBlt) {
|
|
|
|
PLOTDBG(DBG_TEMPSRC, ("DrvCopyBits: psoHTBlt=%ld x %ld, psoSrc=%ld x %ld, pptlSrc=(%ld, %ld)",
|
|
psoHTBlt->sizlBitmap.cx, psoHTBlt->sizlBitmap.cy,
|
|
psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy,
|
|
pptlSrc->x, pptlSrc->y));
|
|
|
|
PLOTDBG(DBG_TEMPSRC, ("DrvCopyBits: szlHTBlt=(%ld, %ld)-(%ld, %ld) = %ld x %ld",
|
|
pPDev->rclHTBlt.left, pPDev->rclHTBlt.top,
|
|
pPDev->rclHTBlt.right, pPDev->rclHTBlt.bottom,
|
|
pPDev->rclHTBlt.right - pPDev->rclHTBlt.left,
|
|
pPDev->rclHTBlt.bottom - pPDev->rclHTBlt.top));
|
|
|
|
PLOTASSERT(1, "DrvCopyBits: psoHTBlt Type != psoSrc Type",
|
|
psoHTBlt->iType == psoSrc->iType, 0);
|
|
|
|
PLOTASSERT(0, "DrvCopyBits: ??? pptlSrc [%08lx] != (0, 0)",
|
|
(pptlSrc->x == 0) && (pptlSrc->y == 0), pptlSrc);
|
|
|
|
if ((!pco) || (pco->iDComplexity == DC_TRIVIAL)) {
|
|
|
|
PLOTASSERT(1, "DrvCopyBits: psoHTBlt Size < psoSrc Size",
|
|
(psoHTBlt->sizlBitmap.cx >= psoSrc->sizlBitmap.cx) &&
|
|
(psoHTBlt->sizlBitmap.cy >= psoSrc->sizlBitmap.cy), 0);
|
|
|
|
PLOTASSERT(1, "DrvCopyBits: rclHTBlt > psoHTBlt size",
|
|
(pPDev->rclHTBlt.left <= psoHTBlt->sizlBitmap.cx) &&
|
|
(pPDev->rclHTBlt.right <= psoHTBlt->sizlBitmap.cx) &&
|
|
(pPDev->rclHTBlt.top <= psoHTBlt->sizlBitmap.cy) &&
|
|
(pPDev->rclHTBlt.bottom <= psoHTBlt->sizlBitmap.cy),
|
|
0);
|
|
|
|
PLOTASSERT(1, "DrvCopyBits: pPDev->rclHTBlt Size != psoSrc Size",
|
|
((pPDev->rclHTBlt.right - pPDev->rclHTBlt.left) ==
|
|
psoSrc->sizlBitmap.cx) &&
|
|
((pPDev->rclHTBlt.bottom - pPDev->rclHTBlt.top) ==
|
|
psoSrc->sizlBitmap.cy),
|
|
0);
|
|
|
|
} else if (pco->iDComplexity == DC_RECT) {
|
|
|
|
PLOTWARN(("DrvCopyBits: **** MAY BE EngStretchBlt(HALFTONE) FAILED but we got EngStretchBlt(COLORONCOLOR) instead"));
|
|
|
|
PLOTASSERT(1, "DrvCopyBits: rclHTBlt != pco->rclBounds, pco=%08lx",
|
|
((pPDev->rclHTBlt.right - pPDev->rclHTBlt.left) ==
|
|
(pco->rclBounds.right - pco->rclBounds.left)) &&
|
|
((pPDev->rclHTBlt.bottom - pPDev->rclHTBlt.top) ==
|
|
(pco->rclBounds.bottom - pco->rclBounds.top)), pco);
|
|
|
|
} else {
|
|
|
|
PLOTASSERT(1, "DrvCopyBits: <psoHTBlt>, pco [%08lx] is Complex.",
|
|
pco->iDComplexity != DC_COMPLEX, pco);
|
|
}
|
|
|
|
if (!EngCopyBits(psoHTBlt, // psoDst
|
|
psoSrc, // psoSrc
|
|
pco, // pco
|
|
NULL, // pxlo
|
|
&(pPDev->rclHTBlt), // prclDst
|
|
pptlSrc)) { // pptlSrc
|
|
|
|
PLOTERR(("DrvCopyBits: EngCopyBits(psoHTBlt, psoSrc) Failed"));
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
if (!IS_RASTER(pPDev)) {
|
|
|
|
PLOTDBG(DBG_COPYBITS, ("DrvCopyBits: Pen Plotter: IGNORE and return OK"));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// First validate everything to see if this one is the halftoned result
|
|
// or is compatible with halftoned result, otherwise we will call
|
|
// EngStretchBlt(HALFTONE) halftone the sources then it will eventually
|
|
// come back to this function to output the halftoned result.
|
|
//
|
|
|
|
if (IsHTCompatibleSurfObj(pPDev,
|
|
psoSrc,
|
|
pxlo,
|
|
ISHTF_ALTFMT | ISHTF_HTXB | ISHTF_DSTPRIM_OK)) {
|
|
|
|
DWORD Rop;
|
|
|
|
if (!(Rop = (DWORD)(pPDev->Rop3CopyBits & 0xFF))) {
|
|
|
|
Rop = 0xCC;
|
|
}
|
|
|
|
PLOTDBG(DBG_COPYBITS, ("DrvCopyBits: HTCompatible: Rop=%08lx", Rop));
|
|
|
|
pPDev->Rop3CopyBits = 0xCC; // RESET!!!
|
|
|
|
return(OutputHTBitmap(pPDev,
|
|
psoSrc,
|
|
pco,
|
|
(PPOINTL)&rclDst,
|
|
NULL,
|
|
Rop,
|
|
NULL));
|
|
|
|
} else {
|
|
|
|
RECTL rclSrc;
|
|
|
|
|
|
rclSrc.left = pptlSrc->x;
|
|
rclSrc.top = pptlSrc->y;
|
|
rclSrc.right = rclSrc.left + (rclDst.right - rclDst.left);
|
|
rclSrc.bottom = rclSrc.top + (rclDst.bottom - rclDst.top);
|
|
|
|
//
|
|
// Validate that we only BLT the available source size
|
|
//
|
|
|
|
if ((rclSrc.right > psoSrc->sizlBitmap.cx) ||
|
|
(rclSrc.bottom > psoSrc->sizlBitmap.cy)) {
|
|
|
|
PLOTWARN(("DrvCopyBits: Engine passed SOURCE != DEST size, CLIP IT"));
|
|
|
|
rclSrc.right = psoSrc->sizlBitmap.cx;
|
|
rclSrc.bottom = psoSrc->sizlBitmap.cy;
|
|
|
|
rclDst.right = (LONG)(rclSrc.right - rclSrc.left + rclDst.left);
|
|
rclDst.bottom = (LONG)(rclSrc.bottom - rclSrc.top + rclDst.top);
|
|
}
|
|
|
|
PLOTDBG(DBG_COPYBITS, ("DrvCopyBits CALLING BandingHTBlt()"));
|
|
|
|
return(BandingHTBlt(pPDev, // pPDev
|
|
psoDst, // psoDst
|
|
psoSrc, // psoSrc
|
|
NULL, // psoMask,
|
|
pco, // pco
|
|
pxlo, // pxlo
|
|
NULL, // pca
|
|
NULL, // pptlHTOrg
|
|
&rclDst, // prclDst
|
|
&rclSrc, // prclSrc
|
|
NULL, // pptlMask
|
|
0xCCCC, // HTRop3
|
|
FALSE)); // InvertMask
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DrvStretchBlt(
|
|
SURFOBJ *psoDst,
|
|
SURFOBJ *psoSrc,
|
|
SURFOBJ *psoMask,
|
|
CLIPOBJ *pco,
|
|
XLATEOBJ *pxlo,
|
|
COLORADJUSTMENT *pca,
|
|
POINTL *pptlBrushOrg,
|
|
PRECTL prclDst,
|
|
PRECTL prclSrc,
|
|
PPOINTL pptlMask,
|
|
ULONG iMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function halftones a source rectangle and optionally can invert
|
|
the source and handle a mask.
|
|
|
|
It also provides, StretchBlt capabilities between Device managed and
|
|
GDI managed surfaces. We want the driver to be able to write on GDI
|
|
managed bitmaps, especially when doing halftoning. This allows the same
|
|
algorithm to be used for both GDI and device surfaces.
|
|
|
|
This function is optional in drivers, it can return FALSE if it does
|
|
not know how to handle the work.
|
|
|
|
Arguments:
|
|
|
|
psoDst - This is a pointer to a SURFOBJ. It identifies the surface
|
|
on which to draw.
|
|
|
|
psoSrc - This SURFOBJ defines the source for the Blt operation. The
|
|
driver must call GDI Services to find out if this is a device
|
|
managed surface or a bitmap managed by GDI.
|
|
|
|
psoMask - This optional surface provides a mask for the source. It is
|
|
defined by a logic map, i.e. a bitmap with one bit per pel.
|
|
|
|
The mask is used to limit the area of the source that is
|
|
copied. When a mask is provided there is an implicit rop4 of
|
|
0xCCAA, which means that the source should be copied wherever
|
|
the mask is 1, but the destination should be left alone
|
|
wherever the mask is 0.
|
|
|
|
When this argument is NULL there is an implicit rop4 of
|
|
0xCCCC, which means that the source should be copied
|
|
everywhere in the source rectangle.
|
|
|
|
The mask will always be large enough to contain the source
|
|
rectangle, tiling does not need to be done.
|
|
|
|
pco - This is a pointer to a CLIPOBJ. GDI Services are provided
|
|
to enumerate the clipping region as a set of rectangles or
|
|
trapezoids. This limits the area of the destination that will
|
|
be modified.
|
|
|
|
Whenever possible, GDI will simplify the clipping involved.
|
|
However, unlike DrvBitBlt, DrvStretchBlt may be called with a
|
|
single clipping rectangle. This is necessary to prevent
|
|
roundoff errors in clipping the output.
|
|
|
|
pxlo - This is a pointer to an XLATEOBJ. It tells how color indices
|
|
should be translated between the source and target surfaces.
|
|
|
|
The XLATEOBJ can also be queried to find the RGB color for
|
|
any source index. A high quality stretching Blt will need
|
|
to interpolate colors in some cases.
|
|
|
|
pca - This is a pointer to COLORADJUSTMENT structure, if NULL it
|
|
specified that appiclation did not set any color adjustment
|
|
for this DC, and is up to the driver to provide default
|
|
adjustment
|
|
|
|
pptlBrushOrg- Pointer to the POINT structure to specified the location
|
|
where halftone brush should alignment to, if this pointer is
|
|
NULL then it assume that (0, 0) as origin of the brush
|
|
|
|
prclDst - This RECTL defines the area in the coordinate system of the
|
|
destination surface that can be modified.
|
|
|
|
The rectangle is defined by two points. These points are
|
|
not well ordered, i.e. the coordinates of the second point
|
|
are not necessarily larger than those of the first point.
|
|
The rectangle they describe does not include the lower and
|
|
right edges. DrvStretchBlt will never be called with an
|
|
empty destination rectangle.
|
|
|
|
DrvStretchBlt can do inversions in both x and y, this happens
|
|
when the destination rectangle is not well ordered.
|
|
|
|
prclSrc - This RECTL defines the area in the coordinate system of the
|
|
source surface that will be copied. The rectangle is defined
|
|
by two points, and will map onto the rectangle defined by
|
|
prclDst. The points of the source rectangle are well
|
|
ordered. DrvStretch will never be given an empty source
|
|
rectangle.
|
|
|
|
Note that the mapping to be done is defined by prclSrc and
|
|
prclDsst. To be precise, the given points in prclDst and
|
|
prclSrc lie on integer coordinates, which we consider to
|
|
correspond to pel centers. A rectangle defined by two such
|
|
points should be considered a geometric rectangle with two
|
|
vertices whose coordinates are the given points, but with 0.5
|
|
subtracted from each coordinate. (The POINTLs should just be
|
|
considered a shorthand notation for specifying these
|
|
fractional coordinate vertices.) Note thate the edges of any
|
|
such rectangle never intersect a pel, but go around a set of
|
|
pels. Note also that the pels that are inside the rectangle
|
|
are just what you would expect for a "bottom-right exclusive"
|
|
rectangle. The mapping to be done by DrvStretchBlt will map
|
|
the geometric source rectangle exactly onto the geometric
|
|
destination rectangle.
|
|
|
|
pptlMask - This POINTL specifies which pel in the given mask corresponds
|
|
to the upper left pel in the source rectangle. Ignore this
|
|
argument if there is no given mask.
|
|
|
|
|
|
iMode - This defines how source pels should be combined to get output
|
|
pels. The methods SB_OR, SB_AND, and SB_IGNORE are all simple
|
|
and fast. They provide compatibility for old applications,
|
|
but don't produce the best looking results for color surfaces.
|
|
|
|
|
|
SB_OR On a shrinking Blt the pels should be combined
|
|
with an OR operation. On a stretching Blt pels
|
|
should be replicated.
|
|
|
|
SB_AND On a shrinking Blt the pels should be combined
|
|
with an AND operation. On a stretching Blt
|
|
pels should be replicated.
|
|
|
|
SB_IGNORE On a shrinking Blt enough pels should be
|
|
ignored so that pels don't need to be combined.
|
|
On a stretching Blt pels should be replicated.
|
|
|
|
SB_BLEND RGB colors of output pels should be a linear
|
|
blending of the RGB colors of the pels that get
|
|
mapped onto them.
|
|
|
|
SB_HALFTONE The driver may use groups of pels in the output
|
|
surface to best approximate the color or gray
|
|
level of the input.
|
|
|
|
For this function we will ignored this parameter and always
|
|
output the SB_HALFTONE result
|
|
|
|
Return Value:
|
|
|
|
|
|
TRUE if sucessful FALSE if failed
|
|
|
|
Author:
|
|
|
|
11-Feb-1993 Thu 19:52:29 created
|
|
|
|
06-Jan-1994 Thu 04:34:37 updated
|
|
Make sure we do not do this for pen plotter
|
|
|
|
23-Feb-1994 Wed 11:02:45 updated
|
|
Re-write and take banding the bitmap into account
|
|
|
|
01-Mar-1994 Tue 10:55:03 updated
|
|
spawan out to a separate function and Make call to BandingHTBlt()
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PPDEV pPDev;
|
|
|
|
UNREFERENCED_PARAMETER(iMode); // we always do HALFTONE
|
|
|
|
//
|
|
// get the pointer to our DEVDATA structure and make sure it is ours.
|
|
//
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(psoDst))) {
|
|
|
|
PLOTERR(("DrvStretchBlt: invalid pPDev"));
|
|
return(FALSE);
|
|
}
|
|
|
|
return(BandingHTBlt(pPDev, // pPDev
|
|
psoDst, // psoDst
|
|
psoSrc, // psoSrc
|
|
psoMask, // psoMask,
|
|
pco, // pco
|
|
pxlo, // pxlo
|
|
pca, // pca
|
|
pptlBrushOrg, // pptlHTOrg
|
|
prclDst, // prclDst
|
|
prclSrc, // prclSrc
|
|
pptlMask, // pptlMask
|
|
0x88CC, // HTRo3
|
|
FALSE)); // InvertMask
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
DrvBitBlt(
|
|
SURFOBJ *psoDst,
|
|
SURFOBJ *psoSrc,
|
|
SURFOBJ *psoMask,
|
|
CLIPOBJ *pco,
|
|
XLATEOBJ *pxlo,
|
|
PRECTL prclDst,
|
|
PPOINTL pptlSrc,
|
|
PPOINTL pptlMask,
|
|
BRUSHOBJ *pbo,
|
|
PPOINTL pptlBrushOrg,
|
|
ROP4 Rop4
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Provides general Blt capabilities to device managed surfaces. The Blt
|
|
might be from an Engine managed bitmap. In that case, the bitmap is
|
|
one of the standard format bitmaps. The driver will never be asked
|
|
to Blt to an Engine managed surface.
|
|
|
|
This function is required if any drawing is done to device managed
|
|
surfaces. The basic functionality required is:
|
|
|
|
1 Blt from any standard format bitmap or device surface to a device
|
|
surface,
|
|
|
|
2 with any ROP,
|
|
|
|
3 optionally masked,
|
|
|
|
4 with color index translation,
|
|
|
|
5 with arbitrary clipping.
|
|
|
|
Engine services allow the clipping to be reduced to a series of clip
|
|
rectangles. A translation vector is provided to assist in color index
|
|
translation for palettes.
|
|
|
|
This is a large and complex function. It represents most of the work
|
|
in writing a driver for a raster display device that does not have
|
|
a standard format frame buffer. The Microsoft VGA driver provides
|
|
example code that supports the basic function completely for a planar
|
|
device.
|
|
|
|
NOTE: Plotters do not support copying from device bitmaps. Nor can they
|
|
perform raster operations on bitmaps. Therefore, it is not possible
|
|
to support ROPs which interact with the destination (ie inverting
|
|
the destination). The driver will do its best to map these ROPs
|
|
into ROPs utilizing functions on the Source or Pattern.
|
|
|
|
This driver supports the bitblt cases indicated below:
|
|
|
|
Device -> Memory No
|
|
Device -> Device No
|
|
Memory -> Memory No
|
|
Memory -> Device Yes
|
|
Brush -> Memory No
|
|
Brush -> Device Yes
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
psoDest - This is a pointer to a device managed SURFOBJ. It
|
|
identifies the surface on which to draw.
|
|
|
|
psoSrc - If the rop requires it, this SURFOBJ defines the source
|
|
for the Blt operation. The driver must call the Engine
|
|
Services to find out if this is a device managed surface
|
|
or a bitmap managed by the Engine.
|
|
|
|
psoMask - This optional surface provides another input for the
|
|
Rop4. It is defined by a logic map, i.e. a bitmap with
|
|
one bit per pel. The mask is typically used to limit the
|
|
area of the destination that should be modified. This
|
|
masking is accomplished by a Rop4 whose lower byte is AA,
|
|
leaving the destination unaffected when the mask is 0.
|
|
|
|
This mask, like a brush, may be of any size and is
|
|
assumed to tile to cover the destination of the Blt. If
|
|
this argument is NULL and a mask is required by the Rop4,
|
|
the implicit mask in the brush will be used.
|
|
|
|
pco - This is a pointer to a CLIPOBJ. Engine Services are
|
|
provided to enumerate the clipping region as a set of
|
|
rectangles or trapezoids. This limits the area of the
|
|
destination that will be modified. Whenever possible,
|
|
the Graphics Engine will simplify the clipping involved.
|
|
For example, BitBlt will never be called with exactly one
|
|
clipping rectangle. The Engine will have clipped the
|
|
destination rectangle before calling, so that no clipping
|
|
needs to be considered.
|
|
|
|
pxlo - This is a pointer to an XLATEOBJ. It tells how color
|
|
indices should be translated between the source and
|
|
target surfaces.
|
|
|
|
If the source surface is palette managed, then its colors
|
|
are represented by indices into a list of RGB colors.
|
|
In this case, the XLATEOBJ can be queried to get a
|
|
translate vector that will allow the device driver to
|
|
quickly translate any source index into a color index for
|
|
the destination.
|
|
|
|
The situation is more complicated when the source is, for
|
|
example, RGB but the destination is palette managed. In
|
|
this case a closest match to each source RGB must be
|
|
found in the destination palette. The XLATEOBJ provides
|
|
a service routine to do this matching. (The device
|
|
driver is allowed to do the matching itself when the
|
|
target palette is the default device palette.)
|
|
|
|
prclDst - This RECTL defines the area in the coordinate system of
|
|
the destination surface that will be modified. The
|
|
rectangle is defined as two points, upper left and lower
|
|
right. The lower and right edges of this rectangle are
|
|
not part of the Blt, i.e. the rectangle is lower right
|
|
exclusive. vBitBlt will never be called with an empty
|
|
destination rectangle, and the two points of the
|
|
rectangle will always be well ordered.
|
|
|
|
pptlSrc - This POINTL defines the upper left corner of the source
|
|
rectangle, if there is a source. Ignore this argument
|
|
if there is no source.
|
|
|
|
pptlMask - This POINTL defines which pel in the mask corresponds to
|
|
the upper left corner of the destination rectangle.
|
|
Ignore this argument if no mask is provided with psoMask.
|
|
|
|
pdbrush - This is a pointer to the device's realization of the
|
|
brush to be used in the Blt. The pattern for the Blt is
|
|
defined by this brush. Ignore this argument if the Rop4
|
|
does not require a pattern.
|
|
|
|
pptlBrushOrg - This is a pointer to a POINTL which defines the origin of
|
|
the brush. The upper left pel of the brush is aligned
|
|
here and the brush repeats according to its dimensions.
|
|
Ignore this argument if the Rop4 does not require a
|
|
pattern.
|
|
|
|
Rop4 - This raster operation defines how the mask, pattern,
|
|
source, and destination pels should be combined to
|
|
determine an output pel to be written on the destination
|
|
surface.
|
|
|
|
This is a quaternary raster operation, which is a natural
|
|
extension of the usual ternary rop3. There are 16
|
|
relevant bits in the Rop4, these are like the 8 defining
|
|
bits of a rop3. (We ignore the other bits of the rop3,
|
|
which are redundant.) The simplest way to implement a
|
|
Rop4 is to consider its two bytes separately. The lower
|
|
byte specifies a rop3 that should be computed wherever
|
|
the mask is 0. The high byte specifies a rop3 that
|
|
should then be computed and applied wherever the mask
|
|
is 1.
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if sucessfule FALSE otherwise
|
|
|
|
|
|
Author:
|
|
|
|
04-Dec-1990
|
|
Wrote it.
|
|
|
|
27-Mar-1992 Fri 00:08:43 updated
|
|
1) Remove 'pco' parameter and replaced it with prclClipBound parameter,
|
|
since pco is never referenced, prclClipBound is used for the
|
|
halftone.
|
|
2) Add another parameter to do NOTSRCCOPY
|
|
|
|
11-Feb-1993 Thu 21:29:15 updated
|
|
Modified so that it call DrvStretchBlt(HALFTONE) when it can.
|
|
|
|
18-Dec-1993 Sat 09:08:16 updated
|
|
Clean up for plotter driver
|
|
|
|
06-Jan-1994 Thu 04:34:37 updated
|
|
Make sure we do not do this for pen plotter
|
|
|
|
15-Jan-1994 Sat 04:02:22 updated
|
|
Re-write
|
|
|
|
17-Mar-1994 Thu 22:36:42 updated
|
|
Changed it so we only use PATTERN=psoMask if the ROP4 do not required
|
|
PATTERNs and a MASK is required
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PPDEV pPDev;
|
|
DWORD Rop3FG;
|
|
DWORD Rop3BG;
|
|
RECTL rclSrc;
|
|
RECTL rclPat;
|
|
UINT i;
|
|
BOOL Ok = TRUE;
|
|
|
|
|
|
//
|
|
// if the source is NULL it must be a fill, so call the fill code,
|
|
//
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: ROP4 = %08lx", Rop4));
|
|
|
|
PLOTASSERT(1, "DrvBitBlt: Invalid ROP code = %08lx",
|
|
(Rop4 & 0xffff0000) == 0, Rop4);
|
|
|
|
//
|
|
// get the pointer to our DEVDATA structure and make sure it is ours.
|
|
//
|
|
|
|
if (!(pPDev = SURFOBJ_GETPDEV(psoDst))) {
|
|
|
|
PLOTERR(("DrvBithBlt: invalid pPDev"));
|
|
return(FALSE);
|
|
}
|
|
|
|
if (IS_RASTER(pPDev)) {
|
|
|
|
i = (UINT)pPDev->pPlotGPC->ROPLevel;
|
|
|
|
} else {
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: Pen Plotter: TRY ROP_LEVEL_0"));
|
|
|
|
i = ROP_LEVEL_0;
|
|
}
|
|
|
|
Rop3BG = (DWORD)ROP4_BG_ROP(Rop4);
|
|
Rop3FG = (DWORD)ROP4_FG_ROP(Rop4);
|
|
|
|
switch (i) {
|
|
|
|
case ROP_LEVEL_0:
|
|
|
|
//
|
|
// For RopLevel 0, or Pen Plotter we will only process the pattern
|
|
// which is compatible with our device
|
|
//
|
|
|
|
if (ROP3_NEED_PAT(Rop3FG)) {
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: Device ROP_LEVEL_0, NEED PAT"));
|
|
|
|
if (GetColor(pPDev, pbo, NULL, NULL, Rop3FG) <= 0) {
|
|
|
|
PLOTWARN(("DrvBitBlt: NOT Device Comptible PAT"));
|
|
return(TRUE);
|
|
}
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: Device ROP_LEVEL_0, TRY COMPATIBLE PAT"));
|
|
|
|
} else {
|
|
|
|
PLOTWARN(("DrvBitBlt: Device ROP_LEVEL_0, CANNOT Do RASTER BLT"));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Make it PAT Copy
|
|
//
|
|
|
|
Rop4 = 0xF0F0;
|
|
Rop3BG =
|
|
Rop3FG = 0xF0;
|
|
|
|
break;
|
|
|
|
case ROP_LEVEL_1:
|
|
|
|
//
|
|
// Can only do ROP1 SRC COPY/NOT SRCCOPY
|
|
//
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: Device ROP_LEVEL_1, Rop4=%08lx", Rop4));
|
|
|
|
switch(Rop4 = ROP4_FG_ROP(Rop4)) {
|
|
|
|
case 0xAA:
|
|
case 0xCC:
|
|
case 0x33:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: Make ROP4 = 0xCC"));
|
|
|
|
Rop4 = 0xCC;
|
|
break;
|
|
}
|
|
|
|
Rop4 |= (Rop4 << 8);
|
|
break;
|
|
|
|
|
|
case ROP_LEVEL_2:
|
|
case ROP_LEVEL_3:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: Device RopLevel=%ld, do nothing",
|
|
(DWORD)pPDev->pPlotGPC->ROPLevel));
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Do DrvStrethcBlt (HALFTONE) first if we can. Since there is no way
|
|
// for us to read back the device surface we can only try our best
|
|
// to simulate the requested drawing operation.
|
|
//
|
|
|
|
if (pptlSrc) {
|
|
|
|
rclSrc.left = pptlSrc->x;
|
|
rclSrc.top = pptlSrc->y;
|
|
|
|
} else {
|
|
|
|
rclSrc.left =
|
|
rclSrc.top = 0;
|
|
}
|
|
|
|
rclSrc.right = rclSrc.left + (prclDst->right - prclDst->left);
|
|
rclSrc.bottom = rclSrc.top + (prclDst->bottom - prclDst->top);
|
|
|
|
switch (Rop4) {
|
|
|
|
case 0xAAAA: // D
|
|
|
|
return(TRUE);
|
|
|
|
case 0xAACC:
|
|
case 0xCCAA:
|
|
case 0xAA33:
|
|
case 0x33AA:
|
|
|
|
//
|
|
// If we have ~S (NOT SOURCE) then we want to make the non-mask area
|
|
// black , we do this using S^D (0x66).
|
|
//
|
|
|
|
if ((Rop4 == 0xAA33) || (Rop4 == 0x33AA)) {
|
|
|
|
Rop4 = 0x6666;
|
|
|
|
} else {
|
|
|
|
Rop4 = 0x8888;
|
|
}
|
|
|
|
return(BandingHTBlt(pPDev, // pPDev
|
|
psoDst, // psoDst
|
|
psoSrc, // psoSrc
|
|
psoMask, // psoMask,
|
|
pco, // pco
|
|
pxlo, // pxlo
|
|
NULL, // pca
|
|
pptlBrushOrg, // pptlHTOrg
|
|
prclDst, // prclDst
|
|
&rclSrc, // prclSrc
|
|
pptlMask, // pptlMask
|
|
(WORD)Rop4, // HTRo3
|
|
Rop3FG == 0xAA)); // InvertMask
|
|
|
|
case 0x3333: // ~S
|
|
case 0xCCCC: // S
|
|
|
|
//
|
|
// We will output the bitmap directly to the surface if the following
|
|
// conditions are all met
|
|
//
|
|
// 1. SRC = STYPE_BITMAP
|
|
// 2. Format is compatible with HT
|
|
//
|
|
|
|
if ((psoSrc->iType == STYPE_BITMAP) &&
|
|
(IsHTCompatibleSurfObj(pPDev,
|
|
psoSrc,
|
|
pxlo,
|
|
ISHTF_ALTFMT |
|
|
ISHTF_HTXB |
|
|
ISHTF_DSTPRIM_OK))) {
|
|
|
|
return(OutputHTBitmap(pPDev,
|
|
psoSrc,
|
|
pco,
|
|
(PPOINTL)prclDst,
|
|
&rclSrc,
|
|
Rop4 & 0xFF,
|
|
NULL));
|
|
|
|
} else {
|
|
|
|
//
|
|
// Call BandingHTBlt(Rop4) to do the job
|
|
//
|
|
|
|
return(BandingHTBlt(pPDev, // pPDev
|
|
psoDst, // psoDst
|
|
psoSrc, // psoSrc
|
|
NULL, // psoMask,
|
|
pco, // pco
|
|
pxlo, // pxlo
|
|
NULL, // pca
|
|
pptlBrushOrg, // pptlHTOrg
|
|
prclDst, // prclDst
|
|
&rclSrc, // prclSrc
|
|
NULL, // pptlMask
|
|
(WORD)Rop4, // HTRo3
|
|
FALSE)); // InvertMask
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if ((Rop3BG != Rop3FG) && // NEED MASK?
|
|
(!ROP3_NEED_DST(Rop3BG)) &&
|
|
(!ROP3_NEED_DST(Rop3FG))) {
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: Not required DEST, Calling EngBitBlt()"));
|
|
|
|
if (!(Ok = EngBitBlt(psoDst, // psoDst
|
|
psoSrc, // psoSrc
|
|
psoMask, // psoMask
|
|
pco, // pco
|
|
pxlo, // pxlo
|
|
prclDst, // prclDst
|
|
pptlSrc, // pptlSrc
|
|
pptlMask, // pptlMask
|
|
pbo, // pbo
|
|
pptlBrushOrg, // pptlBrushOrg ZERO
|
|
Rop4))) {
|
|
|
|
PLOTERR(("DrvBitBlt: EngBitBlt(%04lx) FAILED", Rop4));
|
|
}
|
|
|
|
} else {
|
|
|
|
CLONESO CloneSO[CSI_TOTAL];
|
|
|
|
//
|
|
// Clear all the clone surface memory
|
|
//
|
|
|
|
ZeroMemory(CloneSO, sizeof(CloneSO));
|
|
|
|
//
|
|
// We will using psoMask as Pattern ONLY IF
|
|
//
|
|
// 1. ROP4 required a MASK
|
|
// 2. Forground NOT required a PATTERN
|
|
// 3. Background NOT reauired a PATTERN
|
|
//
|
|
|
|
if ((Rop3BG != Rop3FG) &&
|
|
(!ROP3_NEED_PAT(Rop3BG)) &&
|
|
(!ROP3_NEED_PAT(Rop3FG))) {
|
|
|
|
//
|
|
// We will condense the ROP4 to a ROP3 and use the psoMAsk
|
|
// as the Pattern. We must make sure the pptlBrushOrg is NULL
|
|
// so we DON'T align rclPat on the destination.
|
|
//
|
|
|
|
Rop3FG = (Rop3BG & 0xF0) | (Rop3FG & 0x0F);
|
|
Rop3BG = 0xAA;
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: Rop4=%04lx, Pattern=psoMask=%08lx, Rop3=%02lx/%02lx",
|
|
Rop4, psoMask, Rop3BG, Rop3FG));
|
|
|
|
rclPat.left = pptlMask->x;
|
|
rclPat.top = pptlMask->y;
|
|
rclPat.right = rclPat.left + (rclSrc.right - rclSrc.left);
|
|
rclPat.bottom = rclPat.top + (rclSrc.bottom - rclSrc.top);
|
|
pptlBrushOrg = NULL;
|
|
|
|
} else {
|
|
|
|
//
|
|
// We will NOT do the background operation for now
|
|
//
|
|
|
|
if (Rop3FG == 0xAA) {
|
|
|
|
Rop3FG = Rop3BG;
|
|
|
|
} else {
|
|
|
|
Rop3BG = Rop3FG;
|
|
}
|
|
|
|
//
|
|
// We have a real pattern so make sure we aligned rclPat on
|
|
// the destination correctly by passing a valid pptlBrushOrg,
|
|
// NOTE: The rclPat will be setup by CloneBitBltSURFOBJ()
|
|
//
|
|
|
|
psoMask = NULL;
|
|
|
|
if (!pptlBrushOrg) {
|
|
|
|
pptlBrushOrg = (PPOINTL)&ptlZeroOrigin;
|
|
}
|
|
}
|
|
|
|
if (!(Ok = CloneBitBltSURFOBJ(pPDev,
|
|
psoDst,
|
|
psoSrc,
|
|
psoMask,
|
|
pxlo,
|
|
prclDst,
|
|
&rclSrc,
|
|
&rclPat,
|
|
pbo,
|
|
CloneSO,
|
|
Rop3BG,
|
|
Rop3FG))) {
|
|
|
|
PLOTDBG(DBG_BITBLT, ("DrvBitBlt: CloneBitbltSURFOBJ: failed"));
|
|
}
|
|
|
|
if (CloneSO[CSI_SRC].pso) {
|
|
|
|
psoSrc = CloneSO[CSI_SRC].pso;
|
|
pxlo = NULL;
|
|
}
|
|
|
|
//
|
|
// Only do background if BG != FG, and BG != DEST
|
|
//
|
|
|
|
if ((Ok) && (Rop3BG != Rop3FG) && (Rop3BG != 0xAA)) {
|
|
|
|
if (!(Ok = DoRop3(pPDev,
|
|
psoDst,
|
|
psoSrc,
|
|
CloneSO[CSI_PAT].pso,
|
|
CloneSO[CSI_TMP].pso,
|
|
pco,
|
|
pxlo,
|
|
prclDst,
|
|
&rclSrc,
|
|
&rclPat,
|
|
pptlBrushOrg,
|
|
pbo,
|
|
Rop3BG))) {
|
|
|
|
PLOTERR(("DrvBitBlt(Rop3BG=%02lx) FAILED", Rop3BG));
|
|
}
|
|
}
|
|
|
|
if ((Ok) && (Rop3FG != 0xAA)) {
|
|
|
|
if (!(Ok = DoRop3(pPDev,
|
|
psoDst,
|
|
psoSrc,
|
|
CloneSO[CSI_PAT].pso,
|
|
CloneSO[CSI_TMP].pso,
|
|
pco,
|
|
pxlo,
|
|
prclDst,
|
|
&rclSrc,
|
|
&rclPat,
|
|
pptlBrushOrg,
|
|
pbo,
|
|
Rop3FG))) {
|
|
|
|
PLOTERR(("DrvBitBlt(Rop3FG=%02lx) FAILED", Rop3FG));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Release all cloned objects
|
|
//
|
|
|
|
for (i = 0; i < CSI_TOTAL; i++) {
|
|
|
|
if (CloneSO[i].pso) {
|
|
|
|
PLOTDBG(DBG_CSI, ("DrvBitBlt: EngUnlockSuface(%hs)", pCSIName[i]));
|
|
|
|
EngUnlockSurface(CloneSO[i].pso);
|
|
}
|
|
|
|
if (CloneSO[i].hBmp) {
|
|
|
|
PLOTDBG(DBG_CSI, ("DrvBitBlt: EngDeleteSurface(%hs)", pCSIName[i]));
|
|
|
|
if (!EngDeleteSurface((HSURF)CloneSO[i].hBmp)) {
|
|
|
|
PLOTERR(("PLOTTER: DrvBitBlt, EngDeleteSurface(%ld:%p) FAILED",
|
|
(DWORD)i, (DWORD_PTR)CloneSO[i].hBmp));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return(Ok);
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
DrvDitherColor(
|
|
DHPDEV dhpdev,
|
|
ULONG iMode,
|
|
ULONG rgbColor,
|
|
ULONG *pulDither
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the hooked brush creation function, it asks CreateHalftoneBrush()
|
|
to do the actual work (By returning DCR_HALFTONE).
|
|
|
|
|
|
Arguments:
|
|
|
|
dhpdev - DHPDEV passed, it is our pDEV
|
|
|
|
iMode - Not used
|
|
|
|
rgbColor - Solid rgb color to be used
|
|
|
|
pulDither - buffer to put the halftone brush.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN
|
|
|
|
Author:
|
|
|
|
02-May-1995 Tue 10:34:10 created
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
UNREFERENCED_PARAMETER(dhpdev);
|
|
UNREFERENCED_PARAMETER(iMode);
|
|
UNREFERENCED_PARAMETER(rgbColor);
|
|
UNREFERENCED_PARAMETER(pulDither);
|
|
|
|
return(DCR_HALFTONE);
|
|
}
|