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.
3089 lines
94 KiB
3089 lines
94 KiB
/******************************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);
|
|
}
|