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