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.
 
 
 
 
 
 

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