/******************************Module*Header*******************************\ * Module Name: htblt.cxx * * Contains routine to halftone a bitmap. This path is used when a * StretchBlt or PlgBlt is called with StretchBltMode == HALFTONE. * * Created: 18-Nov-1991 16:06:47 * Author: Wendy Wu [wendywu] * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.hxx" #if ((PRIMARY_ORDER_ABC != PRIMARY_ORDER_123) || \ (PRIMARY_ORDER_ACB != PRIMARY_ORDER_132) || \ (PRIMARY_ORDER_BAC != PRIMARY_ORDER_213) || \ (PRIMARY_ORDER_BCA != PRIMARY_ORDER_231) || \ (PRIMARY_ORDER_CAB != PRIMARY_ORDER_312) || \ (PRIMARY_ORDER_CBA != PRIMARY_ORDER_321)) #error * PRIMARY_ORDER different in winddi.h and ht.h * #endif /*****************************Private*Function*****************************\ * bSetHTSrcSurfInfo * * Initialise the HTSURFACEINFO structure. The structure is alloacted * elsewhere, we simply fill it in given the nature of the surface * required for drawing. Used by source surface only. * * History: * 18-Nov-1991 -by- Wendy Wu [wendywu] * Stole from gdi\printers\rasdd\stretch.c. \**************************************************************************/ BOOL bSetHTSrcSurfInfo( SURFOBJ *pSurfObj, XEPALOBJ palSrc, HTSURFACEINFO *pHTSurfInfo, XLATEOBJ *pxlo ) { COUNT cMaxPalEntries; BYTE cBytesPerEntry; BOOL bBitFields; ASSERTGDI(palSrc.bValid(),"bhtBlt: invalid src pal\n"); bBitFields = palSrc.bIsBitfields(); switch (pSurfObj->iBitmapFormat) { case BMF_1BPP: cBytesPerEntry = sizeof(ULONG); cMaxPalEntries = 2; break; case BMF_4BPP: cBytesPerEntry = sizeof(ULONG); cMaxPalEntries = 16; break; case BMF_8BPP: cBytesPerEntry = sizeof(ULONG); cMaxPalEntries = 256; break; case BMF_16BPP: cBytesPerEntry = 2; cMaxPalEntries = 3; bBitFields = TRUE; break; case BMF_24BPP: cBytesPerEntry = 3; cMaxPalEntries = 0; break; case BMF_32BPP: cBytesPerEntry = 4; cMaxPalEntries = 3; bBitFields = TRUE; break; default: WARNING("This bitmap format is not implemented"); return(FALSE); } // // The halftone now taking ScanLineDelta rather than compute the scanline // delta by itself, because many driver fake the pvBits, pvScan0 and // scanline delta for creating smaller surface and that sometime cause // halftone to break, to do this we passed to halftone ScanLineDelta and // (from lDelta in SURFOBJ) and pvScan0. // HTSURFACEINFO HTSurfInfo; HTSurfInfo.hSurface = (ULONG_PTR)pSurfObj; HTSurfInfo.SurfaceFormat = (BYTE)pSurfObj->iBitmapFormat; HTSurfInfo.ScanLineAlignBytes = BMF_ALIGN_DWORD; HTSurfInfo.Width = pSurfObj->sizlBitmap.cx; HTSurfInfo.Height = pSurfObj->sizlBitmap.cy; HTSurfInfo.ScanLineDelta = pSurfObj->lDelta; HTSurfInfo.pPlane = (LPBYTE)pSurfObj->pvScan0; HTSurfInfo.Flags = (USHORT)((pSurfObj->fjBitmap & BMF_TOPDOWN) ? HTSIF_SCANLINES_TOPDOWN : 0); COUNT cPalEntries = bBitFields ? 3 : palSrc.cEntries(); if (cPalEntries > cMaxPalEntries) cPalEntries = cMaxPalEntries; if (HTSurfInfo.pColorTriad = (PCOLORTRIAD)PALLOCNOZ( cPalEntries * sizeof(ULONG) + sizeof(COLORTRIAD),'cthG')) { PCOLORTRIAD pColorTriad = HTSurfInfo.pColorTriad; pColorTriad->Type = COLOR_TYPE_RGB; pColorTriad->pColorTable = (LPBYTE)pColorTriad + sizeof(COLORTRIAD); pColorTriad->PrimaryOrder = PRIMARY_ORDER_RGB; // May not be needed by halftoning code, but just to be sure pColorTriad->PrimaryValueMax = 0; if (palSrc.bIsBGR()) pColorTriad->PrimaryOrder = PRIMARY_ORDER_BGR; if (bBitFields) { // 16 or 32BPP. pColorTriad->BytesPerPrimary = 0; pColorTriad->BytesPerEntry = cBytesPerEntry; pColorTriad->ColorTableEntries = 3; ULONG *pulColors = (ULONG *)pColorTriad->pColorTable; if (palSrc.bIsBitfields()) { pulColors[0] = palSrc.flRed(); pulColors[1] = palSrc.flGre(); pulColors[2] = palSrc.flBlu(); } else { // BMF_32BPP, it's not BITFIELD so default to 888 pulColors[1] = 0x00ff00; if (palSrc.bIsBGR()) { pulColors[0] = 0xff0000; pulColors[2] = 0x0000ff; } else { pulColors[0] = 0x0000ff; pulColors[2] = 0xff0000; } } } else { pColorTriad->BytesPerPrimary = 1; pColorTriad->BytesPerEntry = cBytesPerEntry; pColorTriad->ColorTableEntries = cPalEntries; pColorTriad->PrimaryValueMax = 255; if (cPalEntries != 0) { // Not 24BPP or 32BPP // Bug #418345 // If the source palette is monochrome, then we need to // use the foreground and background colors of the DC // which have been previously stored for us in the // translation object. XLATE* pxlate = (XLATE*) pxlo; if(palSrc.bIsMonochrome() && (pxlate->flPrivate & XLATE_FROM_MONO)) { ULONG *pulColors = (ULONG *)pColorTriad->pColorTable; // WINBUG #235687 bhouse 1-19-2000 DIBINDEX values not handled properly by halftone // When given a monochrome palette with a monochrome translate // we need to be sure to also translate DIBINDEX values appropriately pulColors[0] = ulColorRefToRGB(pxlate->ppalDst, pxlate->ppalDstDC, pxlate->iForeDst); pulColors[1] = ulColorRefToRGB(pxlate->ppalDst, pxlate->ppalDstDC, pxlate->iBackDst); } else { palSrc.ulGetEntries(0, cPalEntries, (PPALETTEENTRY)pColorTriad->pColorTable,FALSE); } } } } else { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return(FALSE); } *pHTSurfInfo = HTSurfInfo; return(TRUE); } /*****************************Private*Function*****************************\ * bSetHTSurfInfo * * Initialise the HTSURFACEINFO structure for destination and mask. * * History: * 14-Apr-1992 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/ BOOL bSetHTSurfInfo( SURFOBJ *pSurfObj, HTSURFACEINFO *pHTSurfInfo, // Where data is placed LONG iFormatHT) { HTSURFACEINFO HTSurfInfo; // // The halftone now taking ScanLineDelta rather than compute the scanline // delta by itself, because many driver fake the pvBits, pvScan0 and // scanline delta for creating smaller surface and that sometime cause // halftone to break, to do this we passed to halftone ScanLineDelta and // (from lDelta in SURFOBJ) and pvScan0. // HTSurfInfo.hSurface = (ULONG_PTR)pSurfObj; HTSurfInfo.SurfaceFormat = (BYTE)iFormatHT; HTSurfInfo.ScanLineAlignBytes = BMF_ALIGN_DWORD; HTSurfInfo.Width = pSurfObj->sizlBitmap.cx; HTSurfInfo.Height = pSurfObj->sizlBitmap.cy; HTSurfInfo.ScanLineDelta = pSurfObj->lDelta; HTSurfInfo.pPlane = (LPBYTE)pSurfObj->pvScan0; HTSurfInfo.Flags = (USHORT)((pSurfObj->fjBitmap & BMF_TOPDOWN) ? HTSIF_SCANLINES_TOPDOWN : 0); HTSurfInfo.pColorTriad = NULL; *pHTSurfInfo = HTSurfInfo; return(TRUE); } /******************************Public*Routine******************************\ * ppalGetFromXlate * * The halftoning algorithm needs to know the source palette. Unfortunately * the system wasn't designed to preserve that information, but with some * work we can do it. This routine starts the process of finding the source * palette in more of the cases. This routine will probably be modified * greatly to get 100% accuracy. We would need to construct a palette from * the table of indices given based on the DST palette or DST DC palette (if * pal managed) and return it. If this routine starts manufacturing palettes * it would need to inc the ref count on ones it doesn't create and then when * done dec the count and delete if 0. However this would require the rest * of palette world to use this convention and it all would take a week of * work. * * History: * 18-Feb-1994 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ PPALETTE ppalGetFromXlate(SURFACE *pSurfSrc, SURFACE *pSurfDst, XLATE *pxlo, UINT iPal, BOOL bFirstTime) { ASSERTGDI((iPal == XO_SRCPALETTE) || (iPal == XO_DESTPALETTE), "ERROR invalid type requested"); // // See if the source palette is lying in the source surface like // it usually is. // PPALETTE ppalReturn; if (iPal == XO_SRCPALETTE) { ppalReturn = pSurfSrc->ppal(); } else { ppalReturn = pSurfDst->ppal(); } if (ppalReturn == NULL) { // // Check xlate is passed in is not NULL and it's really valid. // Global ident xlate is not valid, it's just a shell with the // accelerators filled in. // if (pxlo != NULL) { if (iPal == XO_SRCPALETTE) { ppalReturn = pxlo->ppalSrc; } else { ppalReturn = pxlo->ppalDst; } } if (ppalReturn == NULL) { // // Let's try and grab it out of the PDEV now. // if (iPal == XO_SRCPALETTE) { PDEVOBJ po(pSurfSrc->hdev()); if (po.bValid() && po.bIsPalManaged()) { if (pSurfSrc->iFormat() == po.iDitherFormat()) { ppalReturn = po.ppalSurf(); } } } else { PDEVOBJ po(pSurfDst->hdev()); if (po.bValid() && !po.bIsPalManaged()) { if (pSurfDst->iFormat() == po.iDitherFormat()) { ppalReturn = po.ppalSurf(); } } } if (ppalReturn == NULL) { if ((pxlo == NULL) || (pxlo->flXlate & XO_TRIVIAL)) { // // Well if we can't figure it out from the source // and it's identity just get it from the destination // if (bFirstTime) ppalReturn = ppalGetFromXlate(pSurfSrc, pSurfDst, pxlo, iPal == XO_SRCPALETTE ? XO_DESTPALETTE : XO_SRCPALETTE, FALSE); } } } } return(ppalReturn); } /******************************Public*Function*****************************\ * EngHTBlt * * Stretch/PlgBlt with halftone mode. * * History: * 19-Nov-1991 -by- Wendy Wu [wendywu] * Adapted from gdi\printers\rasdd\stretch.c. \**************************************************************************/ int EngHTBlt ( IN SURFOBJ *psoDst, IN SURFOBJ *psoSrc, IN SURFOBJ *psoMask, IN CLIPOBJ *pco, IN XLATEOBJ *pxlo, IN COLORADJUSTMENT *pca, IN PPOINTL pptlBrushOrg, IN PRECTL prclDest, IN PRECTL prclSrc, IN PPOINTL pptlMask, IN ULONG uFlags, IN BLENDOBJ *pBlendObj) { PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst); PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc); PSURFACE pSurfMask = SURFOBJ_TO_SURFACE(psoMask); HTSURFACEINFO HTDest; HTSURFACEINFO HTSrc; HTSURFACEINFO HTMask; COLORTRIAD clrtri; BYTE aclr[256]; LONG cjDstWidth; PDEVOBJ poDst(pSurfDst->hdev()); if (!poDst.bValid()) return(HTBLT_NOTSUPPORTED); // Halftoning will relay on driver's halftone palette and output format, // even the target surface is not device surface. so that during halftoning, // we need to prevent happen dynamic mode chage, if the device is display. // thus we hold devlock here. DEVLOCKOBJ dlo; if (poDst.bDisplayPDEV()) dlo.vLock(poDst); else dlo.vInit(); // iFormatDst: The format of the destination bitmap. This is also used for // shadow bitmap creation if destination is not an engine bitmap. // iFormatHT: The halftone format that we'll pass to HT_HalftoneBitmap. // iFormatHTPal: The halftone format that we'll use to determine what kind // of halftone palette to create. ULONG iFormatDst, iFormatHT, iFormatHTPal; // Determine the halftone and destination bitmap formats. // If the destination is a DIB, we'll write directly to it unless the halftone // palette is different from the dest palette. So the halftone format has // to be the same as the destination format. // If the destination is not a DIB, we'll halftone to a shadow bitmap. // The format of this bitmap can be different from the device format and // is depending on the halftone format in GDIINFO. if (psoDst->iType == STYPE_BITMAP) { switch(pSurfDst->iFormat()) { case BMF_1BPP: cjDstWidth = ((psoDst->sizlBitmap.cx + 31) & ~31) >> 3; iFormatHT = iFormatDst = BMF_1BPP; iFormatHTPal = HT_FORMAT_1BPP; break; case BMF_4BPP: cjDstWidth = ((psoDst->sizlBitmap.cx + 7) & ~7) >> 1; iFormatDst = BMF_4BPP; if (poDst.GdiInfo()->ulHTOutputFormat == HT_FORMAT_4BPP) { iFormatHT = BMF_4BPP; iFormatHTPal = HT_FORMAT_4BPP; } else { iFormatHT = BMF_4BPP_VGA16; iFormatHTPal = HT_FORMAT_4BPP_IRGB; } break; case BMF_8BPP: cjDstWidth = ((psoDst->sizlBitmap.cx + 3) & ~3); iFormatHT = BMF_8BPP_VGA256; iFormatDst = BMF_8BPP; iFormatHTPal = HT_FORMAT_8BPP; break; case BMF_16BPP: cjDstWidth = ((psoDst->sizlBitmap.cx + 1) & ~1) << 1; iFormatHT = BMF_16BPP_555; iFormatDst = BMF_16BPP; iFormatHTPal = HT_FORMAT_16BPP; break; case BMF_24BPP: cjDstWidth = (((psoDst->sizlBitmap.cx * 3) + 3) & ~3); iFormatHT = BMF_24BPP; iFormatDst = BMF_24BPP; iFormatHTPal = HT_FORMAT_24BPP; break; case BMF_32BPP: cjDstWidth = (((psoDst->sizlBitmap.cx << 2) + 3) & ~3); iFormatHT = BMF_32BPP; iFormatDst = BMF_32BPP; iFormatHTPal = HT_FORMAT_32BPP; break; default: return(HTBLT_NOTSUPPORTED); } } else { iFormatHTPal = poDst.GdiInfo()->ulHTOutputFormat; switch(iFormatHTPal) { case HT_FORMAT_1BPP: iFormatHT = iFormatDst = BMF_1BPP; break; case HT_FORMAT_4BPP: iFormatHT = iFormatDst = BMF_4BPP; break; case HT_FORMAT_4BPP_IRGB: iFormatHT = BMF_4BPP_VGA16; iFormatDst = BMF_4BPP; break; case HT_FORMAT_8BPP: iFormatHT = BMF_8BPP_VGA256; iFormatDst = BMF_8BPP; break; case HT_FORMAT_16BPP: iFormatHT = BMF_16BPP_555; iFormatDst = BMF_16BPP; break; case HT_FORMAT_24BPP: iFormatHT = BMF_24BPP; iFormatDst = BMF_24BPP; break; case HT_FORMAT_32BPP: iFormatHT = BMF_32BPP; iFormatDst = BMF_32BPP; break; default: return(HTBLT_NOTSUPPORTED); } } ERECTL erclTrim(0, 0, psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy); erclTrim *= *prclSrc; if (erclTrim.bEmpty()) return(HTBLT_SUCCESS); // // Initialize halftone structure and get ready. // if ((poDst.pDevHTInfo() == NULL) && !poDst.bEnableHalftone(pca)) return(HTBLT_ERROR); SURFACE *pSurfTempSrc; SURFMEM dimoSrc; // // Synchronize with the source device driver. // if ( pSurfSrc->flags() & HOOK_SYNCHRONIZE) { PDEVOBJ po( pSurfSrc->hdev()); po.vSync(psoSrc,NULL,0); } if ((psoSrc->iType == STYPE_BITMAP) && (psoSrc->iBitmapFormat != BMF_4RLE) && (psoSrc->iBitmapFormat != BMF_8RLE)) { pSurfTempSrc = pSurfSrc; } else { // Get the bits from the device. // Find out the format to use by looking at the preferred format in // the surface's pdev devinfo structure. We want to keep the original // color as much as possible since the halftone routine does a better // job in converting colors. DEVBITMAPINFO dbmiSrc; dbmiSrc.cxBitmap = psoSrc->sizlBitmap.cx; dbmiSrc.cyBitmap = psoSrc->sizlBitmap.cy; dbmiSrc.hpal = (HPALETTE) 0; dbmiSrc.fl = pSurfSrc->bUMPD() ? UMPD_SURFACE : 0; switch (psoSrc->iBitmapFormat) { case BMF_4RLE: dbmiSrc.iFormat = BMF_4BPP; break; case BMF_8RLE: dbmiSrc.iFormat = BMF_8BPP; break; default: dbmiSrc.iFormat = psoSrc->iBitmapFormat; break; } if (!dimoSrc.bCreateDIB(&dbmiSrc, (PVOID) NULL)) { WARNING("dimoSrc.bCreateDIB failed in EngHTBlt\n"); return(HTBLT_ERROR); } // Copy the bits, dispatch off dst's ldev which is the engine. if (!EngCopyBits(dimoSrc.pSurfobj(), psoSrc, (CLIPOBJ *) NULL, &xloIdent, &erclTrim, (POINTL *)&erclTrim)) { WARNING("EngHTBlt:CopyBits failes\n"); return(HTBLT_ERROR); } pSurfTempSrc = dimoSrc.ps; } // // Get the source palette. // PPALETTE ppalS = ppalGetFromXlate(pSurfSrc, pSurfDst, (XLATE *) pxlo, XO_SRCPALETTE, TRUE); if (ppalS == NULL) { WARNING("EngHTBlt could not find Source palette to use\n"); return(HTBLT_NOTSUPPORTED); } XEPALOBJ palSrc(ppalS); // // Dest surface palette will be invalid only if it's a 256 color bitmap. // XEPALOBJ palDstSurf(ppalGetFromXlate( pSurfSrc, pSurfDst, (XLATE *) pxlo, XO_DESTPALETTE, TRUE)); // Let's see if halftone palette is the same as the destination palette. BOOL bNoXlate; PALMEMOBJ palHTDst; XEPALOBJ *ppalHT = (XEPALOBJ *)NULL; if (iFormatHTPal != poDst.GdiInfo()->ulHTOutputFormat) { if (!palHTDst.bCreateHTPalette(iFormatHTPal, poDst.GdiInfo())) { return(HTBLT_ERROR); } ppalHT = (XEPALOBJ *)&palHTDst; bNoXlate = palHTDst.bEqualEntries(palDstSurf); } else { bNoXlate = poDst.bHTPalIsDevPal(); } // Prepare for HT_HalftoneBitmap call. BITBLTPARAMS BitbltParams; ABINFO AbInfo; if(uFlags == BBPF_DO_ALPHA_BLEND) { BLENDFUNCTION BlendFunction = pBlendObj->BlendFunction; if(BlendFunction.BlendOp == AC_SRC_OVER) { AbInfo.Flags = 0; AbInfo.pDstPal = 0; AbInfo.cDstPal = 0; AbInfo.ConstAlphaValue = BlendFunction.SourceConstantAlpha; if(BlendFunction.AlphaFormat == AC_SRC_ALPHA && BlendFunction.SourceConstantAlpha == 255) { // Per pixel Alpha : Need palette info. if(!bIsSourceBGRA(pSurfSrc)) return HTBLT_ERROR; AbInfo.Flags |= ABIF_SRC_ALPHA_IS_PREMUL; //if(iFormatDst == BMF_32BPP) // AbInfo.Flags |= ABIF_BLEND_DEST_ALPHA; } else { AbInfo.Flags |= ABIF_USE_CONST_ALPHA_VALUE; } // Set Destination palette values for Halftone. if(palDstSurf.bValid()) { AbInfo.pDstPal = (LPPALETTEENTRY)palDstSurf.apalColorGet(); AbInfo.cDstPal = (WORD)palDstSurf.cEntries(); if(palDstSurf.bIsBGR() || ((palDstSurf.bIsBitfields()) && (palDstSurf.flRed() == 0xff0000) && (palDstSurf.flGre() == 0xff00) && (palDstSurf.flBlu() == 0xff))) AbInfo.Flags |= ABIF_DSTPAL_IS_RGBQUAD; } BitbltParams.pABInfo = &AbInfo; } else uFlags = 0; } // // Remove pAbort, since it never used and delete by ht.h // BitbltParams.rclSrc = *prclSrc; BitbltParams.rclDest = *prclDest; BitbltParams.Flags = (USHORT)uFlags; BitbltParams.ptlBrushOrg = *pptlBrushOrg; BitbltParams.DestPrimaryOrder = (BYTE)poDst.GdiInfo()->ulPrimaryOrder; // Set ICM flags for halftoning ULONG lIcmMode = pxlo ? ((XLATE *) pxlo)->lIcmMode : DC_ICM_OFF; // 1) IF application ICM, BBPF_ICM_ON is ON. // 2) IF other ICM and not device caribrate, BBPF_ICM_ON is ON. if((IS_ICM_OUTSIDEDC(lIcmMode)) || (!IS_ICM_DEVICE_CALIBRATE(lIcmMode) && (IS_ICM_HOST(lIcmMode) || (IS_ICM_DEVICE(lIcmMode))))) { ICMDUMP(("EngHTBlt(): ICM with Halftone (Dynamic Bit On)\n")); // Some kind of ICM (ICM on Application, Graphics Engine or Device) // is enabled, so tell halftoning code to disable thier color adjustment. BitbltParams.Flags |= BBPF_ICM_ON; } else { ICMDUMP(("EngHTBlt(): ICM with Halftone (Dynamic Bit Off)\n")); } // Get the relevant information about the destination bitmap. SURFACE *pSurfTempDst = pSurfDst; SURFMEM dimoDst; // Create a temporary bitmap if // 1) the destination bitmap is not an engine bitmap. or // 2) the bitmap width is not equal to the stride, because the halftone // code assumes they are equivalent, or // 3) the destination is not 8bpp (we have special case for this) and // the halftone palette is different from the destination palette, or // 4) the surfaces are overlapping BOOL bCreateShadowBitmap = FALSE; BYTE iDComplexity = (pco == (CLIPOBJ *) NULL) ? DC_TRIVIAL : pco->iDComplexity; // After the following "if" block, pcoNew should be used for clipping instead // of pco. We implement single rect clipping through banding in halftone. // if DC_COMPLEX, create a shadow bitmap to avoid calling HT_Bitmap many times CLIPOBJ *pcoNew = pco; if ((psoDst->iType != STYPE_BITMAP) || (psoDst->lDelta != cjDstWidth) || ((iFormatDst != BMF_8BPP) && !bNoXlate) || (iDComplexity == DC_COMPLEX)|| ((psoDst == psoSrc) && bIntersect(prclSrc, prclDest))) { bCreateShadowBitmap = TRUE; PRECTL prcl = prclDest; if (iDComplexity != DC_TRIVIAL) { // Clipping is not DC_TRIVIAL, use rclBounds as dest rect. prcl = &pco->rclBounds; // Clipping is done through banding if DC_RECT, do not clip // in CopyBits. if (iDComplexity == DC_RECT) pcoNew = NULL; // Do not enumerate clipping when calling halftone by marking // complexity to DC_TRIVIAL. iDComplexity = DC_TRIVIAL; } // Banding rect has to be well ordered and confined in the surface area. LONG lDxDst, lDyDst; SIZEL sizlDst = pSurfDst->sizl(); LONG lLeft, lRight, lTop, lBottom; // Do the x part. if (prcl->right > prcl->left) { lLeft = prcl->left; lRight = prcl->right; } else { lLeft = prcl->right; lRight = prcl->left; } if (lLeft < 0L) lLeft = 0L; if (lRight > sizlDst.cx) lRight = sizlDst.cx; if ((lDxDst = (lRight - lLeft)) <= 0L) return(HTBLT_SUCCESS); BitbltParams.rclBand.left = lLeft; BitbltParams.rclBand.right = lRight; // Do the y part. if (prcl->bottom > prcl->top) { lTop = prcl->top; lBottom = prcl->bottom; } else { lTop = prcl->bottom; lBottom = prcl->top; } if (lTop < 0) lTop = 0; if (lBottom > sizlDst.cy) lBottom = sizlDst.cy; if ((lDyDst = (lBottom - lTop)) <= 0L) return(HTBLT_SUCCESS); BitbltParams.rclBand.top = lTop; BitbltParams.rclBand.bottom = lBottom; BitbltParams.Flags |= BBPF_HAS_BANDRECT; // Create the shadow bitmap. DEVBITMAPINFO dbmiDst; dbmiDst.cxBitmap = lDxDst; dbmiDst.cyBitmap = lDyDst; dbmiDst.hpal = 0; dbmiDst.fl = pSurfDst->bUMPD() ? UMPD_SURFACE : 0; dbmiDst.iFormat = iFormatDst; if (!dimoDst.bCreateDIB(&dbmiDst, (PVOID) NULL)) { WARNING("dimoDst.bCreateDIB failed in EngHTBlt\n"); return(HTBLT_ERROR); } pSurfTempDst = dimoDst.ps; } // // We need to xlate from halftone palette to dest surface palette if // the halftone palette is different from the destination palette. // EXLATEOBJ xloHTToDst, xloDstToHT; XLATEOBJ *pxloHTToDst = &xloIdent, *pxloDstToHT = &xloIdent; DEVICEHALFTONEINFO *pDevHTInfo = (DEVICEHALFTONEINFO *)poDst.pDevHTInfo(); if (!bNoXlate) { XEPALOBJ palDstDC; EPALOBJ palHT((HPALETTE)pDevHTInfo->DeviceOwnData); ASSERTGDI(palHT.bValid(),"EngHTBlt: invalid HT pal\n"); if (ppalHT == (XEPALOBJ *)NULL) { ppalHT = &palHT; } if ((pxlo == NULL) || (((XLATE *) pxlo)->ppalDstDC == NULL)) { palDstDC.ppalSet(ppalDefault); } else { palDstDC.ppalSet(((XLATE *) pxlo)->ppalDstDC); } if (!xloHTToDst.bInitXlateObj( NULL, DC_ICM_OFF, *ppalHT, palDstSurf, palDstDC, palDstDC, 0, 0x00FFFFFF, 0x00FFFFFF )) { WARNING("EngHTBlt: bInitXlateObj HT to Dst failed\n"); return(HTBLT_ERROR); } pxloHTToDst = xloHTToDst.pxlo(); // Init the Dst pal to HT pal xlateobj so we can do CopyBits from // the destination surface to the halftone buffer. if ((pSurfMask || uFlags == BBPF_DO_ALPHA_BLEND) && bCreateShadowBitmap) { if (!xloDstToHT.bInitXlateObj( NULL, DC_ICM_OFF, palDstSurf, *ppalHT, palDstDC, palDstDC, 0, 0x00FFFFFF, 0x00FFFFFF )) { WARNING("EngHTBlt: bInitXlateObj Dst to HT failed\n"); return(HTBLT_ERROR); } pxloDstToHT = xloDstToHT.pxlo(); } } // If there is a source mask, copy the destination bits to the buffer // so we can do CopyBits later on. This is fater than creating a // stretched mask and BitBlt with the created masks. // Synchronize with the destination device driver. poDst.vSync(psoDst,NULL,0); if ((pSurfMask || uFlags == BBPF_DO_ALPHA_BLEND) && bCreateShadowBitmap) { ERECTL ercl(0, 0, pSurfTempDst->sizl().cx, pSurfTempDst->sizl().cy); // Inc target surface uniqueness INC_SURF_UNIQ(pSurfTempDst); if (!(*PPFNGET(poDst,CopyBits, pSurfDst->flags())) ( pSurfTempDst->pSurfobj(), // Target surf psoDst, // Source surf (CLIPOBJ *)NULL, // ClipObj pxloDstToHT, // XlateObj (RECTL *)&ercl, // Dest rect (POINTL *)&BitbltParams.rclBand // Src offset )) { // CopyBits failed. We'll paint the background white. if (!EngBitBlt(pSurfTempDst->pSurfobj(), // Target surf (SURFOBJ *)NULL, // Source surf (SURFOBJ *)NULL, // Mask surf (CLIPOBJ *)NULL, // ClipObj NULL, // XlateObj (RECTL *)&ercl, // Dest rect (POINTL *)NULL, // Src offset (POINTL *)NULL, // Mask offset (BRUSHOBJ *)NULL, // BrushObj (POINTL *)NULL, // Brush origin 0xFFFF)) // Rop { return(HTBLT_ERROR); } } } HTSrc.pColorTriad = (PCOLORTRIAD)NULL; // assume not allocate BOOL bRet = FALSE; if (bSetHTSrcSurfInfo(pSurfTempSrc->pSurfobj(), palSrc, &HTSrc, pxlo) && bSetHTSurfInfo(pSurfTempDst->pSurfobj(), &HTDest, iFormatHT) && (!pSurfMask || bSetHTSurfInfo(pSurfMask->pSurfobj(), &HTMask, psoMask->iBitmapFormat))) { PHTSURFACEINFO pMask = (PHTSURFACEINFO)NULL; if (pSurfMask) { BitbltParams.ptlSrcMask = *pptlMask; pMask = &HTMask; } if (!(poDst.GdiInfo()->flHTFlags & HT_FLAG_OUTPUT_CMY)) BitbltParams.Flags |= BBPF_USE_ADDITIVE_PRIMS; // 8BPP halftone does color translations. So pass the xlate along. if (iFormatDst == BMF_8BPP) { HTDest.pColorTriad = &clrtri; clrtri.Type = COLOR_TYPE_RGB; clrtri.BytesPerPrimary = 1; clrtri.BytesPerEntry = 1; clrtri.PrimaryOrder = COLOR_TYPE_RGB; clrtri.PrimaryValueMax = 255; clrtri.ColorTableEntries = 256;; clrtri.pColorTable = aclr; COUNT iLimit = MIN(256,pxloHTToDst->cEntries); for(COUNT i = 0; i < iLimit; i++) { aclr[i] = (BYTE)(*(pxloHTToDst->pulXlate + i)); } pxloHTToDst = &xloIdent; } // HT_HalftoneBitmap will return number of scans being drawn. switch (iDComplexity) { case DC_RECT: BitbltParams.Flags |= BBPF_HAS_DEST_CLIPRECT; BitbltParams.rclClip = pcoNew->rclBounds; case DC_TRIVIAL: bRet = (HT_HalftoneBitmap(pDevHTInfo, (PHTCOLORADJUSTMENT)pca, (PHTSURFACEINFO)&HTSrc, pMask, (PHTSURFACEINFO)&HTDest, (PBITBLTPARAMS)&BitbltParams) >= 0L); break; default: // DC_COMPLEX BitbltParams.Flags |= BBPF_HAS_DEST_CLIPRECT; ((ECLIPOBJ *) pcoNew)->cEnumStart(FALSE,CT_RECTANGLES, CD_ANY,CLIPOBJ_ENUM_LIMIT); bRet = TRUE; BOOL bMore; CLIPENUMRECT clenr; do { bMore = ((ECLIPOBJ *) pcoNew)->bEnum(sizeof(clenr), (PVOID) &clenr); for (ULONG iRT = 0; iRT < clenr.c; iRT++) { BitbltParams.rclClip = clenr.arcl[iRT]; bRet &= (HT_HalftoneBitmap(pDevHTInfo, (PHTCOLORADJUSTMENT)pca, (PHTSURFACEINFO)&HTSrc, pMask, (PHTSURFACEINFO)&HTDest, (PBITBLTPARAMS)&BitbltParams) >= 0L); } } while (bMore && bRet); break; } if (bCreateShadowBitmap && bRet) { // Dispatch the call. Give it no mask. EPOINTL eptl(0,0); // Inc target surface uniqueness INC_SURF_UNIQ(pSurfDst); if (psoDst->iType != STYPE_BITMAP) { bRet = (*PPFNGET(poDst,CopyBits, pSurfDst->flags())) ( psoDst, pSurfTempDst->pSurfobj(), pcoNew, pxloHTToDst, &BitbltParams.rclBand, (POINTL *)&eptl); } else { bRet = EngCopyBits( psoDst, pSurfTempDst->pSurfobj(), pcoNew, pxloHTToDst, &BitbltParams.rclBand, (POINTL *)&eptl); } } } if (HTSrc.pColorTriad) VFREEMEM((LPSTR)HTSrc.pColorTriad); return(bRet ? HTBLT_SUCCESS : HTBLT_ERROR); }