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.
578 lines
18 KiB
578 lines
18 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: engbrush.cxx
|
|
*
|
|
* Brush realization for the engine.
|
|
*
|
|
* Created: 13-May-1991 23:25:49
|
|
* Author: Patrick Haluptzok patrickh
|
|
*
|
|
* Copyright (c) 1990-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
#if DBG
|
|
ULONG engbrushalloc = 0, engbrushcachecheck = 0;
|
|
ULONG engbrushcachegrabbed = 0, engbrushcachehit = 0;
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* EngRealizeBrush
|
|
*
|
|
* Realizes a brush for the engine simulations.
|
|
*
|
|
* We realize a brush by converting psoPattern to have the same bpp and color
|
|
* format as the destination surface. We copy the monochrome mask unmodified.
|
|
*
|
|
* psoPattern is assumed never to be NULL.
|
|
*
|
|
* Returns: TRUE for success, FALSE for failure.
|
|
*
|
|
* History:
|
|
* 21-Nov-1993 -by- Michael Abrash [mikeab]
|
|
* Removed impossible case of psoPattern == NULL, cleaned up.
|
|
*
|
|
* 20-Jan-1992 -by- Donald Sidoroff [donalds]
|
|
* Tiled pattern and mask to DWORD boundaries
|
|
*
|
|
* 25-Apr-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL EngRealizeBrush(
|
|
BRUSHOBJ *pbo,
|
|
SURFOBJ *psoTarget,
|
|
SURFOBJ *psoPattern,
|
|
SURFOBJ *psoMask,
|
|
XLATEOBJ *pxlo,
|
|
ULONG iHatch)
|
|
{
|
|
PSURFACE pSurfTarg = SURFOBJ_TO_SURFACE(psoTarget);
|
|
PSURFACE pSurfPat = SURFOBJ_TO_SURFACE(psoPattern);
|
|
PSURFACE pSurfMsk = SURFOBJ_TO_SURFACE(psoMask);
|
|
ULONG ulSizeTotal;
|
|
ULONG ulSizePat;
|
|
ULONG cjScanPat, cjScanMsk;
|
|
SIZEL sizlPat;
|
|
SIZEL sizlMsk;
|
|
LONG cxPatRealized;
|
|
LONG cxMskRealized;
|
|
ULONG iFormat;
|
|
POINTL ptlSrc;
|
|
RECTL rclDst;
|
|
DEVBITMAPINFO dbmi;
|
|
BOOL bHalftoneTile = FALSE;
|
|
|
|
ASSERTGDI(pbo->iSolidColor == 0xFFFFFFFF, "ERROR GDI iSolidColor");
|
|
ASSERTGDI(pSurfTarg != NULL, "ERROR GDI EngRealizeBrush NULL psoTarg");
|
|
ASSERTGDI(pSurfPat != NULL, "ERROR GDI EngRealizeBrush NULL psoPattern");
|
|
ASSERTGDI(!(iHatch & RB_DITHERCOLOR),
|
|
"ERROR GDI EngRealizeBrush RB_DITHERCOLOR set");
|
|
|
|
//
|
|
// Calculate the space needed for the pattern.
|
|
//
|
|
iFormat = pSurfTarg->iFormat();
|
|
|
|
//
|
|
// Check if they are having the engine simulate to a bitmap compatible
|
|
// with their surface. The brushobj has the device's surfobj in it
|
|
// but we assume if they got here it's because they created a bitmap
|
|
// compatible with thier format and
|
|
// are drawing on it. Maybe we should have the pvGetEngBrush pass
|
|
// the pSurfTarg along so we know what it is here, because from
|
|
// here we haven't got access to the real surfobj being painted on.
|
|
//
|
|
|
|
ASSERTGDI(pSurfPat->iType() == STYPE_BITMAP, "ERROR GDI EngRealizeBrush2");
|
|
sizlPat = pSurfPat->sizl();
|
|
|
|
PDEVICEHALFTONEINFO pDevHTInfo = NULL;
|
|
|
|
PDEVOBJ po(pSurfTarg->hdev());
|
|
|
|
// The following list shows the halftone dithering cell size mapped to
|
|
// cxPattern x cyPattern in pDevHTInfo
|
|
//
|
|
// This is done only for 1bpp in the following code
|
|
//
|
|
// dither cell chosen at UI --> what we got from pDevHTInfo
|
|
//
|
|
// 2x2 --> 8x4
|
|
// 4x4 --> 8x4
|
|
// 6x6 --> 12x6
|
|
// 8x8 --> 8x8
|
|
// 10x10 --> 10x10
|
|
// 12x12 --> 12x12
|
|
// 14x14 --> 14x14
|
|
// 16x16 --> 16x16
|
|
// 91x91 --> 91x91
|
|
//
|
|
|
|
if ((po.pDevHTInfo() != NULL) || po.bEnableHalftone(NULL))
|
|
{
|
|
pDevHTInfo = (DEVICEHALFTONEINFO *)po.pDevHTInfo();
|
|
}
|
|
|
|
switch(iFormat)
|
|
{
|
|
case BMF_1BPP:
|
|
ulSizePat = 1;
|
|
if ((sizlPat.cx == 32) ||
|
|
(sizlPat.cx == 16) ||
|
|
(sizlPat.cx == 8))
|
|
{
|
|
cxPatRealized = 32;
|
|
|
|
//
|
|
// take the least common multiple
|
|
// of 32(dword aligned) and pDevHTInfocxPattern
|
|
//
|
|
if (pDevHTInfo)
|
|
{
|
|
switch (pDevHTInfo->cxPattern)
|
|
{
|
|
case 12:
|
|
cxPatRealized = 96;
|
|
bHalftoneTile = TRUE;
|
|
break;
|
|
|
|
case 10:
|
|
cxPatRealized = 160;
|
|
bHalftoneTile = TRUE;
|
|
break;
|
|
|
|
case 14:
|
|
cxPatRealized = 224;
|
|
bHalftoneTile = TRUE;
|
|
break;
|
|
|
|
case 91:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
cxPatRealized = (sizlPat.cx + 63) & ~31;
|
|
}
|
|
break;
|
|
case BMF_4BPP:
|
|
ulSizePat = 4;
|
|
if (sizlPat.cx == 8)
|
|
{
|
|
cxPatRealized = 8;
|
|
}
|
|
else
|
|
{
|
|
cxPatRealized = (sizlPat.cx + 15) & ~7;
|
|
}
|
|
break;
|
|
case BMF_8BPP:
|
|
ulSizePat = 8;
|
|
cxPatRealized = (sizlPat.cx + 7) & ~3;
|
|
break;
|
|
case BMF_16BPP:
|
|
ulSizePat = 16;
|
|
cxPatRealized = (sizlPat.cx + 7) & ~3;
|
|
break;
|
|
case BMF_24BPP:
|
|
ulSizePat = 24;
|
|
cxPatRealized = (sizlPat.cx + 7) & ~3;
|
|
break;
|
|
case BMF_32BPP:
|
|
ulSizePat = 32;
|
|
cxPatRealized = sizlPat.cx;
|
|
break;
|
|
default:
|
|
RIP("ERROR GDI EngRealizeBrush3");
|
|
}
|
|
|
|
//
|
|
// Calculate the size to hold the pattern in the Target's format.
|
|
//
|
|
cjScanPat = (ulSizePat * cxPatRealized) >> 3;
|
|
|
|
ulSizeTotal = sizeof(ENGBRUSH) + (ulSizePat = sizlPat.cy * cjScanPat);
|
|
|
|
//
|
|
// Calculate the additional space needed if we have a mask passed down.
|
|
//
|
|
if (pSurfMsk != NULL)
|
|
{
|
|
ASSERTGDI(pSurfMsk->iFormat() == BMF_1BPP, "ERROR GDI EngRealizeBrush4");
|
|
ASSERTGDI(pSurfMsk->iType() == STYPE_BITMAP, "ERROR GDI EngRealizeBrush5");
|
|
sizlMsk = pSurfMsk->sizl();
|
|
if ((sizlMsk.cx == 32) ||
|
|
(sizlMsk.cx == 16) ||
|
|
(sizlMsk.cx == 8))
|
|
{
|
|
cxMskRealized = 32;
|
|
}
|
|
else
|
|
{
|
|
cxMskRealized = (sizlMsk.cx + 63) & ~31;
|
|
}
|
|
cjScanMsk = cxMskRealized >> 3;
|
|
ulSizeTotal += sizlMsk.cy * cjScanMsk;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for the realization.
|
|
//
|
|
PENGBRUSH pengbrush;
|
|
|
|
#if DBG
|
|
engbrushalloc++;
|
|
#endif
|
|
|
|
//
|
|
// If there's a cached ENGBRUSH, try to use it instead of allocating
|
|
//
|
|
if (gpCachedEngbrush != NULL)
|
|
{
|
|
|
|
#if DBG
|
|
engbrushcachecheck++;
|
|
#endif
|
|
|
|
//
|
|
// Try to grab the cached ENGBRUSH
|
|
//
|
|
if ((pengbrush =
|
|
(PENGBRUSH) InterlockedExchangePointer((PVOID *)&gpCachedEngbrush,
|
|
NULL))
|
|
!= NULL)
|
|
{
|
|
|
|
#if DBG
|
|
engbrushcachegrabbed++;
|
|
#endif
|
|
|
|
//
|
|
// Got the cached ENGBRUSH; see if it's big enough
|
|
//
|
|
// Note: -4 because we define the realization buffer start as aj[0]
|
|
if (pengbrush->ulSizeGet() >= (sizeof(ENGBRUSH) - 4 + ulSizeTotal))
|
|
{
|
|
|
|
#if DBG
|
|
engbrushcachehit++;
|
|
#endif
|
|
|
|
//
|
|
// It's big enough, so we'll use it and we're done
|
|
//
|
|
goto BrushAllocated;
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Not big enough; free it and do a normal allocation
|
|
//
|
|
VFREEMEM(pengbrush);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Note: -4 because we define the realization buffer start as aj[0]
|
|
if ((pengbrush = (PENGBRUSH)
|
|
PALLOCMEM(ULONG(sizeof(ENGBRUSH) - 4 + ulSizeTotal),'rbeG'))
|
|
== NULL)
|
|
{
|
|
WARNING("GDI EngRealizeBrush Couldn't allocate for engine realization");
|
|
return(FALSE);
|
|
}
|
|
|
|
BrushAllocated:
|
|
|
|
EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo;
|
|
|
|
//
|
|
// Store the pointer to the realization in the brush.
|
|
//
|
|
pebo->pengbrush(pengbrush);
|
|
|
|
//
|
|
// Remember the size of the allocation, for caching.
|
|
//
|
|
pengbrush->ulSizeSet(sizeof(ENGBRUSH) - 4 + ulSizeTotal);
|
|
|
|
//
|
|
// Set up the Pat part. The pattern can never be NULL.
|
|
//
|
|
pengbrush->lDeltaPat = cjScanPat;
|
|
pengbrush->cxPatR = cxPatRealized;
|
|
pengbrush->cxPat = bHalftoneTile ? cxPatRealized : sizlPat.cx;
|
|
pengbrush->cyPat = sizlPat.cy;
|
|
pengbrush->pjPat = pengbrush->aj;
|
|
pengbrush->iDitherFormat = iFormat;
|
|
|
|
dbmi.iFormat = iFormat;
|
|
dbmi.cxBitmap = cxPatRealized;
|
|
dbmi.cyBitmap = sizlPat.cy;
|
|
dbmi.hpal = 0;
|
|
dbmi.fl = BMF_TOPDOWN;
|
|
|
|
SURFMEM SurfDimo;
|
|
SurfDimo.bCreateDIB(&dbmi, pengbrush->pjPat);
|
|
|
|
if (!SurfDimo.bValid())
|
|
{
|
|
// hmgr logs out of memory error
|
|
return(FALSE);
|
|
}
|
|
|
|
ptlSrc.x = 0;
|
|
ptlSrc.y = 0;
|
|
|
|
rclDst.left = 0;
|
|
rclDst.top = 0;
|
|
rclDst.right = sizlPat.cx;
|
|
rclDst.bottom = sizlPat.cy;
|
|
|
|
// Below cases, we need halftoning for this brush.
|
|
//
|
|
// 1) Target surface is 1bpp, and this is pattern/bitmap brush, and the foreground
|
|
// and background are differrent
|
|
// 2) Target surface is 4bpp, and ICM is enabled in system or apps, and this is NOT
|
|
// monochrone brush with same fore and background color.
|
|
|
|
BOOL bSameColor = (((EBRUSHOBJ *)pbo)->crCurrentText() == ((EBRUSHOBJ *)pbo)->crCurrentBack());
|
|
|
|
if (((iFormat == BMF_1BPP) && (iHatch >= HS_NULL) && !bSameColor) // 1
|
|
||
|
|
((iFormat == BMF_4BPP) && (pebo->bIsAppsICM() || pebo->bIsHostICM()) // 2
|
|
&& !(bSameColor && (pebo->bIsMonochrome())))
|
|
)
|
|
{
|
|
PALMEMOBJ palHatch;
|
|
EXLATEOBJ exloHatch;
|
|
PALETTE *ppalOrg = NULL;
|
|
|
|
// Special case to go thru halftone code
|
|
|
|
POINTL ptl;
|
|
ptl.x = 0; ptl.y = 0;
|
|
RECTL rclSrc;
|
|
|
|
rclSrc = rclDst;
|
|
|
|
SurfDimo.ps->hdev(pSurfTarg->hdev());
|
|
|
|
BOOL bHatch = (iHatch < HS_DDI_MAX);
|
|
|
|
// If this is Hatch or monochrome brush, and ICM is enabled, ...
|
|
|
|
if ((bHatch || pebo->bIsMonochrome()) &&
|
|
(pebo->bIsAppsICM() || pebo->bIsHostICM()))
|
|
{
|
|
// Create temporary palette for hatch/mono brush from back/foregournd color
|
|
// This is nessesary to let halftone bitblt work correctly.
|
|
|
|
COLORREF aPalHatch[2];
|
|
|
|
// If this is hatch brush, get foreground color from crRealized.
|
|
// For monochrome brush, get from current text color.
|
|
|
|
if (bHatch)
|
|
{
|
|
ICMMSG(("EngRealizeBrush called with hatch brush\n"));
|
|
ICMMSG(("Forground color = %x\n", pebo->crRealized()));
|
|
ICMMSG(("Background color = %x\n", pebo->crCurrentBack()));
|
|
|
|
// crCurrentBack goes to index 0
|
|
// crRealized goes to index 1
|
|
//
|
|
// See brushddi.cxx : bGetRealizedBrush() for hatch brush case.
|
|
|
|
aPalHatch[0] = pebo->crCurrentBack();
|
|
aPalHatch[1] = pebo->crRealized();
|
|
}
|
|
else // if (pebo->bIsMonochorme())
|
|
{
|
|
ICMMSG(("EngRealizeBrush called with monochrome brush\n"));
|
|
ICMMSG(("Forground color = %x\n", pebo->crCurrentText()));
|
|
ICMMSG(("Background color = %x\n", pebo->crCurrentBack()));
|
|
|
|
// Text color goes to index 0.
|
|
// Background color goes to index 1.
|
|
//
|
|
// See ylateobj.cxx : CreateXlateObject() when source is monochrome case.
|
|
|
|
aPalHatch[0] = pebo->crCurrentText();
|
|
aPalHatch[1] = pebo->crCurrentBack();
|
|
}
|
|
|
|
if (palHatch.bCreatePalette(PAL_INDEXED, 2, (PULONG) aPalHatch,
|
|
0, 0, 0, PAL_FREE))
|
|
{
|
|
if (exloHatch.bInitXlateObj(
|
|
pebo->hcmXform(),
|
|
pebo->lIcmMode(),
|
|
palHatch.ppalGet(),
|
|
pebo->psoTarg()->ppal(),
|
|
pebo->palDC(),
|
|
pebo->palDC(),
|
|
pebo->crCurrentText(),
|
|
pebo->crCurrentBack(),
|
|
0x00FFFFFF))
|
|
{
|
|
pxlo = exloHatch.pxlo();
|
|
|
|
//
|
|
// Halftone code always pick up palette from surface, if it exist,
|
|
// and the palette in monochrome bitmap is black/white, but here,
|
|
// text/background color must be used, so disable surface palette
|
|
// here by put null, so that halftone code will pick up right palette
|
|
// from XLATEOBJ.
|
|
//
|
|
ppalOrg = pSurfPat->ppal();
|
|
pSurfPat->ppal(NULL);
|
|
}
|
|
else
|
|
{
|
|
WARNING1("EngRealizeBrush: failed to create xlate for ICM\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING1("EngRealizeBrush: failed to create palette for ICM\n");
|
|
}
|
|
}
|
|
|
|
if ((iFormat == BMF_1BPP) && bHalftoneTile)
|
|
{
|
|
rclDst.right = cxPatRealized;
|
|
|
|
EngHTBlt(
|
|
SurfDimo.pSurfobj(), // Target surface
|
|
pSurfPat->pSurfobj(), // Source surface
|
|
NULL, // mask surface
|
|
(CLIPOBJ *) NULL, // Clip through this
|
|
pxlo, // Color translation
|
|
NULL, // pca
|
|
&ptl, // pptlBrushOrg
|
|
&rclDst,
|
|
&rclSrc,
|
|
NULL,
|
|
BBPF_TILE_SRC,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
while (rclDst.left != cxPatRealized)
|
|
{
|
|
EngStretchBlt(
|
|
SurfDimo.pSurfobj(), // Target surface
|
|
pSurfPat->pSurfobj(), // Source surface
|
|
NULL, // mask surface
|
|
(CLIPOBJ *) NULL, // Clip through this
|
|
pxlo, // Color translation
|
|
NULL, // pca
|
|
&ptl, // pptlBrushOrg
|
|
&rclDst,
|
|
&rclSrc,
|
|
NULL,
|
|
HALFTONE);
|
|
|
|
rclDst.left = rclDst.right;
|
|
rclDst.right += sizlPat.cx;
|
|
if (rclDst.right > cxPatRealized)
|
|
rclDst.right = cxPatRealized;
|
|
}
|
|
}
|
|
|
|
if (ppalOrg)
|
|
{
|
|
pSurfPat->ppal(ppalOrg);
|
|
}
|
|
}
|
|
else // normal cases
|
|
{
|
|
while (rclDst.left != cxPatRealized)
|
|
{
|
|
EngCopyBits(
|
|
SurfDimo.pSurfobj(), // Target surface
|
|
pSurfPat->pSurfobj(), // Source surface
|
|
(CLIPOBJ *) NULL, // Clip through this
|
|
pxlo, // Color translation
|
|
&rclDst, // Target offset and extent
|
|
&ptlSrc);
|
|
|
|
rclDst.left = rclDst.right;
|
|
rclDst.right += sizlPat.cx;
|
|
if (rclDst.right > cxPatRealized)
|
|
rclDst.right = cxPatRealized;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set up the Msk part.
|
|
//
|
|
if (pSurfMsk == (PSURFACE) NULL)
|
|
{
|
|
//
|
|
// Flag that there's no mask.
|
|
//
|
|
pengbrush->pjMsk = (PBYTE) NULL;
|
|
}
|
|
else
|
|
{
|
|
pengbrush->lDeltaMsk = cjScanMsk;
|
|
pengbrush->cxMskR = cxMskRealized;
|
|
pengbrush->cxMsk = sizlMsk.cx;
|
|
pengbrush->cyMsk = sizlMsk.cy;
|
|
pengbrush->pjMsk = pengbrush->aj + ulSizePat;
|
|
|
|
dbmi.iFormat = BMF_1BPP;
|
|
dbmi.cxBitmap = cxMskRealized;
|
|
dbmi.cyBitmap = sizlMsk.cy;
|
|
dbmi.hpal = (HPALETTE)0;
|
|
dbmi.fl = BMF_TOPDOWN;
|
|
|
|
SURFMEM SurfDimo;
|
|
SurfDimo.bCreateDIB(&dbmi, pengbrush->pjMsk);
|
|
|
|
if (!SurfDimo.bValid())
|
|
{
|
|
// hmgr logs out of memory error
|
|
return(FALSE);
|
|
}
|
|
|
|
ptlSrc.x = 0;
|
|
ptlSrc.y = 0;
|
|
|
|
rclDst.left = 0;
|
|
rclDst.top = 0;
|
|
rclDst.right = sizlMsk.cx;
|
|
rclDst.bottom = sizlMsk.cy;
|
|
|
|
while (rclDst.left != cxMskRealized)
|
|
{
|
|
EngCopyBits(
|
|
SurfDimo.pSurfobj(), // target surface
|
|
pSurfMsk->pSurfobj(), // source surface
|
|
(CLIPOBJ *) NULL, // no clipping
|
|
NULL, // no color translation
|
|
&rclDst, // target offset and extent
|
|
&ptlSrc // source start point
|
|
);
|
|
|
|
rclDst.left = rclDst.right;
|
|
rclDst.right += sizlMsk.cx;
|
|
if (rclDst.right > cxMskRealized)
|
|
{
|
|
rclDst.right = cxMskRealized;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|