2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS win32 subsystem
4 * PURPOSE: Functions for brushes
5 * FILE: subsystem/win32/win32k/objects/brush.c
14 #define GDIOBJATTRFREE 170
16 typedef struct _GDI_OBJ_ATTR_FREELIST
20 PVOID AttrList
[GDIOBJATTRFREE
];
21 } GDI_OBJ_ATTR_FREELIST
, *PGDI_OBJ_ATTR_FREELIST
;
23 typedef struct _GDI_OBJ_ATTR_ENTRY
25 RGN_ATTR Attr
[GDIOBJATTRFREE
];
26 } GDI_OBJ_ATTR_ENTRY
, *PGDI_OBJ_ATTR_ENTRY
;
28 static const USHORT HatchBrushes
[NB_HATCH_STYLES
][8] =
30 {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF}, /* HS_HORIZONTAL */
31 {0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7}, /* HS_VERTICAL */
32 {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, /* HS_FDIAGONAL */
33 {0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE}, /* HS_BDIAGONAL */
34 {0xF7, 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7}, /* HS_CROSS */
35 {0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E} /* HS_DIAGCROSS */
41 AllocateObjectAttr(VOID
)
46 PGDI_OBJ_ATTR_FREELIST pGdiObjAttrFreeList
;
47 PGDI_OBJ_ATTR_ENTRY pGdiObjAttrEntry
;
50 pti
= PsGetCurrentThreadWin32Thread();
51 if (pti
->pgdiBrushAttr
)
53 pAttr
= pti
->pgdiBrushAttr
; // Get the free one.
54 pti
->pgdiBrushAttr
= NULL
;
58 ppi
= PsGetCurrentProcessWin32Process();
60 if (!ppi
->pBrushAttrList
) // If set point is null, allocate new group.
62 pGdiObjAttrEntry
= EngAllocUserMem(sizeof(GDI_OBJ_ATTR_ENTRY
), 0);
64 if (!pGdiObjAttrEntry
)
66 DPRINT1("Attr Failed User Allocation!\n");
70 DPRINT("AllocObjectAttr User 0x%x\n",pGdiObjAttrEntry
);
72 pGdiObjAttrFreeList
= ExAllocatePoolWithTag( PagedPool
,
73 sizeof(GDI_OBJ_ATTR_FREELIST
),
74 GDITAG_BRUSH_FREELIST
);
75 if ( !pGdiObjAttrFreeList
)
77 EngFreeUserMem(pGdiObjAttrEntry
);
81 RtlZeroMemory(pGdiObjAttrFreeList
, sizeof(GDI_OBJ_ATTR_FREELIST
));
83 DPRINT("AllocObjectAttr Ex 0x%x\n",pGdiObjAttrFreeList
);
85 InsertHeadList( &ppi
->GDIBrushAttrFreeList
, &pGdiObjAttrFreeList
->Entry
);
87 pGdiObjAttrFreeList
->nEntries
= GDIOBJATTRFREE
;
88 // Start at the bottom up and set end of free list point.
89 ppi
->pBrushAttrList
= &pGdiObjAttrEntry
->Attr
[GDIOBJATTRFREE
-1];
90 // Build the free attr list.
91 for ( i
= 0; i
< GDIOBJATTRFREE
; i
++)
93 pGdiObjAttrFreeList
->AttrList
[i
] = &pGdiObjAttrEntry
->Attr
[i
];
97 pAttr
= ppi
->pBrushAttrList
;
98 pGdiObjAttrFreeList
= (PGDI_OBJ_ATTR_FREELIST
)ppi
->GDIBrushAttrFreeList
.Flink
;
100 // Free the list when it is full!
101 if ( pGdiObjAttrFreeList
->nEntries
-- == 1)
102 { // No more free entries, so yank the list.
103 RemoveEntryList( &pGdiObjAttrFreeList
->Entry
);
105 ExFreePoolWithTag( pGdiObjAttrFreeList
, GDITAG_BRUSH_FREELIST
);
107 if ( IsListEmpty( &ppi
->GDIBrushAttrFreeList
) )
109 ppi
->pBrushAttrList
= NULL
;
113 pGdiObjAttrFreeList
= (PGDI_OBJ_ATTR_FREELIST
)ppi
->GDIBrushAttrFreeList
.Flink
;
116 ppi
->pBrushAttrList
= pGdiObjAttrFreeList
->AttrList
[pGdiObjAttrFreeList
->nEntries
-1];
123 FreeObjectAttr(PVOID pAttr
)
127 PGDI_OBJ_ATTR_FREELIST pGdiObjAttrFreeList
;
129 pti
= PsGetCurrentThreadWin32Thread();
133 if (!pti
->pgdiBrushAttr
)
134 { // If it is null, just cache it for the next time.
135 pti
->pgdiBrushAttr
= pAttr
;
139 ppi
= PsGetCurrentProcessWin32Process();
141 pGdiObjAttrFreeList
= (PGDI_OBJ_ATTR_FREELIST
)ppi
->GDIBrushAttrFreeList
.Flink
;
143 // We add to the list of free entries, so this will grows!
144 if ( IsListEmpty(&ppi
->GDIBrushAttrFreeList
) ||
145 pGdiObjAttrFreeList
->nEntries
== GDIOBJATTRFREE
)
147 pGdiObjAttrFreeList
= ExAllocatePoolWithTag( PagedPool
,
148 sizeof(GDI_OBJ_ATTR_FREELIST
),
149 GDITAG_BRUSH_FREELIST
);
150 if ( !pGdiObjAttrFreeList
)
154 InsertHeadList( &ppi
->GDIBrushAttrFreeList
, &pGdiObjAttrFreeList
->Entry
);
155 pGdiObjAttrFreeList
->nEntries
= 0;
157 // Up count, save the entry and set end of free list point.
158 ++pGdiObjAttrFreeList
->nEntries
; // Top Down...
159 pGdiObjAttrFreeList
->AttrList
[pGdiObjAttrFreeList
->nEntries
-1] = pAttr
;
160 ppi
->pBrushAttrList
= pAttr
;
168 BRUSH_Cleanup(PVOID ObjectBody
)
170 PBRUSH pbrush
= (PBRUSH
)ObjectBody
;
171 if (pbrush
->flAttrs
& (GDIBRUSH_IS_HATCH
| GDIBRUSH_IS_BITMAP
))
173 ASSERT(pbrush
->hbmPattern
);
174 GDIOBJ_SetOwnership(pbrush
->hbmPattern
, PsGetCurrentProcess());
175 GreDeleteObject(pbrush
->hbmPattern
);
178 /* Free the kmode styles array of EXTPENS */
181 ExFreePool(pbrush
->pStyle
);
189 BRUSH_GetObject(PBRUSH pbrush
, INT Count
, LPLOGBRUSH Buffer
)
191 if (Buffer
== NULL
) return sizeof(LOGBRUSH
);
192 if (Count
== 0) return 0;
195 Buffer
->lbColor
= pbrush
->BrushAttr
.lbColor
;
198 if ((pbrush
->flAttrs
& GDIBRUSH_IS_HATCH
)!=0)
200 /* FIXME : this is not the right value */
201 Buffer
->lbHatch
= (LONG
)pbrush
->hbmPattern
;
210 /* Get the type of style */
211 if ((pbrush
->flAttrs
& GDIBRUSH_IS_SOLID
)!=0)
213 Buffer
->lbStyle
= BS_SOLID
;
215 else if ((pbrush
->flAttrs
& GDIBRUSH_IS_NULL
)!=0)
217 Buffer
->lbStyle
= BS_NULL
; // BS_HOLLOW
219 else if ((pbrush
->flAttrs
& GDIBRUSH_IS_HATCH
)!=0)
221 Buffer
->lbStyle
= BS_HATCHED
;
223 else if ((pbrush
->flAttrs
& GDIBRUSH_IS_BITMAP
)!=0)
225 Buffer
->lbStyle
= BS_PATTERN
;
227 else if ((pbrush
->flAttrs
& GDIBRUSH_IS_DIB
)!=0)
229 Buffer
->lbStyle
= BS_DIBPATTERN
;
233 else if ((pbrush->flAttrs & )!=0)
235 Buffer->lbStyle = BS_INDEXED;
237 else if ((pbrush->flAttrs & )!=0)
239 Buffer->lbStyle = BS_DIBPATTERNPT;
244 return sizeof(LOGBRUSH
);
248 * @name CalculateColorTableSize
250 * Internal routine to calculate the number of color table entries.
252 * @param BitmapInfoHeader
253 * Input bitmap information header, can be any version of
254 * BITMAPINFOHEADER or BITMAPCOREHEADER.
257 * Pointer to variable which specifiing the color mode (DIB_RGB_COLORS
258 * or DIB_RGB_COLORS). On successful return this value is normalized
259 * according to the bitmap info.
261 * @param ColorTableSize
262 * On successful return this variable is filled with number of
263 * entries in color table for the image with specified parameters.
266 * TRUE if the input values together form a valid image, FALSE otherwise.
270 CalculateColorTableSize(
271 CONST BITMAPINFOHEADER
*BitmapInfoHeader
,
273 UINT
*ColorTableSize
)
280 * At first get some basic parameters from the passed BitmapInfoHeader
281 * structure. It can have one of the following formats:
282 * - BITMAPCOREHEADER (the oldest one with totally different layout
284 * - BITMAPINFOHEADER (the standard and most common header)
285 * - BITMAPV4HEADER (extension of BITMAPINFOHEADER)
286 * - BITMAPV5HEADER (extension of BITMAPV4HEADER)
288 if (BitmapInfoHeader
->biSize
== sizeof(BITMAPCOREHEADER
))
290 BitCount
= ((LPBITMAPCOREHEADER
)BitmapInfoHeader
)->bcBitCount
;
292 Compression
= BI_RGB
;
296 BitCount
= BitmapInfoHeader
->biBitCount
;
297 ClrUsed
= BitmapInfoHeader
->biClrUsed
;
298 Compression
= BitmapInfoHeader
->biCompression
;
304 if (*ColorSpec
== DIB_PAL_COLORS
)
305 *ColorSpec
= DIB_RGB_COLORS
;
307 if (BitCount
!= 16 && BitCount
!= 32)
310 /* For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in
311 * the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask).
312 * For BITMAPINFOHEADER the color masks are stored in the palette. */
313 if (BitmapInfoHeader
->biSize
> sizeof(BITMAPINFOHEADER
))
324 *ColorTableSize
= ClrUsed
? min(ClrUsed
, 2) : 2;
328 *ColorTableSize
= ClrUsed
? min(ClrUsed
, 16) : 16;
332 *ColorTableSize
= ClrUsed
? min(ClrUsed
, 256) : 256;
336 if (*ColorSpec
== DIB_PAL_COLORS
)
337 *ColorSpec
= DIB_RGB_COLORS
;
338 if (BitCount
!= 16 && BitCount
!= 24 && BitCount
!= 32)
340 *ColorTableSize
= ClrUsed
;
347 *ColorTableSize
= ClrUsed
? min(ClrUsed
, 16) : 16;
355 *ColorTableSize
= ClrUsed
? min(ClrUsed
, 256) : 256;
362 *ColorTableSize
= ClrUsed
;
372 IntGdiCreateDIBBrush(
373 CONST BITMAPINFO
*BitmapInfo
,
376 CONST VOID
*PackedDIB
)
382 UINT PaletteEntryCount
;
383 PSURFACE psurfPattern
;
386 if (BitmapInfo
->bmiHeader
.biSize
< sizeof(BITMAPINFOHEADER
))
388 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
392 if (!CalculateColorTableSize(&BitmapInfo
->bmiHeader
,
396 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
400 // FIXME: What about BI_BITFIELDS
401 DataPtr
= (ULONG_PTR
)BitmapInfo
+ BitmapInfo
->bmiHeader
.biSize
;
402 if (ColorSpec
== DIB_RGB_COLORS
)
403 DataPtr
+= PaletteEntryCount
* sizeof(RGBQUAD
);
405 DataPtr
+= PaletteEntryCount
* sizeof(USHORT
);
407 hPattern
= IntGdiCreateBitmap(BitmapInfo
->bmiHeader
.biWidth
,
408 BitmapInfo
->bmiHeader
.biHeight
,
409 BitmapInfo
->bmiHeader
.biPlanes
,
410 BitmapInfo
->bmiHeader
.biBitCount
,
412 if (hPattern
== NULL
)
414 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
418 psurfPattern
= SURFACE_LockSurface(hPattern
);
419 ASSERT(psurfPattern
!= NULL
);
420 psurfPattern
->hDIBPalette
= BuildDIBPalette(BitmapInfo
, &PaletteType
);
421 SURFACE_UnlockSurface(psurfPattern
);
423 pbrush
= BRUSH_AllocBrushWithHandle();
426 GreDeleteObject(hPattern
);
427 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
430 hBrush
= pbrush
->BaseObject
.hHmgr
;
432 pbrush
->flAttrs
|= GDIBRUSH_IS_BITMAP
| GDIBRUSH_IS_DIB
;
433 pbrush
->hbmPattern
= hPattern
;
434 /* FIXME: Fill in the rest of fields!!! */
436 GDIOBJ_SetOwnership(hPattern
, NULL
);
438 BRUSH_UnlockBrush(pbrush
);
445 IntGdiCreateHatchBrush(
453 if (Style
< 0 || Style
>= NB_HATCH_STYLES
)
458 hPattern
= IntGdiCreateBitmap(8, 8, 1, 1, (LPBYTE
)HatchBrushes
[Style
]);
459 if (hPattern
== NULL
)
461 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
465 pbrush
= BRUSH_AllocBrushWithHandle();
468 GreDeleteObject(hPattern
);
469 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
472 hBrush
= pbrush
->BaseObject
.hHmgr
;
474 pbrush
->flAttrs
|= GDIBRUSH_IS_HATCH
;
475 pbrush
->hbmPattern
= hPattern
;
476 pbrush
->BrushAttr
.lbColor
= Color
& 0xFFFFFF;
478 GDIOBJ_SetOwnership(hPattern
, NULL
);
480 BRUSH_UnlockBrush(pbrush
);
487 IntGdiCreatePatternBrush(
494 hPattern
= BITMAP_CopyBitmap(hBitmap
);
495 if (hPattern
== NULL
)
497 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
501 pbrush
= BRUSH_AllocBrushWithHandle();
504 GreDeleteObject(hPattern
);
505 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
508 hBrush
= pbrush
->BaseObject
.hHmgr
;
510 pbrush
->flAttrs
|= GDIBRUSH_IS_BITMAP
;
511 pbrush
->hbmPattern
= hPattern
;
512 /* FIXME: Fill in the rest of fields!!! */
514 GDIOBJ_SetOwnership(hPattern
, NULL
);
516 BRUSH_UnlockBrush(pbrush
);
523 IntGdiCreateSolidBrush(
529 pbrush
= BRUSH_AllocBrushWithHandle();
532 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
535 hBrush
= pbrush
->BaseObject
.hHmgr
;
537 pbrush
->flAttrs
|= GDIBRUSH_IS_SOLID
;
539 pbrush
->BrushAttr
.lbColor
= Color
;
540 /* FIXME: Fill in the rest of fields!!! */
542 BRUSH_UnlockBrush(pbrush
);
549 IntGdiCreateNullBrush(VOID
)
554 pbrush
= BRUSH_AllocBrushWithHandle();
557 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
560 hBrush
= pbrush
->BaseObject
.hHmgr
;
562 pbrush
->flAttrs
|= GDIBRUSH_IS_NULL
;
563 BRUSH_UnlockBrush(pbrush
);
570 IntGdiSetSolidBrushColor(HBRUSH hBrush
, COLORREF Color
)
574 pbrush
= BRUSH_LockBrush(hBrush
);
575 if (pbrush
->flAttrs
& GDIBRUSH_IS_SOLID
)
577 pbrush
->BrushAttr
.lbColor
= Color
& 0xFFFFFF;
579 BRUSH_UnlockBrush(pbrush
);
583 /* PUBLIC FUNCTIONS ***********************************************************/
588 IN PVOID BitmapInfoAndData
,
590 IN UINT BitmapInfoSize
,
595 BITMAPINFO
*SafeBitmapInfoAndData
;
596 NTSTATUS Status
= STATUS_SUCCESS
;
599 SafeBitmapInfoAndData
= EngAllocMem(FL_ZERO_MEMORY
, BitmapInfoSize
, TAG_DIB
);
600 if (SafeBitmapInfoAndData
== NULL
)
602 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
608 ProbeForRead(BitmapInfoAndData
, BitmapInfoSize
, 1);
609 RtlCopyMemory(SafeBitmapInfoAndData
, BitmapInfoAndData
, BitmapInfoSize
);
611 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
613 Status
= _SEH2_GetExceptionCode();
617 if (!NT_SUCCESS(Status
))
619 EngFreeMem(SafeBitmapInfoAndData
);
620 SetLastNtError(Status
);
624 hBrush
= IntGdiCreateDIBBrush(SafeBitmapInfoAndData
,
629 EngFreeMem(SafeBitmapInfoAndData
);
636 NtGdiCreateHatchBrushInternal(
641 return IntGdiCreateHatchBrush(Style
, Color
);
646 NtGdiCreatePatternBrushInternal(
651 return IntGdiCreatePatternBrush(hBitmap
);
656 NtGdiCreateSolidBrush(COLORREF Color
,
657 IN OPTIONAL HBRUSH hbr
)
659 return IntGdiCreateSolidBrush(Color
);
663 * \name NtGdiSetBrushOrg
665 * \brief Sets the brush origin that GDI assigns to
666 * the next brush an application selects into the specified device context.
672 NtGdiSetBrushOrg(HDC hDC
, INT XOrg
, INT YOrg
, LPPOINT Point
)
680 SetLastWin32Error(ERROR_INVALID_HANDLE
);
683 pdcattr
= dc
->pdcattr
;
687 NTSTATUS Status
= STATUS_SUCCESS
;
689 SafePoint
.x
= pdcattr
->ptlBrushOrigin
.x
;
690 SafePoint
.y
= pdcattr
->ptlBrushOrigin
.y
;
693 ProbeForWrite(Point
, sizeof(POINT
), 1);
696 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
698 Status
= _SEH2_GetExceptionCode();
702 if (!NT_SUCCESS(Status
))
705 SetLastNtError(Status
);
710 pdcattr
->ptlBrushOrigin
.x
= XOrg
;
711 pdcattr
->ptlBrushOrigin
.y
= YOrg
;
712 IntptlBrushOrigin(dc
, XOrg
, YOrg
);