[WIN32K]
[reactos.git] / reactos / win32ss / gdi / ntgdi / brush.cpp
1 /*
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)
6 *
7 * REFERENCES: http://support.microsoft.com/kb/kbview/108497
8 */
9
10 #include "brush.hpp"
11
12 DBG_DEFAULT_CHANNEL(GdiBrush);
13
14 BRUSH::BRUSH(
15 _In_ FLONG flAttrs,
16 _In_ COLORREF crColor,
17 _In_ ULONG iHatch,
18 _In_opt_ HBITMAP hbmPattern,
19 _In_opt_ PVOID pvClient,
20 _In_ GDILOOBJTYPE loobjtype = GDILoObjType_LO_BRUSH_TYPE)
21 : BASEOBJECT(loobjtype)
22 {
23 static ULONG ulGlobalBrushUnique = 0;
24
25 /* Get a unique value */
26 this->ulBrushUnique = InterlockedIncrementUL(&ulGlobalBrushUnique);
27
28 /* Start with kmode brush attribute */
29 this->pBrushAttr = &this->BrushAttr;
30
31 /* Set parameters */
32 this->flAttrs = flAttrs;
33 this->iHatch = iHatch;
34 this->hbmPattern = hbmPattern;
35 this->hbmClient = (HBITMAP)pvClient;
36 this->pBrushAttr->lbColor = crColor;
37
38 /* Initialize the other fields */
39 this->ptOrigin.x = 0;
40 this->ptOrigin.y = 0;
41 this->bCacheGrabbed = FALSE;
42 this->crBack = 0;
43 this->crFore = 0;
44 this->ulPalTime = 0;
45 this->ulSurfTime = 0;
46 this->pvRBrush = NULL;
47 this->hdev = NULL;
48 }
49
50 BRUSH::~BRUSH(
51 VOID)
52 {
53 /* Check if we have a user mode brush attribute */
54 if (this->pBrushAttr != &this->BrushAttr)
55 {
56 /* Free memory to the process GDI pool */
57 GdiPoolFree(GetBrushAttrPool(), this->pBrushAttr);
58 }
59
60 /* Delete the pattern bitmap */
61 if (this->hbmPattern != NULL)
62 {
63 GreSetBitmapOwner(this->hbmPattern, BASEOBJECT::OWNER::POWNED);
64 GreDeleteObject(this->hbmPattern);
65 }
66 }
67
68 VOID
69 BRUSH::vDeleteObject(
70 _In_ PVOID pvObject)
71 {
72 PBRUSH pbr = static_cast<PBRUSH>(pvObject);
73 NT_ASSERT((GDI_HANDLE_GET_TYPE(pbr->hHmgr()) == GDILoObjType_LO_BRUSH_TYPE) ||
74 (GDI_HANDLE_GET_TYPE(pbr->hHmgr()) == GDILoObjType_LO_PEN_TYPE) ||
75 (GDI_HANDLE_GET_TYPE(pbr->hHmgr()) == GDILoObjType_LO_EXTPEN_TYPE));
76 delete pbr;
77 }
78
79 BOOL
80 BRUSH::bAllocateBrushAttr(
81 VOID)
82 {
83 PBRUSH_ATTR pBrushAttr;
84 NT_ASSERT(this->pBrushAttr == &this->BrushAttr);
85
86 /* Allocate a brush attribute from the pool */
87 pBrushAttr = static_cast<PBRUSH_ATTR>(GdiPoolAllocate(GetBrushAttrPool()));
88 if (pBrushAttr == NULL)
89 {
90 ERR("Could not allocate brush attr\n");
91 return FALSE;
92 }
93
94 /* Copy the content from the kernel mode brush attribute */
95 this->pBrushAttr = pBrushAttr;
96 *this->pBrushAttr = this->BrushAttr;
97
98 /* Set the object attribute in the handle table */
99 vSetObjectAttr(pBrushAttr);
100
101 return TRUE;
102 }
103
104 VOID
105 BRUSH::vSetSolidColor(
106 _In_ COLORREF crColor)
107 {
108 NT_ASSERT(this->flAttrs & BR_IS_SOLID);
109
110 /* Set new color and reset the pal times */
111 this->pBrushAttr->lbColor = crColor & 0xFFFFFF;
112 this->ulPalTime = -1;
113 this->ulSurfTime = -1;
114 }
115
116 HBITMAP
117 BRUSH::hbmGetBitmapHandle(
118 _Out_ PUINT puUsage) const
119 {
120 /* Return the color usage based on flags */
121 *puUsage = (this->flAttrs & BR_IS_DIBPALCOLORS) ? DIB_PAL_COLORS :
122 (this->flAttrs & BR_IS_DIBPALINDICES) ? DIB_PAL_INDICES :
123 DIB_RGB_COLORS;
124
125 return this->hbmPattern;
126 }
127
128 UINT
129 BRUSH::cjGetObject(
130 _In_ UINT cjSize,
131 _Out_bytecap_(cjSize) PLOGBRUSH plb) const
132 {
133 /* Check if only size is requested */
134 if (plb == NULL)
135 return sizeof(LOGBRUSH);
136
137 /* Check if size is ok */
138 if (cjSize == 0)
139 return 0;
140
141 /* Set color */
142 plb->lbColor = this->BrushAttr.lbColor;
143
144 /* Set style and hatch based on the attribute flags */
145 if (this->flAttrs & BR_IS_SOLID)
146 {
147 plb->lbStyle = BS_SOLID;
148 plb->lbHatch = 0;
149 }
150 else if (this->flAttrs & BR_IS_HATCH)
151 {
152 plb->lbStyle = BS_HATCHED;
153 plb->lbHatch = this->iHatch;
154 }
155 else if (this->flAttrs & BR_IS_DIB)
156 {
157 plb->lbStyle = BS_DIBPATTERN;
158 plb->lbHatch = (ULONG_PTR)this->hbmClient;
159 }
160 else if (this->flAttrs & BR_IS_BITMAP)
161 {
162 plb->lbStyle = BS_PATTERN;
163 plb->lbHatch = (ULONG_PTR)this->hbmClient;
164 }
165 else if (this->flAttrs & BR_IS_NULL)
166 {
167 plb->lbStyle = BS_NULL;
168 plb->lbHatch = 0;
169 }
170 else
171 {
172 NT_ASSERT(FALSE);
173 }
174
175 return sizeof(LOGBRUSH);
176 }
177
178 static
179 HBRUSH
180 CreateBrushInternal(
181 _In_ ULONG flAttrs,
182 _In_ COLORREF crColor,
183 _In_ ULONG iHatch,
184 _In_opt_ HBITMAP hbmPattern,
185 _In_opt_ PVOID pvClient)
186 {
187 BASEOBJECT::OWNER owner;
188 PBRUSH pbr;
189 HBRUSH hbr;
190
191 NT_ASSERT(((flAttrs & BR_IS_BITMAP) == 0) || (hbmPattern != NULL));
192
193 /* Create the brush (brush takes ownership of the bitmap) */
194 pbr = new BRUSH(flAttrs, crColor, iHatch, hbmPattern, pvClient);
195 if (pbr == NULL)
196 {
197 ERR("Failed to allocate a brush\n");
198 GreSetBitmapOwner(hbmPattern, BASEOBJECT::OWNER::POWNED);
199 GreDeleteObject(hbmPattern);
200 return NULL;
201 }
202
203 /* Check if this is a global brush */
204 if (!(flAttrs & BR_IS_GLOBAL))
205 {
206 /* Not a global brush, so allocate a user mode brush attribute */
207 if (!pbr->bAllocateBrushAttr())
208 {
209 ERR("Failed to allocate brush attribute\n");
210 delete pbr;
211 return NULL;
212 }
213 }
214
215 /* Set the owner, either public or process owned */
216 owner = (flAttrs & BR_IS_GLOBAL) ? BASEOBJECT::OWNER::PUBLIC :
217 BASEOBJECT::OWNER::POWNED;
218
219 /* Insert the object into the GDI handle table */
220 hbr = static_cast<HBRUSH>(pbr->hInsertObject(owner));
221 if (hbr == NULL)
222 {
223 ERR("Failed to insert brush\n");
224 delete pbr;
225 return NULL;
226 }
227
228 /* Unlock the brush */
229 pbr->vUnlock();
230
231 return hbr;
232 }
233
234
235 /* C interface ***************************************************************/
236
237 extern "C" {
238
239 VOID
240 NTAPI
241 BRUSH_vDeleteObject(
242 PVOID pvObject)
243 {
244 BRUSH::vDeleteObject(pvObject);
245 }
246
247 INT
248 FASTCALL
249 BRUSH_GetObject(
250 PBRUSH pbr,
251 INT cjBuffer,
252 LPLOGBRUSH plbBuffer)
253 {
254 return pbr->cjGetObject(cjBuffer, plbBuffer);
255 }
256
257 HBRUSH
258 NTAPI
259 IntGdiCreateNullBrush(
260 VOID)
261 {
262 /* Call the internal function */
263 return CreateBrushInternal(BR_IS_NULL | BR_IS_GLOBAL, 0, 0, NULL, NULL);
264 }
265
266 HBRUSH
267 APIENTRY
268 IntGdiCreateSolidBrush(
269 COLORREF crColor)
270 {
271 /* Call the internal function */
272 return CreateBrushInternal(BR_IS_SOLID | BR_IS_GLOBAL,
273 crColor,
274 0,
275 NULL,
276 NULL);
277 }
278
279 HBRUSH
280 NTAPI
281 IntGdiCreatePatternBrush(
282 HBITMAP hbmPattern)
283 {
284 NT_ASSERT(hbmPattern != NULL);
285 GreSetBitmapOwner(hbmPattern, BASEOBJECT::OWNER::PUBLIC);
286 return CreateBrushInternal(BR_IS_BITMAP | BR_IS_GLOBAL,
287 0,
288 0,
289 hbmPattern,
290 NULL);
291 }
292
293 VOID
294 NTAPI
295 IntGdiSetSolidBrushColor(
296 _In_ HBRUSH hbr,
297 _In_ COLORREF crColor)
298 {
299 PBRUSH pbr;
300
301 /* Lock the brush */
302 pbr = BRUSH::LockAny(hbr);
303 if (pbr == NULL)
304 {
305 ERR("Failed to lock brush %p\n", hbr);
306 return;
307 }
308
309 /* Call the member function */
310 pbr->vSetSolidColor(crColor);
311
312 /* Unlock the brush */
313 pbr->vUnlock();
314 }
315
316 __kernel_entry
317 HBRUSH
318 APIENTRY
319 NtGdiCreateSolidBrush(
320 _In_ COLORREF crColor,
321 _In_opt_ HBRUSH hbr)
322 {
323 if (hbr != NULL)
324 {
325 WARN("hbr is not supported, ignoring\n");
326 }
327
328 /* Call the internal function */
329 return CreateBrushInternal(BR_IS_SOLID, crColor, 0, NULL, NULL);
330 }
331
332 __kernel_entry
333 HBRUSH
334 APIENTRY
335 NtGdiCreateHatchBrushInternal(
336 _In_ ULONG iHatch,
337 _In_ COLORREF crColor,
338 _In_ BOOL bPen)
339 {
340 FLONG flAttr;
341
342 if (bPen)
343 {
344 WARN("bPen is not supported, ignoring\n");
345 }
346
347 /* Check what kind if hatch style this is */
348 if (iHatch < HS_DDI_MAX)
349 {
350 flAttr = BR_IS_HATCH;
351 }
352 else if (iHatch < HS_API_MAX)
353 {
354 flAttr = BR_IS_SOLID;
355 }
356 else
357 {
358 ERR("Invalid iHatch: %lu\n", iHatch);
359 return NULL;
360 }
361
362 /* Call the internal function */
363 return CreateBrushInternal(flAttr, crColor, iHatch, NULL, NULL);
364 }
365
366 __kernel_entry
367 HBRUSH
368 APIENTRY
369 NtGdiCreatePatternBrushInternal(
370 _In_ HBITMAP hbmClient,
371 _In_ BOOL bPen,
372 _In_ BOOL b8X8)
373 {
374 HBITMAP hbmPattern;
375
376 if (b8X8)
377 {
378 WARN("b8X8 is not supported, ignoring\n");
379 }
380
381 if (bPen)
382 {
383 WARN("bPen is not supported, ignoring\n");
384 }
385
386 /* Copy the bitmap */
387 hbmPattern = BITMAP_CopyBitmap(hbmClient);
388 if (hbmPattern == NULL)
389 {
390 ERR("Failed to copy the bitmap %p\n", hbmPattern);
391 return NULL;
392 }
393
394 /* Call the internal function (will delete hbmPattern on failure) */
395 return CreateBrushInternal(BR_IS_BITMAP, 0, 0, hbmPattern, hbmClient);
396 }
397
398 __kernel_entry
399 HBRUSH
400 APIENTRY
401 NtGdiCreateDIBBrush(
402 _In_reads_bytes_(cj) PVOID pv,
403 _In_ FLONG uUsage,
404 _In_ UINT cj,
405 _In_ BOOL b8X8,
406 _In_ BOOL bPen,
407 _In_ PVOID pvClient)
408 {
409 PVOID pvPackedDIB;
410 FLONG flAttrs;
411 HBITMAP hbm;
412 HBRUSH hbr = NULL;
413
414 if (b8X8)
415 {
416 WARN("b8X8 is not supported, ignoring\n");
417 }
418
419 if (bPen)
420 {
421 WARN("bPen is not supported, ignoring\n");
422 }
423
424 if (uUsage > DIB_PAL_INDICES)
425 {
426 ERR("Invalid uUsage value: %lu\n", uUsage);
427 EngSetLastError(ERROR_INVALID_PARAMETER);
428 return NULL;
429 }
430
431 /* Allocate a buffer for the packed DIB */
432 pvPackedDIB = ExAllocatePoolWithTag(PagedPool, cj, GDITAG_TEMP);
433 if (pvPackedDIB == NULL)
434 {
435 ERR("Failed to allocate temp buffer of %u bytes\n", cj);
436 return NULL;
437 }
438
439 /* Probe and copy the packed DIB */
440 _SEH2_TRY
441 {
442 ProbeForRead(pv, cj, 1);
443 RtlCopyMemory(pvPackedDIB, pv, cj);
444 }
445 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
446 {
447 ERR("Got exception, pv = %p, cj = %lu\n", pv, cj);
448 goto cleanup;
449 }
450 _SEH2_END;
451
452 flAttrs = BR_IS_BITMAP | BR_IS_DIB;
453
454 /* Check what kind of color table we have */
455 if (uUsage == DIB_PAL_COLORS)
456 {
457 /* Remember it and use DIB_PAL_BRUSHHACK to create a "special" palette */
458 flAttrs |= BR_IS_DIBPALCOLORS;
459 uUsage = DIB_PAL_BRUSHHACK;
460 }
461 else if (uUsage == DIB_PAL_INDICES)
462 {
463 /* No color table, bitmap contains device palette indices */
464 flAttrs |= BR_IS_DIBPALINDICES;
465
466 /* FIXME: This makes tests pass, but needs investigation. */
467 flAttrs |= BR_IS_NULL;
468 }
469
470 /* Create a bitmap from the DIB */
471 hbm = GreCreateDIBitmapFromPackedDIB(pvPackedDIB, cj, uUsage);
472 if (hbm == NULL)
473 {
474 ERR("Failed to create bitmap from DIB\n");
475 goto cleanup;
476 }
477
478 /* Call the internal function (will delete hbm on failure) */
479 hbr = CreateBrushInternal(flAttrs, 0, 0, hbm, pvClient);
480
481 cleanup:
482
483 ExFreePoolWithTag(pvPackedDIB, GDITAG_TEMP);
484
485 return hbr;
486 }
487
488 __kernel_entry
489 HBITMAP
490 APIENTRY
491 NtGdiGetObjectBitmapHandle(
492 _In_ HBRUSH hbr,
493 _Out_ UINT *piUsage)
494 {
495 PBRUSH pbr;
496 HBITMAP hbm;
497 UINT uUsage;
498
499 /* Lock the brush */
500 pbr = BRUSH::LockForRead(hbr);
501 if (pbr == NULL)
502 {
503 ERR("Failed to lock brush %p\n", hbr);
504 return NULL;
505 }
506
507 /* Call the member function */
508 hbm = pbr->hbmGetBitmapHandle(&uUsage);
509
510 /* Unlock the brush */
511 pbr->vUnlock();
512
513 _SEH2_TRY
514 {
515 ProbeForWrite(piUsage, sizeof(*piUsage), 1);
516 *piUsage = uUsage;
517 }
518 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
519 {
520 ERR("Got exception! piUsage = %p\n", piUsage);
521 hbm = NULL;
522 }
523 _SEH2_END;
524
525 return hbm;
526 }
527
528 __kernel_entry
529 HBRUSH
530 APIENTRY
531 NtGdiSetBrushAttributes(
532 _In_ HBRUSH hbr,
533 _In_ DWORD dwFlags)
534 {
535 __debugbreak();
536 return NULL;
537 }
538
539 __kernel_entry
540 HBRUSH
541 APIENTRY
542 NtGdiClearBrushAttributes(
543 _In_ HBRUSH hbr,
544 _In_ DWORD dwFlags)
545 {
546 __debugbreak();
547 return NULL;
548 }
549
550 } /* extern "C" */