Sample Code
Windows Driver Samples/ MSPLOT Plotter Driver Sample/ C++/ plotter/ bitblt.c/
/*++ 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 = {0}; RECTL rclMask; RECTL rclBounds; DWORD MaskRop3 = 0; 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 // PLOTDBG(DBG_BITBLT, ("DrvStretchBlt: INVALID ColorAdjustment Flags=%04lx, USE DEFAULT", ((pca) && (pca->caFlags & ~(CA_NEGATIVE | CA_LOG_FILTER))), (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; LONG lBmpDelta; // // 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)); lBmpDelta = GetBmpDelta(BmpFormat, (DoRotate) ? szlDst.cy : szlDst.cx); if ( 0 == lBmpDelta ) { // // To hit this condition, the bitmap must be of 0 area // which should not occur because GDI would never call us // with such a bitmap. But we are being ultra-cautious here // to prevent a divide-by-zero error. // PLOTDBG(DBG_BANDINGHTBLT, ("Bitmap is of 0 area. Skipping")); break; } cScan = (LONG)(MAX_STRETCH_BLT_SIZE / lBmpDelta); // // 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; UNREFERENCED_PARAMETER(psoSrc); UNREFERENCED_PARAMETER(pxlo); UNREFERENCED_PARAMETER(pptlSrc); 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); } } _Use_decl_annotations_ BOOL WINAPI 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 } } _Use_decl_annotations_ BOOL WINAPI 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 ); } _Use_decl_annotations_ BOOL WINAPI 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; UNREFERENCED_PARAMETER(pxo); // // 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 WINAPI 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 fix 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 } } _Use_decl_annotations_ BOOL WINAPI 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 } _Use_decl_annotations_ BOOL WINAPI 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); } _Use_decl_annotations_ ULONG WINAPI 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); }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials