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