/*++ Copyright (c) 2000 Microsoft Corporation Module Name: xlddi.cpp Abstract: Implementation of PCLXL drawing DDI entry points Functions: PCLXLBitBlt PCLXLStretchBlt PCLXLStretchBltROP PCLXLCopyBits PCLXLPlgBlt PCLXLAlphaBlend PCLXLGradientFill PCLXLTextOut PCLXLStrokePath PCLXLFillPath PCLXLStrokeAndFillPath PCLXLRealizeBrush PCLXLStartPage PCLXLSendPage PCLXLEscape PCLXLStartDcc PCLXLEndDoc Environment: Windows XP/Windows Server 2003 family. Revision History: 08/23/99 Created it. --*/ #include "lib.h" #include "gpd.h" #include "winres.h" #include "pdev.h" #include "common.h" #include "xlpdev.h" #include "pclxle.h" #include "pclxlcmd.h" #include "xldebug.h" #include "xlbmpcvt.h" #include "xlgstate.h" #include "xloutput.h" #include "pclxlcmd.h" #include "pclxlcmn.h" #include "xltt.h" //////////////////////////////////////////////////////////////////////////////// // // Globals // extern const LINEATTRS *pgLineAttrs; //////////////////////////////////////////////////////////////////////////////// // // Local function prototypes // HRESULT CommonRopBlt( IN PDEVOBJ pdevobj, IN SURFOBJ *psoSrc, IN CLIPOBJ *pco, IN XLATEOBJ *pxlo, IN BRUSHOBJ *pbo, IN RECTL *prclSrc, IN RECTL *prclDst, IN POINTL *pptlBrush, IN ROP4 rop4); BOOL BSendReadImageData( IN PDEVOBJ pdevobj, IN CompressMode CMode, IN PBYTE pBuf, IN LONG lStart, IN LONG lHeight, IN DWORD dwcbSize); PDWORD PdwChangeTransparentPalette( ULONG iTransColor, PDWORD pdwColorTable, DWORD dwEntries); HRESULT hrChangePixelColorInScanLine( IN PBYTE pubSrc, IN ULONG ulBPP, IN ULONG ulNumPixels, IN ULONG ulTransColor, IN OUT PBYTE pubChanged, IN ULONG ulNumBytes); extern "C" BOOL CreateMaskSurface( SURFOBJ *psoSrc, SURFOBJ *psoMsk, ULONG iTransColor); extern "C" SURFOBJ * CreateBitmapSURFOBJ( PDEV *pPDev, HBITMAP *phBmp, LONG cxSize, LONG cySize, DWORD Format); //////////////////////////////////////////////////////////////////////////////// // // Drawing DDI entries // extern "C" BOOL APIENTRY PCLXLBitBlt( SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclTrg, POINTL *pptlSrc, POINTL *pptlMask, BRUSHOBJ *pbo, POINTL *pptlBrush, ROP4 rop4) /*++ Routine Description: Implementation of DDI entry point DrvBitBlt. Please refer to DDK documentation for more details. Arguments: psoTrg - Describes the target surface psoSrc - Describes the source surface psoMask - Describes the mask for rop4 pco - Limits the area to be modified pxlo - Specifies how color indices are translated between the source and target surfaces prclTrg - Defines the area to be modified pptlSrc - Defines the upper left corner of the source rectangle pptlMask - Defines which pixel in the mask corresponds to the upper left corner of the source rectangle pbo - Defines the pattern for bitblt pptlBrush - Defines the origin of the brush in the Dstination surface rop4 - ROP code that defines how the mask, pattern, source, and Dstination pixels are combined to write to the Dstination surface Return Value: TRUE if successful, FALSE if there is an error --*/ { PDEVOBJ pdevobj = (PDEVOBJ)psoTrg->dhpdev; PXLPDEV pxlpdev; VERBOSE(("PCLXLBitBlt() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; { RECTL rclSrc; // // create prclSrc (source rectangle) // if (pptlSrc) { rclSrc.left = pptlSrc->x; rclSrc.top = pptlSrc->y; rclSrc.right = pptlSrc->x + RECT_WIDTH(prclTrg); rclSrc.bottom = pptlSrc->y + RECT_HEIGHT(prclTrg); } else { rclSrc.left = 0; rclSrc.top = 0; rclSrc.right = RECT_WIDTH(prclTrg); rclSrc.bottom = RECT_HEIGHT(prclTrg); } if (S_OK == CommonRopBlt(pdevobj, psoSrc, pco, pxlo, pbo, &rclSrc, prclTrg, pptlBrush, rop4)) return TRUE; else return FALSE; } } extern "C" BOOL APIENTRY PCLXLStretchBlt( SURFOBJ *psoDst, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, COLORADJUSTMENT *pca, POINTL *pptlHTOrg, RECTL *prclDst, RECTL *prclSrc, POINTL *pptlMask, ULONG iMode) /*++ Routine Description: Implementation of DDI entry point DrvStretchBlt. Please refer to DDK documentation for more details. Arguments: psoDst - Defines the surface on which to draw psoSrc - Defines the source for blt operation psoMask - Defines a surface that provides a mask for the source pco - Limits the area to be modified on the Dstination pxlo - Specifies how color dwIndexes are to be translated between the source and target surfaces pca - Defines color adjustment values to be applied to the source bitmap pptlHTOrg - Specifies the origin of the halftone brush prclDst - Defines the area to be modified on the Dstination surface prclSrc - Defines the area to be copied from the source surface pptlMask - Specifies which pixel in the given mask corresponds to the upper left pixel in the source rectangle iMode - Specifies how source pixels are combined to get output pixels Return Value: TRUE if successful, FALSE if there is an error --*/ { PDEVOBJ pdevobj = (PDEVOBJ)psoDst->dhpdev; PXLPDEV pxlpdev; VERBOSE(("PCLXLStretchBlt() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; if (S_OK == CommonRopBlt(pdevobj, psoSrc, pco, pxlo, NULL, prclSrc, prclDst, NULL, 0xCC)) return TRUE; else return FALSE; } extern "C" BOOL APIENTRY PCLXLStretchBltROP( SURFOBJ *psoDst, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, COLORADJUSTMENT *pca, POINTL *pptlHTOrg, RECTL *prclDst, RECTL *prclSrc, POINTL *pptlMask, ULONG iMode, BRUSHOBJ *pbo, ROP4 rop4) /*++ Routine Description: Implementation of DDI entry point DrvStretchBltROP. Please refer to DDK documentation for more details. Arguments: psoDst - Specifies the target surface psoSrc - Specifies the source surface psoMask - Specifies the mask surface pco - Limits the area to be modified pxlo - Specifies how color indices are translated between the source and target surfaces pca - Defines color adjustment values to be applied to the source bitmap prclHTOrg - Specifies the halftone origin prclDst - Area to be modified on the destination surface prclSrc - Rectangle area on the source surface prclMask - Rectangle area on the mask surface pptlMask - Defines which pixel in the mask corresponds to the upper left corner of the source rectangle iMode - Specifies how source pixels are combined to get output pixels pbo - Defines the pattern for bitblt rop4 - ROP code that defines how the mask, pattern, source, and destination pixels are combined on the destination surface Return Value: TRUE if successful, FALSE if there is an error --*/ { PDEVOBJ pdevobj = (PDEVOBJ)psoDst->dhpdev; PXLPDEV pxlpdev; VERBOSE(("PCLXLStretchBltROP() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; if (S_OK == CommonRopBlt(pdevobj, psoSrc, pco, pxlo, pbo, prclSrc, prclDst, NULL, rop4)) return TRUE; else return FALSE; } extern "C" BOOL APIENTRY PCLXLCopyBits( SURFOBJ *psoDst, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclDst, POINTL *pptlSrc) /*++ Routine Description: Implementation of DDI entry point DrvCopyBits. Please refer to DDK documentation for more details. Arguments: psoDst - Points to the Dstination surface psoSrc - Points to the source surface pxlo - XLATEOBJ provided by the engine pco - Defines a clipping region on the Dstination surface pxlo - Defines the translation of color indices between the source and target surfaces prclDst - Defines the area to be modified pptlSrc - Defines the upper-left corner of the source rectangle Return Value: TRUE if successful, FALSE if there is an error --*/ { PDEVOBJ pdevobj = (PDEVOBJ)psoDst->dhpdev; PXLPDEV pxlpdev; RECTL rclSrc; VERBOSE(("PCLXLCopyBits() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; // // create prclSrc (source rectangle) // rclSrc.top = pptlSrc->y; rclSrc.left = pptlSrc->x; rclSrc.bottom = pptlSrc->y + RECT_HEIGHT(prclDst); rclSrc.right = pptlSrc->x + RECT_WIDTH(prclDst); if (S_OK == CommonRopBlt(pdevobj, psoSrc, pco, pxlo, NULL, &rclSrc, prclDst, NULL, 0xCC)) return TRUE; else return FALSE; } extern "C" BOOL APIENTRY PCLXLPlgBlt( SURFOBJ *psoDst, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo, COLORADJUSTMENT *pca, POINTL *pptlBrushOrg, POINTFIX *pptfixDst, RECTL *prclSrc, POINTL *pptlMask, ULONG iMode) /*++ Routine Description: Implementation of DDI entry point DrvPlgBlt. Please refer to DDK documentation for more details. Arguments: psoDst - Defines the surface on which to draw psoSrc - Defines the source for blt operation psoMask - Defines a surface that provides a mask for the source pco - Limits the area to be modified on the Dstination pxlo - Specifies how color dwIndexes are to be translated between the source and target surfaces pca - Defines color adjustment values to be applied to the source bitmap pptlBrushOrg - Specifies the origin of the halftone brush ppfixDest - Defines the area to be modified on the Dstination surface prclSrc - Defines the area to be copied from the source surface pptlMask - Specifies which pixel in the given mask corresponds to the upper left pixel in the source rectangle iMode - Specifies how source pixels are combined to get output pixels Return Value: TRUE if successful, FALSE if there is an error --*/ { VERBOSE(("PCLXLBltBlt() entry.\n")); return EngPlgBlt(psoDst, psoSrc, psoMask, pco, pxlo, pca, pptlBrushOrg, pptfixDst, prclSrc, pptlMask, iMode); } extern "C" BOOL APIENTRY PCLXLAlphaBlend( SURFOBJ *psoDst, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclDst, RECTL *prclSrc, BLENDOBJ *pBlendObj) /*++ Routine Description: Arguments: Return Value: Note: --*/ { VERBOSE(("PCLXLAlphaBlend() entry.\n")); PDEV *pPDev = (PDEV*)psoDst->dhpdev; BOOL bRet; if (NULL == pPDev) { return FALSE; } pPDev->fMode2 |= PF2_WHITEN_SURFACE; bRet = EngAlphaBlend(psoDst, psoSrc, pco, pxlo, prclDst, prclSrc, pBlendObj); pPDev->fMode2 &= ~(PF2_WHITEN_SURFACE|PF2_SURFACE_WHITENED); return bRet; } extern "C" BOOL APIENTRY PCLXLGradientFill( SURFOBJ *psoDst, CLIPOBJ *pco, XLATEOBJ *pxlo, TRIVERTEX *pVertex, ULONG nVertex, PVOID pMesh, ULONG nMesh, RECTL *prclExtents, POINTL *pptlDitherOrg, ULONG ulMode) /*++ Routine Description: Arguments: Return Value: Note: --*/ { VERBOSE(("PCLXLGradientFill() entry.\n")); PDEV *pPDev = (PDEV*) psoDst->dhpdev; BOOL bRet; if (NULL == pPDev) { return FALSE; } if (ulMode == GRADIENT_FILL_TRIANGLE) { pPDev->fMode2 |= PF2_WHITEN_SURFACE; } bRet = EngGradientFill(psoDst, pco, pxlo, pVertex, nVertex, pMesh, nMesh, prclExtents, pptlDitherOrg, ulMode); pPDev->fMode2 &= ~(PF2_WHITEN_SURFACE|PF2_SURFACE_WHITENED); return bRet; } extern "C" BOOL APIENTRY PCLXLTransparentBlt( SURFOBJ *psoDst, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclDst, RECTL *prclSrc, ULONG iTransColor, ULONG ulReserved) { PDEVOBJ pdevobj = (PDEVOBJ) psoDst->dhpdev; PDEV *pPDev = (PDEV*) psoDst->dhpdev; PXLPDEV pxlpdev = (PXLPDEV)pdevobj->pdevOEM; HRESULT hr = E_FAIL; ULONG ulXlate[2] = {0x0, RGB_WHITE}; //2 colors in psoMsk. Black and White. XLATEOBJ xlo; ZeroMemory ( &xlo, sizeof (XLATEOBJ) ); xlo.cEntries = 2; xlo.pulXlate = (PULONG)ulXlate; xlo.flXlate = XO_TABLE; // use the entries in pulXlate table. if ( NULL == pxlpdev || NULL == psoSrc ) { return FALSE; } // // Step 1. Create a mask and download it to printer using ROP DSO (238 = 0xEE). // The mask is a 1bpp image created out of the image in psoSrc. Wherever // the TransColor is present // in the image, the corresponding pixel in the mask gets value 0. At all other places // the pixel will get value of 1. // if we copy the mask to a color printer (using ROP of SRC_COPY), // you will notice that the image is black and white, // and black is present on the same place where the Transparent Color should be there. // Instead of SRC_COPY if we use rop=238 which is (SOURCE | DESTINATION), the white color // of the mask will get OR'ed with destinaion and the region becomes white. The black // color // of the mask will not be printed and instead whatever is there already on the sheet // (if something is present) will be visible // Assuming x is the pixel already present on the sheet. // 0 | x = x (ORing anything with 0 is anything) // 1 | x = 1 // 1 represents white color (RGB_WHITE = 0xFFFFFF = all 1s). // // Step 2. // In the image, wherever the TransColor is present, change it to white. // Now the image has 2 kinds of white colors. Those that // are originally present in the image, and those that we just put in there. // Step 3. // Download the image with rop DSAnd (=136 = 0x88). // Assuming x is the pixel already present on the sheet // and y be the pixel in the image and 1 represents white color // (RGB_WHITE = 0xFFFFFF = all 1s). // 1 & y = y Image falling on the area that we whited in step 1. // 1 & x = x The white parts of the image (that was earlier TransColor) falling in // the area. // that is supposed to be visible from under the image. // // // // Step 1 Create appropriate mask. // For images that are greater than 1bpp // Use unidrv's CreateMaskSurface to create mask. The logic of a mask surface // is explained above. // For images that are 1bpp // CreateMaskSurface does not create mask for 1bpp image. So for that we'll // create mask ourselves. Since mask is 1bpp and so is the image, we can simply // use the image as the mask, except that we might need to manipulate the palette. // The benefit here is that we are using the same image as mask, instead of // creating a new image and using memory. // if ( BMF_1BPP == psoSrc->iBitmapFormat ) { // // For paletted images (1bpp images have palette), iTransColor is actually the index into // the palette, and not the actual RGB color itself. // As explained above, the transparent color should be black in the mask, while the // non-transparent color should be white. Black is // index 0 in xlo.pulXlate = (PULONG)ulXlate. So if TransColor is 0, then // we can simply use the xlo that we created above. // If not, we need to switch black and white in the palette. // (To repeat. While sending the mask, iTransColor should be sent as black and // the color that is to be printed should be sent as white). // if ( 0 != iTransColor ) { // // Reverse Colors. // ulXlate[0] = RGB_WHITE; ulXlate[1] = RGB_BLACK; } hr = CommonRopBlt(pdevobj, psoSrc, pco, &xlo, NULL, prclSrc, prclDst, NULL, 0xEE); } else { SURFOBJ *psoMsk = NULL; HBITMAP hBmpMsk = NULL; if (psoMsk = CreateBitmapSURFOBJ(pPDev, &hBmpMsk, psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy, BMF_1BPP) ) { if ( CreateMaskSurface(psoSrc,psoMsk,iTransColor) ) { hr = CommonRopBlt(pdevobj, psoMsk, pco, &xlo, NULL, prclSrc, prclDst, NULL, 0xEE); } } // // Release allocated objects. // if ( psoMsk ) { EngUnlockSurface(psoMsk); psoMsk = NULL; } if (hBmpMsk) { EngDeleteSurface((HSURF)hBmpMsk); hBmpMsk = NULL; } } if ( FAILED (hr) ) { ERR(("PCLXLTransparentBlt: Mask could not be created or rendered.\n")); goto Cleanup; } // // Step 2 and 3. // Set the flags and call CommonRopBlt. CommonRopBlt is the function that // dumps images to printer. CommonRopBlt will look at the // flags and know that for this image, it has to replace // the colored pixels with White // pxlpdev->dwFlags |= XLPDEV_FLAGS_SUBST_TRNCOLOR_WITH_WHITE; pxlpdev->ulTransColor = iTransColor; // // ROP is DSAnd = 136 = 0x88. // hr = CommonRopBlt(pdevobj, psoSrc, pco, pxlo, NULL, prclSrc, prclDst, NULL, 136); pxlpdev->ulTransColor = 0; pxlpdev->dwFlags &= ~XLPDEV_FLAGS_SUBST_TRNCOLOR_WITH_WHITE; Cleanup: if ( SUCCEEDED (hr) ) { return TRUE; } return FALSE; } extern "C" BOOL APIENTRY PCLXLTextOut( SURFOBJ *pso, STROBJ *pstro, FONTOBJ *pfo, CLIPOBJ *pco, RECTL *prclExtra, RECTL *prclOpaque, BRUSHOBJ *pboFore, BRUSHOBJ *pboOpaque, POINTL *pptlOrg, MIX mix) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)pso->dhpdev; VERBOSE(("PCLXLTextOut() entry.\n")); PXLPDEV pxlpdev= (PXLPDEV)pdevobj->pdevOEM; XLOutput *pOutput = pxlpdev->pOutput; // // Clip // if (!SUCCEEDED(pOutput->SetClip(pco))) return FALSE; ROP4 rop = GET_FOREGROUND_ROP3(UlVectMixToRop4(mix)); if (!ROP3_NEED_SOURCE(rop)) rop = 0x00fc; // // Set ROP and TxMode. // Send NewPath to flush memory. // pOutput->SetROP3(rop); pOutput->Send_cmd(eNewPath); pOutput->SetPaintTxMode(eOpaque); pOutput->SetSourceTxMode(eOpaque); // // Opaque Rectangle // if (prclOpaque) { pOutput->SetPenColor(NULL, NULL); pOutput->SetBrush(pboOpaque, pptlOrg); pOutput->Send_cmd(eNewPath); pOutput->RectanglePath(prclOpaque); pOutput->Paint(); } // // Draw underline, strikeout, etc. // if (prclExtra) { pOutput->SetPenColor(NULL, NULL); pOutput->SetBrush(pboFore, pptlOrg); pOutput->Send_cmd(eNewPath); while(NULL != prclExtra) { pOutput->RectanglePath(prclExtra++); } pOutput->Paint(); } // // Text Color // pOutput->SetBrush(pboFore, pptlOrg); pOutput->Flush(pdevobj); // // Device font/TrueType download // DrvTextOut( pso, pstro, pfo, pco, prclExtra, prclOpaque, pboFore, pboOpaque, pptlOrg, mix); // // Bug reported by HP. // Plug-in could have command callback and DrvStartPage sets plug-in's // pdev in pdevOEM. // Need to reset it. // ((PPDEV)pdevobj)->devobj.pdevOEM = ((PPDEV)pdevobj)->pVectorPDEV; // // Flush cached text before changing font // FlushCachedText(pdevobj); // // Reset text angle // pxlpdev->dwTextAngle = 0; // // Close TrueType font // pxlpdev->pTTFile->CloseTTFile(); return TRUE; } extern "C" BOOL APIENTRY PCLXLLineTo( SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo, LONG x1, LONG y1, LONG x2, LONG y2, RECTL *prclBounds, MIX mix) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)pso->dhpdev; PXLPDEV pxlpdev; POINTFIX Pointfix; LINEATTRS lineattrs; VERBOSE(("PCLXLLineTo() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; Pointfix.x = x2 << 4; Pointfix.y = y2 << 4; lineattrs = *pgLineAttrs; lineattrs.elWidth.e = FLOATL_IEEE_1_0F; ROP4 rop = GET_FOREGROUND_ROP3(UlVectMixToRop4(mix)); TxMode TxModeValue; // // Quick return in the case of AA (destination). // if (rop == 0xAA) { return TRUE; } // // If there is any Pattern involved, set TxMode to Opaque. // if (ROP3_NEED_PATTERN(rop)) { TxModeValue = eOpaque; } else { TxModeValue = eTransparent; } BOOL bRet; XLOutput *pOutput = pxlpdev->pOutput; if (S_OK == pOutput->SetClip(pco) && S_OK == pOutput->SetROP3(rop) && S_OK == pOutput->SetPaintTxMode(TxModeValue) && S_OK == pOutput->SetSourceTxMode(TxModeValue) && S_OK == pOutput->SetPen(&lineattrs, NULL) && S_OK == pOutput->SetPenColor(pbo, NULL) && S_OK == pOutput->SetBrush(NULL, NULL) && S_OK == pOutput->Send_cmd(eNewPath) && S_OK == pOutput->SetCursor(x1, y1) && S_OK == pOutput->LinePath(&Pointfix, 1) && S_OK == pOutput->Paint() && S_OK == pOutput->Flush(pdevobj)) bRet = TRUE; else { pOutput->Delete(); bRet = FALSE; } return bRet; } extern "C" BOOL APIENTRY PCLXLStrokePath( SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, XFORMOBJ *pxo, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, LINEATTRS *plineattrs, MIX mix) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)pso->dhpdev; PXLPDEV pxlpdev; TxMode TxModeValue; VERBOSE(("PCLXLStokePath() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; BOOL bRet; XLOutput *pOutput = pxlpdev->pOutput; ROP4 rop = GET_FOREGROUND_ROP3(UlVectMixToRop4(mix)); // // Quick return in the case of AA (destination). // if (rop == 0xAA) { return TRUE; } // // If there is any Pattern involved, set TxMode to Opaque. // if (ROP3_NEED_PATTERN(rop)) { TxModeValue = eOpaque; } else { TxModeValue = eTransparent; } if (S_OK == pOutput->SetClip(pco) && S_OK == pOutput->SetROP3(rop) && S_OK == pOutput->SetPaintTxMode(TxModeValue) && S_OK == pOutput->SetSourceTxMode(TxModeValue) && S_OK == pOutput->SetPen(plineattrs, pxo) && S_OK == pOutput->SetPenColor(pbo, pptlBrushOrg) && S_OK == pOutput->SetBrush(NULL, NULL) && S_OK == pOutput->Path(ppo) && S_OK == pOutput->Paint() && S_OK == pOutput->Flush(pdevobj)) bRet = TRUE; else { pOutput->Delete(); bRet = FALSE; } return bRet; } extern "C" BOOL APIENTRY PCLXLFillPath( SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, MIX mix, FLONG flOptions) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)pso->dhpdev; PXLPDEV pxlpdev; VERBOSE(("PCLXLFillPath() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; BOOL bRet; XLOutput *pOutput = pxlpdev->pOutput; ROP4 rop = GET_FOREGROUND_ROP3(UlVectMixToRop4(mix)); TxMode TxModeValue; // // Quick return in the case of AA (destination). // if (rop == 0xAA) { return TRUE; } // // Performance fix suggested by HP. // Fix the performance problem on CD9T_LET.cdr. // if (pco && pco->iFComplexity == FC_COMPLEX) { return FALSE; } // // If there is any Pattern involved, set TxMode to Opaque. // if (ROP3_NEED_PATTERN(rop)) { TxModeValue = eOpaque; } else { TxModeValue = eTransparent; } // // Setup fill mode // FillMode FM; if (flOptions == FP_ALTERNATEMODE) { FM = eFillEvenOdd; } else if (flOptions == FP_WINDINGMODE) { FM = eFillNonZeroWinding; } if (S_OK == pOutput->SetClip(pco) && S_OK == pOutput->SetROP3(rop) && S_OK == pOutput->SetPaintTxMode(TxModeValue) && S_OK == pOutput->SetSourceTxMode(TxModeValue) && S_OK == pOutput->SetFillMode(FM) && S_OK == pOutput->SetPenColor(NULL, NULL) && S_OK == pOutput->SetBrush(pbo, pptlBrushOrg) && S_OK == pOutput->Path(ppo) && S_OK == pOutput->Paint() && S_OK == pOutput->Flush(pdevobj)) bRet = TRUE; else { pOutput->Delete(); bRet = FALSE; } return bRet; } extern "C" BOOL APIENTRY PCLXLStrokeAndFillPath( SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, XFORMOBJ *pxo, BRUSHOBJ *pboStroke, LINEATTRS *plineattrs, BRUSHOBJ *pboFill, POINTL *pptlBrushOrg, MIX mixFill, FLONG flOptions) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)pso->dhpdev; PXLPDEV pxlpdev; VERBOSE(("PCLXLStrokeAndFillPath() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; XLOutput *pOutput = pxlpdev->pOutput; BOOL bRet; ROP4 rop = GET_FOREGROUND_ROP3(UlVectMixToRop4(mixFill)); TxMode TxModeValue; // // Quick return in the case of AA (destination). // if (rop == 0xAA) { return TRUE; } // // If there is any Pattern involved, set TxMode to Opaque. // if (ROP3_NEED_PATTERN(rop)) { TxModeValue = eOpaque; } else { TxModeValue = eTransparent; } // // Setup fill mode // FillMode FM; if (flOptions == FP_ALTERNATEMODE) { FM = eFillEvenOdd; } else if (flOptions == FP_WINDINGMODE) { FM = eFillNonZeroWinding; } if (S_OK == pOutput->SetClip(pco) && S_OK == pOutput->SetROP3(rop) && S_OK == pOutput->SetPaintTxMode(TxModeValue) && S_OK == pOutput->SetSourceTxMode(TxModeValue) && S_OK == pOutput->SetFillMode(FM) && S_OK == pOutput->SetPen(plineattrs, pxo) && S_OK == pOutput->SetPenColor(pboStroke, pptlBrushOrg) && S_OK == pOutput->SetBrush(pboFill, pptlBrushOrg) && S_OK == pOutput->Path(ppo) && S_OK == pOutput->Paint() && S_OK == pOutput->Flush(pdevobj)) bRet = TRUE; else { pOutput->Delete(); bRet = FALSE; } return bRet; } extern "C" BOOL APIENTRY PCLXLRealizeBrush( BRUSHOBJ *pbo, SURFOBJ *psoTarget, SURFOBJ *psoPattern, SURFOBJ *psoMask, XLATEOBJ *pxlo, ULONG iHatch) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)psoTarget->dhpdev; PXLPDEV pxlpdev; XLBRUSH *pBrush; BOOL bRet; OutputFormat OutputF; VERBOSE(("PCLXLRealizeBrush() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; // // the OEM DLL should NOT hook out this function unless it wants to draw // graphics directly to the device surface. In that case, it calls // EngRealizeBrush which causes GDI to call DrvRealizeBrush. // Note that it cannot call back into Unidrv since Unidrv doesn't hook it. // if (iHatch >= HS_DDI_MAX) { LONG lHeight, lWidth, lScanline; ULONG ulOutputBPP, ulInputBPP; DWORD dwI, dwBufSize, dwLenNormal, dwLenRLE,dwLenDRC, dwcbLineSize, dwcbBmpSize; PDWORD pdwLen; PBYTE pubSrc, pBufNormal, pBufRLE, pBufDRC, pBuf, pBmpSize; XLOutput *pOutput = pxlpdev->pOutput; DetermineOutputFormat(pxlo, pOutput->GetDeviceColorDepth(), psoPattern->iBitmapFormat, &OutputF, &ulOutputBPP); // // Get Info // ulInputBPP = UlBPPtoNum((BPP)psoPattern->iBitmapFormat); lHeight = psoPattern->sizlBitmap.cy; lWidth = psoPattern->sizlBitmap.cx; dwcbLineSize = ((lWidth * ulInputBPP) + 7) >> 3; dwBufSize = lHeight * (((lWidth * ulOutputBPP + 31) >> 5 ) << 2) + DATALENGTH_HEADER_SIZE + sizeof(PCLXL_EndRastPattern); VERBOSE(("PCLXLRealizeBrush():InBPP=%d,Width=%d,Height=%d,Line=%d,Size=%d.\n", ulInputBPP, lWidth, lHeight, dwcbLineSize, dwBufSize)); // // Allocate output buffer // pBufNormal = pBufRLE = pBufDRC = NULL; if (COMMANDPTR(((PPDEV)pdevobj)->pDriverInfo,CMD_ENABLEDRC)) { if (NULL == (pBufDRC = (PBYTE)MemAlloc(dwBufSize))) { ERR(("PCLXLRealizeBrush: MemAlloc failed.\n")); return FALSE; } } if (NULL == (pBufNormal = (PBYTE)MemAlloc(dwBufSize)) || NULL == (pBufRLE = (PBYTE)MemAlloc(dwBufSize)) ) { if (pBufNormal != NULL) MemFree(pBufNormal); if (pBufRLE != NULL) MemFree(pBufRLE); ERR(("PCLXLRealizeBrush: MemAlloc failed.\n")); return FALSE; } CompressMode CMode; BMPConv BMPC; PBYTE pubDst; DWORD dwDstSize; #if DBG BMPC.SetDbgLevel(BRUSHDBG); #endif BMPC.BSetInputBPP((BPP)psoPattern->iBitmapFormat); BMPC.BSetOutputBPP(NumToBPP(ulOutputBPP)); BMPC.BSetOutputBMPFormat(OutputF); BMPC.BSetXLATEOBJ(pxlo); dwLenNormal = dwLenRLE = dwLenDRC = 0; #define NO_COMPRESSION 0 #define RLE_COMPRESSION 1 #define DRC_COMPRESSION 2 DWORD dwComp; if (COMMANDPTR(((PPDEV)pdevobj)->pDriverInfo,CMD_ENABLEDRC)) { // // Try DRC compression. // dwComp = 3; } else { // // Only non and RLE comp. // dwComp = 2; } for (dwI = 0; dwI < dwComp; dwI ++) { bRet = TRUE; if (NO_COMPRESSION == dwI) { pBuf = pBufNormal; pdwLen = &dwLenNormal; CMode = eNoCompression; } else if (RLE_COMPRESSION == dwI) { pBuf = pBufRLE; pdwLen = &dwLenRLE; CMode = eRLECompression; } else if (DRC_COMPRESSION == dwI) { pBuf = pBufDRC; pdwLen = &dwLenDRC; CMode = eDeltaRowCompression; } BMPC.BSetCompressionType(CMode); lScanline = lHeight; pubSrc = (PBYTE)psoPattern->pvScan0; *pBuf = PCLXL_dataLength; pBmpSize = pBuf + 1; // DWORD bitmap size pBuf += DATALENGTH_HEADER_SIZE; (*pdwLen) = DATALENGTH_HEADER_SIZE; dwcbBmpSize = 0; while (lScanline-- > 0 && dwcbBmpSize + *pdwLen < dwBufSize) { pubDst = BMPC.PubConvertBMP(pubSrc, dwcbLineSize); dwDstSize = BMPC.DwGetDstSize(); VERBOSE(("PCLXLRealizeBrush[0x%x]: dwDstSize=0x%x\n", lScanline, dwDstSize)); if ( dwcbBmpSize + dwDstSize + DATALENGTH_HEADER_SIZE + sizeof(PCLXL_EndRastPattern) > dwBufSize || NULL == pubDst) { ERR(("PCLXLRealizeBrush: Buffer size is too small.(%d)\n", dwI)); bRet = FALSE; break; } memcpy(pBuf, pubDst, dwDstSize); dwcbBmpSize += dwDstSize; pBuf += dwDstSize; pubSrc += psoPattern->lDelta; } if (lScanline > 0) { bRet = FALSE; #if DBG ERR(("PCLXLRealizeBrush: Conversion failed.\n")); #endif } if (bRet) { if (dwI == NO_COMPRESSION) { // // Scanline on PCL-XL has to be DWORD align. // // count byte of scanline = lWidth * ulOutputBPP / 8 // dwcbBmpSize = lHeight * (((lWidth * ulOutputBPP + 31) >> 5 ) << 2); } CopyMemory(pBmpSize, &dwcbBmpSize, sizeof(dwcbBmpSize)); (*pdwLen) += dwcbBmpSize; *pBuf = PCLXL_EndRastPattern; (*pdwLen) ++; } else { *pdwLen = 0; } } #undef NO_COMPRESSION #undef RLE_COMPRESSION #undef DRC_COMPRESSION if (dwLenRLE == 0 && dwLenDRC != 0 && dwLenDRC < dwLenNormal || dwLenRLE != 0 && dwLenDRC != 0 && dwLenDRC < dwLenRLE && dwLenDRC < dwLenNormal ) { pBuf = pBufDRC; pdwLen = &dwLenDRC; CMode = eDeltaRowCompression; MemFree(pBufNormal); MemFree(pBufRLE); } else if (dwLenRLE != 0 && dwLenRLE < dwLenNormal) { pBuf = pBufRLE; pdwLen = &dwLenRLE; CMode = eRLECompression; MemFree(pBufNormal); MemFree(pBufDRC); } else if (dwLenNormal != 0) { pBuf = pBufNormal; pdwLen = &dwLenNormal; CMode = eNoCompression; MemFree(pBufRLE); MemFree(pBufDRC); } else { MemFree(pBufNormal); MemFree(pBufRLE); MemFree(pBufDRC); ERR(("PCLXLRealizeBrush: Conversion failed. Return FALSE.\n")); return FALSE; } // // Output // ColorMapping CMapping; DWORD dwScale; // // Pattern scaling factor // Scale the destination size of pattern. // Resolution / 150 seems to be a good scaling factor. // dwScale = (pOutput->GetResolutionForBrush() + 149)/ 150; if (pOutput->GetDeviceColorDepth() == e24Bit) { pOutput->SetColorSpace(eRGB); } else { pOutput->SetColorSpace(eGray); } if (OutputF == eOutputPal) { DWORD *pdwColorTable; if ((pdwColorTable = GET_COLOR_TABLE(pxlo))) { pOutput->SetPalette(ulOutputBPP, pxlo->cEntries, pdwColorTable); CMapping = eIndexedPixel; } else { CMapping = eDirectPixel; } } else { CMapping = eDirectPixel; } pOutput->Send_cmd(eSetColorSpace); pOutput->SetOutputBPP(CMapping, ulOutputBPP); pOutput->SetSourceWidth((uint16)lWidth); pOutput->SetSourceHeight((uint16)lHeight); pOutput->SetDestinationSize((uint16)(lWidth * dwScale), (uint16)(lHeight * dwScale)); pOutput->SetPatternDefineID((sint16)pxlpdev->dwLastBrushID); pOutput->SetPatternPersistence(eSessionPattern); pOutput->Send_cmd(eBeginRastPattern); pOutput->Flush(pdevobj); pOutput->ReadRasterPattern(lHeight, CMode); pOutput->Flush(pdevobj); DWORD dwBitmapSize; CopyMemory(&dwBitmapSize, pBuf + 1, sizeof(DWORD)); if (dwBitmapSize > 0xff) { // // dataLength // size (uin32) (bitmap size) // DATA // EndImage // WriteSpoolBuf((PPDEV)pdevobj, pBuf, *pdwLen); } else { // // dataLength // size (byte) (bitmap size) // DATA // EndImage // PBYTE pTmp = pBuf; pBuf += 3; *pBuf = PCLXL_dataLengthByte; *(pBuf + 1) = (BYTE)dwBitmapSize; WriteSpoolBuf((PPDEV)pdevobj, pBuf, (*pdwLen) - 3); // // Restore the original pointer // pBuf = pTmp; } MemFree(pBuf); } DWORD dwBrushSize; if (pxlo->cEntries) { dwBrushSize = sizeof(XLBRUSH) + (pxlo->cEntries + 1) * sizeof(DWORD); } else { dwBrushSize = sizeof(XLBRUSH) + sizeof(DWORD); } if (pBrush = (XLBRUSH*)BRUSHOBJ_pvAllocRbrush(pbo, dwBrushSize)) { pBrush->dwSig = XLBRUSH_SIG; pBrush->dwHatch = iHatch; if (iHatch >= HS_DDI_MAX) { pBrush->dwPatternID = pxlpdev->dwLastBrushID++; } else { // // Set 0 for hatch brush case // pBrush->dwPatternID = 0; } DWORD *pdwColorTable; pdwColorTable = GET_COLOR_TABLE(pxlo); // // get color for Graphics state cache for either palette case or // solid color. // pBrush->dwColor = BRUSHOBJ_ulGetBrushColor(pbo); if (pdwColorTable && pxlo->cEntries != 0) { // // Copy palette table. // CopyMemory(pBrush->adwColor, pdwColorTable, pxlo->cEntries * sizeof(DWORD)); pBrush->dwCEntries = pxlo->cEntries; } else { pBrush->dwCEntries = 0; } pBrush->dwOutputFormat = (DWORD)OutputF; pbo->pvRbrush = (PVOID)pBrush; bRet = TRUE; } else { bRet = FALSE; } return bRet; } extern "C" BOOL APIENTRY PCLXLStartPage( SURFOBJ *pso) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)pso->dhpdev; PXLPDEV pxlpdev; BOOL bRet; VERBOSE(("PCLXLStartPage() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; XLOutput *pOutput = pxlpdev->pOutput; pxlpdev->dwFlags |= XLPDEV_FLAGS_STARTPAGE_CALLED; bRet = DrvStartPage(pso); // // Bug reported by HP. // Plug-in could have command callback and DrvStartPage sets plug-in's // pdev in pdevOEM. // Need to reset it. // ((PPDEV)pdevobj)->devobj.pdevOEM = ((PPDEV)pdevobj)->pVectorPDEV; // // Reset printing mode. // SourceTxMode, PaintTxMode // ROP // pOutput->SetPaintTxMode(eOpaque); pOutput->SetSourceTxMode(eOpaque); pOutput->SetROP3(0xCC); pOutput->Flush(pdevobj); // // Needs to reset attribute when EndPage and BeginPage are sent. // if (!(pxlpdev->dwFlags & XLPDEV_FLAGS_FIRSTPAGE)) { BSaveFont(pdevobj); // // Reset graphcis state each page. // pOutput->ResetGState(); } else { pxlpdev->dwFlags &= ~XLPDEV_FLAGS_FIRSTPAGE; } return bRet; } extern "C" BOOL APIENTRY PCLXLSendPage( SURFOBJ *pso) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)pso->dhpdev; PXLPDEV pxlpdev; XLOutput *pOutput; VERBOSE(("PCLXLEndPage() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; pxlpdev->dwFlags &= ~XLPDEV_FLAGS_STARTPAGE_CALLED; pOutput = pxlpdev->pOutput; pOutput->Flush(pdevobj); return DrvSendPage(pso); } extern "C" ULONG APIENTRY PCLXLEscape( SURFOBJ *pso, ULONG iEsc, ULONG cjIn, PVOID pvIn, ULONG cjOut, PVOID pvOut) /*++ Routine Description: Arguments: Return Value: Note: --*/ { VERBOSE(("PCLXLEscape() entry.\n")); return DrvEscape( pso, iEsc, cjIn, pvIn, cjOut, pvOut); } extern "C" BOOL APIENTRY PCLXLStartDoc( SURFOBJ *pso, PWSTR pwszDocName, DWORD dwJobId) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)pso->dhpdev; PXLPDEV pxlpdev; VERBOSE(("PCLXLStartDoc() entry.\n")); pxlpdev = (PXLPDEV)pdevobj->pdevOEM; // // Initialize flag // pxlpdev->dwFlags |= XLPDEV_FLAGS_FIRSTPAGE; return DrvStartDoc( pso, pwszDocName, dwJobId); } extern "C" BOOL APIENTRY PCLXLEndDoc( SURFOBJ *pso, FLONG fl) /*++ Routine Description: Arguments: Return Value: Note: --*/ { PDEVOBJ pdevobj = (PDEVOBJ)pso->dhpdev; PXLPDEV pxlpdev; BOOL bRet; VERBOSE(("PCLXLEndDoc() entry.\n")); if (NULL == pdevobj->pdevOEM) { bRet = FALSE; } { pxlpdev = (PXLPDEV)pdevobj->pdevOEM; if (S_OK == RemoveAllFonts(pdevobj)) { bRet = TRUE; } else { bRet = FALSE; } } pxlpdev->dwFlags |= XLPDEV_FLAGS_ENDDOC_CALLED; return bRet && DrvEndDoc(pso, fl); } //////////////////////////////////////////////////////////////////////////////// // // Sub functions // HRESULT RemoveAllFonts( PDEVOBJ pdevobj) { PXLPDEV pxlpdev; XLOutput *pOutput; DWORD dwI; HRESULT hResult; pxlpdev = (PXLPDEV)pdevobj->pdevOEM; pOutput = pxlpdev->pOutput; hResult = S_OK; for (dwI = 0; dwI < pxlpdev->dwNumOfTTFont; dwI++) { if (S_OK != pOutput->Send_ubyte_array_header(PCLXL_FONTNAME_SIZE) || S_OK != pOutput->Write(PubGetFontName(pdevobj, dwI+1), PCLXL_FONTNAME_SIZE)|| S_OK != pOutput->Send_attr_ubyte(eFontName) || S_OK != pOutput->Send_cmd(eRemoveFont)) { hResult = S_FALSE; break; } } pOutput->Flush(pdevobj); pxlpdev->dwNumOfTTFont = 0; return hResult; } HRESULT CommonRopBlt( IN PDEVOBJ pdevobj, IN SURFOBJ *psoSrc, IN CLIPOBJ *pco, IN XLATEOBJ *pxlo, IN BRUSHOBJ *pbo, IN RECTL *prclSrc, IN RECTL *prclDst, IN POINTL *pptlBrush, IN ROP4 rop4) /*++ Routine Description: Arguments: Return Value: Note: --*/ { HRESULT hRet; VERBOSE(("CommonRopBlt() entry.\n")); // // Error check // if (pdevobj == NULL || prclDst == NULL ) { ERR(("CommonRopBlt: one of parameters is NULL.\n")); return E_UNEXPECTED; } PXLPDEV pxlpdev= (PXLPDEV)pdevobj->pdevOEM; hRet = S_OK; XLOutput *pOutput = pxlpdev->pOutput; OutputFormat OutputF; // // Set Clip // if (!SUCCEEDED(pOutput->SetClip(pco))) return S_FALSE; // // Set Cursor // pOutput->SetCursor(prclDst->left, prclDst->top); // // 1. ROP conversion // // (1) Fill Dstination // 0x00 BLACKNESS // 0xFF WHITENESS // // (2) Pattern copy -> P // 0xF0 PATCOPY P // // (3) SRC/NOTSRCOPY -> S or ~S // 0x11 ~( S | D) // 0x33 ~S // 0x44 ( S & ~D) // 0x66 ( D ^ S) // 0x77 ~( D & S) // 0x99 ~( S ^ D) // 0xCC S // 0xDD ( S | ~D) // // (4) Misc ROP support // 0xAA D // 0x0F PATNOT ~P // // ROP3 rop3 = GET_FOREGROUND_ROP3(rop4); DWORD dwCase = 0; #define ROP_BLACKWHITE 0x1 #define ROP_PATTERN 0x2 #define ROP_BITMAP 0x4 #define ROP_DEST 0x8 // // Set ROP3 // pOutput->SetROP3(GET_FOREGROUND_ROP3(rop4)); switch (rop3) { case 0x00: case 0xFF: dwCase = ROP_BLACKWHITE; break; case 0xF0: dwCase = ROP_PATTERN; break; case 0x11: case 0x33: case 0x44: case 0x66: case 0x77: case 0x99: case 0xCC: case 0xDD: dwCase = ROP_BITMAP; break; case 0xAA: dwCase = ROP_DEST; break; case 0x0F: dwCase = ROP_PATTERN; break; default: if (ROP3_NEED_SOURCE(rop3)) { dwCase |= ROP_BITMAP; } if (ROP3_NEED_PATTERN(rop3)) { dwCase |= ROP_PATTERN; } if (ROP3_NEED_DEST(rop3)) { dwCase |= ROP_DEST; } break; } // // Black & White case // if (dwCase & ROP_BLACKWHITE) { VERBOSE(("CommonRopBlt(): BlackWhite.\n")); // // SetBrushSource // NewPath // RectanglePath // PaintPath // CMNBRUSH CmnBrush; CmnBrush.dwSig = BRUSH_SIGNATURE; CmnBrush.BrushType = kBrushTypeSolid; CmnBrush.ulSolidColor = 0x00; CmnBrush.ulHatch = 0xFFFFFFFF; CmnBrush.dwColor = 0x00FFFFFF; CmnBrush.dwPatternBrushID = 0xFFFFFFFF; pOutput->SetSourceTxMode(eOpaque); pOutput->SetPaintTxMode(eOpaque); if(rop3 == 0x00) { if (e24Bit == pOutput->GetDeviceColorDepth()) { pOutput->SetRGBColor(0); CmnBrush.dwColor = 0x00; } else { pOutput->SetGrayLevel(0x00); CmnBrush.dwColor = 0x00; } } else { if (e24Bit == pOutput->GetDeviceColorDepth()) { pOutput->SetRGBColor(0x00ffffff); CmnBrush.dwColor = 0x00ffffff; } else { pOutput->SetGrayLevel(0xff); CmnBrush.dwColor = 0x00ffffff; } } ((XLBrush*)pOutput)->SetBrush(&CmnBrush); pOutput->Send_cmd(eSetBrushSource); pOutput->SetPenColor(NULL, NULL); if (!(dwCase & ROP_BITMAP)) { pOutput->Send_cmd(eNewPath); pOutput->RectanglePath(prclDst); pOutput->Send_cmd(ePaintPath); } pOutput->Flush(pdevobj); } // // Pattern fill case // if (dwCase & (ROP_DEST|ROP_PATTERN)) { VERBOSE(("CommonRopBlt(): Pattern.\n")); // // SetPaintTxMode // SetSourceTxMode // SetBrushSource // NewPath // RectanglePath // PaintPath // pOutput->SetSourceTxMode(eOpaque); pOutput->SetPaintTxMode(eOpaque); pOutput->SetBrush(pbo, pptlBrush); pOutput->SetPenColor(NULL, NULL); if (!(dwCase & ROP_BITMAP)) { pOutput->Send_cmd(eNewPath); pOutput->RectanglePath(prclDst); pOutput->Send_cmd(ePaintPath); } pOutput->Flush(pdevobj); } // // Bitmap case // if (dwCase & ROP_BITMAP) { LONG lHeight, lWidth, lScanline; ULONG ulOutputBPP, ulInputBPP; DWORD dwI, dwBufSize, dwLen, dwcbLineSize, dwcbBmpSize; PDWORD pdwLen; PBYTE pubSrc, pBuf, pBufOrg = NULL, pBmpSize, pBufEnd; ColorMapping CMapping; SURFOBJ *psoBmp; HBITMAP hBitmap = NULL; PBYTE pubChanged = NULL; // temporary rectangle used if the image is downscaled by the engine RECTL rctlBitmap; // zero out the temporary rectangle memset( &rctlBitmap, 0, sizeof(RECTL) ); VERBOSE(("CommonRopBlt(): Bitmap\n")); if (psoSrc == NULL || prclSrc == NULL ) { ERR(("UNIDRV:CommonRopBlt:psoSrc, pxlo, or prclSrc == NULL.\n")); pOutput->Flush(pdevobj); return E_UNEXPECTED; } // // Input BPP // ulInputBPP = UlBPPtoNum((BPP)psoSrc->iBitmapFormat); psoBmp = NULL; // // If the source image is larger than it will appear on the // destination surface, shrink it to the target size. No point // in sending extra bits. // // This optimization could be further optimized by building up a clip // object here if one is specified. How much of a gain this is // worth I don't know. // if (prclDst->right - prclDst->left < prclSrc->right - prclSrc->left || prclDst->bottom - prclDst->top < prclSrc->bottom - prclSrc->top ) { // // Shrink source bitmap. // PDEV *pPDev = (PDEV*)pdevobj; SIZEL sizlDest; DWORD dwScanlineLength; POINTL ptlBrushOrg; // Translate destination rectangle to origin 0,0 and same dimensions as before rctlBitmap.left = 0; rctlBitmap.top = 0; rctlBitmap.right = prclDst->right - prclDst->left; rctlBitmap.bottom = prclDst->bottom - prclDst->top; sizlDest.cx = prclDst->right - prclDst->left; sizlDest.cy = prclDst->bottom - prclDst->top; dwScanlineLength = (sizlDest.cx * ulInputBPP + 7 ) >> 3; if (pptlBrush) { ptlBrushOrg = *pptlBrush; } else { ptlBrushOrg.x = ptlBrushOrg.y = 0; } // When we do the transfer, don't do color translation because that will be handled by the printer. // Also, don't pass the clip object, because it's in the wrong coordinate space. We could build a // a new clip object, but the value of doing so is questionable, and it would take a lot more testing. if ((psoBmp = CreateBitmapSURFOBJ(pPDev, &hBitmap, sizlDest.cx, sizlDest.cy, psoSrc->iBitmapFormat)) && EngStretchBlt(psoBmp, psoSrc, NULL, NULL, NULL, NULL, &ptlBrushOrg, &rctlBitmap, prclSrc, NULL, HALFTONE)) { psoSrc = psoBmp; prclSrc = &rctlBitmap; } else { ERR(("CreateBitmapSURFOBJ or EngStretchBlt failed.\n")); } } // // Set source opaque mode // GDI bug. CopyBits is called recursively. // { PDEV *pPDev = (PDEV*)pdevobj; if (pPDev->fMode2 & PF2_SURFACE_WHITENED) { pOutput->SetSourceTxMode(eTransparent); } else { pOutput->SetSourceTxMode(eOpaque); } } pOutput->SetPaintTxMode(eOpaque); // // Bitmap output // DetermineOutputFormat(pxlo, pOutput->GetDeviceColorDepth(), psoSrc->iBitmapFormat, &OutputF, &ulOutputBPP); if (pOutput->GetDeviceColorDepth() == e24Bit) { pOutput->SetColorSpace(eRGB); } else { pOutput->SetColorSpace(eGray); } if (OutputF == eOutputPal) { DWORD *pdwColorTable = NULL; if (pdwColorTable = GET_COLOR_TABLE(pxlo)) { if ( pxlpdev->dwFlags & XLPDEV_FLAGS_SUBST_TRNCOLOR_WITH_WHITE ) { ULONG ulTransColor = pxlpdev->ulTransColor; pdwColorTable = PdwChangeTransparentPalette(ulTransColor, pdwColorTable, pxlo->cEntries); if (pdwColorTable) { pOutput->SetPalette(ulOutputBPP, pxlo->cEntries, pdwColorTable); MemFree (pdwColorTable); pdwColorTable = NULL; } else { ERR(("CommonRopBlt: PdwChangeTransparentPalette returned NULL.\n")); goto ErrorReturn; } } else { pOutput->SetPalette(ulOutputBPP, pxlo->cEntries, pdwColorTable); } } CMapping = eIndexedPixel; } else { CMapping = eDirectPixel; } pOutput->Send_cmd(eSetColorSpace); // // Get height, width, and scanline size. // lWidth = prclSrc->right - prclSrc->left; lHeight = prclSrc->bottom - prclSrc->top; dwcbLineSize = ((lWidth * ulInputBPP) + 7) >> 3; // // Allocates memory to hold whole bitmap. // dwBufSize = lHeight * (((lWidth * ulOutputBPP + 31) >> 5 ) << 2); // // Limit Buffer Size to 16k, else if the scan line is big, huge memory will // be allocated. But the size has to be at least able to hold one scanline. // #define BMPBUFSIZE 16384 if (dwBufSize > BMPBUFSIZE) { if (dwcbLineSize > BMPBUFSIZE) dwBufSize = dwcbLineSize; else dwBufSize = BMPBUFSIZE; } // // Allocate appropriate buffers before doing BeginImage. // PCLXL expects certain things to happen after BeginImage. // If we attempt to allocate within BeginImage and then allocation // fails, and we try to exit midway, PCLXL will not be able to handle // the resulting output properly. // // When doing TransparentBlt, we need to change colors of pixels. Instead of // altering memory within psoSrc, we'll make copy of scan line and then alter images. // So memory needs to be allocated for that. // if ( pxlpdev->dwFlags & XLPDEV_FLAGS_SUBST_TRNCOLOR_WITH_WHITE && eDirectPixel == CMapping ) { if ( NULL == (pubChanged = (PBYTE) MemAlloc(dwcbLineSize)) ) { ERR(("CommonRopBlt: Cannot allocate memory for pubChanged.\n")); goto ErrorReturn; } } // // Allocate output buffer // if (NULL == (pBuf = (PBYTE)MemAlloc(dwBufSize))) { ERR(("CommonRopBlt: MemAlloc failed.\n")); } else { // // BeginImage // pOutput->BeginImage( CMapping, ulOutputBPP, lWidth, lHeight, prclDst->right - prclDst->left, prclDst->bottom - prclDst->top); pOutput->Flush(pdevobj); VERBOSE(("CommonRopBlt: ulInputBPP=%d, ulOutputBPP=%d, lWidth=0x%x, lHeight=0x%x, dwcbLineSize=0x%x, dwBufSize=0x%x\n",ulInputBPP, ulOutputBPP, lWidth, lHeight, dwcbLineSize, dwBufSize)); pBufOrg = pBuf; pBufEnd = pBuf + (ULONG_PTR)(dwBufSize); //point pBufEnd to byte after last allocatted byte. CompressMode CurrentCMode, PreviousCMode; BMPConv BMPC; PBYTE pubDst; DWORD dwSize; LONG lScans, //number of scan lines stored in pBufOrg lStart; //From which scan line do we start sending scan lines to printer. //e.g. if lStart=5, it means 0-4 scan lines have been sent, now 5th scan line (and may be more) has to be sent #if DBG BMPC.SetDbgLevel(BITMAPDBG); #endif BMPC.BSetInputBPP((BPP)psoSrc->iBitmapFormat); BMPC.BSetOutputBPP(NumToBPP(ulOutputBPP)); BMPC.BSetOutputBMPFormat(OutputF); BMPC.BSetXLATEOBJ(pxlo); lScanline = lHeight; // // Set pubSrc // pubSrc = (PBYTE)psoSrc->pvScan0; if (!psoBmp) { pubSrc += (LONG_PTR) prclSrc->top * psoSrc->lDelta + ((ulInputBPP * prclSrc->left) >> 3); } dwcbBmpSize = 0; lScans = 0; lStart = 0; PreviousCMode = eInvalidValue; while (lScanline-- > 0) { PBYTE pubSrcLocal = pubSrc; // // When this is called from TransparentBlt, the Transparent Color // has to be replaced by white. This is to be done only for // direct images, not for paletted images. // if ( (pxlpdev->dwFlags & XLPDEV_FLAGS_SUBST_TRNCOLOR_WITH_WHITE) && eDirectPixel == CMapping ) { hRet = hrChangePixelColorInScanLine( pubSrc, ulInputBPP, lWidth, pxlpdev->ulTransColor, pubChanged, dwcbLineSize); if ( FAILED (hRet) ) { goto ErrorReturn; } pubSrcLocal = pubChanged; } // // First try compression and see if the compress data is smaller // than the original data. If it's smaller, go ahead to use the // compression. Otherwise, use original data. // // While it is permitted to mix eRLECompression and eNoCompression // blocks of ReadImage data, XL does not allow mixing JPEG or // DeltaRow image blocks with any other compression method. // // // DRC Compression // if (COMMANDPTR(((PPDEV)pdevobj)->pDriverInfo,CMD_ENABLEDRC)) { CurrentCMode = eDeltaRowCompression; BMPC.BSetCompressionType(CurrentCMode); pubDst = BMPC.PubConvertBMP(pubSrcLocal, dwcbLineSize); dwSize = BMPC.DwGetDstSize(); VERBOSE(("CommonRopBlt: Comp(DRC:0x%x)\n", dwSize)); } else { // // RLE compression // BMPC.BSetCompressionType(eRLECompression); pubDst = BMPC.PubConvertBMP(pubSrcLocal, dwcbLineSize); dwSize = BMPC.DwGetDstSize(); VERBOSE(("CommonRopBlt: Comp(RLE:0x%x)\n", dwSize)); if (dwSize < dwcbLineSize) { CurrentCMode = eRLECompression; } else { CurrentCMode = eNoCompression; BMPC.BSetCompressionType(eNoCompression); pubDst = BMPC.PubConvertBMP(pubSrcLocal, dwcbLineSize); dwSize = BMPC.DwGetDstSize(); VERBOSE(("CommonRopBlt: Comp(NO:0x%x)\n", dwSize)); } } // // Output bitmap. // 1. Mostly we try to store the data bits in pBufOrg and send them // all at once after processing has been done on the full image. // This storage is done on a per scan line basis. // But if image is really big, pBufOrg gets filled up and more // scan lines cannot be copied. So we empty pBufOrg to make place // for remaining scan lines. If either of these is true, pBufOrg // needs to be flushed. (Both these conditions are essentially the same). // dwcbBmpSize + dwSize > dwBufSize // pBuf + dwSize > pBufEnd // // 2. If the compression has to change, we dump the data bits // using the older compression method that have been stored in // pBufOrg and/or pbDst. // if (dwcbBmpSize + dwSize > dwBufSize || PreviousCMode != eInvalidValue && PreviousCMode != CurrentCMode) { if (PreviousCMode == eInvalidValue) { PreviousCMode = CurrentCMode; } // // Four possible cases // 1&2. dwcbBmpSize == 0 i.e. nothing is present in pBufOrg // So just dump whatever is present in pubDst. // This covers both cases i.e. whether dwSize > dwBufSize or not. // 3. dwcmBmpSize is not zero // dump the image in pBufOrg, clean pBufOrg, and then later // on put the contents of pubDst in pBufOrg(pBuf). // 4. dwcbBmpSize is not zero and dwSize > dwBufSize // i.e. somehow the compression caused the size of the // scan line to increase beyond the dwBufSize. // Because pBufOrg is at most dwBufSize, we cannot // copy pubDst to pBufOrg. So we have to dump pubDst here. // if (dwcbBmpSize == 0) { // // Case 1&2 // BSendReadImageData(pdevobj, PreviousCMode, pubDst, lStart, 1, dwSize); dwSize = 0; lStart++; //One line emitted. Therefore increment lStart } else { // // There is some image data stored in the pBufOrg buffer. // Emit that data. (case 3) // BSendReadImageData(pdevobj, PreviousCMode, pBufOrg, lStart, lScans, dwcbBmpSize); lStart += lScans; //lScans lines emitted if ( dwSize > dwBufSize ) { // // Case 4. // BSendReadImageData(pdevobj, PreviousCMode, pubDst, lStart, 1, dwSize); dwSize = 0; lStart++; } } // // Reset parameters // dwcbBmpSize = 0; lScans = 0; pBuf = pBufOrg; } if (NULL == pubDst) { ERR(("CommonRopBlt: Conversion failed. pubDst is NULL.\n")); goto ErrorReturn; } // // If post-compression size of image is more than zero, AND // if destination buffer(pBuf) has enough space, then copy the compressed // data to the destination. (Data can also be in uncompressed format if // compression does not result in size saving). // Increment lScans to indicicate that we are putting one more scan // line worth of data in pBufOrg // if (dwSize > 0 && pBuf + dwSize <= pBufEnd) { memcpy(pBuf, pubDst, dwSize); dwcbBmpSize += dwSize; pBuf += dwSize; lScans ++; } PreviousCMode = CurrentCMode; if (CurrentCMode == eNoCompression) { DWORD dwDiff = (((lWidth * ulOutputBPP + 31) >> 5) << 2) - dwSize; if (dwDiff) { memset(pBuf, 0, dwDiff); dwcbBmpSize += dwDiff; pBuf += dwDiff; } } pubSrc += psoSrc->lDelta; } if (dwcbBmpSize > 0) { BSendReadImageData(pdevobj, CurrentCMode, pBufOrg, lStart, lScans, dwcbBmpSize); } pOutput->Send_cmd(eEndImage); pOutput->Flush(pdevobj); } ErrorReturn: if (pBufOrg != NULL) MemFree(pBufOrg); if ( NULL != pubChanged ) { MemFree(pubChanged); } if (NULL != psoBmp) { EngUnlockSurface(psoBmp); if (hBitmap && !EngDeleteSurface((HSURF)hBitmap)) { ERR(("CommonRopBlt: EngDeleteSurface failed.\n")); hRet = FALSE; } } } return hRet; } BOOL BSendReadImageData( IN PDEVOBJ pdevobj, IN CompressMode CMode, IN PBYTE pBuf, IN LONG lStart, IN LONG lHeight, IN DWORD dwcbSize) { VERBOSE(("BSendReadImageData(CMode=%d, lHeight=0x%x, dwcbSize=0x%x\n", CMode, lHeight, dwcbSize)); // // dataLength (1) // size (byte or long) (1 or 4) // DWORD dwHeaderSize; BYTE aubHeader[DATALENGTH_HEADER_SIZE]; PXLPDEV pxlpdev = (PXLPDEV)pdevobj->pdevOEM; XLOutput *pOutput = pxlpdev->pOutput; // // Print the converted data. // pOutput->ReadImage(lStart, lHeight, CMode); pOutput->Flush(pdevobj); if (dwcbSize > 0xff) { // // dataLength // size (uin32) (bitmap size) // aubHeader[0] = PCLXL_dataLength; dwHeaderSize = DATALENGTH_HEADER_SIZE; CopyMemory(aubHeader + 1, &dwcbSize, sizeof(dwcbSize)); } else { // // dataLength // size (byte) (bitmap size) // aubHeader[0] = PCLXL_dataLengthByte; dwHeaderSize = DATALENGTH_HEADER_SIZE - 3; CopyMemory(aubHeader + 1, &dwcbSize, sizeof(BYTE)); } // // dataLength // size (byte/uint32) // DATA // EndImage // WriteSpoolBuf((PPDEV)pdevobj, aubHeader, dwHeaderSize); WriteSpoolBuf((PPDEV)pdevobj, pBuf, dwcbSize); return TRUE; } inline VOID DetermineOutputFormat( XLATEOBJ *pxlo, ColorDepth DeviceColorDepth, INT iBitmapFormat, OutputFormat *pOutputF, ULONG *pulOutputBPP) /*++ Routine Description: Arguments: Return Value: Note: --*/ { switch ((BPP)iBitmapFormat) { case e1bpp: case e4bpp: *pOutputF = eOutputPal; break; case e8bpp: case e16bpp: // // Color device or not? // if (DeviceColorDepth == e24Bit) *pOutputF = eOutputPal; else *pOutputF = eOutputGray; break; case e24bpp: case e32bpp: // // Color device or not? // if (DeviceColorDepth == e24Bit) *pOutputF = eOutputRGB; else *pOutputF = eOutputGray; break; } switch (*pOutputF) { case eOutputGray: *pulOutputBPP = 8; break; case eOutputPal: *pulOutputBPP = UlBPPtoNum((BPP)iBitmapFormat); break; case eOutputRGB: case eOutputCMYK: *pulOutputBPP = 24; break; } // // Make sure that color table is available for palette output. // if (*pOutputF == eOutputPal) { if (!(GET_COLOR_TABLE(pxlo))) { if (DeviceColorDepth == e24Bit) { *pOutputF = eOutputRGB; *pulOutputBPP = 24; } else { *pOutputF = eOutputGray; *pulOutputBPP = 8; } } } } PDWORD PdwChangeTransparentPalette( ULONG iTransColor, PDWORD pdwColorTable, DWORD dwEntries) /*++ Routine Description: Creates another copy of palatte and replace the transparent color by white Returns the pointer of a new palette. The calling function has responsibility to release the palette. Arguments: Return Value: Note: --*/ { PDWORD pdwNewPalette = NULL; // // Parameter check // if (NULL == pdwColorTable || dwEntries == 0 ) { return NULL; } if (NULL == (pdwNewPalette = (PDWORD)MemAlloc(sizeof(DWORD) * dwEntries))) { return NULL; } CopyMemory(pdwNewPalette, pdwColorTable, sizeof(DWORD) * dwEntries); // // When printing in palette mode, iTransColor indicates the index into // the palette, instead of the color in the palette. The palette entry // at that index is the color. // pdwNewPalette[iTransColor] = RGB_WHITE; return pdwNewPalette; } /*++ Routine Name hrChangePixelColorInScanLine Routine Description: Changes the pixels in scan line that match a certain color to White Arguments: pubSrc : The original scan line. ulBPP : Bits Per Pixel of scan line. ulNumPixels : Number of Pixels in the scan line. ulTransColor: The color that needs to be changed. pubChanged : The memory where the new(changed) scan line should be put. ulNumBytes : Number of bytes in pubChanged buffer. Return Value: S_OK : if success E_FAIL: Otherwise Note: --*/ HRESULT hrChangePixelColorInScanLine( IN PBYTE pubSrc, IN ULONG ulBPP, IN ULONG ulNumPixels, IN ULONG ulTransColor, IN OUT PBYTE pubChanged, IN ULONG ulNumBytes )//NumBytes in pubChanged { ULONG ulBytesPerPixel = 3; //24bpp is more common that 16 or 32bpp ULONG ulColor = 0; ULONG ulDestSize = 0; //Required destination number of bytes. HRESULT hr = S_OK; // // First do input validation // if ( NULL == pubSrc || NULL == pubChanged ) { ASSERT(("Null Parameter\n")); return E_UNEXPECTED; } // // Make sure pubChanged has enough memory to hold // the changed scan line. // ulBytesPerPixel = ulBPP >> 3; //8 bits per pixel. ulDestSize = ulBytesPerPixel * ulNumPixels; if ( ulNumBytes < ulDestSize ) { ASSERT((FALSE, "Insufficient size of destination buffer\n")); return E_FAIL; } // // Copy Scanline from Source to Destination. Then go through the scan line and // change the transparent color to white // Go through each pixel (there are ulNumPixels pixels). // Whenever the pixels's color is same as ulTransColor, replace it // with white. // // Only direct images are supported in this function. // No palletes. // 8bpp images are mostly palettes. But when printing to monochrome // pclxl device, they are being treated as direct images. // CopyMemory (pubChanged, pubSrc, ulNumBytes); switch (ulBPP) { case 8: { for (ULONG ul = 0; ul < ulNumPixels ; ul++, pubChanged += ulBytesPerPixel) { ulColor = (ULONG) pubChanged[0] ; if ( ulTransColor == ulColor ) { pubChanged[0] = 0xFF; } } } break; case 16: { for (ULONG ul = 0; ul < ulNumPixels ; ul++, pubChanged += ulBytesPerPixel) { ulColor = ((ULONG) pubChanged[0]) | ((ULONG) pubChanged[1] << 8); if ( ulTransColor == ulColor ) { pubChanged[0] = 0xFF; pubChanged[1] = 0xFF; } } } break; case 24: { for (ULONG ul = 0; ul < ulNumPixels ; ul++, pubChanged += ulBytesPerPixel) { ulColor = ((ULONG) pubChanged[0]) | ((ULONG) pubChanged[1] << 8) | ((ULONG) pubChanged[2] << 16); if ( ulTransColor == ulColor ) { // // White is 0xFFFFFF (3 bytes of FF) // pubChanged[0] = 0xFF; pubChanged[1] = 0xFF; pubChanged[2] = 0xFF; } } } break; case 32: { for (ULONG ul = 0; ul < ulNumPixels ; ul++, pubChanged += ulBytesPerPixel) { ulColor = *(PDWORD)pubChanged; if ( ulTransColor == ulColor ) { *(PDWORD)pubChanged |= 0x00FFFFFF; //This modifies only RGB. Alpha channel info retained. } } } break; default: ASSERT((FALSE, "Unsupported bpp value %d\n", ulBPP)); hr = E_FAIL; } //switch return hr; }