2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS win32 subsystem
4 * PURPOSE: BRUSH class implementation
5 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7 * REFERENCES: http://support.microsoft.com/kb/kbview/108497
12 DBG_DEFAULT_CHANNEL(GdiBrush
);
16 _In_ COLORREF crColor
,
18 _In_opt_ HBITMAP hbmPattern
,
19 _In_opt_ PVOID pvClient
,
20 _In_ GDILOOBJTYPE loobjtype
= GDILoObjType_LO_BRUSH_TYPE
)
21 : BASEOBJECT(loobjtype
)
23 static ULONG ulGlobalBrushUnique
= 0;
25 /* Get a unique value */
26 this->ulBrushUnique
= InterlockedIncrementUL(&ulGlobalBrushUnique
);
28 /* Start with kmode brush attribute */
29 this->pBrushAttr
= &this->BrushAttr
;
32 this->flAttrs
= flAttrs
;
33 this->iHatch
= iHatch
;
34 this->hbmPattern
= hbmPattern
;
35 this->hbmClient
= (HBITMAP
)pvClient
;
36 this->pBrushAttr
->lbColor
= crColor
;
38 /* Initialize the other fields */
41 this->bCacheGrabbed
= FALSE
;
46 this->pvRBrush
= NULL
;
49 /* FIXME: should be done only in PEN constructor,
50 but our destructor needs it! */
51 this->dwStyleCount
= 0;
58 /* Check if we have a user mode brush attribute */
59 if (this->pBrushAttr
!= &this->BrushAttr
)
61 /* Free memory to the process GDI pool */
62 GdiPoolFree(GetBrushAttrPool(), this->pBrushAttr
);
65 /* Delete the pattern bitmap (may have already been deleted during gdi cleanup) */
66 if (this->hbmPattern
!= NULL
&& GreIsHandleValid(this->hbmPattern
))
68 GreSetBitmapOwner(this->hbmPattern
, BASEOBJECT::OWNER::POWNED
);
69 GreDeleteObject(this->hbmPattern
);
73 if ((this->pStyle
!= NULL
) && !(this->flAttrs
& BR_IS_DEFAULTSTYLE
))
75 ExFreePoolWithTag(this->pStyle
, GDITAG_PENSTYLE
);
83 PBRUSH pbr
= static_cast<PBRUSH
>(pvObject
);
84 NT_ASSERT((GDI_HANDLE_GET_TYPE(pbr
->hHmgr()) == GDILoObjType_LO_BRUSH_TYPE
) ||
85 (GDI_HANDLE_GET_TYPE(pbr
->hHmgr()) == GDILoObjType_LO_PEN_TYPE
) ||
86 (GDI_HANDLE_GET_TYPE(pbr
->hHmgr()) == GDILoObjType_LO_EXTPEN_TYPE
));
91 BRUSH::bAllocateBrushAttr(
94 PBRUSH_ATTR pBrushAttr
;
95 NT_ASSERT(this->pBrushAttr
== &this->BrushAttr
);
97 /* Allocate a brush attribute from the pool */
98 pBrushAttr
= static_cast<PBRUSH_ATTR
>(GdiPoolAllocate(GetBrushAttrPool()));
99 if (pBrushAttr
== NULL
)
101 ERR("Could not allocate brush attr\n");
105 /* Copy the content from the kernel mode brush attribute */
106 this->pBrushAttr
= pBrushAttr
;
107 *this->pBrushAttr
= this->BrushAttr
;
109 /* Set the object attribute in the handle table */
110 vSetObjectAttr(pBrushAttr
);
116 BRUSH::vSetSolidColor(
117 _In_ COLORREF crColor
)
119 NT_ASSERT(this->flAttrs
& BR_IS_SOLID
);
121 /* Set new color and reset the pal times */
122 this->pBrushAttr
->lbColor
= crColor
& 0xFFFFFF;
123 this->ulPalTime
= -1;
124 this->ulSurfTime
= -1;
128 BRUSH::hbmGetBitmapHandle(
129 _Out_ PUINT puUsage
) const
131 /* Return the color usage based on flags */
132 *puUsage
= (this->flAttrs
& BR_IS_DIBPALCOLORS
) ? DIB_PAL_COLORS
:
133 (this->flAttrs
& BR_IS_DIBPALINDICES
) ? DIB_PAL_INDICES
:
136 return this->hbmPattern
;
142 _Out_bytecap_(cjSize
) PLOGBRUSH plb
) const
144 /* Check if only size is requested */
146 return sizeof(LOGBRUSH
);
148 /* Check if size is ok */
153 plb
->lbColor
= this->BrushAttr
.lbColor
;
155 /* Set style and hatch based on the attribute flags */
156 if (this->flAttrs
& BR_IS_SOLID
)
158 plb
->lbStyle
= BS_SOLID
;
161 else if (this->flAttrs
& BR_IS_HATCH
)
163 plb
->lbStyle
= BS_HATCHED
;
164 plb
->lbHatch
= this->iHatch
;
166 else if (this->flAttrs
& BR_IS_DIB
)
168 plb
->lbStyle
= BS_DIBPATTERN
;
169 plb
->lbHatch
= (ULONG_PTR
)this->hbmClient
;
171 else if (this->flAttrs
& BR_IS_BITMAP
)
173 plb
->lbStyle
= BS_PATTERN
;
174 plb
->lbHatch
= (ULONG_PTR
)this->hbmClient
;
176 else if (this->flAttrs
& BR_IS_NULL
)
178 plb
->lbStyle
= BS_NULL
;
186 return sizeof(LOGBRUSH
);
193 _In_ COLORREF crColor
,
195 _In_opt_ HBITMAP hbmPattern
,
196 _In_opt_ PVOID pvClient
)
198 BASEOBJECT::OWNER owner
;
202 NT_ASSERT(((flAttrs
& BR_IS_BITMAP
) == 0) || (hbmPattern
!= NULL
));
204 /* Create the brush (brush takes ownership of the bitmap) */
205 pbr
= new BRUSH(flAttrs
, crColor
, iHatch
, hbmPattern
, pvClient
);
208 ERR("Failed to allocate a brush\n");
209 GreSetBitmapOwner(hbmPattern
, BASEOBJECT::OWNER::POWNED
);
210 GreDeleteObject(hbmPattern
);
214 /* Check if this is a global brush */
215 if (!(flAttrs
& BR_IS_GLOBAL
))
217 /* Not a global brush, so allocate a user mode brush attribute */
218 if (!pbr
->bAllocateBrushAttr())
220 ERR("Failed to allocate brush attribute\n");
226 /* Set the owner, either public or process owned */
227 owner
= (flAttrs
& BR_IS_GLOBAL
) ? BASEOBJECT::OWNER::PUBLIC
:
228 BASEOBJECT::OWNER::POWNED
;
230 /* Insert the object into the GDI handle table */
231 hbr
= static_cast<HBRUSH
>(pbr
->hInsertObject(owner
));
234 ERR("Failed to insert brush\n");
239 /* Unlock the brush */
246 /* C interface ***************************************************************/
255 BRUSH::vDeleteObject(pvObject
);
263 LPLOGBRUSH plbBuffer
)
265 return pbr
->cjGetObject(cjBuffer
, plbBuffer
);
270 IntGdiCreateNullBrush(
273 /* Call the internal function */
274 return CreateBrushInternal(BR_IS_NULL
| BR_IS_GLOBAL
, 0, 0, NULL
, NULL
);
279 IntGdiCreateSolidBrush(
282 /* Call the internal function */
283 return CreateBrushInternal(BR_IS_SOLID
| BR_IS_GLOBAL
,
292 IntGdiCreatePatternBrush(
295 NT_ASSERT(hbmPattern
!= NULL
);
296 GreSetBitmapOwner(hbmPattern
, BASEOBJECT::OWNER::PUBLIC
);
297 return CreateBrushInternal(BR_IS_BITMAP
| BR_IS_GLOBAL
,
306 IntGdiSetSolidBrushColor(
308 _In_ COLORREF crColor
)
313 pbr
= BRUSH::LockAny(hbr
);
316 ERR("Failed to lock brush %p\n", hbr
);
320 /* Call the member function */
321 pbr
->vSetSolidColor(crColor
);
323 /* Unlock the brush */
330 NtGdiCreateSolidBrush(
331 _In_ COLORREF crColor
,
336 WARN("hbr is not supported, ignoring\n");
339 /* Call the internal function */
340 return CreateBrushInternal(BR_IS_SOLID
, crColor
, 0, NULL
, NULL
);
346 NtGdiCreateHatchBrushInternal(
348 _In_ COLORREF crColor
,
355 WARN("bPen is not supported, ignoring\n");
358 /* Check what kind if hatch style this is */
359 if (iHatch
< HS_DDI_MAX
)
361 flAttr
= BR_IS_HATCH
;
363 else if (iHatch
< HS_API_MAX
)
365 flAttr
= BR_IS_SOLID
;
369 ERR("Invalid iHatch: %lu\n", iHatch
);
373 /* Call the internal function */
374 return CreateBrushInternal(flAttr
, crColor
, iHatch
, NULL
, NULL
);
380 NtGdiCreatePatternBrushInternal(
381 _In_ HBITMAP hbmClient
,
389 WARN("b8X8 is not supported, ignoring\n");
394 WARN("bPen is not supported, ignoring\n");
397 /* Copy the bitmap */
398 hbmPattern
= BITMAP_CopyBitmap(hbmClient
);
399 if (hbmPattern
== NULL
)
401 ERR("Failed to copy the bitmap %p\n", hbmPattern
);
405 /* Call the internal function (will delete hbmPattern on failure) */
406 return CreateBrushInternal(BR_IS_BITMAP
, 0, 0, hbmPattern
, hbmClient
);
413 _In_reads_bytes_(cj
) PVOID pv
,
427 WARN("b8X8 is not supported, ignoring\n");
432 WARN("bPen is not supported, ignoring\n");
435 if (uUsage
> DIB_PAL_INDICES
)
437 ERR("Invalid uUsage value: %lu\n", uUsage
);
438 EngSetLastError(ERROR_INVALID_PARAMETER
);
442 /* Allocate a buffer for the packed DIB */
443 pvPackedDIB
= ExAllocatePoolWithTag(PagedPool
, cj
, GDITAG_TEMP
);
444 if (pvPackedDIB
== NULL
)
446 ERR("Failed to allocate temp buffer of %u bytes\n", cj
);
450 /* Probe and copy the packed DIB */
453 ProbeForRead(pv
, cj
, 1);
454 RtlCopyMemory(pvPackedDIB
, pv
, cj
);
456 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
458 ERR("Got exception, pv = %p, cj = %lu\n", pv
, cj
);
463 flAttrs
= BR_IS_BITMAP
| BR_IS_DIB
;
465 /* Check what kind of color table we have */
466 if (uUsage
== DIB_PAL_COLORS
)
468 /* Remember it and use DIB_PAL_BRUSHHACK to create a "special" palette */
469 flAttrs
|= BR_IS_DIBPALCOLORS
;
470 uUsage
= DIB_PAL_BRUSHHACK
;
472 else if (uUsage
== DIB_PAL_INDICES
)
474 /* No color table, bitmap contains device palette indices */
475 flAttrs
|= BR_IS_DIBPALINDICES
;
477 /* FIXME: This makes tests pass, but needs investigation. */
478 flAttrs
|= BR_IS_NULL
;
481 /* Create a bitmap from the DIB */
482 hbm
= GreCreateDIBitmapFromPackedDIB(pvPackedDIB
, cj
, uUsage
);
485 ERR("Failed to create bitmap from DIB\n");
489 /* Call the internal function (will delete hbm on failure) */
490 hbr
= CreateBrushInternal(flAttrs
, 0, 0, hbm
, pvClient
);
494 ExFreePoolWithTag(pvPackedDIB
, GDITAG_TEMP
);
502 NtGdiGetObjectBitmapHandle(
511 pbr
= BRUSH::LockForRead(hbr
);
514 ERR("Failed to lock brush %p\n", hbr
);
518 /* Call the member function */
519 hbm
= pbr
->hbmGetBitmapHandle(&uUsage
);
521 /* Unlock the brush */
526 ProbeForWrite(piUsage
, sizeof(*piUsage
), 1);
529 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
531 ERR("Got exception! piUsage = %p\n", piUsage
);
542 NtGdiSetBrushAttributes(
553 NtGdiClearBrushAttributes(