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 ULONG 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
);
249 IntGdiCreateDIBBrush(
250 CONST BITMAPINFO
*BitmapInfo
,
253 CONST VOID
*PackedDIB
)
259 PSURFACE psurfPattern
;
262 if (BitmapInfo
->bmiHeader
.biSize
< sizeof(BITMAPINFOHEADER
))
264 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
268 DataPtr
= (ULONG_PTR
)BitmapInfo
+ DIB_BitmapInfoSize(BitmapInfo
, ColorSpec
);
270 hPattern
= GreCreateBitmap(BitmapInfo
->bmiHeader
.biWidth
,
271 BitmapInfo
->bmiHeader
.biHeight
,
272 BitmapInfo
->bmiHeader
.biPlanes
,
273 BitmapInfo
->bmiHeader
.biBitCount
,
275 if (hPattern
== NULL
)
277 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
281 psurfPattern
= SURFACE_LockSurface(hPattern
);
282 ASSERT(psurfPattern
!= NULL
);
283 if(ColorSpec
== DIB_PAL_COLORS
) DPRINT1("FIXME, unsupported color spec!\n");
284 hpal
= BuildDIBPalette(BitmapInfo
);
285 psurfPattern
->ppal
= PALETTE_ShareLockPalette(hpal
);
286 /* Lazy delete palette, it will be freed when its shared reference is zeroed */
287 GreDeleteObject(hpal
);
288 SURFACE_UnlockSurface(psurfPattern
);
290 pbrush
= BRUSH_AllocBrushWithHandle();
293 GreDeleteObject(hPattern
);
294 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
297 hBrush
= pbrush
->BaseObject
.hHmgr
;
299 pbrush
->flAttrs
|= GDIBRUSH_IS_BITMAP
| GDIBRUSH_IS_DIB
;
300 pbrush
->hbmPattern
= hPattern
;
301 /* FIXME: Fill in the rest of fields!!! */
303 GDIOBJ_SetOwnership(hPattern
, NULL
);
305 BRUSH_UnlockBrush(pbrush
);
312 IntGdiCreateHatchBrush(
320 if (Style
< 0 || Style
>= NB_HATCH_STYLES
)
325 hPattern
= GreCreateBitmap(8, 8, 1, 1, (LPBYTE
)HatchBrushes
[Style
]);
326 if (hPattern
== NULL
)
328 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
332 pbrush
= BRUSH_AllocBrushWithHandle();
335 GreDeleteObject(hPattern
);
336 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
339 hBrush
= pbrush
->BaseObject
.hHmgr
;
341 pbrush
->flAttrs
|= GDIBRUSH_IS_HATCH
;
342 pbrush
->hbmPattern
= hPattern
;
343 pbrush
->BrushAttr
.lbColor
= Color
& 0xFFFFFF;
345 GDIOBJ_SetOwnership(hPattern
, NULL
);
347 BRUSH_UnlockBrush(pbrush
);
354 IntGdiCreatePatternBrush(
361 hPattern
= BITMAP_CopyBitmap(hBitmap
);
362 if (hPattern
== NULL
)
364 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
368 pbrush
= BRUSH_AllocBrushWithHandle();
371 GreDeleteObject(hPattern
);
372 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
375 hBrush
= pbrush
->BaseObject
.hHmgr
;
377 pbrush
->flAttrs
|= GDIBRUSH_IS_BITMAP
;
378 pbrush
->hbmPattern
= hPattern
;
379 /* FIXME: Fill in the rest of fields!!! */
381 GDIOBJ_SetOwnership(hPattern
, NULL
);
383 BRUSH_UnlockBrush(pbrush
);
390 IntGdiCreateSolidBrush(
396 pbrush
= BRUSH_AllocBrushWithHandle();
399 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
402 hBrush
= pbrush
->BaseObject
.hHmgr
;
404 pbrush
->flAttrs
|= GDIBRUSH_IS_SOLID
;
406 pbrush
->BrushAttr
.lbColor
= Color
;
407 /* FIXME: Fill in the rest of fields!!! */
409 BRUSH_UnlockBrush(pbrush
);
416 IntGdiCreateNullBrush(VOID
)
421 pbrush
= BRUSH_AllocBrushWithHandle();
424 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
427 hBrush
= pbrush
->BaseObject
.hHmgr
;
429 pbrush
->flAttrs
|= GDIBRUSH_IS_NULL
;
430 BRUSH_UnlockBrush(pbrush
);
437 IntGdiSetSolidBrushColor(HBRUSH hBrush
, COLORREF Color
)
441 pbrush
= BRUSH_LockBrush(hBrush
);
442 if (pbrush
->flAttrs
& GDIBRUSH_IS_SOLID
)
444 pbrush
->BrushAttr
.lbColor
= Color
& 0xFFFFFF;
446 BRUSH_UnlockBrush(pbrush
);
450 /* PUBLIC FUNCTIONS ***********************************************************/
455 IN PVOID BitmapInfoAndData
,
457 IN UINT BitmapInfoSize
,
462 BITMAPINFO
*SafeBitmapInfoAndData
;
463 NTSTATUS Status
= STATUS_SUCCESS
;
466 SafeBitmapInfoAndData
= EngAllocMem(FL_ZERO_MEMORY
, BitmapInfoSize
, TAG_DIB
);
467 if (SafeBitmapInfoAndData
== NULL
)
469 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
475 ProbeForRead(BitmapInfoAndData
, BitmapInfoSize
, 1);
476 RtlCopyMemory(SafeBitmapInfoAndData
, BitmapInfoAndData
, BitmapInfoSize
);
478 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
480 Status
= _SEH2_GetExceptionCode();
484 if (!NT_SUCCESS(Status
))
486 EngFreeMem(SafeBitmapInfoAndData
);
487 SetLastNtError(Status
);
491 hBrush
= IntGdiCreateDIBBrush(SafeBitmapInfoAndData
,
496 EngFreeMem(SafeBitmapInfoAndData
);
503 NtGdiCreateHatchBrushInternal(
508 return IntGdiCreateHatchBrush(Style
, Color
);
513 NtGdiCreatePatternBrushInternal(
518 return IntGdiCreatePatternBrush(hBitmap
);
523 NtGdiCreateSolidBrush(COLORREF Color
,
524 IN OPTIONAL HBRUSH hbr
)
526 return IntGdiCreateSolidBrush(Color
);
530 * \name NtGdiSetBrushOrg
532 * \brief Sets the brush origin that GDI assigns to
533 * the next brush an application selects into the specified device context.
539 NtGdiSetBrushOrg(HDC hDC
, INT XOrg
, INT YOrg
, LPPOINT Point
)
547 SetLastWin32Error(ERROR_INVALID_HANDLE
);
550 pdcattr
= dc
->pdcattr
;
554 NTSTATUS Status
= STATUS_SUCCESS
;
556 SafePoint
.x
= pdcattr
->ptlBrushOrigin
.x
;
557 SafePoint
.y
= pdcattr
->ptlBrushOrigin
.y
;
560 ProbeForWrite(Point
, sizeof(POINT
), 1);
563 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
565 Status
= _SEH2_GetExceptionCode();
569 if (!NT_SUCCESS(Status
))
572 SetLastNtError(Status
);
577 pdcattr
->ptlBrushOrigin
.x
= XOrg
;
578 pdcattr
->ptlBrushOrigin
.y
= YOrg
;
579 IntptlBrushOrigin(dc
, XOrg
, YOrg
);