41edb11ce1c088f2dd458f3172d04ff4a04872f0
[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 PSURFACE psurfPattern;
260 HPALETTE hpal ;
261
262 if (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
263 {
264 SetLastWin32Error(ERROR_INVALID_PARAMETER);
265 return NULL;
266 }
267
268 DataPtr = (ULONG_PTR)BitmapInfo + DIB_BitmapInfoSize(BitmapInfo, ColorSpec);
269
270 hPattern = GreCreateBitmap(BitmapInfo->bmiHeader.biWidth,
271 BitmapInfo->bmiHeader.biHeight,
272 BitmapInfo->bmiHeader.biPlanes,
273 BitmapInfo->bmiHeader.biBitCount,
274 (PVOID)DataPtr);
275 if (hPattern == NULL)
276 {
277 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
278 return NULL;
279 }
280
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);
289
290 pbrush = BRUSH_AllocBrushWithHandle();
291 if (pbrush == NULL)
292 {
293 GreDeleteObject(hPattern);
294 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
295 return NULL;
296 }
297 hBrush = pbrush->BaseObject.hHmgr;
298
299 pbrush->flAttrs |= GDIBRUSH_IS_BITMAP | GDIBRUSH_IS_DIB;
300 pbrush->hbmPattern = hPattern;
301 /* FIXME: Fill in the rest of fields!!! */
302
303 GDIOBJ_SetOwnership(hPattern, NULL);
304
305 BRUSH_UnlockBrush(pbrush);
306
307 return hBrush;
308 }
309
310 HBRUSH
311 APIENTRY
312 IntGdiCreateHatchBrush(
313 INT Style,
314 COLORREF Color)
315 {
316 HBRUSH hBrush;
317 PBRUSH pbrush;
318 HBITMAP hPattern;
319
320 if (Style < 0 || Style >= NB_HATCH_STYLES)
321 {
322 return 0;
323 }
324
325 hPattern = GreCreateBitmap(8, 8, 1, 1, (LPBYTE)HatchBrushes[Style]);
326 if (hPattern == NULL)
327 {
328 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
329 return NULL;
330 }
331
332 pbrush = BRUSH_AllocBrushWithHandle();
333 if (pbrush == NULL)
334 {
335 GreDeleteObject(hPattern);
336 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
337 return NULL;
338 }
339 hBrush = pbrush->BaseObject.hHmgr;
340
341 pbrush->flAttrs |= GDIBRUSH_IS_HATCH;
342 pbrush->hbmPattern = hPattern;
343 pbrush->BrushAttr.lbColor = Color & 0xFFFFFF;
344
345 GDIOBJ_SetOwnership(hPattern, NULL);
346
347 BRUSH_UnlockBrush(pbrush);
348
349 return hBrush;
350 }
351
352 HBRUSH
353 APIENTRY
354 IntGdiCreatePatternBrush(
355 HBITMAP hBitmap)
356 {
357 HBRUSH hBrush;
358 PBRUSH pbrush;
359 HBITMAP hPattern;
360
361 hPattern = BITMAP_CopyBitmap(hBitmap);
362 if (hPattern == NULL)
363 {
364 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
365 return NULL;
366 }
367
368 pbrush = BRUSH_AllocBrushWithHandle();
369 if (pbrush == NULL)
370 {
371 GreDeleteObject(hPattern);
372 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
373 return NULL;
374 }
375 hBrush = pbrush->BaseObject.hHmgr;
376
377 pbrush->flAttrs |= GDIBRUSH_IS_BITMAP;
378 pbrush->hbmPattern = hPattern;
379 /* FIXME: Fill in the rest of fields!!! */
380
381 GDIOBJ_SetOwnership(hPattern, NULL);
382
383 BRUSH_UnlockBrush(pbrush);
384
385 return hBrush;
386 }
387
388 HBRUSH
389 APIENTRY
390 IntGdiCreateSolidBrush(
391 COLORREF Color)
392 {
393 HBRUSH hBrush;
394 PBRUSH pbrush;
395
396 pbrush = BRUSH_AllocBrushWithHandle();
397 if (pbrush == NULL)
398 {
399 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
400 return NULL;
401 }
402 hBrush = pbrush->BaseObject.hHmgr;
403
404 pbrush->flAttrs |= GDIBRUSH_IS_SOLID;
405
406 pbrush->BrushAttr.lbColor = Color;
407 /* FIXME: Fill in the rest of fields!!! */
408
409 BRUSH_UnlockBrush(pbrush);
410
411 return hBrush;
412 }
413
414 HBRUSH
415 APIENTRY
416 IntGdiCreateNullBrush(VOID)
417 {
418 HBRUSH hBrush;
419 PBRUSH pbrush;
420
421 pbrush = BRUSH_AllocBrushWithHandle();
422 if (pbrush == NULL)
423 {
424 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
425 return NULL;
426 }
427 hBrush = pbrush->BaseObject.hHmgr;
428
429 pbrush->flAttrs |= GDIBRUSH_IS_NULL;
430 BRUSH_UnlockBrush(pbrush);
431
432 return hBrush;
433 }
434
435 VOID
436 FASTCALL
437 IntGdiSetSolidBrushColor(HBRUSH hBrush, COLORREF Color)
438 {
439 PBRUSH pbrush;
440
441 pbrush = BRUSH_LockBrush(hBrush);
442 if (pbrush->flAttrs & GDIBRUSH_IS_SOLID)
443 {
444 pbrush->BrushAttr.lbColor = Color & 0xFFFFFF;
445 }
446 BRUSH_UnlockBrush(pbrush);
447 }
448
449
450 /* PUBLIC FUNCTIONS ***********************************************************/
451
452 HBRUSH
453 APIENTRY
454 NtGdiCreateDIBBrush(
455 IN PVOID BitmapInfoAndData,
456 IN FLONG ColorSpec,
457 IN UINT BitmapInfoSize,
458 IN BOOL b8X8,
459 IN BOOL bPen,
460 IN PVOID PackedDIB)
461 {
462 BITMAPINFO *SafeBitmapInfoAndData;
463 NTSTATUS Status = STATUS_SUCCESS;
464 HBRUSH hBrush;
465
466 SafeBitmapInfoAndData = EngAllocMem(FL_ZERO_MEMORY, BitmapInfoSize, TAG_DIB);
467 if (SafeBitmapInfoAndData == NULL)
468 {
469 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
470 return NULL;
471 }
472
473 _SEH2_TRY
474 {
475 ProbeForRead(BitmapInfoAndData, BitmapInfoSize, 1);
476 RtlCopyMemory(SafeBitmapInfoAndData, BitmapInfoAndData, BitmapInfoSize);
477 }
478 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
479 {
480 Status = _SEH2_GetExceptionCode();
481 }
482 _SEH2_END;
483
484 if (!NT_SUCCESS(Status))
485 {
486 EngFreeMem(SafeBitmapInfoAndData);
487 SetLastNtError(Status);
488 return 0;
489 }
490
491 hBrush = IntGdiCreateDIBBrush(SafeBitmapInfoAndData,
492 ColorSpec,
493 BitmapInfoSize,
494 PackedDIB);
495
496 EngFreeMem(SafeBitmapInfoAndData);
497
498 return hBrush;
499 }
500
501 HBRUSH
502 APIENTRY
503 NtGdiCreateHatchBrushInternal(
504 ULONG Style,
505 COLORREF Color,
506 BOOL bPen)
507 {
508 return IntGdiCreateHatchBrush(Style, Color);
509 }
510
511 HBRUSH
512 APIENTRY
513 NtGdiCreatePatternBrushInternal(
514 HBITMAP hBitmap,
515 BOOL bPen,
516 BOOL b8x8)
517 {
518 return IntGdiCreatePatternBrush(hBitmap);
519 }
520
521 HBRUSH
522 APIENTRY
523 NtGdiCreateSolidBrush(COLORREF Color,
524 IN OPTIONAL HBRUSH hbr)
525 {
526 return IntGdiCreateSolidBrush(Color);
527 }
528
529 /**
530 * \name NtGdiSetBrushOrg
531 *
532 * \brief Sets the brush origin that GDI assigns to
533 * the next brush an application selects into the specified device context.
534 *
535 * @implemented
536 */
537 BOOL
538 APIENTRY
539 NtGdiSetBrushOrg(HDC hDC, INT XOrg, INT YOrg, LPPOINT Point)
540 {
541 PDC dc;
542 PDC_ATTR pdcattr;
543
544 dc = DC_LockDc(hDC);
545 if (dc == NULL)
546 {
547 SetLastWin32Error(ERROR_INVALID_HANDLE);
548 return FALSE;
549 }
550 pdcattr = dc->pdcattr;
551
552 if (Point != NULL)
553 {
554 NTSTATUS Status = STATUS_SUCCESS;
555 POINT SafePoint;
556 SafePoint.x = pdcattr->ptlBrushOrigin.x;
557 SafePoint.y = pdcattr->ptlBrushOrigin.y;
558 _SEH2_TRY
559 {
560 ProbeForWrite(Point, sizeof(POINT), 1);
561 *Point = SafePoint;
562 }
563 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
564 {
565 Status = _SEH2_GetExceptionCode();
566 }
567 _SEH2_END;
568
569 if (!NT_SUCCESS(Status))
570 {
571 DC_UnlockDc(dc);
572 SetLastNtError(Status);
573 return FALSE;
574 }
575 }
576
577 pdcattr->ptlBrushOrigin.x = XOrg;
578 pdcattr->ptlBrushOrigin.y = YOrg;
579 IntptlBrushOrigin(dc, XOrg, YOrg );
580 DC_UnlockDc(dc);
581
582 return TRUE;
583 }
584
585 /* EOF */