|
|
/******************************Module*Header*******************************\
* Module Name: brushobj.cxx * * Support for brmemobj.hxx and brushobj.hxx. * * Created: 06-Dec-1990 12:02:24 * Author: Walt Moore [waltm] * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/
#include "precomp.hxx"
extern "C" BOOL bInitBRUSHOBJ(); extern "C" BOOL bInitBrush(int iBrush, COLORREF cr, DWORD dwHS, PULONG_PTR pdw, BOOL bEnableDither);
#pragma alloc_text(INIT, bInitBRUSHOBJ)
#pragma alloc_text(INIT, bInitBrush)
// Global pointer to the last RBRUSH freed, if any (for one-deep caching).
PRBRUSH gpCachedDbrush = NULL; PRBRUSH gpCachedEngbrush = NULL;
#define MAX_STOCKBRUSHES 4*1024
LONG gStockBrushFree = MAX_STOCKBRUSHES;
//#define DBG_STOCKBRUSHES 1
#if DBG_STOCKBRUSHES
#define STOCKWARNING DbgPrint
#define STOCKINFO DbgPrint
#else
#define STOCKWARNING
#define STOCKINFO
#endif
extern "C" HFASTMUTEX ghfmMemory;
#if DBG
LONG bo_inits, bo_realize, bo_notdirty, bo_cachehit; LONG bo_missnotcached, bo_missfg, bo_missbg, bo_misspaltime, bo_misssurftime; #endif
/****************************Global*Public*Data******************************\
* * These are the 5 global brushes and 3 global pens maintained by GDI. * These are retrieved through GetStockObject. * * History: * 20-May-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
HBRUSH ghbrText; HBRUSH ghbrBackground; HBRUSH ghbrGrayPattern; PBRUSH gpbrText; PBRUSH gpbrNull; PBRUSH gpbrBackground; PPEN gpPenNull;
HBRUSH ghbrDCBrush; PBRUSH gpbrDCBrush;
HBRUSH ghbrDCPen; PBRUSH gpbrDCPen;
// Uniqueness so a logical handle can be reused without having it look like
// the same brush as before. We don't really care where this starts.
ULONG BRUSH::_ulGlobalBrushUnique = 0;
ULONG gCacheHandleEntries[GDI_CACHED_HADNLE_TYPES] = { CACHE_BRUSH_ENTRIES , CACHE_PEN_ENTRIES , CACHE_REGION_ENTRIES, CACHE_LFONT_ENTRIES };
ULONG gCacheHandleOffsets[GDI_CACHED_HADNLE_TYPES] = { 0, CACHE_BRUSH_ENTRIES, ( CACHE_BRUSH_ENTRIES + CACHE_PEN_ENTRIES ), ( CACHE_BRUSH_ENTRIES + CACHE_PEN_ENTRIES + CACHE_PEN_ENTRIES ) };
/******************************Public*Routine******************************\
* bPEBCacheHandle * * Try to place the object(handle) in a free list on the PEB. The objects * are removed from this list in user mode. * * Arguments: * * Handle - handle to cache * HandleType - type of handle to attempt cache * pBrushattr - pointer to user-mode object * * Return Value: * * TRUE if handle is cached, FALSE otherwise * * History: * * 30-Jan-1996 -by- Mark Enstrom [marke] * \**************************************************************************/
BOOL bPEBCacheHandle( HANDLE Handle, HANDLECACHETYPE HandleType, POBJECTATTR pObjectattr, PENTRY pentry ) { BOOL bRet = FALSE; PBRUSHATTR pBrushattr = (PBRUSHATTR)pObjectattr; PW32PROCESS pw32Process = W32GetCurrentProcess(); PPEB Peb;
#if !defined(_GDIPLUS_)
ASSERTGDI(((HandleType == BrushHandle) || (HandleType == PenHandle) || (HandleType == RegionHandle) ||(HandleType == LFontHandle) ),"hGetPEBHandle: illegal handle type");
Peb = PsGetProcessPeb(pw32Process->Process); if (Peb != NULL) { PGDIHANDLECACHE pCache = (PGDIHANDLECACHE)(&Peb->GdiHandleBuffer[0]); BOOL bStatus;
//
// Lock Handle cache on PEB
//
LOCK_HANDLE_CACHE(pCache,PsGetCurrentThread(),bStatus);
if (bStatus) { //
// are any free slots still availablle
//
if (pCache->ulNumHandles[HandleType] < gCacheHandleEntries[HandleType]) { ULONG Index = gCacheHandleOffsets[HandleType]; PHANDLE pHandle,pMaxHandle;
//
// calculate handle offset in PEB array
//
pHandle = &(pCache->Handle[Index]); pMaxHandle = pHandle + gCacheHandleEntries[HandleType];
//
// search array for a free entry
//
while (pHandle != pMaxHandle) { if (*pHandle == NULL) { //
// for increased robust behavior, increment handle unique
//
pentry->FullUnique += UNIQUE_INCREMENT; Handle = (HOBJ)MAKE_HMGR_HANDLE((ULONG)(ULONG_PTR)Handle & INDEX_MASK, pentry->FullUnique); pentry->einfo.pobj->hHmgr = Handle;
//
// store handle in cache and inc stored count
//
*pHandle = Handle; pCache->ulNumHandles[HandleType]++; bRet = TRUE;
//
// clear to be deleted and select flags,
// set cached flag
//
pBrushattr->AttrFlags &= ~(ATTR_TO_BE_DELETED | ATTR_CANT_SELECT); pBrushattr->AttrFlags |= ATTR_CACHED;
break; } pHandle++; }
ASSERTGDI(bRet,"bPEBCacheHandle: count indicates free handle, but none free\n"); } UNLOCK_HANDLE_CACHE(pCache); } }
#endif
return(bRet); }
/******************************Public*Routine******************************\
* BRUSHMEMOBJ::pbrAllocBrush(bPen) * * Base constructor for brush memory object. This constructor is to be * called by the various public brush constructors only. * * History: * 29-Oct-1992 -by- Michael Abrash [mikeab] * changed to allocate but not get a handle or lock (so the brush can be fully * set up before the handle exists, exposing the data to the outside world). * * Wed 19-Jun-1991 -by- Patrick Haluptzok [patrickh] * 0 out the brush. * * Thu 06-Dec-1990 12:02:41 -by- Walt Moore [waltm] * Wrote it. \**************************************************************************/
PBRUSH BRUSHMEMOBJ::pbrAllocBrush(BOOL bPen) { PBRUSH pbrush;
bKeep = FALSE;
// Allocate a new brush or pen
//
// Note: if anyone decides to try turning off zeroinit for performance,
// make sure to initialize the pen's psytle and cstyle to zero. Of
// course, other dependencies may creep in, so do this very very very
// carefully (if you even dare!).
if ((pbrush = (PBRUSH)ALLOCOBJ(bPen ? sizeof(PEN) : sizeof(BRUSH), BRUSH_TYPE, TRUE)) != NULL) { pbrush->pBrushattr(&pbrush->_Brushattr);
pbrush->pIcmDIBList(NULL); // no ICM translated DIBs
pbrush->iUsage(0);
// Set up as initially not caching any realization
pbrush->vSetNotCached(); // no one's trying to cache a realization
// in this logical brush yet
pbrush->crFore((COLORREF)BO_NOTCACHED); // no cached realization yet (no need to
// worry about crFore not being set when
// someone tries to check for caching,
// because we don't have a handle yet, and
// we'll lock when we do get the handle,
// forcing writes to flush)
pbrush->ulBrushUnique(pbrush->ulGlobalBrushUnique()); // set the uniqueness so the are-you-
// really-dirty check in vInitBrush will
// know this is not the brush in the DC
}
return(pbrush); }
/******************************Public*Routine******************************\
* BRUSHMEMOBJ::BRUSHMEMOBJ * * Create a pattern brush or a DIB brush. * * History: * 29-Oct-1992 -by- Michael Abrash [mikeab] * changed to get handle only after fully initialized * * 14-May-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
BRUSHMEMOBJ::BRUSHMEMOBJ(HBITMAP hbmClone, HBITMAP hbmClient,BOOL bMono, FLONG flDIB, FLONG flType, BOOL bPen) { if (flDIB == DIB_PAL_COLORS) { flType |= BR_IS_DIBPALCOLORS; } else if (flDIB == DIB_PAL_INDICES) { flType |= BR_IS_DIBPALINDICES; }
PBRUSH pbrush;
if ((pbp.pbr = pbrush = pbrAllocBrush(bPen)) != NULL) { pbrush->crColor(0); pbrush->ulStyle(HS_PAT); pbrush->hbmPattern(hbmClone); pbrush->hbmClient(hbmClient);
pbrush->AttrFlags(0);
pbrush->flAttrs(flType);
if (bMono) { pbrush->flAttrs(pbrush->flAttrs() | (BR_NEED_BK_CLR | BR_NEED_FG_CLR | BR_IS_MONOCHROME)); }
// Now that everything is set up, create the handle and expose this logical
// brush
if (HmgInsertObject(pbrush, HMGR_ALLOC_ALT_LOCK, BRUSH_TYPE) == 0) { FREEOBJ(pbrush, BRUSH_TYPE); pbp.pbr = NULL; } } else { WARNING1("Brush allocation failed\n"); } }
/******************************Public*Routine******************************\
* GreSetSolidBrush * * Chicago API to change the color of a solid color brush. * * History: * 19-Apr-1994 -by- Patrick Haluptzok patrickh * Made it a function that User can call too. * * 03-Dec-1993 -by- Eric Kutter [erick] * Wrote it - bReset. \**************************************************************************/
BOOL GreSetSolidBrush(HBRUSH hbr, COLORREF clr) { return(GreSetSolidBrushInternal(hbr, clr, FALSE, TRUE)); }
BOOL GreSetSolidBrushInternal( HBRUSH hbr, COLORREF clr, BOOL bPen, BOOL bUserCalled ) { BOOL bReturn = FALSE;
BRUSHSELOBJ ebo(hbr);
PBRUSH pbrush = ebo.pbrush();
if (pbrush != NULL) { if ((pbrush->flAttrs() & BR_IS_SOLID) && ((!pbrush->bIsGlobal()) || bUserCalled) && ((!!pbrush->bIsPen()) == bPen)) {
#if DBG
if (bPen) { ASSERTGDI(((PPEN) pbrush)->pstyle() == NULL || (pbrush->flAttrs() & BR_IS_DEFAULTSTYLE), "GreSetSolidBrush - bad attrs\n"); } #endif
ASSERTGDI(pbrush->hbmPattern() == NULL, "ERROR how can solid have pat"); PRBRUSH prbrush = (PRBRUSH) NULL; RBTYPE rbType;
{ //
// Can't do the delete of the RBRUSH under MLOCK, takes too
// long and it may try and grab it again.
//
MLOCKFAST mlo;
//
// User may call when the brush is selected in a DC, but
// the client side should only ever call on a brush that's
// not in use.
//
if ((pbrush->cShareLockGet() == 1) || bUserCalled) { bReturn = TRUE; pbrush->crColor(clr);
HANDLELOCK HandleLock(PENTRY_FROM_POBJ(pbrush), FALSE);
if (HandleLock.bValid()) { if (pbrush->cShareLockGet() == 1) { //
// Nobody is using it and we have the handle lock
// so noone can select it in till we are done. So
// clean out the old realization now.
//
if ((pbrush->crFore() != BO_NOTCACHED) && !pbrush->bCachedIsSolid()) { prbrush = (PRBRUSH) pbrush->ulRealization(); rbType = pbrush->bIsEngine() ? RB_ENGINE : RB_DRIVER; }
// Set up as initially not caching any realization
pbrush->vSetNotCached(); // no one's trying to cache a realization
// in this logical brush yet
pbrush->crFore((COLORREF)BO_NOTCACHED); // no cached realization yet (no need to
// worry about crFore not being set when
// someone tries to check for caching,
// because we don't have a handle yet, and
// we'll lock when we do get the handle,
// forcing writes to flush)
if (!bUserCalled) { //
// If it's not User calling we are resetting the
// attributes / type.
//
pbrush->ulStyle(HS_DITHEREDCLR); pbrush->flAttrs(BR_IS_SOLID | BR_DITHER_OK); } else { pbrush->vClearSolidRealization(); } } else { //ASSERTGDI(bUserCalled,
// "Client side is hosed, shouldn't "
// "call this with it still selected");
ASSERTGDI(pbrush->flAttrs() & BR_IS_SOLID, "ERROR not solid"); ASSERTGDI(pbrush->ulStyle() == HS_DITHEREDCLR, "ERROR not HS_DI");
//
// Mark this brushes realization as dirty by setting
// it's cache id's to invalid states. Note that if a
// realization hasn't been cached yet this will cause
// no problem either.
//
pbrush->crBack(0xFFFFFFFF); pbrush->ulPalTime(0xFFFFFFFF); pbrush->ulSurfTime(0xFFFFFFFF);
//
// This brush is being used other places, check for
// any DC's that have this brush selected in and mark
// their realizations dirty.
//
// Note there is the theoretical possibility that
// somebody is realizing the brush while we are
// marking them dirty and they won't pick up the new
// color. We set the color first and set the
// uniqueness last so that it is extremely unlikely
// (maybe impossible) that someone gets a realization
// that incorrectly thinks it has the proper
// realization. This is fixable by protecting access
// to the realization and cache fields but we aren't
// going to do it for Daytona.
//
// Mark every DC in the system that has this brush
// selected as a dirty brush.
//
HOBJ hobj = (HOBJ) 0; DC *pdc;
while ((pdc = (DC *) HmgSafeNextObjt(hobj, DC_TYPE)) != NULL) { if (pdc->peboFill()->pbrush() == pbrush) { pdc->flbrushAdd(DIRTY_FILL); }
hobj = (HOBJ) pdc->hGet(); }
}
HandleLock.vUnlock(); }
//
// Set the uniqueness so the are-you-
// really-dirty check in vInitBrush will
// not think an old realization is still valid.
//
pbrush->ulBrushUnique(pbrush->ulGlobalBrushUnique()); } else { WARNING1("Error, SetSolidBrush with cShare != 1"); } }
if (prbrush) { prbrush->vRemoveRef(rbType); } } #if DBG
else { if (bPen) { WARNING1("bPen True\n"); }
if (pbrush->bIsPen()) { WARNING1("bIsPen True\n"); }
if (bUserCalled) { WARNING1("bUserCalled\n"); }
if (pbrush->bIsGlobal()) { WARNING1("bIsGlobal\n"); }
if (pbrush->flAttrs() & BR_IS_SOLID) { WARNING1("BR_IS_SOLID is set\n"); }
WARNING1("GreSetSolidBrush not passed a solid color brush\n"); } #endif
} #if DBG
else { WARNING1("GreSetSolidBrush failed to lock down brush\n"); } #endif
return(bReturn); }
/******************************Public*Routine******************************\
* GreSetSolidBrushLight: * * Private version of GreSetSolidBrush, user can't call * * Arguments: * * pbrush - pointer to log brush * clr - new color * bPen - Brush is a pen * * Return Value: * * Status * * History: * * 2-Nov-1995 -by- Mark Enstrom [marke] * \**************************************************************************/
BOOL GreSetSolidBrushLight( PBRUSH pbrush, COLORREF clr, BOOL bPen ) { BOOL bReturn = FALSE;
if (pbrush != NULL) { if ( (pbrush->flAttrs() & BR_IS_SOLID) && (!pbrush->bIsGlobal()) ) { //
// make sure bPen flag matches brush type
//
if ((bPen != 0) == (pbrush->bIsPen() != 0)) {
#if DBG
if (bPen) { ASSERTGDI(((PPEN) pbrush)->pstyle() == NULL || (pbrush->flAttrs() & BR_IS_DEFAULTSTYLE), "GreSetSolidBrushLight - illegal PEN attrs\n"); } #endif
ASSERTGDI(pbrush->hbmPattern() == NULL, "ERROR how can solid have pat"); PRBRUSH prbrush = (PRBRUSH) NULL; RBTYPE rbType;
{ //
// Grab the handle lock to stabize the lock counts.
// Do not attempt to free the realized brush under
// this lock; it may take to long.
//
ASSERTGDI(pbrush->hGet(), "ERROR brush obj has no handle\n");
HANDLELOCK HandleLock(PENTRY_FROM_POBJ(pbrush),FALSE);
if (HandleLock.bValid()) { if (pbrush->cShareLockGet() == 1) { bReturn = TRUE; pbrush->crColor(clr);
//
// Nobody is using it and we have the HANDLELOCK
// so noone can select it in till we are done. So
// clean out the old realization now.
//
if ((pbrush->crFore() != BO_NOTCACHED) && !pbrush->bCachedIsSolid()) { prbrush = (PRBRUSH) pbrush->ulRealization(); rbType = pbrush->bIsEngine() ? RB_ENGINE : RB_DRIVER; }
//
// Set up as initially not caching any realization
//
pbrush->vSetNotCached(); // no one's trying to cache a realization
// in this logical brush yet
pbrush->crFore((COLORREF)BO_NOTCACHED); // no cached realization yet (no need to
// worry about crFore not being set when
// someone tries to check for caching,
// because we don't have a handle yet, and
// we'll lock when we do get the handle,
// forcing writes to flush)
//
// we are resetting the attributes / type.
//
if (bPen) { pbrush->ulStyle(HS_DITHEREDCLR);
FLONG flOldAttrs = pbrush->flAttrs() & (BR_IS_PEN | BR_IS_OLDSTYLEPEN); pbrush->flAttrs(BR_IS_SOLID | flOldAttrs); } else { pbrush->ulStyle(HS_DITHEREDCLR); pbrush->flAttrs(BR_IS_SOLID | BR_DITHER_OK); }
//
// Set the uniqueness so the are-you-
// really-dirty check in vInitBrush will
// not think an old realization is still valid.
//
pbrush->ulBrushUnique(pbrush->ulGlobalBrushUnique()); } else { WARNING1("Error, SetSolidBrush with cShare != 1"); }
HandleLock.vUnlock(); } }
if (prbrush) { prbrush->vRemoveRef(rbType); } } } #if DBG
else { if (pbrush->bIsGlobal()) { WARNING1("bIsGlobal\n"); }
if (pbrush->flAttrs() & BR_IS_SOLID) { WARNING1("BR_IS_SOLID is set\n"); }
WARNING("GreSetSolidBrush not passed a solid color brush\n"); } #endif
} #if DBG
else { WARNING1("GreSetSolidBrush failed to lock down brush\n"); } #endif
return(bReturn); }
/******************************Public*Routine******************************\
* GreGetBrushColor * * Call for User to retrieve the color from any brush owned by any process * so User can repaint the background correctly in full drag. To make sure * we don't hose an app we need to hold the mult-lock while we do this so * any operation by the app (such as a Delete) will wait and not fail * because we're temporarily locking the brush down to peek inside of it. * * History: * 14-Jun-1994 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
COLORREF GreGetBrushColor(HBRUSH hbr) { COLORREF clrRet = 0xFFFFFFFF;
//
// Grab the multi-lock so everyone waits while do our quick hack
// to return the brush color.
//
MLOCKFAST mlo;
//
// Lock it down but don't check ownership because we want to succeed
// no matter what.
//
//
// using try except to make sure we will not crash
// when a bad handle passed in.
//
__try { PENTRY pentry = &gpentHmgr[HmgIfromH(hbr)];
PBRUSH pbrush = (PBRUSH)(pentry->einfo.pobj);
if (pbrush) { if ((pbrush->ulStyle() == HS_SOLIDCLR) || (pbrush->ulStyle() == HS_DITHEREDCLR)) { clrRet = pbrush->crColor(); } } } __except(EXCEPTION_EXECUTE_HANDLER) { WARNING1("GreGetBrushColor - bad handle passed in\n"); }
return(clrRet); }
/******************************Public*Routine******************************\
* BRUSHMEMOBJ::BRUSHMEMOBJ * * Creates hatched brushes and solid color brushes. * * History: * 29-Oct-1992 -by- Michael Abrash [mikeab] * changed to get handle only after fully initialized * * Wed 26-Feb-1992 -by- Patrick Haluptzok [patrickh] * rewrote to subsume other constructors, add new hatch styles. * * Sun 19-May-1991 -by- Patrick Haluptzok [patrickh] * Wrote it. \**************************************************************************/
BRUSHMEMOBJ::BRUSHMEMOBJ(COLORREF cr, ULONG ulStyle_, BOOL bPen, BOOL bSharedMem) { if (ulStyle_ > HS_NULL) { WARNING1("Invalid style type\n"); pbp.pbr = NULL; return; }
PBRUSH pbrush;
if ((pbp.pbr = pbrush = pbrAllocBrush(bPen)) == NULL) { WARNING1("Brush allocation failed\n"); return; }
pbrush->crColor(cr); pbrush->ulStyle(ulStyle_); pbrush->hbmPattern(0); pbrush->AttrFlags(0);
if (ulStyle_ < HS_DDI_MAX) { // The old hatch brushes have been extended to include all the default
// patterns passed back by the driver. There are 19 default pattens.
pbrush->flAttrs(BR_IS_HATCH | BR_NEED_BK_CLR | BR_IS_MASKING); goto CreateHandle; }
// Handle the other brush types
switch(ulStyle_) { case HS_SOLIDCLR: pbrush->flAttrs(BR_IS_SOLID); break;
case HS_DITHEREDCLR: pbrush->flAttrs(BR_IS_SOLID | BR_DITHER_OK); break;
case HS_SOLIDTEXTCLR: pbrush->flAttrs(BR_IS_SOLID | BR_NEED_FG_CLR); break;
case HS_DITHEREDTEXTCLR: pbrush->flAttrs(BR_IS_SOLID | BR_NEED_FG_CLR | BR_DITHER_OK); break;
case HS_SOLIDBKCLR: pbrush->flAttrs(BR_IS_SOLID | BR_NEED_BK_CLR); break;
case HS_DITHEREDBKCLR: pbrush->flAttrs(BR_IS_SOLID | BR_NEED_BK_CLR | BR_DITHER_OK); break;
case HS_NULL: pbrush->flAttrs(BR_IS_NULL); break;
default: RIP("ERROR BRUSHMEMOBJ hatches invalid type"); }
// Now that everything is set up, create the handle and expose this logical
// brush
CreateHandle:
if (HmgInsertObject(pbrush, HMGR_ALLOC_ALT_LOCK, BRUSH_TYPE) == 0) { FREEOBJ(pbrush, BRUSH_TYPE); pbp.pbr = NULL; } else { if (bSharedMem) { //
// Setup the user mode BRUSHATTR
//
PBRUSHATTR pUser = (PBRUSHATTR)HmgAllocateObjectAttr();
if (pUser) { HANDLELOCK BrushLock;
BrushLock.bLockHobj((HOBJ)pbrush->hHmgr,BRUSH_TYPE);
if (BrushLock.bValid()) {
PENTRY pent = BrushLock.pentry();
//
// fill up the brushattr
//
*pUser = pbrush->_Brushattr;
pent->pUser = (PVOID)pUser; pbrush->pBrushattr(pUser);
BrushLock.vUnlock(); } } } } }
/******************************Public*Routine******************************\
* EBRUSHOBJ::vInitBrush * * Initializes the brush user object. If the color can be represented * without dithering, we set iSolidColor. * * History: * Tue 08-Dec-1992 -by- Michael Abrash [mikeab] * Rewrote for speed. * * Sun 23-Jun-1991 -by- Patrick Haluptzok [patrickh] * Wrote it. \**************************************************************************/
VOID EBRUSHOBJ::vInitBrush( PDC pdc, // current dc or a fake dc with only back/foreground clr info
PBRUSH pbrushIn, // Current logical brush
XEPALOBJ palDC, // Target's DC palette
XEPALOBJ palSurf, // Target's surface palette
SURFACE *pSurface, // Target surface
BOOL bCanDither // If FALSE then never dither
) {
// Note: If more members of pdc are accessed in the future, then code must be
// added in drvsup.cxx to initialize the members in each place a fake DC
// object is initialized. There's also a fake DC in bDynamicModeChange in
// opendc.cxx which must be updated.
// If the palSurf isn't valid, then the target is a bitmap for a palette
// managed device; therefore the palette means nothing until we actually blt,
// and only the DC palette is relevant. Likewise, if the target is a palette
// managed surface, the brush is realized as indices into the logical palette,
// and unless the logical palette is changed, the brush doesn't need to be
// rerealized. This causes us effectively to check the logical palette time
// twice, but that's cheaper than checking whether we need to check the surface
// palette time and then possibly checking it.
ULONG ulSurfTime = (palSurf.bValid() && !palSurf.bIsPalManaged()) ? palSurf.ulTime() : 1;
#if DBG
bo_inits++; #endif
// If the brush really is dirty, we have to set this anyway; if it's not dirty,
// this takes care of the case where the surface has changed out from under us,
// and then a realization is required and we would otherwise fault trying to
// access the target surface structure in the process of realization.
psoTarg1 = pSurface; // surface for which brush is realized
// The journaling code depends on this
// being set correctly. This has the PDEV
// for the device it's selected into.
COLORREF crTextDC = pdc->crTextClr(); COLORREF crBackDC = pdc->crBackClr();
LONG lIcmModeDC = pdc->lIcmMode(); HANDLE hcmXformDC = pdc->hcmXform();
// See if the brush really isn't dirty and doesn't need to be rerealized
if ( ( pbrushIn->ulBrushUnique() == _ulUnique ) && (!bCareAboutFg() || (crCurrentText() == crTextDC) ) && (!bCareAboutBg() || (crCurrentBack() == crBackDC) ) && (palDC.ulTime() == ulDCPalTime()) && (ulSurfTime == ulSurfPalTime()) && (pbrushIn != gpbrDCBrush)&& (pbrushIn != gpbrDCPen) && (lIcmMode() == lIcmModeDC) && (hcmXform() == hcmXformDC) && (bCanDither == _bCanDither)) { #if DBG
bo_notdirty++; #endif
return; }
// Get Cached Values
flAttrs = pbrushIn->flAttrs();
// Remember the characteristics of the brush
_pbrush = pbrushIn; _ulUnique = pbrushIn->ulBrushUnique(); // brush uniqueness
crCurrentText1 = crTextDC; // text color at realization time
crCurrentBack1 = crBackDC; // background color at realization time
_ulDCPalTime = palDC.ulTime(); // DC palette set time at realization time
_ulSurfPalTime = ulSurfTime; // surface palette set time at realization time
_bCanDither = bCanDither; // dither enabled?
// Initialize ICM stuffs
BOOL bCMYKColorSolid = FALSE;
flColorType = 0; // Initialized with zero.
// Set icm modes
if (IS_ICM_ON(lIcmModeDC)) { BOOL bIcmBrush = FALSE;
// color translation should happen, check we have nessesary data for ICM.
if (flAttrs & (BR_IS_SOLID|BR_IS_HATCH|BR_IS_MONOCHROME)) { if (IS_ICM_HOST(lIcmModeDC)) { // DC attributes should have ICM-ed color.
//
// (or with null-ColorTransform, no color translation happen)
if (flAttrs & (BR_IS_SOLID|BR_IS_MONOCHROME)) { if ((flAttrs & (BR_NEED_FG_CLR|BR_NEED_BK_CLR)) || (pbrushIn == gpbrDCBrush) || (pbrushIn == gpbrDCPen)) { bIcmBrush = TRUE; } }
if (bIcmBrush == FALSE) { if (pbrushIn->bIsPen()) { if ((hcmXformDC == NULL) || pdc->bValidIcmPenColor()) { bIcmBrush = TRUE; } else { ICMMSG(("vInitBrush():ERROR: No ICMed pen color for this brush\n")); } } else { if ((hcmXformDC == NULL) || pdc->bValidIcmBrushColor()) { bIcmBrush = TRUE; } else { ICMMSG(("vInitBrush():ERROR: No ICMed brush color for this brush\n")); } } } } else // other ICM modes (Device and Apps)
{ bIcmBrush = TRUE; } } else if (flAttrs & BR_IS_DIB) { if (IS_ICM_HOST(lIcmModeDC)) { // Brush should have ICM-ed DIB
//
// (or with null-ColorTransform, no color translation happen)
if ((hcmXformDC == NULL) || pbrushIn->hFindIcmDIB(hcmXformDC)) { bIcmBrush = TRUE; } else { ICMMSG(("vInitBrush():ERROR: No ICMed DIB for this brush\n")); } } else // other ICM modes (Device and Apps)
{ bIcmBrush = TRUE; } } else { // Other stlyes, no ICM
}
if (bIcmBrush) { lIcmMode(lIcmModeDC); // ICM mode
hcmXform(hcmXformDC); // ICM molor Transform handle
// setup colortype flag.
if (bIsAppsICM() || bIsHostICM()) { flColorType |= BR_HOST_ICM; } else if (bIsDeviceICM()) { flColorType |= BR_DEVICE_ICM; }
// If the brush is solid, iSolidColor will have CMKY color. Otherwise,
// iSolidColor will be 0xFFFFFFFF and flColorType does not have BR_CMYKCOLOR.
bCMYKColorSolid = (bIsCMYKColor() && (flAttrs & BR_IS_SOLID));
if (bCMYKColorSolid) { flColorType |= BR_CMYKCOLOR; // color type is CMYK color
} } else { ICMMSG(("vInitBrush():This brush is not ICMed\n"));
lIcmMode(DC_ICM_OFF); // ICM mode
hcmXform(NULL); // ICM molor Transform handle
} } else { lIcmMode(DC_ICM_OFF); // ICM mode
hcmXform(NULL); // ICM molor Transform handle
}
// Get the target PDEV
PDEVOBJ po(pSurface->hdev()); ASSERTGDI(po.bValid(), "ERROR BRUSHOBJ PDEVOBJ");
// Set palettes
palDC1.ppalSet(palDC.ppalGet()); palSurf1.ppalSet(palSurf.ppalGet()); palMeta1.ppalSet(po.ppalSurfNotDynamic()); _iMetaFormat = po.iDitherFormatNotDynamic();
ASSERTGDI(pSurface != NULL, "ERROR BRUSHOBJ::bInit0"); ASSERTGDI(palDC.bValid(), "ERROR BRUSHOBJ::bInit4");
// Clean up what was already here
// If this brush object had an engine brush realization, get rid of it
if (pengbrush1 != (PENGBRUSH) NULL) { PRBRUSH prbrush = pengbrush1; // point to engine brush realization
prbrush->vRemoveRef(RB_ENGINE); // decrement the reference count on the
// realization and free the brush if
// this is the last reference
pengbrush1 = NULL; // mark that there's no realization
}
// If this brush object had a device brush realization, get rid of it
if (pvRbrush != (PVOID) NULL) { PRBRUSH prbrush = (PDBRUSH)DBRUSHSTART(pvRbrush); // point to DBRUSH (pvRbrush points to
// realization, which is at the end of DBRUSH)
prbrush->vRemoveRef(RB_DRIVER); // decrement the reference count on the
// realization and free the brush if
// this is the last reference
pvRbrush = NULL; // mark that there's no realization
}
// Remember the color so we do the realization code correctly later
// if it's a dithered brush. We may need this even if we have
// a hit in the cache since we have driver/engine distinction.
if (flAttrs & BR_IS_SOLID) { if (flAttrs & BR_NEED_FG_CLR) { crRealize = crCurrentText(); // use text brush
if (bIsHostICM()) crRealizeOrignal = pdc->ulTextClr(); } else if (flAttrs & BR_NEED_BK_CLR) { crRealize = crCurrentBack(); // use back brush
if (bIsHostICM()) crRealizeOrignal = pdc->ulBackClr(); } else if (pbrushIn == gpbrDCBrush) { crRealize = pdc->crDCBrushClr(); // use DC brush
if (bIsHostICM()) crRealizeOrignal = pdc->ulDCBrushClr(); } else if (pbrushIn == gpbrDCPen) { crRealize = pdc->crDCPenClr(); // use DC pen
if (bIsHostICM()) crRealizeOrignal = pdc->ulDCPenClr(); } else { crRealize = pbrushIn->crColor();
if (bIsHostICM()) { crRealizeOrignal = crRealize;
if (pbrushIn->bIsPen()) { if (pdc->bValidIcmPenColor()) { crRealize = pdc->crIcmPenColor(); // use ICM translated pen
} } else { if (pdc->bValidIcmBrushColor()) { crRealize = pdc->crIcmBrushColor(); // use ICM translated brush
} } } } } else if (flAttrs & BR_IS_HATCH) { crRealize = pbrushIn->crColor();
if (bIsHostICM()) { crRealizeOrignal = crRealize;
if (pbrushIn->bIsPen()) { if (pdc->bValidIcmPenColor()) { crRealize = pdc->crIcmPenColor(); } } else { if (pdc->bValidIcmBrushColor()) { crRealize = pdc->crIcmBrushColor(); } } } }
// See if there's a cached realization that we can use
// Note that the check for crFore MUST come first, because if and only if
// that field is not BO_NOTCACHED is there a valid cached realization.
#if DBG
bo_realize++;
if ( (pbrushIn->crFore() == BO_NOTCACHED) ) { bo_missnotcached++; } else if ( pbrushIn->bCareAboutFg() && (pbrushIn->crFore() != crTextDC) ) { bo_missfg++; } else if (pbrushIn->bCareAboutBg() && (pbrushIn->crBack() != crBackDC) ) { bo_missbg++; } else if ( pbrushIn->ulPalTime() != ulDCPalTime() ) { bo_misspaltime++; } else if ( pbrushIn->ulSurfTime() != ulSurfPalTime() ) { bo_misssurftime++; } else { bo_cachehit++; } #endif
if ( (pbrushIn->crFore() != BO_NOTCACHED) && ( (!pbrushIn->bCareAboutFg()) || (pbrushIn->crFore() == crTextDC) ) && ( (!pbrushIn->bCareAboutBg()) || (pbrushIn->crBack() == crBackDC) ) && (pbrushIn->ulPalTime() == ulDCPalTime()) && (pbrushIn->ulSurfTime() == ulSurfPalTime()) && (pbrushIn->hdevRealization() == po.hdev()) && (pbrushIn != gpbrDCBrush) && (pbrushIn != gpbrDCPen) ) {
// Uncache the realization according to the realization type (solid,
// driver realization, or engine realization)
if (pbrushIn->bCachedIsSolid()) { // Retrieve the cached solid color and done
iSolidColor = (ULONG)pbrushIn->ulRealization(); crPaletteColor = pbrushIn->crPalColor(); } else { // See whether this is an engine or driver realization
PRBRUSH prbrush = (PRBRUSH)pbrushIn->ulRealization();
if (pbrushIn->bIsEngine()) { pengbrush1 = (PENGBRUSH)prbrush; } else { // Skip over the RBRUSH at the start of the DBRUSH, so that the
// driver doesn't see that
pvRbrush = (PVOID)(((PDBRUSH)prbrush)->aj); }
// Whether this was an engine or driver realization, now we've got
// it selected into another DC, so increment the reference count
// so it won't get deleted until it's no longer selected into any
// DC and the logical brush no longer exists
prbrush->vAddRef();
// Indicate that this is a pattern brush
iSolidColor = 0xffffffff; crPaletteColor = pbrushIn->crPalColor(); }
// Nothing more to do once we've found that the realization is cached;
// this tells us all we hoped to find out in this call, either the
// solid color for the realization or else that the realization isn't
// solid (in which case we probably found the realization too, although
// if the cached realization is driver and this time the engine will do
// the drawing, or vice-versa, the cached realization won't help us)
return; }
// If brush isn't based on color (if it is a bitmap or hatch), we're done
// here, because all we want to do is set iSolidColor if possible
if (!(flAttrs & BR_IS_SOLID)) { iSolidColor = crPaletteColor = 0xffffffff; return; }
// See if we can find exactly the color we want
if (bCMYKColorSolid) { // crRealize is CMKY color just set it to iSolidColor
iSolidColor = crPaletteColor = crRealize; } else if (po.bCapsForceDither() && bCanDither) { // printer drivers may set the FORCEDITHER flag. In this case, we always
// want to dither brushes, even if they map to a color in the drivers palette.
iSolidColor = 0xffffffff; crPaletteColor = crRealize; } else { iSolidColor = ulGetMatchingIndexFromColorref( palSurf, palDC, crRealize ); crPaletteColor = rgbFromColorref(palSurf, palDC, crRealize ); }
// Under CMYK color context, there is no dither.
if ((iSolidColor == 0xFFFFFFFF) && (!bCMYKColorSolid)) {
// Not an exact match. If we can dither, then we're done for now; we'll
// realize the brush when the driver wants it, so if all conditions are
// met for dithering this brush, then we're done
// we dither the brush if the caller says we can and if either the brush
// says it is ditherable or the driver has requested dithering.
if (((flAttrs & BR_DITHER_OK) || (po.bCapsForceDither())) && bCanDither) { // ...and the PDEV allows color dithering and either the bitmap is
// for a palette managed device, or if the surface and device
// palettes are the same palette, or if the destination surface is
// monochrome and the pdev has hooked mono dithering.
//
// Note: There is a dynamic mode change synchronization hole here
// between the time we check GCAPS_COLOR_DITHER/MONO_DITHER
// and the time that we go to actually realize the brush --
// the driver's capabilities may have changed in the mean
// time. Note that this will happen only when drawing to
// DIB based compatible bitmaps. Since it will be rare, and
// since we won't fall over, I'm letting it through...
if ( ( ( (!palSurf.bValid()) || (palSurf.ppalGet() == po.ppalSurfNotDynamic()) ) && (po.flGraphicsCapsNotDynamic() & GCAPS_COLOR_DITHER) ) || (palSurf.bIsMonochrome() && (po.flGraphicsCapsNotDynamic() & GCAPS_MONO_DITHER) ) ) { // ...then we can dither this brush, so we can't set iSolidColor
// and we're done. Dithering will be done when the driver
// requests realization
//
crPaletteColor = crRealize; return; } }
// We can't dither and there's no exact match, so find the nearest
// color and that'll have to do
if (pSurface->iFormat() == BMF_1BPP) {
// For monochrome surface, we'll have background mapped to
// background and everything else mapped to foreground.
iSolidColor = ulGetNearestIndexFromColorref( palSurf, palDC, crBackDC, SE_DONT_SEARCH_EXACT_FIRST ); crPaletteColor = rgbFromColorref(palSurf, palDC, crBackDC);
if (crBackDC != crRealize) { iSolidColor = 1 - iSolidColor;
// Obtain corresponding color from index.
PAL_ULONG ulPalTemp; ulPalTemp.pal = palSurf.palentryGet(iSolidColor); crPaletteColor = ulPalTemp.ul; } } else { iSolidColor = ulGetNearestIndexFromColorref( palSurf, palDC, crRealize, SE_DONT_SEARCH_EXACT_FIRST ); crPaletteColor = rgbFromColorref(palSurf, palDC, crRealize); } }
// See if we can cache this brush color in the logical brush; we can't if
// another realization has already been cached in the logical brush
// See vTryToCacheRealization, in BRUSHDDI.CXX, for a detailed explanation
// of caching in the logical brush
if ( !pbrushIn->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 ( pbrushIn->bGrabCache() ) {
// We got the "can cache" flag, so now we can cache this realization
// in the logical brush
// 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
pbrushIn->crBack(crCurrentBack1); pbrushIn->ulPalTime(ulDCPalTime()); pbrushIn->ulSurfTime(ulSurfPalTime()); pbrushIn->ulRealization(iSolidColor); pbrushIn->crPalColor(crPaletteColor); pbrushIn->SetSolidRealization();
// 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
pbrushIn->crForeLocked(crCurrentText1);
// The realization is now cached in the logical brush
} }
return; }
/******************************Public*Routine******************************\
* EBRUSHOBJ::vNuke() * * Clean up framed EBRUSHOBJ * * History: * 20-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/
VOID EBRUSHOBJ::vNuke() { if (pengbrush1 != (PENGBRUSH) NULL) { PRBRUSH prbrush = pengbrush1; // point to engine brush realization
prbrush->vRemoveRef(RB_ENGINE); // decrement the reference count on the
// realization and free the brush if
// this is the last reference
}
if (pvRbrush != (PVOID) NULL) { PRBRUSH prbrush = (PDBRUSH)DBRUSHSTART(pvRbrush); // point to DBRUSH (pvRbrush points to
// realization, which is at the end of DBRUSH)
prbrush->vRemoveRef(RB_DRIVER); // decrement the reference count on the
// realization and free the brush if
// this is the last reference
} }
// This is the brusheng.cxx section
/******************************Public*Routine******************************\
* bInitBRUSHOBJ * * Initializes the default brushes and and the dclevel default values for * brushes and pens. * * Explanation of the NULL brush (alias Hollow Brush) * The Null brush is special. Only 1 is ever created * (at initialization time in hbrNull). The only API's for * getting a Null brush are CreateBrushIndirect and GetStockObject which * both return "the 1 and only 1" Null brush. A Null brush is never * realized by a driver or the engine. No output call should ever occur * that requires a brush if the brush is NULL, the engine should stop * these before they get to the driver. * * History: * 20-May-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
extern "C" BOOL bInitBrush( int iBrush, COLORREF cr, DWORD dwHS, PULONG_PTR pdw, BOOL bEnableDither ) { BOOL bSuccess = FALSE; BRUSHMEMOBJ brmo(cr,dwHS,FALSE,FALSE);
if (brmo.bValid()) { brmo.vKeepIt(); brmo.vGlobal();
if (bEnableDither) brmo.vEnableDither();
if (pdw) *pdw = (ULONG_PTR)brmo.pbrush();
bSetStockObject(brmo.hbrush(),iBrush);
// init DcAttrDefault brush
if (iBrush == WHITE_BRUSH) { DcAttrDefault.hbrush = brmo.hbrush(); }
bSuccess = TRUE; } else { #if DBG
DbgPrint("couldn't create default brush %lx, %lx\n",cr,iBrush); #endif
return(FALSE); } return(bSuccess); }
BOOL bInitBRUSHOBJ() { if (!bInitBrush(WHITE_BRUSH,(COLORREF)RGB(0xFF,0xFF,0xFF), HS_DITHEREDCLR,(PULONG_PTR)&dclevelDefault.pbrFill,FALSE) || !bInitBrush(BLACK_BRUSH, (COLORREF)RGB(0x0, 0x0, 0x0), HS_DITHEREDCLR,NULL,FALSE) || !bInitBrush(GRAY_BRUSH, (COLORREF)RGB(0x80,0x80,0x80),HS_DITHEREDCLR,NULL,TRUE) || !bInitBrush(DKGRAY_BRUSH,(COLORREF)RGB(0x40,0x40,0x40),HS_DITHEREDCLR,NULL,TRUE) || !bInitBrush(LTGRAY_BRUSH,(COLORREF)RGB(0xc0,0xc0,0xc0),HS_DITHEREDCLR,NULL,TRUE) || !bInitBrush(NULL_BRUSH, (COLORREF)0,HS_NULL,(PULONG_PTR)&gpbrNull,FALSE)) { return(FALSE); }
// Init default Null Pen
{ BRUSHMEMOBJ brmo((COLORREF) 0, HS_NULL, TRUE, FALSE); // TRUE signifies a pen
if (brmo.bValid()) { brmo.vKeepIt(); brmo.vGlobal(); brmo.vSetOldStylePen(); brmo.flStylePen(PS_NULL); brmo.lWidthPen(1); HmgModifyHandleType((HOBJ)MODIFY_HMGR_TYPE(brmo.hbrush(),LO_PEN_TYPE)); bSetStockObject(brmo.hbrush(),NULL_PEN); gpPenNull = (PPEN)brmo.pbrush(); } else { WARNING("Failed Null Pen"); return(FALSE); } }
// Init default Black Pen
{ BRUSHMEMOBJ brmo((COLORREF) (RGB(0,0,0)), HS_DITHEREDCLR, TRUE, FALSE);
if (brmo.bValid()) { brmo.vKeepIt(); brmo.vGlobal(); brmo.vSetOldStylePen(); brmo.flStylePen(PS_SOLID); brmo.lWidthPen(0); brmo.l_eWidthPen(IEEE_0_0F); brmo.iJoin(JOIN_ROUND); brmo.iEndCap(ENDCAP_ROUND); brmo.pstyle((PFLOAT_LONG) NULL); HmgModifyHandleType((HOBJ)MODIFY_HMGR_TYPE(brmo.hbrush(),LO_PEN_TYPE)); bSetStockObject(brmo.hbrush(),BLACK_PEN); DcAttrDefault.hpen = (HPEN)brmo.hbrush(); dclevelDefault.pbrLine = brmo.pbrush(); } else { WARNING("failed black pen"); return(FALSE); } }
// Init default White Pen
{ BRUSHMEMOBJ brmo((COLORREF) (RGB(0xFF,0xFF,0xFF)), HS_DITHEREDCLR, TRUE, FALSE);
if (brmo.bValid()) { brmo.vKeepIt(); brmo.vGlobal(); brmo.vSetOldStylePen(); brmo.flStylePen(PS_SOLID); brmo.lWidthPen(0); brmo.l_eWidthPen(IEEE_0_0F); brmo.iJoin(JOIN_ROUND); brmo.iEndCap(ENDCAP_ROUND); brmo.pstyle((PFLOAT_LONG) NULL); HmgModifyHandleType((HOBJ)MODIFY_HMGR_TYPE(brmo.hbrush(),LO_PEN_TYPE)); bSetStockObject(brmo.hbrush(),WHITE_PEN); } else { WARNING("Failed white pen"); return(FALSE); } }
// Init the stock DC Pen
{ BRUSHMEMOBJ brmo((COLORREF) (RGB(0,0,0)), HS_DITHEREDCLR, TRUE, FALSE);
if (brmo.bValid()) { brmo.vKeepIt(); brmo.vGlobal(); brmo.vSetOldStylePen(); brmo.flStylePen(PS_SOLID); brmo.lWidthPen(0); brmo.l_eWidthPen(IEEE_0_0F); brmo.iJoin(JOIN_ROUND); brmo.iEndCap(ENDCAP_ROUND); brmo.pstyle((PFLOAT_LONG) NULL); HmgModifyHandleType((HOBJ)MODIFY_HMGR_TYPE(brmo.hbrush(),LO_PEN_TYPE)); bSetStockObject(brmo.hbrush(),DC_PEN); ghbrDCPen = brmo.hbrush(); gpbrDCPen = brmo.pbrush();
} else { WARNING("Failed DC pen"); return(FALSE); } }
// init the text brush
{ BRUSHMEMOBJ brmo((COLORREF) (RGB(0,0,0)),HS_DITHEREDTEXTCLR,FALSE,FALSE);
if (brmo.bValid()) { brmo.vKeepIt(); brmo.vGlobal(); ghbrText = brmo.hbrush(); gpbrText = brmo.pbrush(); } else { WARNING("Could not create default text brush"); return(FALSE); } }
// init the background brush
{ BRUSHMEMOBJ brmo((COLORREF) (RGB(0xff,0xff,0xff)),HS_DITHEREDBKCLR,FALSE,FALSE);
if (brmo.bValid()) { brmo.vKeepIt(); brmo.vGlobal(); ghbrBackground = brmo.hbrush(); gpbrBackground = brmo.pbrush(); } else { WARNING("Could not create default background brush"); return(FALSE); } }
// init the global pattern gray brush
{ static WORD patGray[8] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa }; HBITMAP hbmGray;
hbmGray = GreCreateBitmap(8, 8, 1, 1, (LPBYTE)patGray);
if (hbmGray == (HBITMAP) 0) { WARNING1("bInitBRUSHOBJ failed GreCreateBitmap\n"); return(FALSE); }
ghbrGrayPattern = GreCreatePatternBrush(hbmGray);
if (ghbrGrayPattern == (HBRUSH) 0) { WARNING1("bInitBRUSHOBJ failed GreCreatePatternBrush\n"); return(FALSE); } GreDeleteObject(hbmGray); GreSetBrushOwnerPublic((HBRUSH)ghbrGrayPattern); }
// init the stock DC brush
{ BRUSHMEMOBJ brmo((COLORREF) (RGB(0xff,0xff,0xff)),HS_DITHEREDCLR,FALSE,FALSE);
if (brmo.bValid()) { brmo.vKeepIt(); brmo.vGlobal();
bSetStockObject(brmo.hbrush(), DC_BRUSH);
ghbrDCBrush = brmo.hbrush(); gpbrDCBrush = brmo.pbrush();
} else { WARNING("Could not create direct dc brush"); return(FALSE); } }
return(TRUE); }
/******************************Public*Routine******************************\
* GreSelectBrush * * Selects the given brush into the given DC. Fast SelectObject * * History: * Thu 21-Oct-1993 -by- Patrick Haluptzok [patrickh] * wrote it. \**************************************************************************/
HBRUSH GreSelectBrush(HDC hdc, HBRUSH hbrush) { HBRUSH hbrReturn = (HBRUSH) 0;
//
// Try to lock the DC. If we fail, we just return failure.
//
XDCOBJ dco(hdc);
if (dco.bValid()) { //
// call DC locked version
//
hbrReturn = GreDCSelectBrush(dco.pdc,hbrush); dco.vUnlockFast(); }
return(hbrReturn); }
/******************************Public*Routine******************************\
* GreDCSelectBrush * * Select brush with dc already locked * * Arguments: * * pdc - locked DC pointer * hbrush - brush to select * * Return Value: * * Old hbrush or NULL * * History: * * 19-May-1995 : copied from GreSelectBrush * \**************************************************************************/
HBRUSH GreDCSelectBrush( PDC pdc, HBRUSH hbrush ) { HBRUSH hbrReturn = (HBRUSH) 0; PBRUSH pbrush = NULL;
XDCOBJ dco;
dco.pdc = pdc;
if (dco.bValid()) { HBRUSH hbrOld;
//
// The DC is locked. Set the return value to the old brush in the DC.
//
hbrOld = (HBRUSH) (dco.pdc->pbrushFill())->hGet();
//
// the return value should be the one cached in the dc
//
hbrReturn = dco.pdc->hbrush();
//
// If the new brush is the same as the old brush, nothing to do.
//
if (DIFFHANDLE(hbrush,hbrOld)) { //
// Try to lock down the logical brush so we can get the pointer out.
//
pbrush = (BRUSH *)HmgShareCheckLock((HOBJ)hbrush, BRUSH_TYPE);
if (pbrush) { //
// Undo the lock from when the brush was selected.
//
DEC_SHARE_REF_CNT_LAZY0(dco.pdc->pbrushFill());
//
// Changing pbrushfill, set flag to force re-realization
//
dco.ulDirtyAdd(DIRTY_FILL); //
// Save the pointer to the logical brush in the DC. We don't
// unlock the logical brush, because the alt lock count in the
// logical brush is the reference count for DCs in which the brush
// is currently selected; this protects us from having the actual
// logical brush deleted while it's selected into a DC, and allows
// us to reference the brush with a pointer rather than having to
// lock down the logical brush every time.
//
dco.pdc->pbrushFill(pbrush); } else { WARNING1("SelectBrush got invalid brush handle\n");
hbrReturn = NULL; } } else { pbrush = dco.pdc->pbrushFill(); }
if (pbrush != NULL) { if (hbrReturn != NULL) { //
// must still check brush for new color
//
PBRUSHATTR pUser = pbrush->_pBrushattr;
//
// if the brush handle is a cached solid brush,
// call GreSetSolidBrushInternal to change the color
//
if (pUser != &pbrush->_Brushattr) { if (pUser->AttrFlags & ATTR_NEW_COLOR) { //
// force re-realization in case handle was same
//
dco.ulDirtyAdd(DIRTY_FILL);
//
// set the new color for the cached brush.
// Note: since pbrush is pulled straight
// from the DC, it's reference count will
// be 1, which is needed by SetSolidBrush
//
if (!GreSetSolidBrushLight(pbrush,pUser->lbColor,FALSE)) { WARNING1("GreSyncbrush failed to setsolidbrushiternal\n"); }
pUser->AttrFlags &= ~ATTR_NEW_COLOR; } } }
dco.pdc->hbrush(hbrush); dco.pdc->ulDirtySub(DC_BRUSH_DIRTY); } }
return(hbrReturn); }
/******************************Public*Routine******************************\
* GreDCSelectPen * Selects a hpen into the given pdc * * Arguments: * * pdc - locked dc * hpen - hpen to select * * Return Value: * * old hpen * * History: * * 29-Jan-1996 -by- Mark Enstrom [marke] * \**************************************************************************/
HPEN GreDCSelectPen( PDC pdc, HPEN hpen ) { HPEN hpReturn = (HPEN) NULL; PPEN ppen = NULL;
//
// Try to lock the DC. If we fail, we just return failure.
//
XDCOBJ dco;
dco.pdc = pdc;
if (dco.bValid()) { HPEN hpOld; BOOL bRealize = FALSE;
//
// hpOld is the pen (LINE BRUSH) currently realized in the DC
//
hpOld = (HPEN) (dco.pdc->pbrushLine())->hGet();
//
// Set the return value to the old pen in the DCATTR.
// This is the last hpen the user selected
//
hpReturn = (HPEN)dco.pdc->hpen();
//
// If the new pen is the same as the old pen, nothing to do.
//
if (DIFFHANDLE(hpen, hpOld)) { //
// Try to lock down the logical brush so we can get the pointer out.
//
ppen = (PEN *)HmgShareCheckLock((HOBJ)hpen, BRUSH_TYPE);
if (ppen && ppen->bIsPen()) { //
// Undo the lock from when the pen was selected.
//
DEC_SHARE_REF_CNT_LAZY0(dco.pdc->pbrushLine());
//
// Mark line relization is invalid.
//
dco.ulDirtyAdd(DIRTY_LINE);
//
// Save the pointer to the logical brush in the DC. We don't
// unlock the logical brush, because the alt lock count in the
// logical brush is the reference count for DCs in which the brush
// is currently selected; this protects us from having the actual
// logical brush deleted while it's selected into a DC, and allows
// us to reference the brush with a pointer rather than having to
// lock down the logical brush every time.
//
dco.pdc->pbrushLine(ppen);
//
// The pen changed, so realize the new LINEATTRS, based on
// the current world transform.
//
bRealize = TRUE; } else { WARNING1("SelectPen got invalid pen handle\n");
//
// If this is not pen, can't select it as pen.
//
if (ppen) { DEC_SHARE_REF_CNT(ppen); ppen = NULL; }
hpReturn = NULL; } } else { ppen = (PPEN)dco.pdc->pbrushLine(); }
//
// In case the handle stays the same, but the pen is new
// due to re-use of a user hpen, so re-realize it.
//
if (ppen != (PPEN) NULL) { if (hpReturn != NULL) { PBRUSHATTR pUser = ppen->_pBrushattr;
//
// if the brush handle is a cached solid brush,
// call GreSetSolidBrushInternal to change the color
//
if (pUser != &ppen->_Brushattr) { if (pUser->AttrFlags & ATTR_NEW_COLOR) { //
// set the new color for the cached brush.
// Note: since pbrush is pulled straight
// from the DC, it's reference count will
// be 1, which is needed by SetSolidBrush
//
if (!GreSetSolidBrushLight(ppen,pUser->lbColor,TRUE)) { WARNING ("GreDCSelectPen failed to setsolidbrushiternal\n"); }
dco.ulDirtyAdd(DIRTY_LINE); pUser->AttrFlags &= ~ATTR_NEW_COLOR; bRealize = TRUE; } }
if (bRealize) { //
// The pen changed, so realize the new LINEATTRS, based on
// the current world transform.
//
EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
dco.pdc->vRealizeLineAttrs(exo);
LINEATTRS *pla = dco.plaRealized(); } }
dco.pdc->hpen(hpen); dco.pdc->ulDirtySub(DC_PEN_DIRTY); } }
return(hpReturn); }
/******************************Public*Routine******************************\
* GreSelectPen * * Selects the given brush into the given DC. Fast SelectObject * * History: * Thu 21-Oct-1993 -by- Patrick Haluptzok [patrickh] * wrote it. \**************************************************************************/
HPEN GreSelectPen(HDC hdc, HPEN hpen) { HPEN hpenReturn = (HPEN) 0;
//
// Try to lock the DC. If we fail, we just return failure.
//
XDCOBJ dco(hdc);
if (dco.bValid()) { //
// call DC locked version
//
hpenReturn = GreDCSelectPen(dco.pdc,hpen); dco.vUnlockFast(); }
return(hpenReturn); }
/******************************Public*Routine******************************\
* bDeleteBrush * * This will delete the brush. The brush can only be deleted if it's not * global and not being used by anyone else. * * History: * * 7-Feb-1996 -by- Mark Enstrom [marke] * Add PEB caching for brush and pen objects * 23-May-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
BOOL bDeleteBrush(HBRUSH hbrush, BOOL bCleanup) { PBRUSHPEN pbp; BOOL bReturn = TRUE; HBRUSH hbrushNew; BOOL bDelete = TRUE; PBRUSHATTR pUser = NULL; PENTRY pentTmp; BOOL bMakeNonStock = FALSE;
//
// check handle for user-mode brush
//
if (!bCleanup) { HANDLELOCK BrushLock;
BrushLock.bLockHobj((HOBJ)hbrush,BRUSH_TYPE);
if (BrushLock.bValid()) { POBJ pobj = BrushLock.pObj(); pUser = (PBRUSHATTR)BrushLock.pUser();
ASSERTGDI(pobj->cExclusiveLock == 0, "deletebrush - exclusive lock not 0\n");
//
// If Brush is still in use, mark for lazy deletion and return true
//
if (BrushLock.ShareCount() > 0) { ((PBRUSH)pobj)->AttrFlags(ATTR_TO_BE_DELETED); bDelete = FALSE; } else if (pUser != (PBRUSHATTR)NULL) { if (!(pUser->AttrFlags & ATTR_CACHED)) { BOOL bPen = ((PPEN)pobj)->bIsPen(); INT iType = LO_TYPE(hbrush);
#if DBG
//
// make sure handle type agrees with bPen
//
if (bPen) {
ASSERTGDI(((iType == LO_PEN_TYPE) || (iType == LO_EXTPEN_TYPE)), "bDeleteBrush Error: PEN TYPE NOT LO_PEN OR LO_EXTPEN"); } else { ASSERTGDI((iType == LO_BRUSH_TYPE), "bDeleteBrush error: BRUSH type not LO_BRUSH_TYPE"); }
#endif
//
// try to cache the solid brush
// don't cache LO_EXTPEN_TYPE
//
if ((((PBRUSH)pobj)->flAttrs() & BR_IS_SOLID) && (!bPen || iType != LO_EXTPEN_TYPE)) { BOOL bStatus;
bStatus = bPEBCacheHandle(hbrush,bPen?PenHandle:BrushHandle,(POBJECTATTR)pUser,(PENTRY)BrushLock.pentry()); if (bStatus) { bDelete = FALSE; } } } else { //
// brush is already cached
//
WARNING1("Trying to delete brush marked as cached\n");
bDelete = FALSE; } }
if (bDelete) { if (bMakeNonStock = ((PBRUSH)pobj)->bIsMakeNonStock()) { ((PBRUSH)pobj)->vClearMakeNonStock(); } }
BrushLock.vUnlock(); } }
if (bDelete) { if (bMakeNonStock) { STOCKINFO("Brush(%p) is marked MakeNonStock. Doing it\n", hbrush); if(!GreMakeBrushNonStock(hbrush)) STOCKWARNING("GreMakeBrushNonStock (%p) failed\n", hbrush); }
//
// Try and remove handle from Hmgr. This will fail if the brush
// is locked down on any threads or if it has been marked global
// or undeletable.
//
pbp.pbr = (PBRUSH) HmgRemoveObject((HOBJ)hbrush, 0, 0, FALSE, BRUSH_TYPE);
if (pbp.pbr!= NULL) { //
// Free the style array memory if there is some and it's
// not pointing to our stock default styles:
//
if (pbp.pbr->bIsPen()) { if ((pbp.ppen->pstyle() != (PFLOAT_LONG) NULL) && !pbp.ppen->bIsDefaultStyle()) { //
// We don't set the field to NULL since this brush
// is on it's way out.
//
VFREEMEM(pbp.ppen->pstyle()); } }
//
// Free the bitmap pattern in the brush.
//
if (pbp.pbr->hbmPattern()) { //
// We don't set the field to NULL since this brush
// is on it's way out.
//
BOOL bTemp = bDeleteSurface((HSURF)pbp.pbr->hbmPattern());
ASSERTGDI(bTemp, "ERROR How could pattern brush failed deletion?"); }
//
// Un-reference count the realization cached in the logical brush,
// if any. We don't have to worry about anyone else being in the
// middle of trying to cache a realization for this brush because
// we have removed it from Hmgr and noone else has it locked down.
// We only have to do this if there is a cached realization and the
// brush is non-solid.
//
if ((pbp.pbr->crFore() != BO_NOTCACHED) && !pbp.pbr->bCachedIsSolid()) { ASSERTGDI(pbp.pbr->ulRealization() != NULL, "ERROR ulRealization() is NULL");
((PRBRUSH)pbp.pbr->ulRealization())->vRemoveRef( pbp.pbr->bIsEngine() ? RB_ENGINE : RB_DRIVER); }
//
// Brush is DIB pattern ? if so we may need to free ICM DIBs
//
if (pbp.pbr->flAttrs() & BR_IS_DIB) { //
// Free cached color translated ICM DIBs.
//
pbp.pbr->vDeleteIcmDIBs(); }
FREEOBJ(pbp.pbr, BRUSH_TYPE);
//
// free pUser
//
if (!bCleanup && (pUser != (PBRUSHATTR)NULL)) { HmgFreeObjectAttr((POBJECTATTR)pUser); } } else { //
// Under Win31 deleting stock objects returns True.
//
BRUSHSELOBJ bo(hbrush);
if (!bo.bValid() || !bo.bIsGlobal()) bReturn = FALSE; }
}
return(bReturn); }
/******************************Public*Routine******************************\
* GreSetBrushGlobal * * Sets the brush to be a global one. * \**************************************************************************/
void GreSetBrushGlobal(HBRUSH hbr) { BRUSHSELOBJ ebo(hbr);
if (ebo.bValid()) { ebo.vGlobal(); } }
/******************************Public*Routine******************************\
* GreMakeBrushStock * * Make the brush a stock brush. * \**************************************************************************/ HBRUSH GreMakeBrushStock(HBRUSH hbr) { BRUSHSELOBJAPI ebo(hbr); HANDLE bRet = 0; BOOL bHandleModified = TRUE;
// Can make the brush a stock brush only when:
// (1) It is valid
// (2) Its not global already (i.e already stock)
// (3) Its not a DIBSection based brush.
// (4) Its not selected into any DC already.
if (!ebo.bValid() || ebo.bIsGlobal() || ebo.pbrush()->cShareLockGet() > 0) { STOCKWARNING("GreMakeBrushStock (%p) invalid/global/selected\n",hbr); return (HBRUSH)0; }
bRet = (HANDLE)((ULONG_PTR)hbr | GDISTOCKOBJ);
if (InterlockedDecrement(&gStockBrushFree) >= 0 && GreSetBrushOwner((HBRUSH)hbr,OBJECT_OWNER_PUBLIC) && (bHandleModified = HmgLockAndModifyHandleType((HOBJ)bRet))) { ebo.pbrush()->flAttrs(ebo.pbrush()->flAttrs() | BR_IS_GLOBAL); return (HBRUSH)bRet; } else { if (!bHandleModified) GreSetBrushOwner((HBRUSH)hbr,OBJECT_OWNER_CURRENT);
STOCKWARNING("GreMakeBrushStock (%p) Count/GreSetBrushOwner/ModifyH failed\n",bRet); InterlockedIncrement(&gStockBrushFree); bRet = 0; }
return (HBRUSH)bRet; }
/******************************Public*Routine******************************\
* GreMakeBrushNonStock * * Makes the brush a non stock brush * \**************************************************************************/ HBRUSH GreMakeBrushNonStock(HBRUSH hbr) { HANDLE bRet = 0; BRUSHSELOBJAPI ebo(hbr);
// Can make a stock brush non stock only when
// (1) It is valid
// (2) It is a global brush
// (3) It is not a Fixed stock brush
if (ebo.bValid() && ebo.bIsGlobal() && !ebo.pbrush()->bIsFixedStock()) { bRet = (HANDLE)((ULONG_PTR)hbr & ~GDISTOCKOBJ); if (ebo.pbrush()->cShareLockGet() > 0) { // The brush has more than one share lock. This means it will need
// to be lazy deleted.
ebo.pbrush()->vSetMakeNonStock();
STOCKINFO("GreMakeBrushNonStock (%p) is selected. Delay it\n", hbr); } else if(HmgLockAndModifyHandleType((HOBJ)bRet)) { ebo.pbrush()->flAttrs(ebo.pbrush()->flAttrs() & ~BR_IS_GLOBAL); if(!GreSetBrushOwner((HBRUSH)bRet,OBJECT_OWNER_CURRENT)) { bRet = 0; STOCKWARNING("GreMakeBrushNonStock (%p) GreSetBrushOwner failed\n", bRet); } else { InterlockedIncrement(&gStockBrushFree); } } else { bRet = 0; } } return (HBRUSH)bRet; }
/******************************Public*Routine******************************\
* GreSetBrushOwner * * Sets the brush owner. * \**************************************************************************/
BOOL GreSetBrushOwner( HBRUSH hbr, W32PID lPid ) { // If it is a global brush which by design are public we dont need to
// do anything.
{ BRUSHSELOBJ ebo(hbr);
if (ebo.bValid()) { if (ebo.bIsGlobal()) return TRUE; } }
BOOL bStatus = FALSE; PBRUSHATTR pBrushattr = NULL; PENTRY pentry; UINT uiIndex = (UINT) HmgIfromH(hbr);
if (uiIndex < gcMaxHmgr) { pentry = &gpentHmgr[uiIndex];
if (lPid == OBJECT_OWNER_CURRENT) { pBrushattr = (PBRUSHATTR)HmgAllocateObjectAttr(); }
//
// Accquire handle lock. Don't check PID here because owner could
// be NONE, not PUBLIC
//
HANDLELOCK HandleLock(pentry, FALSE);
if (HandleLock.bValid()) { POBJ pobj = pentry->einfo.pobj;
if ((pentry->Objt == BRUSH_TYPE) && (pentry->FullUnique== HmgUfromH(hbr))) { PBRUSH pBrush = (PBRUSH)pobj;
if ((pobj->cExclusiveLock == 0) || (pobj->Tid == (PW32THREAD)PsGetCurrentThread())) { //
// Handle is locked. It is illegal to accquire the hmgr
// resource when a handle is locked.
//
if ((lPid == OBJECT_OWNER_NONE) || (lPid == OBJECT_OWNER_PUBLIC)) { //
// free PBRUSHATTR if PID matches current process
// transfer brushattributes to kernel mode.
if (HandleLock.Pid() == W32GetCurrentPID()) { //
// If user mode BRUSHATTR is allocated for this
// brush
//
if (pBrush->pBrushattr() != &pBrush->_Brushattr) { // Copy pBrushattr() to _BrushAttr
pBrush->_Brushattr = *(pBrush->pBrushattr()); // Free BRUSHATTR at bottom of function
pBrushattr = pBrush->pBrushattr(); // Set pBrushAttr to point to internal
pBrush->pBrushattr(&pBrush->_Brushattr); // Clear entry
pentry->pUser = NULL; }
// Set Brush owner to NONE or PUBLIC
HandleLock.Pid(lPid); // dec process handle count
HmgDecProcessHandleCount(W32GetCurrentPID());
bStatus = TRUE;
} else if (HandleLock.Pid() == OBJECT_OWNER_NONE) { // Allow to set from NONE to PUBLIC or NONE
HandleLock.Pid(lPid);
bStatus = TRUE;
}
//
// Move bitmap owner if needed. No need to do this if
// we are doing OBJECT_OWNER_NONE.
//
if (bStatus && lPid == OBJECT_OWNER_PUBLIC) { if (pBrush->hbmPattern() != (HBITMAP)NULL) { GreSetBitmapOwner(pBrush->hbmPattern(), OBJECT_OWNER_PUBLIC); } } } else if (lPid == OBJECT_OWNER_CURRENT) { //
// can only set to OBJECT_OWNER_CURRENT if Brush is
// not owned, or already owned by current pid.
//
lPid = W32GetCurrentPID();
if (HandleLock.Pid() == lPid || HandleLock.Pid() == OBJECT_OWNER_NONE || HandleLock.Pid() == OBJECT_OWNER_PUBLIC) { BOOL bIncHandleCount = FALSE;
bStatus = TRUE;
// only inc handle count if assigning new pid
if (HandleLock.Pid() != lPid) { // dont check quota for Brushes. ???
if (HmgIncProcessHandleCount(lPid,BRUSH_TYPE)) bIncHandleCount = TRUE; }
//
// Check if user object already allocated for this
// handle
//
if (pentry->pUser == NULL) { if (pBrushattr != NULL) { // Set BrushAttr pointer
pBrush->pBrushattr(pBrushattr); // Set pUser in ENTRY
pentry->pUser = pBrushattr; // copy clean brush attrs
*pBrushattr = pBrush->_Brushattr; // Set pBrushattr to NULL so it is not freed
pBrushattr = NULL; } else { WARNING("GreSetBrushOwner failed - No BRUSHATTR available");
bStatus = FALSE;
// reduce handle quota count
if (bIncHandleCount) HmgDecProcessHandleCount(lPid); } }
if (bStatus) { // Set new owner
HandleLock.Pid(lPid); //
// Move bitmap owner if needed.
//
if (pBrush->hbmPattern() != (HBITMAP)NULL) { GreSetBitmapOwner(pBrush->hbmPattern(), OBJECT_OWNER_CURRENT); } } } else { WARNING("GreSetBrushOwner failed, trying to set directly from one PID to another"); } } else { WARNING("GreSetBrushOwner failed, bad lPid"); } } else { WARNING("GreSetBrushOwner failed - Handle is exclusivly locked"); } } else { WARNING("GreSetBrushOwner failed - bad unique or object type"); }
HandleLock.vUnlock(); } } else { WARNING("GtreSetBrushOwner failed - invalid handle index\n"); }
// free pBrushattr if needed
if (pBrushattr) { HmgFreeObjectAttr((POBJECTATTR)pBrushattr); }
return(bStatus); }
/******************************Public*Routine******************************\
* vFreeOrCacheRbrush * * Either frees the current RBRUSH (the one pointed to by the this pointer) or * puts it in the 1-deep RBRUSH cache, if the cache is empty. * * History: * * 30-Sep-1996 -by- Tom Zakrajsek [tomzak] * Fixed it for multi brushes (DDML). * * 14-Dec-1993 -by- Michael Abrash [mikeab] * Wrote it. \**************************************************************************/
VOID MulDestroyBrushInternal(VOID*);
VOID RBRUSH::vFreeOrCacheRBrush(RBTYPE rbtype) { //
// If RBRUSH is for UMPD, just free it
//
if (!IS_SYSTEM_ADDRESS(this)) { ASSERTGDI(bUMPDRBrush(),"RBRUSH::vFreeOrCacheRBrush UserMode brush does not have bUMPDBrush() bit on\n"); EngFreeUserMem(this); return; }
PRBRUSH *pprbrush;
// The bMultiBrush check is only valid for DRIVER realizations.
// Otherwise, it is assumed false.
BOOL bMulti = FALSE;
if (rbtype == RB_DRIVER) { pprbrush = &gpCachedDbrush; bMulti = bMultiBrush();
if (bMulti) { PVOID pvRbrush = (PVOID)(((PDBRUSH)this)->aj); MulDestroyBrushInternal(pvRbrush); } } else { pprbrush = &gpCachedEngbrush; }
// If there's already a cached RBRUSH, or this is a DDML brush
// just free this.
if ((*pprbrush != NULL) || (bMulti == TRUE)) { VFREEMEM(this); } else { PRBRUSH pOldRbrush;
// There's no cached RBRUSH, and it's not a DDML brush,
// so cache this one.
if ((pOldRbrush = (PRBRUSH) InterlockedExchangePointer((PVOID *)pprbrush, this)) != NULL) { // Before we could cache this one, someone else cached another one,
// which we just acquired responsibility for, so free it.
VFREEMEM(pOldRbrush); } } }
/******************************Public*Routine******************************\
* BRUSH::hFindIcmDIB * * Search ICM DIBs associated with brush until a match is found * * Arguments: * * Return Value: * * History: * * 9/25/1996 Mark Enstrom [marke] * \**************************************************************************/
HBITMAP BRUSH::hFindIcmDIB(HANDLE hcmXform) { ICMMSG(("hFindIcmDIB: FIND ICM DIB \n"));
if (hcmXform == NULL) { return _hbmPattern; } else { GreAcquireFastMutex(ghfmMemory);
PICM_DIB_LIST pDIBList = pIcmDIBList();
while (pDIBList != NULL) { if (pDIBList->hcmXform == hcmXform) { GreReleaseFastMutex(ghfmMemory); return(pDIBList->hDIB); }
pDIBList = pDIBList->pNext; }
GreReleaseFastMutex(ghfmMemory);
return(NULL); } }
BOOL BRUSH::bAddIcmDIB(HANDLE hcmXform,HBITMAP hDIB) { ICMMSG(("bAddIcmDIB: ADD ICM DIB \n"));
BOOL bRet = FALSE;
//
// Check current hcmform is not on the list.
//
if (hFindIcmDIB(hcmXform)) { ICMMSG(("bAddIcmDIB(): The DIB for hcmXform is exist\n"));
//
// hcmXform is exist,
//
// Do we need to do delete existing one and insert new one ??
//
return (FALSE); }
SURFREF SurfDIB((HSURF) hDIB);
if (SurfDIB.bValid()) { PICM_DIB_LIST pDIBList = (PICM_DIB_LIST)PALLOCNOZ(sizeof(ICM_DIB_LIST),'ldbG');
if (pDIBList) { //
// Inc. ref. count
//
{ SURFACE *ps = SurfDIB.ps; ps->vInc_cRef(); }
//
// Fill DIBList cell.
//
pDIBList->hcmXform = hcmXform; pDIBList->hDIB = hDIB; pDIBList->pNext = pIcmDIBList();
//
// Updates list.
//
GreAcquireFastMutex(ghfmMemory); pIcmDIBList(pDIBList); GreReleaseFastMutex(ghfmMemory);
bRet = TRUE; } else { bRet = FALSE; } }
return(bRet); }
VOID BRUSH::vDeleteIcmDIBs(VOID) { ICMMSG(("vDeleteIcmDIBs: Free ICM DIB \n"));
PICM_DIB_LIST pDIBList = pIcmDIBList();
GreAcquireFastMutex(ghfmMemory);
while (pDIBList != NULL) { PICM_DIB_LIST pNext = pDIBList->pNext; HSURF hSurf = (HSURF) pDIBList->hDIB; BOOL bValidSurface = FALSE;
//
// Dec. ref count, before deleting
//
{ SURFREF SurfDIB(hSurf); if (SurfDIB.bValid()) { SURFACE *ps = SurfDIB.ps; ps->vDec_cRef(); bValidSurface = TRUE; } }
if (bValidSurface) { //
// Delete ICM-ed DIB surface.
//
if (!bDeleteSurface((HSURF)pDIBList->hDIB)) { ICMMSG(("vDeleteICMDIBs(): bDeleteSurface is failed\n")); } } else { ICMMSG(("vDeleteICMDIBs(): Invalid surface\n")); }
//
// free the cell.
//
VFREEMEM(pDIBList); pDIBList = pNext; }
GreReleaseFastMutex(ghfmMemory); }
|