Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1090 lines
35 KiB

/******************************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);
}