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.
1191 lines
36 KiB
1191 lines
36 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: brushddi.cxx
|
|
*
|
|
* This provides the call backs necesary for brush realization.
|
|
*
|
|
* Created: 25-Apr-1991 20:59:49
|
|
* Author: Patrick Haluptzok patrickh
|
|
*
|
|
* Copyright (c) 1990-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
BOOL
|
|
EngRealizeBrush(
|
|
BRUSHOBJ *pbo,
|
|
SURFOBJ *psoTarget,
|
|
SURFOBJ *psoPattern,
|
|
SURFOBJ *psoMask,
|
|
XLATEOBJ *pxlo,
|
|
ULONG iHatch
|
|
);
|
|
|
|
BOOL
|
|
bGetRealizedBrush(
|
|
BRUSH *pbrush,
|
|
EBRUSHOBJ *pebo,
|
|
PFN_DrvRealizeBrush pfnDrv
|
|
);
|
|
|
|
|
|
#if DBG
|
|
ULONG dbrushalloc = 0, dbrushcachecheck = 0;
|
|
ULONG dbrushcachegrabbed = 0, dbrushcachehit = 0;
|
|
#endif
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BRUSHOBJ_pvAllocRbrush
|
|
*
|
|
* Allocates memory for the driver's realization of a brush. This is always
|
|
* called by the driver, never by the engine.
|
|
*
|
|
* History:
|
|
* 25-Apr-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
PVOID
|
|
BRUSHOBJ_pvAllocRbrush(
|
|
BRUSHOBJ *pbo, ULONG cj
|
|
)
|
|
{
|
|
ASSERTGDI(cj != 0, "ERROR GDI BRUSHOBJ_pvAllocRbrush cj = 0");
|
|
ASSERTGDI(pbo->iSolidColor == 0xFFFFFFFF,
|
|
"ERROR GDI BRUSHOBJ_pvAllocRbrush solid color brush passed in");
|
|
|
|
DBRUSH *pdbrush;
|
|
|
|
#if DBG
|
|
dbrushalloc++;
|
|
#endif
|
|
|
|
//
|
|
// If there's a cached DBRUSH, try to use it instead of allocating
|
|
//
|
|
if (gpCachedDbrush != NULL)
|
|
{
|
|
|
|
#if DBG
|
|
dbrushcachecheck++;
|
|
#endif
|
|
//
|
|
// Try to grab the cached DBRUSH
|
|
//
|
|
|
|
if ((pdbrush =
|
|
(PDBRUSH) InterlockedExchangePointer((PVOID *)&gpCachedDbrush,
|
|
NULL))
|
|
!= NULL)
|
|
{
|
|
|
|
#if DBG
|
|
dbrushcachegrabbed++;
|
|
#endif
|
|
|
|
//
|
|
// Got the cached DBRUSH; see if it's big enough
|
|
//
|
|
// Note: -4 because we define the realization buffer start as aj[0]
|
|
//
|
|
|
|
if (pdbrush->ulSizeGet() >= (sizeof(DBRUSH) - 4 + cj))
|
|
{
|
|
|
|
#if DBG
|
|
dbrushcachehit++;
|
|
#endif
|
|
//
|
|
// It's big enough, so we'll use it and we're done
|
|
//
|
|
return(pbo->pvRbrush = pdbrush->aj);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not big enough; free it and do a normal allocation
|
|
//
|
|
VFREEMEM(pdbrush);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Note: -4 because we define the realization buffer start as aj[0]
|
|
if ((pdbrush = (DBRUSH *)PALLOCMEM(ULONGSIZE_T(sizeof(DBRUSH) - 4 + cj),'rbdG'))
|
|
!= NULL)
|
|
{
|
|
//
|
|
// Remember the size of the allocation, for caching.
|
|
//
|
|
pdbrush->ulSizeSet(sizeof(DBRUSH) - 4 + cj);
|
|
|
|
return(pbo->pvRbrush = pdbrush->aj);
|
|
}
|
|
else
|
|
{
|
|
WARNING("Failed memory alloc BRUSHOBJ_pvAllocRbrush\n");
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// User mode printer driver support
|
|
//
|
|
|
|
PVOID
|
|
BRUSHOBJ_pvAllocRbrushUMPD(
|
|
BRUSHOBJ *pbo,
|
|
ULONG cj
|
|
)
|
|
|
|
{
|
|
if (pbo->pvRbrush == NULL)
|
|
{
|
|
DBRUSH *pdbrush;
|
|
|
|
cj += MAGIC_DBR_DIFF;
|
|
|
|
if (pdbrush = (DBRUSH *) EngAllocUserMem(cj, UMPD_MEMORY_TAG))
|
|
{
|
|
pdbrush->ulSizeSet(cj);
|
|
pdbrush->bMultiBrush(FALSE);
|
|
pdbrush->bUMPDRBrush(TRUE);
|
|
|
|
pbo->pvRbrush = pdbrush->aj;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RIP("BRUSHOBJ_pvAllocRbrush when pvRbrush is not NULL\n");
|
|
}
|
|
|
|
return pbo->pvRbrush;
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vTryToCacheRealization
|
|
*
|
|
* Attempt to cache the realization pointed to by pdbrush and described by pebo
|
|
* in the logical brush pointed to by pbrush. The way this works is that only
|
|
* the first realization of the logical brush can be cached. crFore is the key
|
|
* that indicates when the cached realization is valid. If crFore is not -1 when
|
|
* the logical brush is being realized, we just go realize the brush; if it's
|
|
* not -1, we check the cache ID fields to see if we can use the cached fields.
|
|
* InterlockedExchange() is used below to set crFore to make sure the cache ID
|
|
* fields are set before crFore. bCacheGrabbed() is used to protect the setting
|
|
* of the cache ID fields; once it's set, no one else can modify the cache ID
|
|
* fields, but no one else will try to use them until crFore is not -1.
|
|
*
|
|
* Also initializes the reference count in the realization to indicates either
|
|
* 1 or 2 current uses, depending on whether caching took place.
|
|
*
|
|
* History:
|
|
* 31-Oct-1993 -by- Michael Abrash [mikeab]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
vTryToCacheRealization(
|
|
EBRUSHOBJ *pebo,
|
|
PRBRUSH prbrush,
|
|
PBRUSH pbrush,
|
|
BOOL bType
|
|
)
|
|
{
|
|
// Reference count the realization once for being selected into this DC. This
|
|
// assumes we won't succeed in caching the brush next; if we do, we do a double
|
|
// reference count, once for caching in the logical brush and once for
|
|
// selecting into the DC
|
|
|
|
prbrush->cRef(1);
|
|
|
|
// See if we can cache this realization in the logical brush; we can't if
|
|
// another realization has already been cached in the logical brush
|
|
|
|
if ( !pbrush->bCacheGrabbed() )
|
|
{
|
|
|
|
// Try to grab the "can cache" flag; if we don't get it, someone just
|
|
// sneaked in and got it ahead of us, so we're out of luck and can't cache
|
|
|
|
if ( pbrush->bGrabCache() )
|
|
{
|
|
|
|
// We got the "can cache" flag, so now we can cache this realization
|
|
// in the logical brush
|
|
|
|
// It's cached in the brush, so it won't be deleted until the logical
|
|
// brush goes away and it's not selected into any DCs, so reference
|
|
// count the realization again. We don't need to do an
|
|
// InterlockedIncrement here because until crFore is set, no one else
|
|
// can get at this realization. InterlockedExchange() is used below to
|
|
// set crFore to make sure the reference count is set before anyone
|
|
// else can see the caching info
|
|
|
|
prbrush->cRef(2);
|
|
|
|
// These cache ID fields must be set before crFore, because crFore
|
|
// is the key that indicates when the cached realization is valid.
|
|
// If crFore is -1 when the logical brush is being realized, we
|
|
// just go realize the brush; if it's not -1, we check the cache ID
|
|
// fields to see if we can use the cached fields.
|
|
// InterlockedExchange() is used below to set crFore to make sure
|
|
// the cache ID fields are set before crFore
|
|
|
|
if (bType == CR_ENGINE_REALIZATION)
|
|
{
|
|
pbrush->SetEngineRealization();
|
|
}
|
|
else
|
|
{
|
|
pbrush->SetDriverRealization();
|
|
}
|
|
pbrush->crBack(pebo->crCurrentBack());
|
|
pbrush->ulPalTime(pebo->ulDCPalTime());
|
|
pbrush->ulSurfTime(pebo->ulSurfPalTime());
|
|
pbrush->ulRealization((ULONG_PTR)prbrush);
|
|
pbrush->hdevRealization(pebo->psoTarg()->hdev());
|
|
pbrush->crPalColor(pebo->crDCPalColor());
|
|
|
|
// This must be set last, because once it's set, other selections of
|
|
// this logical brush will attempt to use the cached brush. The use of
|
|
// InterlockedExchange in this method enforces this
|
|
|
|
pbrush->crForeLocked(pebo->crCurrentText());
|
|
|
|
// The realization is now cached in the logical brush
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BRUSHOBJ_pvGetRbrush
|
|
*
|
|
* Returns a pointer to the driver's realization of the brush.
|
|
*
|
|
* History:
|
|
* 31-Oct-1993 -by- Michael Abrash
|
|
* Rewrote to cache the first realization in the logical brush.
|
|
*
|
|
* 8-Sep-1992 -by- Paul Butzi
|
|
* Rewrote it.
|
|
*
|
|
* Wed 05-Jun-1991 -by- Patrick Haluptzok [patrickh]
|
|
* major revision
|
|
*
|
|
* 25-Apr-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
PVOID
|
|
BRUSHOBJ_pvGetRbrush(
|
|
BRUSHOBJ *pbo
|
|
)
|
|
{
|
|
EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo;
|
|
|
|
ASSERTGDI(pbo->iSolidColor == 0xFFFFFFFF, "ERROR GDI iSolidColor");
|
|
|
|
//
|
|
// Check if the brush has already been realized.
|
|
//
|
|
|
|
if (pebo->pvRbrush != NULL)
|
|
{
|
|
return(pebo->pvRbrush);
|
|
}
|
|
|
|
//
|
|
// Get this thing realized.
|
|
//
|
|
|
|
PDEVOBJ pdo(pebo->psoTarg()->hdev());
|
|
|
|
if (!bGetRealizedBrush(pebo->pbrush(), pebo, PPFNDRV(pdo, RealizeBrush)))
|
|
{
|
|
if (pebo->pvRbrush != NULL)
|
|
{
|
|
VFREEMEM(DBRUSHSTART(pebo->pvRbrush)); // free the DBRUSH
|
|
pebo->pvRbrush = NULL; // mark that there's no realization
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
//
|
|
// Try to cache the realization in the logical brush
|
|
//
|
|
|
|
//Make sure the brush is indeed realized
|
|
if (pebo->pvRbrush == NULL)
|
|
return(NULL);
|
|
|
|
vTryToCacheRealization(pebo,
|
|
(PDBRUSH) DBRUSHSTART(pebo->pvRbrush),
|
|
pebo->pbrush(),
|
|
CR_DRIVER_REALIZATION);
|
|
|
|
return pebo->pvRbrush;
|
|
}
|
|
|
|
//
|
|
// User mode printer driver support
|
|
//
|
|
|
|
PVOID
|
|
BRUSHOBJ_pvGetRbrushUMPD(
|
|
BRUSHOBJ *pbo
|
|
)
|
|
|
|
{
|
|
EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo;
|
|
|
|
if (pbo->iSolidColor != 0xFFFFFFFF)
|
|
{
|
|
RIP("BRUSHOBJ_pvGetRbrush called for solid brush\n");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Check if the brush has already been realized
|
|
//
|
|
|
|
if (pebo->pvRbrush != NULL)
|
|
return pebo->pvRbrush;
|
|
|
|
//
|
|
// Realize the brush
|
|
//
|
|
|
|
PDEVOBJ pdo(pebo->psoTarg()->hdev());
|
|
|
|
if (!bGetRealizedBrush(pebo->pbrush(), pebo, PPFNDRV(pdo, RealizeBrush)))
|
|
{
|
|
if (pebo->pvRbrush != NULL)
|
|
{
|
|
EngFreeUserMem(DBRUSHSTART(pebo->pvRbrush));
|
|
pebo->pvRbrush = NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//Make sure the brush is indeed realized
|
|
if (pebo->pvRbrush == NULL)
|
|
return(NULL);
|
|
|
|
#if defined(_WIN64)
|
|
//
|
|
// if we are doing WOW64 printing, skip the caching.
|
|
//
|
|
|
|
PW32THREAD pThread = W32GetCurrentThread();
|
|
|
|
if (pThread->pClientID == NULL)
|
|
#endif
|
|
{
|
|
// Try to cache the realization in the logical brush
|
|
|
|
vTryToCacheRealization(pebo, (PDBRUSH)DBRUSHSTART(pebo->pvRbrush),
|
|
pebo->pbrush(), CR_DRIVER_REALIZATION);
|
|
}
|
|
|
|
return pebo->pvRbrush;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BRUSHOBJ_ulGetBrushColor
|
|
*
|
|
* Returns the RGB color for a solid brush.
|
|
*
|
|
* Oct-18-1995 -by- Lingyun Wang
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
ULONG
|
|
BRUSHOBJ_ulGetBrushColor(
|
|
BRUSHOBJ *pbo
|
|
)
|
|
{
|
|
EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo;
|
|
|
|
if (pebo->bIsSolid())
|
|
{
|
|
if(pebo->flColorType & BR_ORIGCOLOR)
|
|
{
|
|
pebo->flColorType &= ~BR_ORIGCOLOR;
|
|
return ((ULONG)(pebo->crOrignal()));
|
|
}
|
|
else
|
|
{
|
|
return ((ULONG)(pebo->crRealized()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (ULONG)(-1);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BRUSHOBJ_hGetColorTransform
|
|
*
|
|
* Retuens the color transform for a brush.
|
|
*
|
|
* Feb-14-1997 -by- Hideyuki Nagase
|
|
* Wrote it.
|
|
***************************************************************************/
|
|
|
|
HANDLE
|
|
BRUSHOBJ_hGetColorTransform(
|
|
BRUSHOBJ *pbo
|
|
)
|
|
{
|
|
ICMAPI(("BRUSHOBJ_hGetColorTransform()\n"));
|
|
|
|
if (pbo == NULL)
|
|
{
|
|
WARNING("BRUSHOBJ_hGetColorTransform() BRUSHOBJ is NULL\n");
|
|
return(NULL);
|
|
}
|
|
|
|
EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo;
|
|
|
|
//
|
|
// if ICM is not enabled for this. Or if ICM is done by host,
|
|
// Color transform handle is for host ICM it is no meanings
|
|
// for device driver. then just return NULL.
|
|
//
|
|
if (pebo->bIsDeviceICM())
|
|
{
|
|
if (pebo->hcmXform())
|
|
{
|
|
COLORTRANSFORMOBJ CXFormObj(pebo->hcmXform());
|
|
|
|
if (CXFormObj.bValid())
|
|
{
|
|
return(CXFormObj.hGetDeviceColorTransform());
|
|
}
|
|
|
|
ICMMSG(("BRUSHOBJ_hGetColorTransform() COLORTRANSFORMOBJ is invalid\n"));
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("BRUSHOBJ_hGetColorTransform() Ident. color transform\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("BRUSHOBJ_hGetColorTransform() ICM on device is not enabled\n"));
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* pvGetEngRbrush
|
|
*
|
|
* Returns: A pointer to the engines's realization of a logical brush.
|
|
*
|
|
* Only the engine calls this, it is not exported.
|
|
*
|
|
* History:
|
|
* 31-Oct-1993 -by- Michael Abrash
|
|
* Rewrote to cache the first realization in the logical brush.
|
|
*
|
|
* 8-Sep-1992 -by- Paul Butzi
|
|
* Rewrote it.
|
|
*
|
|
* Wed 05-Jun-1991 -by- Patrick Haluptzok [patrickh]
|
|
* major revision
|
|
*
|
|
* 25-Apr-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it - First pass.
|
|
\**************************************************************************/
|
|
|
|
PVOID
|
|
pvGetEngRbrush(
|
|
BRUSHOBJ *pbo
|
|
)
|
|
{
|
|
EBRUSHOBJ *pebo = (EBRUSHOBJ *) pbo;
|
|
|
|
ASSERTGDI(pbo->iSolidColor == 0xFFFFFFFF, "ERROR GDI iSolidColor");
|
|
|
|
// Check if the brush has already been realized.
|
|
|
|
if (pebo->pengbrush() != (PVOID) NULL)
|
|
{
|
|
return pebo->pengbrush();
|
|
}
|
|
|
|
// Get this thing realized.
|
|
|
|
PDEVOBJ pdo(pebo->psoTarg()->hdev());
|
|
|
|
if (!bGetRealizedBrush(pebo->pbrush(), pebo, EngRealizeBrush))
|
|
{
|
|
if (pebo->pengbrush() != NULL)
|
|
{
|
|
VFREEMEM(pebo->pengbrush()); // free the DBRUSH
|
|
pebo->pengbrush(NULL); // mark that there's no realization
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
// Try to cache the realization in the logical brush
|
|
|
|
vTryToCacheRealization(pebo, pebo->pengbrush(), pebo->pbrush(),
|
|
CR_ENGINE_REALIZATION);
|
|
|
|
return(pebo->pengbrush());
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bGetRealizedBrush
|
|
*
|
|
* Returns: Pointer to a Realized brush.
|
|
*
|
|
* NOTE: The surface in pebo->psoTarg() is the surface of the original
|
|
* destination of the drawing call. If a display driver was called,
|
|
* but it punts by calling back to the engine with an engine-managed
|
|
* bitmap it created, psoTarg() will still point to the original
|
|
* display surface, not the DIB surface. The surface will have the
|
|
* same hdev, iFormat, etc., but this means that the iType will be
|
|
* wrong, so don't reference it! (EngRealizeBrush actually accounts
|
|
* for this little lie.)
|
|
*
|
|
* History:
|
|
* 14-Jul-1992 -by- Eric Kutter [erick]
|
|
* added exception handling, changed from VOID to BOOL
|
|
*
|
|
* Mon 07-Oct-1991 -by- Patrick Haluptzok [patrickh]
|
|
* add support for DIB_PAL_COLORS flag.
|
|
*
|
|
* 04-Jun-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
bGetRealizedBrush(
|
|
BRUSH *pbrush,
|
|
EBRUSHOBJ *pebo,
|
|
PFN_DrvRealizeBrush pfnDrv
|
|
)
|
|
{
|
|
ASSERTGDI(pebo->iSolidColor == 0xFFFFFFFF, "ERROR GDI iSolidColor");
|
|
ASSERTGDI(pfnDrv != (PFN_DrvRealizeBrush) 0, "ERROR pfnDrv");
|
|
|
|
//
|
|
// quick out if it is a NULL brush
|
|
//
|
|
|
|
if (pbrush->ulStyle() == HS_NULL)
|
|
{
|
|
WARNING1("You are doing output calls with a NULL brush\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Dispatch off to driver to get brush realized.
|
|
//
|
|
|
|
ULONG ulStyle = pbrush->ulStyle();
|
|
SURFOBJ *psoPattern;
|
|
SURFOBJ *psoMask = NULL;
|
|
XEPALOBJ palSrc;
|
|
XEPALOBJ palDest;
|
|
SURFREF SurfBmoPattern;
|
|
EXLATEOBJ exlo;
|
|
XLATE *pxlo = NULL;
|
|
SURFMEM SurfDimo;
|
|
|
|
//
|
|
// We default to this.
|
|
//
|
|
|
|
PDEVOBJ po(pebo->psoTarg()->hdev());
|
|
ASSERTGDI(po.bValid(), "ERROR BRUSHOBJ_ 5");
|
|
|
|
//
|
|
// We need to hold the Devlock to protect against dynamic mode changes
|
|
// while we muck around in the driver. If we're being call by the
|
|
// driver, we're guaranteed to already be holding it, so we only have
|
|
// to do this if we're being called by GDI's Eng functions.
|
|
//
|
|
|
|
DEVLOCKOBJ dlo;
|
|
if (pfnDrv == EngRealizeBrush)
|
|
{
|
|
dlo.vLock(po);
|
|
}
|
|
else
|
|
{
|
|
dlo.vInit();
|
|
}
|
|
|
|
if (pbrush->ulStyle() < HS_DDI_MAX)
|
|
{
|
|
//
|
|
// For hatch brushes, the pattern is also the mask
|
|
//
|
|
|
|
SurfBmoPattern.vAltLock((HSURF)po.hbmPattern(pbrush->ulStyle()));
|
|
psoMask = SurfBmoPattern.pSurfobj();
|
|
|
|
if (exlo.pCreateXlateObject(2))
|
|
{
|
|
ULONG ulValue1, ulValue2;
|
|
|
|
if (pebo->bIsCMYKColor())
|
|
{
|
|
//
|
|
// We are in CMYK color context, we just set CMYK color
|
|
//
|
|
ulValue1 = pebo->crCurrentBack();
|
|
ulValue2 = pebo->crRealized();
|
|
|
|
exlo.pxlo()->vSetIndex(0, ulValue1);
|
|
exlo.pxlo()->vSetIndex(1, ulValue2);
|
|
|
|
pxlo = exlo.pxlo();
|
|
pxlo->vCheckForICM(pebo->hcmXform(),pebo->lIcmMode());
|
|
pxlo->ppalSrc = ppalMono;
|
|
pxlo->ppalDst = pebo->palSurf().ppalGet();
|
|
pxlo->ppalDstDC = pebo->palDC().ppalGet();
|
|
}
|
|
else
|
|
{
|
|
ulValue1 = ulGetNearestIndexFromColorref(
|
|
pebo->palSurf(),
|
|
pebo->palDC(),
|
|
pebo->crCurrentBack()
|
|
);
|
|
|
|
ulValue2 = ulGetNearestIndexFromColorref(
|
|
pebo->palSurf(),
|
|
pebo->palDC(),
|
|
pebo->crRealized()
|
|
);
|
|
|
|
//
|
|
// Windows compability issue:
|
|
// force to draw on the background
|
|
//
|
|
// We force the forground to be mapped
|
|
// to an index opposite to the background
|
|
//
|
|
|
|
if ((pebo->psoTarg()->iFormat() == BMF_1BPP) &&
|
|
(pebo->palSurf().bIsIndexed()) &&
|
|
(pebo->crCurrentBack() != pebo->crRealized()) &&
|
|
(ulValue1 == ulValue2))
|
|
{
|
|
ulValue2 = 1-ulValue1;
|
|
}
|
|
|
|
exlo.pxlo()->vSetIndex(0, ulValue1);
|
|
exlo.pxlo()->vSetIndex(1, ulValue2);
|
|
|
|
pxlo = exlo.pxlo();
|
|
pxlo->vCheckForICM(pebo->hcmXform(),pebo->lIcmMode());
|
|
pxlo->vCheckForTrivial();
|
|
pxlo->ppalSrc = ppalMono;
|
|
pxlo->ppalDst = pebo->palSurf().ppalGet();
|
|
pxlo->ppalDstDC = pebo->palDC().ppalGet();
|
|
}
|
|
pxlo->iForeDst = ulValue1;
|
|
pxlo->iBackDst = ulValue2;
|
|
pxlo->flPrivate |= XLATE_FROM_MONO;
|
|
}
|
|
else
|
|
{
|
|
WARNING("ERROR failed to create hatch xlate\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else if (pbrush->ulStyle() < HS_NULL)
|
|
{
|
|
//
|
|
// For solid brushes.
|
|
//
|
|
|
|
ASSERTGDI(pbrush->flAttrs() & BR_IS_SOLID, "ERROR non-solid brush");
|
|
ASSERTGDI((pbrush->flAttrs() & BR_DITHER_OK) ||
|
|
(po.bCapsForceDither()),
|
|
"ERROR BRUSHOBJ_ 1");
|
|
|
|
//
|
|
// We will not dither CMYK color brush. Driver should not call BRUSHOBJ_pvGetRbrush
|
|
// with CMYK solid color brush.
|
|
//
|
|
|
|
if (pebo->bIsCMYKColor())
|
|
{
|
|
WARNING("ERROR bGetRealizedBrush() Can't dither CMYK color brush\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// This means they want us to dither the color and nothing
|
|
// in their palette is close enough that we can't just use
|
|
// a solid color.
|
|
//
|
|
|
|
if (pebo->crRealized() & 0x01000000)
|
|
{
|
|
pebo->crRealized(rgbFromColorref(pebo->palSurf(),
|
|
pebo->palDC(),
|
|
pebo->crRealized()));
|
|
}
|
|
|
|
//
|
|
// Use the nifty DitherOnRealize option, if the driver supports it and
|
|
// we're not realizing the brush on behalf of the engine simulations
|
|
// (since the engine will be drawing, it will need its own realization,
|
|
// not the driver's):
|
|
//
|
|
|
|
if ((po.flGraphicsCaps() & GCAPS_DITHERONREALIZE) &&
|
|
(pfnDrv != EngRealizeBrush))
|
|
{
|
|
if ((*pfnDrv) (pebo,
|
|
pebo->psoTarg()->pSurfobj(),
|
|
(SURFOBJ *) NULL,
|
|
(SURFOBJ *) NULL,
|
|
NULL,
|
|
pebo->crRealized() | RB_DITHERCOLOR))
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
DEVBITMAPINFO dbmi;
|
|
|
|
if (pebo->psoTarg()->iFormat() == BMF_1BPP)
|
|
{
|
|
dbmi.iFormat = BMF_1BPP;
|
|
}
|
|
else
|
|
{
|
|
dbmi.iFormat = po.iDitherFormat();
|
|
}
|
|
|
|
dbmi.cxBitmap = po.cxDither();
|
|
dbmi.cyBitmap = po.cyDither();
|
|
dbmi.hpal = 0;
|
|
dbmi.fl = BMF_TOPDOWN;
|
|
|
|
if (!SurfDimo.bCreateDIB(&dbmi, NULL))
|
|
{
|
|
WARNING("Failed memory alloc in dither brush\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
ULONG iRes;
|
|
ULONG iDitherMode = ((pebo->psoTarg()->iFormat() == BMF_1BPP) ? DM_MONOCHROME: DM_DEFAULT);
|
|
|
|
if (PPFNVALID(po, DitherColor))
|
|
{
|
|
iRes = (*PPFNDRV(po, DitherColor)) (
|
|
po.bUMPD() ? (DHPDEV)po.ppdev : po.dhpdev(),
|
|
iDitherMode,
|
|
pebo->crRealized(),
|
|
(PULONG) SurfDimo.ps->pvBits());
|
|
}
|
|
else
|
|
{
|
|
iRes = EngDitherColor(po.hdev(),
|
|
iDitherMode,
|
|
pebo->crRealized(),
|
|
(PULONG) SurfDimo.ps->pvBits());
|
|
}
|
|
|
|
switch (iRes)
|
|
{
|
|
case DCR_DRIVER:
|
|
pxlo = &xloIdent;
|
|
break;
|
|
|
|
case DCR_HALFTONE:
|
|
{
|
|
if ((po.pDevHTInfo() == NULL) && !po.bEnableHalftone(NULL))
|
|
return(FALSE);
|
|
|
|
DEVICEHALFTONEINFO *pDevHTInfo = (DEVICEHALFTONEINFO *)po.pDevHTInfo();
|
|
|
|
COLORTRIAD ColorTriad;
|
|
CHBINFO CHBInfo;
|
|
COLORREF cr = pebo->crRealized();
|
|
|
|
ColorTriad.Type = COLOR_TYPE_RGB;
|
|
ColorTriad.BytesPerPrimary = sizeof(BYTE);
|
|
ColorTriad.BytesPerEntry = sizeof(DWORD);
|
|
ColorTriad.PrimaryOrder = PRIMARY_ORDER_RGB;
|
|
ColorTriad.PrimaryValueMax = 255;
|
|
ColorTriad.ColorTableEntries = 1;
|
|
ColorTriad.pColorTable = (LPVOID)&cr;
|
|
|
|
CHBInfo.Flags = (BYTE)((po.GdiInfo()->flHTFlags & HT_FLAG_OUTPUT_CMY) ?
|
|
0 : CHBF_USE_ADDITIVE_PRIMS);
|
|
|
|
// Control ICM bits for halftoning
|
|
|
|
if ((pebo->bIsAppsICM()) ||
|
|
(!pebo->bDeviceCalibrate() && (pebo->bIsHostICM() || pebo->bIsDeviceICM())))
|
|
{
|
|
ICMDUMP(("bGetRealizedBrush(): 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.
|
|
|
|
CHBInfo.Flags |= CHBF_ICM_ON;
|
|
}
|
|
else
|
|
{
|
|
ICMDUMP(("bGetRealizedBrush(): ICM with Halftone (Dynamic Bit Off)\n"));
|
|
}
|
|
|
|
if ((pDevHTInfo->cxPattern != dbmi.cxBitmap) ||
|
|
(pDevHTInfo->cyPattern != dbmi.cyBitmap))
|
|
{
|
|
SurfDimo.ps->bDeleteSurface();
|
|
dbmi.cxBitmap = pDevHTInfo->cxPattern;
|
|
dbmi.cyBitmap = pDevHTInfo->cyPattern;
|
|
|
|
if (!SurfDimo.bCreateDIB(&dbmi, NULL))
|
|
{
|
|
WARNING("Failed memory alloc in dither brush1\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
switch(po.GdiInfo()->ulHTOutputFormat)
|
|
{
|
|
case HT_FORMAT_1BPP:
|
|
CHBInfo.DestSurfaceFormat = (BYTE)BMF_1BPP;
|
|
break;
|
|
case HT_FORMAT_4BPP:
|
|
CHBInfo.DestSurfaceFormat = (BYTE)BMF_4BPP;
|
|
break;
|
|
case HT_FORMAT_4BPP_IRGB:
|
|
CHBInfo.DestSurfaceFormat = (BYTE)BMF_4BPP_VGA16;
|
|
break;
|
|
case HT_FORMAT_8BPP:
|
|
CHBInfo.DestSurfaceFormat = (BYTE)BMF_8BPP_VGA256;
|
|
break;
|
|
case HT_FORMAT_16BPP:
|
|
//
|
|
// Need to switch between BMF_16BPP_555 and BMF_16BPP_565
|
|
//
|
|
CHBInfo.DestSurfaceFormat = (BYTE)BMF_16BPP_555;
|
|
break;
|
|
case HT_FORMAT_32BPP:
|
|
CHBInfo.DestSurfaceFormat = (BYTE)BMF_32BPP;
|
|
break;
|
|
default:
|
|
WARNING("Halftone format not supported\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
CHBInfo.DestScanLineAlignBytes = BMF_ALIGN_DWORD;
|
|
CHBInfo.DestPrimaryOrder = (BYTE)po.GdiInfo()->ulPrimaryOrder;
|
|
|
|
// Brushes, unlike scanned in images, have linear RGB gamma.
|
|
// Use a gamma value of 1 can produce lighter, closer to wfw halftone
|
|
// images for solid brushes. This is to fix powerpnt shaded background
|
|
// printing. Other apps that print black text on dark background will
|
|
// benefit from this fix as well.
|
|
|
|
COLORADJUSTMENT ca = *pebo->pColorAdjustment();
|
|
ca.caRedGamma = 10000;
|
|
ca.caGreenGamma = 10000;
|
|
ca.caBlueGamma = 10000;
|
|
|
|
if (HT_CreateHalftoneBrush(
|
|
pDevHTInfo,
|
|
(PHTCOLORADJUSTMENT)&ca,
|
|
&ColorTriad,
|
|
CHBInfo,
|
|
(PULONG)SurfDimo.ps->pvBits()) > 0)
|
|
{
|
|
// Set up the translate object.
|
|
|
|
if (po.bHTPalIsDevPal())
|
|
{
|
|
pxlo = &xloIdent;
|
|
}
|
|
else
|
|
{
|
|
EPALOBJ palHT((HPALETTE)pDevHTInfo->DeviceOwnData);
|
|
|
|
palDest.ppalSet(pebo->psoTarg()->ppal());
|
|
|
|
if (!exlo.bInitXlateObj(
|
|
pebo->hcmXform(),
|
|
pebo->lIcmMode(),
|
|
palHT, palDest,
|
|
pebo->palDC(),
|
|
pebo->palDC(),
|
|
pebo->crCurrentText(),
|
|
pebo->crCurrentBack(),
|
|
0x00FFFFFF
|
|
))
|
|
{
|
|
WARNING("Failed to create an xlate bGetRealizedBrush DIB_PAL_COLORS\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
pxlo = exlo.pxlo();
|
|
}
|
|
break;
|
|
}
|
|
} // case DCR_HALFTONE
|
|
|
|
default:
|
|
WARNING("DrvDitherColor returned invalid value or failed\n");
|
|
return(FALSE);
|
|
} // switch (iRes)
|
|
}
|
|
else // if (pbrush->ulStyle() >= HS_NULL)
|
|
{
|
|
BOOL bIcmBrush = FALSE;
|
|
|
|
//
|
|
// For bitmap/pattern brushes.
|
|
//
|
|
|
|
HSURF hDIB = (HSURF)pbrush->hbmPattern();
|
|
|
|
ASSERTGDI(pbrush->ulStyle() <= HS_PATMSK, "ERROR ulStyle is bad");
|
|
|
|
// ICM is enabled ? and the Brush is DIB ? For Device Depend Bitmap, we will
|
|
// not enable ICM. Only for DIB.
|
|
|
|
if (pebo->bIsHostICM())
|
|
{
|
|
if (pebo->hcmXform() != NULL)
|
|
{
|
|
if (pbrush->flAttrs() & BR_IS_DIB)
|
|
{
|
|
// if ICM is enabled, the BRUSHOBJ should have color transform.
|
|
|
|
if (pbrush->iUsage() == DIB_RGB_COLORS)
|
|
{
|
|
ICMMSG(("bGetRealizedBrush: TRY Find ICM DIB\n"));
|
|
|
|
// Find color translated brush DIB.
|
|
|
|
HSURF hIcmDIB = (HSURF)(pbrush->hFindIcmDIB(pebo->hcmXform()));
|
|
|
|
if (hIcmDIB == NULL)
|
|
{
|
|
// Somehow, we could not find DIB, just use orginal.
|
|
|
|
WARNING1("bGetRealizedBrush(): hFindIcmDIB() returns NULL\n");
|
|
}
|
|
else
|
|
{
|
|
// Replace DIB handle with ICM-ed DIB.
|
|
|
|
hDIB = hIcmDIB;
|
|
bIcmBrush = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if DIB is other than DIB_RGB_COLORS, ICM DIB will not be used.
|
|
|
|
ICMMSG(("bGetRealizedBrush(): Brush color is not DIB_RGB_COLORS\n"));
|
|
}
|
|
}
|
|
else if (pbrush->flAttrs() & BR_IS_MONOCHROME)
|
|
{
|
|
ICMMSG(("bGetRealizedBrush(): Brush color is BR_IS_MONOCHROME\n"));
|
|
|
|
bIcmBrush = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ICM is enabled, but no color transform, it means identical color transform
|
|
// so, there is no ICM-ed DIB.
|
|
|
|
ICMMSG(("bGetRealizedBrush(): Color transform is identical\n"));
|
|
|
|
// If we are in CMYK mode, we must have color transform.
|
|
|
|
if (!pebo->bIsCMYKColor())
|
|
{
|
|
bIcmBrush = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else if (pebo->bIsAppsICM() || pebo->bIsDeviceICM())
|
|
{
|
|
bIcmBrush = TRUE;
|
|
}
|
|
|
|
SurfBmoPattern.vAltLock(hDIB);
|
|
|
|
if(!SurfBmoPattern.bValid())
|
|
{
|
|
WARNING("WARNING:bGetRealizedBrush(): Invalid SurfBmopattern\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
palSrc.ppalSet(SurfBmoPattern.ps->ppal());
|
|
palDest.ppalSet(pebo->psoTarg()->ppal());
|
|
|
|
if (pbrush->bPalColors())
|
|
{
|
|
ASSERTGDI(palSrc.bValid(), "ERROR3invalid hpal pvGetEngRbrush\n");
|
|
|
|
if (!exlo.bMakeXlate((PUSHORT) palSrc.apalColorGet(),
|
|
pebo->palDC(),
|
|
pebo->psoTarg(),
|
|
palSrc.cColorTableLength(),
|
|
palSrc.cEntries()))
|
|
{
|
|
WARNING("Failed to create an xlate bGetRealizedBrush DIB_PAL_COLORS\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
pxlo = exlo.pxlo();
|
|
}
|
|
else if (pbrush->bPalIndices())
|
|
{
|
|
if (SurfBmoPattern.ps->iFormat() != pebo->psoTarg()->iFormat())
|
|
{
|
|
WARNING("Output failed: DIB_PAL_INDICES brush not compatible with dest surface\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
pxlo = &xloIdent;
|
|
}
|
|
else
|
|
{
|
|
// With our wonderful API we can't fail a brush selection like Windows would.
|
|
// Instead we let the app think he selected the bitmap brush in and then at
|
|
// realize time if that wasn't a valid selection we fail the realize. Good
|
|
// luck writing new apps.
|
|
|
|
PPALETTE ppalSrcTmp;
|
|
|
|
// We need to make sure this could be selected into this DC. If it is a device
|
|
// managed bitmap, it must be the same device.
|
|
|
|
if ((
|
|
(SurfBmoPattern.ps->iType() != STYPE_BITMAP) ||
|
|
(SurfBmoPattern.ps->dhsurf() != 0)
|
|
)
|
|
&&
|
|
(SurfBmoPattern.ps->hdev() != po.hdev()))
|
|
{
|
|
WARNING1("bGetRealizedBrush failed Device surface for another PDEV\n");
|
|
return (FALSE);
|
|
}
|
|
else if (SurfBmoPattern.ps->ppal() != NULL)
|
|
{
|
|
// No problem, we already have color information.
|
|
|
|
ppalSrcTmp = SurfBmoPattern.ps->ppal();
|
|
}
|
|
else
|
|
{
|
|
if (SurfBmoPattern.ps->iFormat() == po.iDitherFormat())
|
|
{
|
|
if (po.bIsPalManaged())
|
|
{
|
|
ppalSrcTmp = (PPALETTE) NULL;
|
|
}
|
|
else
|
|
{
|
|
ppalSrcTmp = po.ppalSurf();
|
|
}
|
|
}
|
|
else if (SurfBmoPattern.ps->iFormat() == pebo->iMetaFormat())
|
|
{
|
|
// We can try to use palette from meta.
|
|
|
|
ppalSrcTmp = pebo->palMeta().ppalGet();
|
|
}
|
|
else if (SurfBmoPattern.ps->iFormat() == BMF_8BPP)
|
|
{
|
|
if (po.bIsPalManaged())
|
|
{
|
|
ppalSrcTmp = (PPALETTE) NULL;
|
|
}
|
|
else
|
|
{
|
|
ppalSrcTmp = ppalDefaultSurface8bpp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (po.bMetaDriver())
|
|
ppalSrcTmp = (PPALETTE) NULL;
|
|
else
|
|
{
|
|
WARNING("bGetRealizedBrush failed - bitmap not compatible with surface\n");
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Replace source palette with proper one which decided in above.
|
|
|
|
palSrc.ppalSet(ppalSrcTmp);
|
|
|
|
if (!exlo.bInitXlateObj(
|
|
(bIcmBrush ? pebo->hcmXform() : NULL),
|
|
(bIcmBrush ? pebo->lIcmMode() : DC_ICM_OFF),
|
|
palSrc,
|
|
palDest,
|
|
pebo->palDC(),
|
|
pebo->palDC(),
|
|
pebo->crCurrentText(),
|
|
pebo->crCurrentBack(),
|
|
0x00FFFFFF
|
|
))
|
|
{
|
|
WARNING("Failed to create an xlate pvGetRbrush\n");
|
|
return (FALSE);
|
|
}
|
|
|
|
pxlo = exlo.pxlo();
|
|
}
|
|
}
|
|
|
|
// Do the right thing if a pattern is provided
|
|
|
|
if (SurfBmoPattern.bValid())
|
|
{
|
|
psoPattern = SurfBmoPattern.pSurfobj();
|
|
}
|
|
else
|
|
{
|
|
// Check for dithering
|
|
|
|
if (SurfDimo.bValid())
|
|
{
|
|
psoPattern = SurfDimo.pSurfobj();
|
|
}
|
|
else
|
|
psoPattern = (SURFOBJ *) NULL;
|
|
}
|
|
|
|
// Call off to driver to the RealizeBrush
|
|
|
|
return((*pfnDrv) (pebo, pebo->psoTarg()->pSurfobj(),
|
|
psoPattern, psoMask,
|
|
pxlo,
|
|
ulStyle));
|
|
}
|