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