[WIN32K]
[reactos.git] / subsystems / win32 / win32k / objects / brush.c
1 /*
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
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #define GDIOBJATTRFREE 170
15
16 typedef struct _GDI_OBJ_ATTR_FREELIST
17 {
18 LIST_ENTRY Entry;
19 DWORD nEntries;
20 PVOID AttrList[GDIOBJATTRFREE];
21 } GDI_OBJ_ATTR_FREELIST, *PGDI_OBJ_ATTR_FREELIST;
22
23 typedef struct _GDI_OBJ_ATTR_ENTRY
24 {
25 RGN_ATTR Attr[GDIOBJATTRFREE];
26 } GDI_OBJ_ATTR_ENTRY, *PGDI_OBJ_ATTR_ENTRY;
27
28 static const ULONG HatchBrushes[NB_HATCH_STYLES][8] =
29 {
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 */
36 };
37
38
39 PVOID
40 FASTCALL
41 AllocateObjectAttr(VOID)
42 {
43 PTHREADINFO pti;
44 PPROCESSINFO ppi;
45 PVOID pAttr;
46 PGDI_OBJ_ATTR_FREELIST pGdiObjAttrFreeList;
47 PGDI_OBJ_ATTR_ENTRY pGdiObjAttrEntry;
48 int i;
49
50 pti = PsGetCurrentThreadWin32Thread();
51 if (pti->pgdiBrushAttr)
52 {
53 pAttr = pti->pgdiBrushAttr; // Get the free one.
54 pti->pgdiBrushAttr = NULL;
55 return pAttr;
56 }
57
58 ppi = PsGetCurrentProcessWin32Process();
59
60 if (!ppi->pBrushAttrList) // If set point is null, allocate new group.
61 {
62 pGdiObjAttrEntry = EngAllocUserMem(sizeof(GDI_OBJ_ATTR_ENTRY), 0);
63
64 if (!pGdiObjAttrEntry)
65 {
66 DPRINT1("Attr Failed User Allocation!\n");
67 return NULL;
68 }
69
70 DPRINT("AllocObjectAttr User 0x%x\n",pGdiObjAttrEntry);
71
72 pGdiObjAttrFreeList = ExAllocatePoolWithTag( PagedPool,
73 sizeof(GDI_OBJ_ATTR_FREELIST),
74 GDITAG_BRUSH_FREELIST);
75 if ( !pGdiObjAttrFreeList )
76 {
77 EngFreeUserMem(pGdiObjAttrEntry);
78 return NULL;
79 }
80
81 RtlZeroMemory(pGdiObjAttrFreeList, sizeof(GDI_OBJ_ATTR_FREELIST));
82
83 DPRINT("AllocObjectAttr Ex 0x%x\n",pGdiObjAttrFreeList);
84
85 InsertHeadList( &ppi->GDIBrushAttrFreeList, &pGdiObjAttrFreeList->Entry);
86
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++)
92 {
93 pGdiObjAttrFreeList->AttrList[i] = &pGdiObjAttrEntry->Attr[i];
94 }
95 }
96
97 pAttr = ppi->pBrushAttrList;
98 pGdiObjAttrFreeList = (PGDI_OBJ_ATTR_FREELIST)ppi->GDIBrushAttrFreeList.Flink;
99
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 );
104
105 ExFreePoolWithTag( pGdiObjAttrFreeList, GDITAG_BRUSH_FREELIST );
106
107 if ( IsListEmpty( &ppi->GDIBrushAttrFreeList ) )
108 {
109 ppi->pBrushAttrList = NULL;
110 return pAttr;
111 }
112
113 pGdiObjAttrFreeList = (PGDI_OBJ_ATTR_FREELIST)ppi->GDIBrushAttrFreeList.Flink;
114 }
115
116 ppi->pBrushAttrList = pGdiObjAttrFreeList->AttrList[pGdiObjAttrFreeList->nEntries-1];
117
118 return pAttr;
119 }
120
121 VOID
122 FASTCALL
123 FreeObjectAttr(PVOID pAttr)
124 {
125 PTHREADINFO pti;
126 PPROCESSINFO ppi;
127 PGDI_OBJ_ATTR_FREELIST pGdiObjAttrFreeList;
128
129 pti = PsGetCurrentThreadWin32Thread();
130
131 if (!pti) return;
132
133 if (!pti->pgdiBrushAttr)
134 { // If it is null, just cache it for the next time.
135 pti->pgdiBrushAttr = pAttr;
136 return;
137 }
138
139 ppi = PsGetCurrentProcessWin32Process();
140
141 pGdiObjAttrFreeList = (PGDI_OBJ_ATTR_FREELIST)ppi->GDIBrushAttrFreeList.Flink;
142
143 // We add to the list of free entries, so this will grows!
144 if ( IsListEmpty(&ppi->GDIBrushAttrFreeList) ||
145 pGdiObjAttrFreeList->nEntries == GDIOBJATTRFREE )
146 {
147 pGdiObjAttrFreeList = ExAllocatePoolWithTag( PagedPool,
148 sizeof(GDI_OBJ_ATTR_FREELIST),
149 GDITAG_BRUSH_FREELIST);
150 if ( !pGdiObjAttrFreeList )
151 {
152 return;
153 }
154 InsertHeadList( &ppi->GDIBrushAttrFreeList, &pGdiObjAttrFreeList->Entry);
155 pGdiObjAttrFreeList->nEntries = 0;
156 }
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;
161
162 return;
163 }
164
165
166 BOOL
167 INTERNAL_CALL
168 BRUSH_Cleanup(PVOID ObjectBody)
169 {
170 PBRUSH pbrush = (PBRUSH)ObjectBody;
171 if (pbrush->flAttrs & (GDIBRUSH_IS_HATCH | GDIBRUSH_IS_BITMAP))
172 {
173 ASSERT(pbrush->hbmPattern);
174 GDIOBJ_SetOwnership(pbrush->hbmPattern, PsGetCurrentProcess());
175 GreDeleteObject(pbrush->hbmPattern);
176 }
177
178 /* Free the kmode styles array of EXTPENS */
179 if (pbrush->pStyle)
180 {
181 ExFreePool(pbrush->pStyle);
182 }
183
184 return TRUE;
185 }
186
187 INT
188 FASTCALL
189 BRUSH_GetObject(PBRUSH pbrush, INT Count, LPLOGBRUSH Buffer)
190 {
191 if (Buffer == NULL) return sizeof(LOGBRUSH);
192 if (Count == 0) return 0;
193
194 /* Set colour */
195 Buffer->lbColor = pbrush->BrushAttr.lbColor;
196
197 /* Set Hatch */
198 if ((pbrush->flAttrs & GDIBRUSH_IS_HATCH)!=0)
199 {
200 /* FIXME : this is not the right value */
201 Buffer->lbHatch = (LONG)pbrush->hbmPattern;
202 }
203 else
204 {
205 Buffer->lbHatch = 0;
206 }
207
208 Buffer->lbStyle = 0;
209
210 /* Get the type of style */
211 if ((pbrush->flAttrs & GDIBRUSH_IS_SOLID)!=0)
212 {
213 Buffer->lbStyle = BS_SOLID;
214 }
215 else if ((pbrush->flAttrs & GDIBRUSH_IS_NULL)!=0)
216 {
217 Buffer->lbStyle = BS_NULL; // BS_HOLLOW
218 }
219 else if ((pbrush->flAttrs & GDIBRUSH_IS_HATCH)!=0)
220 {
221 Buffer->lbStyle = BS_HATCHED;
222 }
223 else if ((pbrush->flAttrs & GDIBRUSH_IS_BITMAP)!=0)
224 {
225 Buffer->lbStyle = BS_PATTERN;
226 }
227 else if ((pbrush->flAttrs & GDIBRUSH_IS_DIB)!=0)
228 {
229 Buffer->lbStyle = BS_DIBPATTERN;
230 }
231
232 /* FIXME
233 else if ((pbrush->flAttrs & )!=0)
234 {
235 Buffer->lbStyle = BS_INDEXED;
236 }
237 else if ((pbrush->flAttrs & )!=0)
238 {
239 Buffer->lbStyle = BS_DIBPATTERNPT;
240 }
241 */
242
243 /* FIXME */
244 return sizeof(LOGBRUSH);
245 }
246
247 HBRUSH
248 APIENTRY
249 IntGdiCreateDIBBrush(
250 CONST BITMAPINFO *BitmapInfo,
251 UINT ColorSpec,
252 UINT BitmapInfoSize,
253 CONST VOID *PackedDIB)
254 {
255 HBRUSH hBrush;
256 PBRUSH pbrush;
257 HBITMAP hPattern;
258 ULONG_PTR DataPtr;
259 PVOID pvDIBits;
260
261 if (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
262 {
263 SetLastWin32Error(ERROR_INVALID_PARAMETER);
264 return NULL;
265 }
266
267 DataPtr = (ULONG_PTR)BitmapInfo + DIB_BitmapInfoSize(BitmapInfo, ColorSpec);
268
269 hPattern = DIB_CreateDIBSection(NULL, BitmapInfo, ColorSpec, &pvDIBits, NULL, 0, 0);
270 if (hPattern == NULL)
271 {
272 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
273 return NULL;
274 }
275 RtlCopyMemory(pvDIBits,
276 (PVOID)DataPtr,
277 DIB_GetDIBImageBytes(BitmapInfo->bmiHeader.biWidth,
278 BitmapInfo->bmiHeader.biHeight,
279 BitmapInfo->bmiHeader.biBitCount * BitmapInfo->bmiHeader.biPlanes));
280
281 pbrush = BRUSH_AllocBrushWithHandle();
282 if (pbrush == NULL)
283 {
284 GreDeleteObject(hPattern);
285 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
286 return NULL;
287 }
288 hBrush = pbrush->BaseObject.hHmgr;
289
290 pbrush->flAttrs |= GDIBRUSH_IS_BITMAP | GDIBRUSH_IS_DIB;
291 pbrush->hbmPattern = hPattern;
292 /* FIXME: Fill in the rest of fields!!! */
293
294 GDIOBJ_SetOwnership(hPattern, NULL);
295
296 BRUSH_UnlockBrush(pbrush);
297
298 return hBrush;
299 }
300
301 HBRUSH
302 APIENTRY
303 IntGdiCreateHatchBrush(
304 INT Style,
305 COLORREF Color)
306 {
307 HBRUSH hBrush;
308 PBRUSH pbrush;
309 HBITMAP hPattern;
310
311 if (Style < 0 || Style >= NB_HATCH_STYLES)
312 {
313 return 0;
314 }
315
316 hPattern = GreCreateBitmap(8, 8, 1, 1, (LPBYTE)HatchBrushes[Style]);
317 if (hPattern == NULL)
318 {
319 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
320 return NULL;
321 }
322
323 pbrush = BRUSH_AllocBrushWithHandle();
324 if (pbrush == NULL)
325 {
326 GreDeleteObject(hPattern);
327 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
328 return NULL;
329 }
330 hBrush = pbrush->BaseObject.hHmgr;
331
332 pbrush->flAttrs |= GDIBRUSH_IS_HATCH;
333 pbrush->hbmPattern = hPattern;
334 pbrush->BrushAttr.lbColor = Color & 0xFFFFFF;
335
336 GDIOBJ_SetOwnership(hPattern, NULL);
337
338 BRUSH_UnlockBrush(pbrush);
339
340 return hBrush;
341 }
342
343 HBRUSH
344 APIENTRY
345 IntGdiCreatePatternBrush(
346 HBITMAP hBitmap)
347 {
348 HBRUSH hBrush;
349 PBRUSH pbrush;
350 HBITMAP hPattern;
351
352 hPattern = BITMAP_CopyBitmap(hBitmap);
353 if (hPattern == NULL)
354 {
355 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
356 return NULL;
357 }
358
359 pbrush = BRUSH_AllocBrushWithHandle();
360 if (pbrush == NULL)
361 {
362 GreDeleteObject(hPattern);
363 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
364 return NULL;
365 }
366 hBrush = pbrush->BaseObject.hHmgr;
367
368 pbrush->flAttrs |= GDIBRUSH_IS_BITMAP;
369 pbrush->hbmPattern = hPattern;
370 /* FIXME: Fill in the rest of fields!!! */
371
372 GDIOBJ_SetOwnership(hPattern, NULL);
373
374 BRUSH_UnlockBrush(pbrush);
375
376 return hBrush;
377 }
378
379 HBRUSH
380 APIENTRY
381 IntGdiCreateSolidBrush(
382 COLORREF Color)
383 {
384 HBRUSH hBrush;
385 PBRUSH pbrush;
386
387 pbrush = BRUSH_AllocBrushWithHandle();
388 if (pbrush == NULL)
389 {
390 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
391 return NULL;
392 }
393 hBrush = pbrush->BaseObject.hHmgr;
394
395 pbrush->flAttrs |= GDIBRUSH_IS_SOLID;
396
397 pbrush->BrushAttr.lbColor = Color;
398 /* FIXME: Fill in the rest of fields!!! */
399
400 BRUSH_UnlockBrush(pbrush);
401
402 return hBrush;
403 }
404
405 HBRUSH
406 APIENTRY
407 IntGdiCreateNullBrush(VOID)
408 {
409 HBRUSH hBrush;
410 PBRUSH pbrush;
411
412 pbrush = BRUSH_AllocBrushWithHandle();
413 if (pbrush == NULL)
414 {
415 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
416 return NULL;
417 }
418 hBrush = pbrush->BaseObject.hHmgr;
419
420 pbrush->flAttrs |= GDIBRUSH_IS_NULL;
421 BRUSH_UnlockBrush(pbrush);
422
423 return hBrush;
424 }
425
426 VOID
427 FASTCALL
428 IntGdiSetSolidBrushColor(HBRUSH hBrush, COLORREF Color)
429 {
430 PBRUSH pbrush;
431
432 pbrush = BRUSH_LockBrush(hBrush);
433 if (pbrush->flAttrs & GDIBRUSH_IS_SOLID)
434 {
435 pbrush->BrushAttr.lbColor = Color & 0xFFFFFF;
436 }
437 BRUSH_UnlockBrush(pbrush);
438 }
439
440
441 /* PUBLIC FUNCTIONS ***********************************************************/
442
443 HBRUSH
444 APIENTRY
445 NtGdiCreateDIBBrush(
446 IN PVOID BitmapInfoAndData,
447 IN FLONG ColorSpec,
448 IN UINT BitmapInfoSize,
449 IN BOOL b8X8,
450 IN BOOL bPen,
451 IN PVOID PackedDIB)
452 {
453 BITMAPINFO *SafeBitmapInfoAndData;
454 NTSTATUS Status = STATUS_SUCCESS;
455 HBRUSH hBrush;
456
457 SafeBitmapInfoAndData = EngAllocMem(FL_ZERO_MEMORY, BitmapInfoSize, TAG_DIB);
458 if (SafeBitmapInfoAndData == NULL)
459 {
460 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
461 return NULL;
462 }
463
464 _SEH2_TRY
465 {
466 ProbeForRead(BitmapInfoAndData, BitmapInfoSize, 1);
467 RtlCopyMemory(SafeBitmapInfoAndData, BitmapInfoAndData, BitmapInfoSize);
468 }
469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
470 {
471 Status = _SEH2_GetExceptionCode();
472 }
473 _SEH2_END;
474
475 if (!NT_SUCCESS(Status))
476 {
477 EngFreeMem(SafeBitmapInfoAndData);
478 SetLastNtError(Status);
479 return 0;
480 }
481
482 hBrush = IntGdiCreateDIBBrush(SafeBitmapInfoAndData,
483 ColorSpec,
484 BitmapInfoSize,
485 PackedDIB);
486
487 EngFreeMem(SafeBitmapInfoAndData);
488
489 return hBrush;
490 }
491
492 HBRUSH
493 APIENTRY
494 NtGdiCreateHatchBrushInternal(
495 ULONG Style,
496 COLORREF Color,
497 BOOL bPen)
498 {
499 return IntGdiCreateHatchBrush(Style, Color);
500 }
501
502 HBRUSH
503 APIENTRY
504 NtGdiCreatePatternBrushInternal(
505 HBITMAP hBitmap,
506 BOOL bPen,
507 BOOL b8x8)
508 {
509 return IntGdiCreatePatternBrush(hBitmap);
510 }
511
512 HBRUSH
513 APIENTRY
514 NtGdiCreateSolidBrush(COLORREF Color,
515 IN OPTIONAL HBRUSH hbr)
516 {
517 return IntGdiCreateSolidBrush(Color);
518 }
519
520 /**
521 * \name NtGdiSetBrushOrg
522 *
523 * \brief Sets the brush origin that GDI assigns to
524 * the next brush an application selects into the specified device context.
525 *
526 * @implemented
527 */
528 BOOL
529 APIENTRY
530 NtGdiSetBrushOrg(HDC hDC, INT XOrg, INT YOrg, LPPOINT Point)
531 {
532 PDC dc;
533 PDC_ATTR pdcattr;
534
535 dc = DC_LockDc(hDC);
536 if (dc == NULL)
537 {
538 SetLastWin32Error(ERROR_INVALID_HANDLE);
539 return FALSE;
540 }
541 pdcattr = dc->pdcattr;
542
543 if (Point != NULL)
544 {
545 NTSTATUS Status = STATUS_SUCCESS;
546 POINT SafePoint;
547 SafePoint.x = pdcattr->ptlBrushOrigin.x;
548 SafePoint.y = pdcattr->ptlBrushOrigin.y;
549 _SEH2_TRY
550 {
551 ProbeForWrite(Point, sizeof(POINT), 1);
552 *Point = SafePoint;
553 }
554 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
555 {
556 Status = _SEH2_GetExceptionCode();
557 }
558 _SEH2_END;
559
560 if (!NT_SUCCESS(Status))
561 {
562 DC_UnlockDc(dc);
563 SetLastNtError(Status);
564 return FALSE;
565 }
566 }
567
568 pdcattr->ptlBrushOrigin.x = XOrg;
569 pdcattr->ptlBrushOrigin.y = YOrg;
570 IntptlBrushOrigin(dc, XOrg, YOrg );
571 DC_UnlockDc(dc);
572
573 return TRUE;
574 }
575
576 /* EOF */