1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Functions for creation and destruction of DCs 5 * FILE: win32ss/gdi/ntgdi/dcobjs.c 6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org) 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 VOID 15 FASTCALL 16 DC_vUpdateFillBrush(PDC pdc) 17 { 18 PDC_ATTR pdcattr = pdc->pdcattr; 19 PBRUSH pbrFill; 20 21 /* Check if the brush handle has changed */ 22 if (pdcattr->hbrush != pdc->dclevel.pbrFill->BaseObject.hHmgr) 23 { 24 /* Try to lock the new brush */ 25 pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush); 26 if (pbrFill) 27 { 28 /* Unlock old brush, set new brush */ 29 BRUSH_ShareUnlockBrush(pdc->dclevel.pbrFill); 30 pdc->dclevel.pbrFill = pbrFill; 31 32 /* Mark eboFill as dirty */ 33 pdcattr->ulDirty_ |= DIRTY_FILL; 34 } 35 else 36 { 37 /* Invalid brush handle, restore old one */ 38 pdcattr->hbrush = pdc->dclevel.pbrFill->BaseObject.hHmgr; 39 } 40 } 41 42 /* Check if the EBRUSHOBJ needs update */ 43 if (pdcattr->ulDirty_ & DIRTY_FILL) 44 { 45 /* Update eboFill */ 46 EBRUSHOBJ_vUpdateFromDC(&pdc->eboFill, pdc->dclevel.pbrFill, pdc); 47 } 48 49 /* Check for DC brush */ 50 if (pdcattr->hbrush == StockObjects[DC_BRUSH]) 51 { 52 /* Update the eboFill's solid color */ 53 EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboFill, pdcattr->crBrushClr); 54 } 55 56 /* Clear flags */ 57 pdcattr->ulDirty_ &= ~(DIRTY_FILL | DC_BRUSH_DIRTY); 58 } 59 60 VOID 61 FASTCALL 62 DC_vUpdateLineBrush(PDC pdc) 63 { 64 PDC_ATTR pdcattr = pdc->pdcattr; 65 PBRUSH pbrLine; 66 67 /* Check if the pen handle has changed */ 68 if (pdcattr->hpen != pdc->dclevel.pbrLine->BaseObject.hHmgr) 69 { 70 /* Try to lock the new pen */ 71 pbrLine = PEN_ShareLockPen(pdcattr->hpen); 72 if (pbrLine) 73 { 74 /* Unlock old brush, set new brush */ 75 BRUSH_ShareUnlockBrush(pdc->dclevel.pbrLine); 76 pdc->dclevel.pbrLine = pbrLine; 77 78 /* Mark eboLine as dirty */ 79 pdcattr->ulDirty_ |= DIRTY_LINE; 80 } 81 else 82 { 83 /* Invalid pen handle, restore old one */ 84 pdcattr->hpen = pdc->dclevel.pbrLine->BaseObject.hHmgr; 85 } 86 } 87 88 /* Check if the EBRUSHOBJ needs update */ 89 if (pdcattr->ulDirty_ & DIRTY_LINE) 90 { 91 /* Update eboLine */ 92 EBRUSHOBJ_vUpdateFromDC(&pdc->eboLine, pdc->dclevel.pbrLine, pdc); 93 } 94 95 /* Check for DC pen */ 96 if (pdcattr->hpen == StockObjects[DC_PEN]) 97 { 98 /* Update the eboLine's solid color */ 99 EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboLine, pdcattr->crPenClr); 100 } 101 102 /* Clear flags */ 103 pdcattr->ulDirty_ &= ~(DIRTY_LINE | DC_PEN_DIRTY); 104 } 105 106 VOID 107 FASTCALL 108 DC_vUpdateTextBrush(PDC pdc) 109 { 110 PDC_ATTR pdcattr = pdc->pdcattr; 111 112 /* Timo : The text brush should never be changed. 113 * Jérôme : Yeah, but its palette must be updated anyway! */ 114 if(pdcattr->ulDirty_ & DIRTY_TEXT) 115 EBRUSHOBJ_vUpdateFromDC(&pdc->eboText, pbrDefaultBrush, pdc); 116 117 /* Update the eboText's solid color */ 118 EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboText, pdcattr->crForegroundClr); 119 120 /* Clear flag */ 121 pdcattr->ulDirty_ &= ~DIRTY_TEXT; 122 } 123 124 VOID 125 FASTCALL 126 DC_vUpdateBackgroundBrush(PDC pdc) 127 { 128 PDC_ATTR pdcattr = pdc->pdcattr; 129 130 if(pdcattr->ulDirty_ & DIRTY_BACKGROUND) 131 EBRUSHOBJ_vUpdateFromDC(&pdc->eboBackground, pbrDefaultBrush, pdc); 132 133 /* Update the eboBackground's solid color */ 134 EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboBackground, pdcattr->crBackgroundClr); 135 136 /* Clear flag */ 137 pdcattr->ulDirty_ &= ~DIRTY_BACKGROUND; 138 } 139 140 VOID 141 NTAPI 142 DC_vSetBrushOrigin(PDC pdc, LONG x, LONG y) 143 { 144 /* Set the brush origin */ 145 pdc->dclevel.ptlBrushOrigin.x = x; 146 pdc->dclevel.ptlBrushOrigin.y = y; 147 148 /* Set the fill origin */ 149 pdc->ptlFillOrigin.x = x + pdc->ptlDCOrig.x; 150 pdc->ptlFillOrigin.y = y + pdc->ptlDCOrig.y; 151 } 152 153 /** 154 * \name NtGdiSetBrushOrg 155 * 156 * \brief Sets the brush origin that GDI uses when drawing with pattern 157 * brushes. The brush origin is relative to the DC origin. 158 * 159 * @implemented 160 */ 161 _Success_(return!=FALSE) 162 __kernel_entry 163 BOOL 164 APIENTRY 165 NtGdiSetBrushOrg( 166 _In_ HDC hdc, 167 _In_ INT x, 168 _In_ INT y, 169 _Out_opt_ LPPOINT pptOut) 170 { 171 172 POINT ptOut; 173 /* Call the internal function */ 174 BOOL Ret = GreSetBrushOrg( hdc, x, y, &ptOut); 175 if (Ret) 176 { 177 /* Check if the old origin was requested */ 178 if (pptOut != NULL) 179 { 180 /* Enter SEH for buffer transfer */ 181 _SEH2_TRY 182 { 183 /* Probe and copy the old origin */ 184 ProbeForWrite(pptOut, sizeof(POINT), 1); 185 *pptOut = ptOut; 186 } 187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 188 { 189 _SEH2_YIELD(return FALSE); 190 } 191 _SEH2_END; 192 } 193 } 194 return Ret; 195 } 196 197 HPALETTE 198 NTAPI 199 GdiSelectPalette( 200 HDC hDC, 201 HPALETTE hpal, 202 BOOL ForceBackground) 203 { 204 PDC pdc; 205 HPALETTE oldPal = NULL; 206 PPALETTE ppal; 207 208 // FIXME: Mark the palette as a [fore\back]ground pal 209 pdc = DC_LockDc(hDC); 210 if (!pdc) 211 { 212 return NULL; 213 } 214 215 /* Check if this is a valid palette handle */ 216 ppal = PALETTE_ShareLockPalette(hpal); 217 if (!ppal) 218 { 219 DC_UnlockDc(pdc); 220 return NULL; 221 } 222 223 /// FIXME: we shouldn't dereference pSurface when the PDEV is not locked 224 /* Is this a valid palette for this depth? */ 225 if ((!pdc->dclevel.pSurface) || 226 (BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) <= 8 227 && (ppal->flFlags & PAL_INDEXED)) || 228 (BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) > 8)) 229 { 230 /* Get old palette, set new one */ 231 oldPal = pdc->dclevel.hpal; 232 pdc->dclevel.hpal = hpal; 233 DC_vSelectPalette(pdc, ppal); 234 235 /* Mark the brushes invalid */ 236 pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE | 237 DIRTY_BACKGROUND | DIRTY_TEXT; 238 } 239 240 if(pdc->dctype == DCTYPE_MEMORY) 241 { 242 // This didn't work anyway 243 //IntGdiRealizePalette(hDC); 244 } 245 246 PALETTE_ShareUnlockPalette(ppal); 247 DC_UnlockDc(pdc); 248 249 return oldPal; 250 } 251 252 /* 253 * @implemented 254 */ 255 HBRUSH 256 APIENTRY 257 NtGdiSelectBrush( 258 IN HDC hDC, 259 IN HBRUSH hBrush) 260 { 261 PDC pDC; 262 HBRUSH hOrgBrush; 263 264 if (hDC == NULL || hBrush == NULL) return NULL; 265 266 pDC = DC_LockDc(hDC); 267 if (!pDC) 268 { 269 return NULL; 270 } 271 272 /* Simply return the user mode value, without checking */ 273 hOrgBrush = pDC->pdcattr->hbrush; 274 pDC->pdcattr->hbrush = hBrush; 275 DC_vUpdateFillBrush(pDC); 276 277 DC_UnlockDc(pDC); 278 279 return hOrgBrush; 280 } 281 282 /* 283 * @implemented 284 */ 285 HPEN 286 APIENTRY 287 NtGdiSelectPen( 288 IN HDC hDC, 289 IN HPEN hPen) 290 { 291 PDC pDC; 292 HPEN hOrgPen; 293 294 if (hDC == NULL || hPen == NULL) return NULL; 295 296 pDC = DC_LockDc(hDC); 297 if (!pDC) 298 { 299 return NULL; 300 } 301 302 /* Simply return the user mode value, without checking */ 303 hOrgPen = pDC->pdcattr->hpen; 304 pDC->pdcattr->hpen = hPen; 305 DC_vUpdateLineBrush(pDC); 306 307 DC_UnlockDc(pDC); 308 309 return hOrgPen; 310 } 311 312 BOOL 313 NTAPI 314 DC_bIsBitmapCompatible(PDC pdc, PSURFACE psurf) 315 { 316 ULONG cBitsPixel; 317 318 /* Must be an API bitmap */ 319 if (!(psurf->flags & API_BITMAP)) return FALSE; 320 321 /* DIB sections are always compatible */ 322 if (psurf->hSecure != NULL) return TRUE; 323 324 /* See if this is the same PDEV */ 325 if (psurf->SurfObj.hdev == (HDEV)pdc->ppdev) 326 return TRUE; 327 328 /* Get the bit depth of the bitmap */ 329 cBitsPixel = gajBitsPerFormat[psurf->SurfObj.iBitmapFormat]; 330 331 /* 1 BPP is compatible */ 332 if ((cBitsPixel == 1) || (cBitsPixel == pdc->ppdev->gdiinfo.cBitsPixel)) 333 return TRUE; 334 335 return FALSE; 336 } 337 338 /* 339 * @implemented 340 */ 341 HBITMAP 342 APIENTRY 343 NtGdiSelectBitmap( 344 IN HDC hdc, 345 IN HBITMAP hbmp) 346 { 347 PDC pdc; 348 HBITMAP hbmpOld; 349 PSURFACE psurfNew, psurfOld; 350 HDC hdcOld; 351 ASSERT_NOGDILOCKS(); 352 353 /* Verify parameters */ 354 if (hdc == NULL || hbmp == NULL) return NULL; 355 356 /* First lock the DC */ 357 pdc = DC_LockDc(hdc); 358 if (!pdc) 359 { 360 return NULL; 361 } 362 363 /* Must be a memory dc to select a bitmap */ 364 if (pdc->dctype != DCTYPE_MEMORY) 365 { 366 DC_UnlockDc(pdc); 367 return NULL; 368 } 369 370 /* Save the old bitmap */ 371 psurfOld = pdc->dclevel.pSurface; 372 373 /* Check if there is a bitmap selected */ 374 if (psurfOld) 375 { 376 /* Get the old bitmap's handle */ 377 hbmpOld = psurfOld->BaseObject.hHmgr; 378 } 379 else 380 { 381 /* Use the default bitmap */ 382 hbmpOld = StockObjects[DEFAULT_BITMAP]; 383 } 384 385 /* Check if the new bitmap is already selected */ 386 if (hbmp == hbmpOld) 387 { 388 /* Unlock the DC and return the old bitmap */ 389 DC_UnlockDc(pdc); 390 return hbmpOld; 391 } 392 393 /* Check if the default bitmap was passed */ 394 if (hbmp == StockObjects[DEFAULT_BITMAP]) 395 { 396 psurfNew = NULL; 397 398 /* Default bitmap is 1x1 pixel */ 399 pdc->dclevel.sizl.cx = 1; 400 pdc->dclevel.sizl.cy = 1; 401 } 402 else 403 { 404 /* Reference the new bitmap and check if it's valid */ 405 psurfNew = SURFACE_ShareLockSurface(hbmp); 406 if (!psurfNew) 407 { 408 DC_UnlockDc(pdc); 409 return NULL; 410 } 411 412 /* Check if the bitmap is compatible with the dc */ 413 if (!DC_bIsBitmapCompatible(pdc, psurfNew)) 414 { 415 /* Dereference the bitmap, unlock the DC and fail. */ 416 SURFACE_ShareUnlockSurface(psurfNew); 417 DC_UnlockDc(pdc); 418 return NULL; 419 } 420 421 /* Set the bitmap's hdc and check if it was set before */ 422 hdcOld = InterlockedCompareExchangePointer((PVOID*)&psurfNew->hdc, hdc, 0); 423 if (hdcOld != NULL) 424 { 425 /* The bitmap is already selected into a different DC */ 426 ASSERT(hdcOld != hdc); 427 428 /* Dereference the bitmap, unlock the DC and fail. */ 429 SURFACE_ShareUnlockSurface(psurfNew); 430 DC_UnlockDc(pdc); 431 return NULL; 432 } 433 434 /* Copy the bitmap size */ 435 pdc->dclevel.sizl = psurfNew->SurfObj.sizlBitmap; 436 437 /* Check if the bitmap is a dibsection */ 438 if (psurfNew->hSecure) 439 { 440 /* Set DIBSECTION attribute */ 441 pdc->pdcattr->ulDirty_ |= DC_DIBSECTION; 442 } 443 else 444 { 445 /* Remove DIBSECTION attribute */ 446 pdc->pdcattr->ulDirty_ &= ~DC_DIBSECTION; 447 } 448 } 449 450 /* Select the new bitmap */ 451 pdc->dclevel.pSurface = psurfNew; 452 453 /* Check if there was a bitmap selected before */ 454 if (psurfOld) 455 { 456 /* Reset hdc of the old bitmap, it isn't selected anymore */ 457 psurfOld->hdc = NULL; 458 459 /* Dereference the old bitmap */ 460 SURFACE_ShareUnlockSurface(psurfOld); 461 } 462 463 /* Mark the DC brushes and the RAO region invalid */ 464 pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE; 465 pdc->fs |= DC_DIRTY_RAO; 466 467 /* Update the system region */ 468 REGION_SetRectRgn(pdc->prgnVis, 469 0, 470 0, 471 pdc->dclevel.sizl.cx, 472 pdc->dclevel.sizl.cy); 473 474 /* Unlock the DC */ 475 DC_UnlockDc(pdc); 476 477 /* Return the old bitmap handle */ 478 return hbmpOld; 479 } 480 481 482 BOOL 483 APIENTRY 484 NtGdiSelectClipPath( 485 HDC hDC, 486 int Mode) 487 { 488 PREGION RgnPath; 489 PPATH pPath, pNewPath; 490 BOOL success = FALSE; 491 PDC_ATTR pdcattr; 492 PDC pdc; 493 494 pdc = DC_LockDc(hDC); 495 if (!pdc) 496 { 497 EngSetLastError(ERROR_INVALID_PARAMETER); 498 return FALSE; 499 } 500 pdcattr = pdc->pdcattr; 501 502 pPath = PATH_LockPath(pdc->dclevel.hPath); 503 if (!pPath) 504 { 505 DC_UnlockDc(pdc); 506 return FALSE; 507 } 508 509 /* Check that path is closed */ 510 if (pPath->state != PATH_Closed) 511 { 512 EngSetLastError(ERROR_CAN_NOT_COMPLETE); 513 success = FALSE; 514 goto Exit; 515 } 516 517 /* Construct a region from the path */ 518 RgnPath = IntSysCreateRectpRgn(0, 0, 0, 0); 519 if (!RgnPath) 520 { 521 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 522 DC_UnlockDc(pdc); 523 return FALSE; 524 } 525 526 pNewPath = PATH_FlattenPath(pPath); 527 528 success = PATH_PathToRegion(pNewPath, pdcattr->jFillMode, RgnPath); 529 530 PATH_UnlockPath(pNewPath); 531 PATH_Delete(pNewPath->BaseObject.hHmgr); 532 533 if (success) success = IntGdiExtSelectClipRgn(pdc, RgnPath, Mode) != ERROR; 534 535 REGION_Delete(RgnPath); 536 537 Exit: 538 PATH_UnlockPath(pPath); 539 PATH_Delete(pdc->dclevel.hPath); 540 pdc->dclevel.flPath &= ~DCPATH_ACTIVE; 541 pdc->dclevel.hPath = NULL; 542 543 DC_UnlockDc(pdc); 544 545 return success; 546 } 547 548 HFONT 549 NTAPI 550 DC_hSelectFont( 551 _In_ PDC pdc, 552 _In_ HFONT hlfntNew) 553 { 554 PLFONT plfntNew; 555 HFONT hlfntOld; 556 557 // Legacy crap that will die with font engine rewrite 558 if (!NT_SUCCESS(TextIntRealizeFont(hlfntNew, NULL))) 559 { 560 return NULL; 561 } 562 563 /* Get the current selected font */ 564 hlfntOld = pdc->dclevel.plfnt->BaseObject.hHmgr; 565 566 /* Check if a new font should be selected */ 567 if (hlfntNew != hlfntOld) 568 { 569 /* Lock the new font */ 570 plfntNew = LFONT_ShareLockFont(hlfntNew); 571 if (plfntNew) 572 { 573 /* Success, dereference the old font */ 574 LFONT_ShareUnlockFont(pdc->dclevel.plfnt); 575 576 /* Select the new font */ 577 pdc->dclevel.plfnt = plfntNew; 578 pdc->pdcattr->hlfntNew = hlfntNew; 579 580 /* Update dirty flags */ 581 pdc->pdcattr->ulDirty_ |= DIRTY_CHARSET; 582 pdc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS; 583 } 584 else 585 { 586 /* Failed, restore old, return NULL */ 587 pdc->pdcattr->hlfntNew = hlfntOld; 588 hlfntOld = NULL; 589 } 590 } 591 592 return hlfntOld; 593 } 594 595 HFONT 596 APIENTRY 597 NtGdiSelectFont( 598 _In_ HDC hdc, 599 _In_ HFONT hfont) 600 { 601 HFONT hfontOld; 602 PDC pdc; 603 604 /* Check parameters */ 605 if ((hdc == NULL) || (hfont == NULL)) 606 { 607 return NULL; 608 } 609 610 /* Lock the DC */ 611 pdc = DC_LockDc(hdc); 612 if (!pdc) 613 { 614 return NULL; 615 } 616 617 /* Call the internal function */ 618 hfontOld = DC_hSelectFont(pdc, hfont); 619 620 /* Unlock the DC */ 621 DC_UnlockDc(pdc); 622 623 /* Return the previously selected font */ 624 return hfontOld; 625 } 626 627 HANDLE 628 APIENTRY 629 NtGdiGetDCObject(HDC hDC, INT ObjectType) 630 { 631 HGDIOBJ SelObject; 632 DC *pdc; 633 PDC_ATTR pdcattr; 634 635 /* From Wine: GetCurrentObject does not SetLastError() on a null object */ 636 if(!hDC) return NULL; 637 638 if(!(pdc = DC_LockDc(hDC))) 639 { 640 return NULL; 641 } 642 pdcattr = pdc->pdcattr; 643 644 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 645 DC_vUpdateFillBrush(pdc); 646 647 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 648 DC_vUpdateLineBrush(pdc); 649 650 switch(ObjectType) 651 { 652 case GDI_OBJECT_TYPE_EXTPEN: 653 case GDI_OBJECT_TYPE_PEN: 654 SelObject = pdcattr->hpen; 655 break; 656 657 case GDI_OBJECT_TYPE_BRUSH: 658 SelObject = pdcattr->hbrush; 659 break; 660 661 case GDI_OBJECT_TYPE_PALETTE: 662 SelObject = pdc->dclevel.hpal; 663 break; 664 665 case GDI_OBJECT_TYPE_FONT: 666 SelObject = pdcattr->hlfntNew; 667 break; 668 669 case GDI_OBJECT_TYPE_BITMAP: 670 { 671 SURFACE *psurf = pdc->dclevel.pSurface; 672 SelObject = psurf ? psurf->BaseObject.hHmgr : StockObjects[DEFAULT_BITMAP]; 673 break; 674 } 675 676 case GDI_OBJECT_TYPE_COLORSPACE: 677 DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n"); 678 // SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ? 679 SelObject = NULL; 680 break; 681 682 default: 683 SelObject = NULL; 684 EngSetLastError(ERROR_INVALID_PARAMETER); 685 break; 686 } 687 688 DC_UnlockDc(pdc); 689 return SelObject; 690 } 691 692 /* See WINE, MSDN, OSR and Feng Yuan - Windows Graphics Programming Win32 GDI and DirectDraw 693 * 694 * 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong! 695 * 696 * The intersection of the clip with the meta region is not Rao it's API! 697 * Go back and read 7.2 Clipping pages 418-19: 698 * Rao = API & Vis: 699 * 1) The Rao region is the intersection of the API region and the system region, 700 * named after the Microsoft engineer who initially proposed it. 701 * 2) The Rao region can be calculated from the API region and the system region. 702 * 703 * API: 704 * API region is the intersection of the meta region and the clipping region, 705 * clearly named after the fact that it is controlled by GDI API calls. 706 */ 707 INT 708 APIENTRY 709 NtGdiGetRandomRgn( 710 HDC hdc, 711 HRGN hrgnDest, 712 INT iCode) 713 { 714 INT ret = 0; 715 PDC pdc; 716 PREGION prgnSrc = NULL; 717 718 pdc = DC_LockDc(hdc); 719 if (!pdc) 720 { 721 EngSetLastError(ERROR_INVALID_HANDLE); 722 return -1; 723 } 724 725 switch (iCode) 726 { 727 case CLIPRGN: 728 prgnSrc = pdc->dclevel.prgnClip; 729 break; 730 731 case METARGN: 732 prgnSrc = pdc->dclevel.prgnMeta; 733 break; 734 735 case APIRGN: 736 if (pdc->fs & DC_DIRTY_RAO) 737 CLIPPING_UpdateGCRegion(pdc); 738 if (pdc->prgnAPI) 739 { 740 prgnSrc = pdc->prgnAPI; 741 } 742 else if (pdc->dclevel.prgnClip) 743 { 744 prgnSrc = pdc->dclevel.prgnClip; 745 } 746 else if (pdc->dclevel.prgnMeta) 747 { 748 prgnSrc = pdc->dclevel.prgnMeta; 749 } 750 break; 751 752 case SYSRGN: 753 prgnSrc = pdc->prgnVis; 754 break; 755 756 default: 757 break; 758 } 759 760 if (prgnSrc) 761 { 762 PREGION prgnDest = REGION_LockRgn(hrgnDest); 763 if (prgnDest) 764 { 765 ret = IntGdiCombineRgn(prgnDest, prgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1; 766 if ((ret == 1) && (iCode == SYSRGN)) 767 { 768 /// \todo FIXME This is not really correct, since we already modified the region 769 ret = REGION_bOffsetRgn(prgnDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y); 770 } 771 REGION_UnlockRgn(prgnDest); 772 } 773 else 774 ret = -1; 775 } 776 777 DC_UnlockDc(pdc); 778 779 return ret; 780 } 781 782 ULONG 783 APIENTRY 784 NtGdiEnumObjects( 785 IN HDC hdc, 786 IN INT iObjectType, 787 IN ULONG cjBuf, 788 OUT OPTIONAL PVOID pvBuf) 789 { 790 UNIMPLEMENTED; 791 return 0; 792 } 793 794 /* EOF */ 795