1 /* 2 * PROJECT: ReactOS win32 kernel mode subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/fillshap.c 5 * PURPOSE: fillshap 6 * PROGRAMMER: 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0))) 15 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0))) 16 17 BOOL FASTCALL 18 IntGdiPolygon(PDC dc, 19 PPOINT Points, 20 int Count) 21 { 22 SURFACE *psurf; 23 PBRUSH pbrLine, pbrFill; 24 BOOL ret = FALSE; // Default to failure 25 RECTL DestRect; 26 int CurrentPoint; 27 PDC_ATTR pdcattr; 28 POINTL BrushOrigin; 29 // int Left; 30 // int Top; 31 32 ASSERT(dc); // Caller's responsibility to pass a valid dc 33 34 if (!Points || Count < 2 ) 35 { 36 EngSetLastError(ERROR_INVALID_PARAMETER); 37 return FALSE; 38 } 39 40 /* 41 // Find start x, y 42 Left = Points[0].x; 43 Top = Points[0].y; 44 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) { 45 Left = min(Left, Points[CurrentPoint].x); 46 Top = min(Top, Points[CurrentPoint].y); 47 } 48 */ 49 50 pdcattr = dc->pdcattr; 51 52 /* Convert to screen coordinates */ 53 IntLPtoDP(dc, Points, Count); 54 for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++) 55 { 56 Points[CurrentPoint].x += dc->ptlDCOrig.x; 57 Points[CurrentPoint].y += dc->ptlDCOrig.y; 58 } 59 // No need to have path here. 60 { 61 DestRect.left = Points[0].x; 62 DestRect.right = Points[0].x; 63 DestRect.top = Points[0].y; 64 DestRect.bottom = Points[0].y; 65 66 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) 67 { 68 DestRect.left = min(DestRect.left, Points[CurrentPoint].x); 69 DestRect.right = max(DestRect.right, Points[CurrentPoint].x); 70 DestRect.top = min(DestRect.top, Points[CurrentPoint].y); 71 DestRect.bottom = max(DestRect.bottom, Points[CurrentPoint].y); 72 } 73 74 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 75 DC_vUpdateFillBrush(dc); 76 77 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 78 DC_vUpdateLineBrush(dc); 79 80 /* Special locking order to avoid lock-ups */ 81 pbrFill = dc->dclevel.pbrFill; 82 pbrLine = dc->dclevel.pbrLine; 83 psurf = dc->dclevel.pSurface; 84 if (psurf == NULL) 85 { 86 /* Memory DC without a bitmap selected, nothing to do. */ 87 return TRUE; 88 } 89 90 /* Now fill the polygon with the current fill brush. */ 91 if (!(pbrFill->flAttrs & BR_IS_NULL)) 92 { 93 BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin); 94 BrushOrigin.x += dc->ptlDCOrig.x; 95 BrushOrigin.y += dc->ptlDCOrig.y; 96 ret = IntFillPolygon (dc, 97 psurf, 98 &dc->eboFill.BrushObject, 99 Points, 100 Count, 101 DestRect, 102 &BrushOrigin); 103 } 104 105 // Draw the Polygon Edges with the current pen ( if not a NULL pen ) 106 if (!(pbrLine->flAttrs & BR_IS_NULL)) 107 { 108 int i; 109 110 for (i = 0; i < Count-1; i++) 111 { 112 113 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n", 114 // Points[0].x, Points[0].y, 115 // Points[1].x, Points[1].y ); 116 117 ret = IntEngLineTo(&psurf->SurfObj, 118 (CLIPOBJ *)&dc->co, 119 &dc->eboLine.BrushObject, 120 Points[i].x, /* From */ 121 Points[i].y, 122 Points[i+1].x, /* To */ 123 Points[i+1].y, 124 &DestRect, 125 ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */ 126 if (!ret) break; 127 } 128 /* Close the polygon */ 129 if (ret) 130 { 131 ret = IntEngLineTo(&psurf->SurfObj, 132 (CLIPOBJ *)&dc->co, 133 &dc->eboLine.BrushObject, 134 Points[Count-1].x, /* From */ 135 Points[Count-1].y, 136 Points[0].x, /* To */ 137 Points[0].y, 138 &DestRect, 139 ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */ 140 } 141 } 142 } 143 144 return ret; 145 } 146 147 BOOL FASTCALL 148 IntGdiPolyPolygon(DC *dc, 149 LPPOINT Points, 150 PULONG PolyCounts, 151 int Count) 152 { 153 if (PATH_IsPathOpen(dc->dclevel)) 154 return PATH_PolyPolygon ( dc, Points, (PINT)PolyCounts, Count); 155 156 while (--Count >=0) 157 { 158 if (!IntGdiPolygon ( dc, Points, *PolyCounts )) 159 return FALSE; 160 Points+=*PolyCounts++; 161 } 162 return TRUE; 163 } 164 165 BOOL FASTCALL 166 IntPolygon(HDC hdc, POINT *Point, int Count) 167 { 168 BOOL bResult; 169 PDC pdc; 170 171 pdc = DC_LockDc(hdc); 172 if (pdc == NULL) 173 { 174 EngSetLastError(ERROR_INVALID_HANDLE); 175 return FALSE; 176 } 177 178 bResult = IntGdiPolygon(pdc, Point, Count); 179 180 DC_UnlockDc(pdc); 181 return bResult; 182 } 183 184 185 /******************************************************************************/ 186 187 /* 188 * NtGdiEllipse 189 * 190 * Author 191 * Filip Navara 192 * 193 * Remarks 194 * This function uses optimized Bresenham's ellipse algorithm. It draws 195 * four lines of the ellipse in one pass. 196 * 197 */ 198 199 BOOL APIENTRY 200 NtGdiEllipse( 201 HDC hDC, 202 int Left, 203 int Top, 204 int Right, 205 int Bottom) 206 { 207 PDC dc; 208 PDC_ATTR pdcattr; 209 RECTL RectBounds; 210 PBRUSH pbrush; 211 BOOL ret = TRUE; 212 LONG PenWidth, PenOrigWidth; 213 LONG RadiusX, RadiusY, CenterX, CenterY; 214 PBRUSH pFillBrushObj; 215 BRUSH tmpFillBrushObj; 216 217 dc = DC_LockDc(hDC); 218 if (dc == NULL) 219 { 220 EngSetLastError(ERROR_INVALID_HANDLE); 221 return FALSE; 222 } 223 224 if (PATH_IsPathOpen(dc->dclevel)) 225 { 226 ret = PATH_Ellipse(dc, Left, Top, Right, Bottom); 227 DC_UnlockDc(dc); 228 return ret; 229 } 230 231 //// 232 //// Could this use PATH_CheckCorners ? 233 //// 234 if ((Left == Right) || (Top == Bottom)) 235 { 236 DC_UnlockDc(dc); 237 return TRUE; 238 } 239 240 if (Right < Left) 241 { 242 INT tmp = Right; Right = Left; Left = tmp; 243 } 244 if (Bottom < Top) 245 { 246 INT tmp = Bottom; Bottom = Top; Top = tmp; 247 } 248 //// 249 250 pdcattr = dc->pdcattr; 251 252 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 253 DC_vUpdateFillBrush(dc); 254 255 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 256 DC_vUpdateLineBrush(dc); 257 258 pbrush = PEN_ShareLockPen(pdcattr->hpen); 259 if (!pbrush) 260 { 261 DPRINT1("Ellipse Fail 1\n"); 262 DC_UnlockDc(dc); 263 EngSetLastError(ERROR_INTERNAL_ERROR); 264 return FALSE; 265 } 266 267 PenOrigWidth = PenWidth = pbrush->lWidth; 268 if (pbrush->ulPenStyle == PS_NULL) PenWidth = 0; 269 270 if (pbrush->ulPenStyle == PS_INSIDEFRAME) 271 { 272 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2; 273 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2; 274 Left += PenWidth / 2; 275 Right -= (PenWidth - 1) / 2; 276 Top += PenWidth / 2; 277 Bottom -= (PenWidth - 1) / 2; 278 } 279 280 if (!PenWidth) PenWidth = 1; 281 pbrush->lWidth = PenWidth; 282 283 RectBounds.left = Left; 284 RectBounds.right = Right; 285 RectBounds.top = Top; 286 RectBounds.bottom = Bottom; 287 288 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2); 289 290 RectBounds.left += dc->ptlDCOrig.x; 291 RectBounds.right += dc->ptlDCOrig.x; 292 RectBounds.top += dc->ptlDCOrig.y; 293 RectBounds.bottom += dc->ptlDCOrig.y; 294 295 // Setup for dynamic width and height. 296 RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room 297 RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2); 298 CenterX = (RectBounds.right + RectBounds.left) / 2; 299 CenterY = (RectBounds.bottom + RectBounds.top) / 2; 300 301 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n", 302 RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom); 303 304 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n", 305 CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2); 306 307 pFillBrushObj = BRUSH_ShareLockBrush(pdcattr->hbrush); 308 if (NULL == pFillBrushObj) 309 { 310 DPRINT1("FillEllipse Fail\n"); 311 EngSetLastError(ERROR_INTERNAL_ERROR); 312 ret = FALSE; 313 } 314 else 315 { 316 RtlCopyMemory(&tmpFillBrushObj, pFillBrushObj, sizeof(tmpFillBrushObj)); 317 //tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left; 318 //tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top; 319 tmpFillBrushObj.ptOrigin.x += dc->ptlDCOrig.x; 320 tmpFillBrushObj.ptOrigin.y += dc->ptlDCOrig.y; 321 322 DC_vPrepareDCsForBlit(dc, &RectBounds, NULL, NULL); 323 324 ret = IntFillEllipse( dc, 325 CenterX - RadiusX, 326 CenterY - RadiusY, 327 RadiusX*2, // Width 328 RadiusY*2, // Height 329 &tmpFillBrushObj); 330 BRUSH_ShareUnlockBrush(pFillBrushObj); 331 332 if (ret) 333 { 334 ret = IntDrawEllipse( dc, 335 CenterX - RadiusX, 336 CenterY - RadiusY, 337 RadiusX*2, // Width 338 RadiusY*2, // Height 339 pbrush); 340 } 341 342 DC_vFinishBlit(dc, NULL); 343 } 344 345 pbrush->lWidth = PenOrigWidth; 346 PEN_ShareUnlockPen(pbrush); 347 DC_UnlockDc(dc); 348 DPRINT("Ellipse Exit.\n"); 349 return ret; 350 } 351 352 #if 0 353 354 // When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and 355 // even-numbered polygon sides on each scan line. That is, GDI fills the area between the 356 // first and second side, between the third and fourth side, and so on. 357 358 // WINDING Selects winding mode (fills any region with a nonzero winding value). 359 // When the fill mode is WINDING, GDI fills any region that has a nonzero winding value. 360 // This value is defined as the number of times a pen used to draw the polygon would go around the region. 361 // The direction of each edge of the polygon is important. 362 363 extern BOOL FillPolygon(PDC dc, 364 SURFOBJ *SurfObj, 365 PBRUSHOBJ BrushObj, 366 MIX RopMode, 367 CONST PPOINT Points, 368 int Count, 369 RECTL BoundRect); 370 371 #endif 372 373 374 ULONG_PTR 375 APIENTRY 376 NtGdiPolyPolyDraw( IN HDC hDC, 377 IN PPOINT UnsafePoints, 378 IN PULONG UnsafeCounts, 379 IN ULONG Count, 380 IN INT iFunc ) 381 { 382 DC *dc; 383 PVOID pTemp; 384 LPPOINT SafePoints; 385 PULONG SafeCounts; 386 NTSTATUS Status = STATUS_SUCCESS; 387 BOOL Ret = TRUE; 388 ULONG nPoints = 0, nMaxPoints = 0, nInvalid = 0, i; 389 390 if (!UnsafePoints || !UnsafeCounts || 391 Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn) 392 { 393 /* Windows doesn't set last error */ 394 return FALSE; 395 } 396 397 _SEH2_TRY 398 { 399 ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1); 400 ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1); 401 402 /* Count points and validate poligons */ 403 for (i = 0; i < Count; i++) 404 { 405 if (UnsafeCounts[i] < 2) 406 { 407 nInvalid++; 408 } 409 nPoints += UnsafeCounts[i]; 410 nMaxPoints = max(nMaxPoints, UnsafeCounts[i]); 411 } 412 } 413 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 414 { 415 Status = _SEH2_GetExceptionCode(); 416 } 417 _SEH2_END; 418 419 if (!NT_SUCCESS(Status)) 420 { 421 /* Windows doesn't set last error */ 422 return FALSE; 423 } 424 425 if (nPoints == 0 || nPoints < nMaxPoints) 426 { 427 /* If all polygon counts are zero, or we have overflow, 428 return without setting a last error code. */ 429 return FALSE; 430 } 431 432 if (nInvalid != 0) 433 { 434 /* If at least one poly count is 0 or 1, fail */ 435 EngSetLastError(ERROR_INVALID_PARAMETER); 436 return FALSE; 437 } 438 439 /* Allocate one buffer for both counts and points */ 440 pTemp = ExAllocatePoolWithTag(PagedPool, 441 Count * sizeof(ULONG) + nPoints * sizeof(POINT), 442 TAG_SHAPE); 443 if (!pTemp) 444 { 445 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 446 return FALSE; 447 } 448 449 SafeCounts = pTemp; 450 SafePoints = (PVOID)(SafeCounts + Count); 451 452 _SEH2_TRY 453 { 454 /* Pointers already probed! */ 455 RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG)); 456 RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT)); 457 } 458 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 459 { 460 Status = _SEH2_GetExceptionCode(); 461 } 462 _SEH2_END; 463 464 if (!NT_SUCCESS(Status)) 465 { 466 ExFreePoolWithTag(pTemp, TAG_SHAPE); 467 return FALSE; 468 } 469 470 /* Special handling for GdiPolyPolyRgn */ 471 if (iFunc == GdiPolyPolyRgn) 472 { 473 INT iMode = (INT)(UINT_PTR)hDC; 474 HRGN hrgn; 475 476 hrgn = GreCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, iMode); 477 478 ExFreePoolWithTag(pTemp, TAG_SHAPE); 479 return (ULONG_PTR)hrgn; 480 } 481 482 dc = DC_LockDc(hDC); 483 if (!dc) 484 { 485 EngSetLastError(ERROR_INVALID_HANDLE); 486 ExFreePoolWithTag(pTemp, TAG_SHAPE); 487 return FALSE; 488 } 489 490 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL); 491 492 if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 493 DC_vUpdateFillBrush(dc); 494 495 if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 496 DC_vUpdateLineBrush(dc); 497 498 /* Perform the actual work */ 499 switch (iFunc) 500 { 501 case GdiPolyPolygon: 502 Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count); 503 break; 504 case GdiPolyPolyLine: 505 Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count); 506 break; 507 case GdiPolyBezier: 508 Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts); 509 break; 510 case GdiPolyLineTo: 511 Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts); 512 break; 513 case GdiPolyBezierTo: 514 Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts); 515 break; 516 default: 517 EngSetLastError(ERROR_INVALID_PARAMETER); 518 Ret = FALSE; 519 } 520 521 /* Cleanup and return */ 522 DC_vFinishBlit(dc, NULL); 523 DC_UnlockDc(dc); 524 ExFreePoolWithTag(pTemp, TAG_SHAPE); 525 526 return (ULONG_PTR)Ret; 527 } 528 529 530 BOOL 531 FASTCALL 532 IntRectangle(PDC dc, 533 int LeftRect, 534 int TopRect, 535 int RightRect, 536 int BottomRect) 537 { 538 SURFACE *psurf = NULL; 539 PBRUSH pbrLine, pbrFill; 540 BOOL ret = FALSE; // Default to failure 541 RECTL DestRect; 542 MIX Mix; 543 PDC_ATTR pdcattr; 544 POINTL BrushOrigin; 545 546 ASSERT ( dc ); // Caller's responsibility to set this up 547 548 pdcattr = dc->pdcattr; 549 550 // Rectangle Path only. 551 if ( PATH_IsPathOpen(dc->dclevel) ) 552 { 553 return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect ); 554 } 555 556 /* Make sure rectangle is not inverted */ 557 DestRect.left = min(LeftRect, RightRect); 558 DestRect.right = max(LeftRect, RightRect); 559 DestRect.top = min(TopRect, BottomRect); 560 DestRect.bottom = max(TopRect, BottomRect); 561 562 IntLPtoDP(dc, (LPPOINT)&DestRect, 2); 563 564 DestRect.left += dc->ptlDCOrig.x; 565 DestRect.right += dc->ptlDCOrig.x; 566 DestRect.top += dc->ptlDCOrig.y; 567 DestRect.bottom += dc->ptlDCOrig.y; 568 569 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 570 { 571 IntUpdateBoundsRect(dc, &DestRect); 572 } 573 574 /* In GM_COMPATIBLE, don't include bottom and right edges */ 575 if (pdcattr->iGraphicsMode == GM_COMPATIBLE) 576 { 577 DestRect.right--; 578 DestRect.bottom--; 579 } 580 581 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL); 582 583 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 584 DC_vUpdateFillBrush(dc); 585 586 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 587 DC_vUpdateLineBrush(dc); 588 589 pbrFill = dc->dclevel.pbrFill; 590 pbrLine = dc->dclevel.pbrLine; 591 if (!pbrLine) 592 { 593 ret = FALSE; 594 goto cleanup; 595 } 596 597 psurf = dc->dclevel.pSurface; 598 if (!psurf) 599 { 600 ret = TRUE; 601 goto cleanup; 602 } 603 604 if (pbrFill) 605 { 606 if (!(pbrFill->flAttrs & BR_IS_NULL)) 607 { 608 BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin); 609 BrushOrigin.x += dc->ptlDCOrig.x; 610 BrushOrigin.y += dc->ptlDCOrig.y; 611 ret = IntEngBitBlt(&psurf->SurfObj, 612 NULL, 613 NULL, 614 (CLIPOBJ *)&dc->co, 615 NULL, 616 &DestRect, 617 NULL, 618 NULL, 619 &dc->eboFill.BrushObject, 620 &BrushOrigin, 621 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY)); 622 } 623 } 624 625 // Draw the rectangle with the current pen 626 627 ret = TRUE; // Change default to success 628 629 if (!(pbrLine->flAttrs & BR_IS_NULL)) 630 { 631 Mix = ROP2_TO_MIX(pdcattr->jROP2); 632 ret = ret && IntEngLineTo(&psurf->SurfObj, 633 (CLIPOBJ *)&dc->co, 634 &dc->eboLine.BrushObject, 635 DestRect.left, DestRect.top, DestRect.right, DestRect.top, 636 &DestRect, // Bounding rectangle 637 Mix); 638 639 ret = ret && IntEngLineTo(&psurf->SurfObj, 640 (CLIPOBJ *)&dc->co, 641 &dc->eboLine.BrushObject, 642 DestRect.right, DestRect.top, DestRect.right, DestRect.bottom, 643 &DestRect, // Bounding rectangle 644 Mix); 645 646 ret = ret && IntEngLineTo(&psurf->SurfObj, 647 (CLIPOBJ *)&dc->co, 648 &dc->eboLine.BrushObject, 649 DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom, 650 &DestRect, // Bounding rectangle 651 Mix); 652 653 ret = ret && IntEngLineTo(&psurf->SurfObj, 654 (CLIPOBJ *)&dc->co, 655 &dc->eboLine.BrushObject, 656 DestRect.left, DestRect.bottom, DestRect.left, DestRect.top, 657 &DestRect, // Bounding rectangle 658 Mix); 659 } 660 661 cleanup: 662 DC_vFinishBlit(dc, NULL); 663 664 /* Move current position in DC? 665 MSDN: The current position is neither used nor updated by Rectangle. */ 666 667 return ret; 668 } 669 670 BOOL 671 APIENTRY 672 NtGdiRectangle(HDC hDC, 673 int LeftRect, 674 int TopRect, 675 int RightRect, 676 int BottomRect) 677 { 678 DC *dc; 679 BOOL ret; // Default to failure 680 681 dc = DC_LockDc(hDC); 682 if (!dc) 683 { 684 EngSetLastError(ERROR_INVALID_HANDLE); 685 return FALSE; 686 } 687 688 /* Do we rotate or shear? */ 689 if (!(dc->pdcattr->mxWorldToDevice.flAccel & XFORM_SCALE)) 690 { 691 POINTL DestCoords[4]; 692 ULONG PolyCounts = 4; 693 694 DestCoords[0].x = DestCoords[3].x = LeftRect; 695 DestCoords[0].y = DestCoords[1].y = TopRect; 696 DestCoords[1].x = DestCoords[2].x = RightRect; 697 DestCoords[2].y = DestCoords[3].y = BottomRect; 698 // Use IntGdiPolyPolygon so to support PATH. 699 ret = IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1); 700 } 701 else 702 { 703 ret = IntRectangle(dc, LeftRect, TopRect, RightRect, BottomRect ); 704 } 705 706 DC_UnlockDc(dc); 707 708 return ret; 709 } 710 711 712 BOOL 713 FASTCALL 714 IntRoundRect( 715 PDC dc, 716 int Left, 717 int Top, 718 int Right, 719 int Bottom, 720 int xCurveDiameter, 721 int yCurveDiameter) 722 { 723 PDC_ATTR pdcattr; 724 PBRUSH pbrLine, pbrFill; 725 RECTL RectBounds; 726 LONG PenWidth, PenOrigWidth; 727 BOOL ret = TRUE; // Default to success 728 BRUSH brushTemp; 729 730 ASSERT ( dc ); // Caller's responsibility to set this up 731 732 if ( PATH_IsPathOpen(dc->dclevel) ) 733 return PATH_RoundRect ( dc, Left, Top, Right, Bottom, 734 xCurveDiameter, yCurveDiameter ); 735 736 if ((Left == Right) || (Top == Bottom)) return TRUE; 737 738 xCurveDiameter = max(abs( xCurveDiameter ), 1); 739 yCurveDiameter = max(abs( yCurveDiameter ), 1); 740 741 if (Right < Left) 742 { 743 INT tmp = Right; Right = Left; Left = tmp; 744 } 745 if (Bottom < Top) 746 { 747 INT tmp = Bottom; Bottom = Top; Top = tmp; 748 } 749 750 pdcattr = dc->pdcattr; 751 752 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 753 DC_vUpdateFillBrush(dc); 754 755 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 756 DC_vUpdateLineBrush(dc); 757 758 pbrLine = PEN_ShareLockPen(pdcattr->hpen); 759 if (!pbrLine) 760 { 761 /* Nothing to do, as we don't have a bitmap */ 762 EngSetLastError(ERROR_INTERNAL_ERROR); 763 return FALSE; 764 } 765 766 PenOrigWidth = PenWidth = pbrLine->lWidth; 767 if (pbrLine->ulPenStyle == PS_NULL) PenWidth = 0; 768 769 if (pbrLine->ulPenStyle == PS_INSIDEFRAME) 770 { 771 if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2; 772 if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2; 773 Left += PenWidth / 2; 774 Right -= (PenWidth - 1) / 2; 775 Top += PenWidth / 2; 776 Bottom -= (PenWidth - 1) / 2; 777 } 778 779 if (!PenWidth) PenWidth = 1; 780 pbrLine->lWidth = PenWidth; 781 782 RectBounds.left = Left; 783 RectBounds.top = Top; 784 RectBounds.right = Right; 785 RectBounds.bottom = Bottom; 786 787 IntLPtoDP(dc, (LPPOINT)&RectBounds, 2); 788 789 RectBounds.left += dc->ptlDCOrig.x; 790 RectBounds.top += dc->ptlDCOrig.y; 791 RectBounds.right += dc->ptlDCOrig.x; 792 RectBounds.bottom += dc->ptlDCOrig.y; 793 794 pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush); 795 if (!pbrFill) 796 { 797 DPRINT1("FillRound Fail\n"); 798 EngSetLastError(ERROR_INTERNAL_ERROR); 799 ret = FALSE; 800 } 801 else 802 { 803 804 DC_vPrepareDCsForBlit(dc, &RectBounds, NULL, NULL); 805 806 RtlCopyMemory(&brushTemp, pbrFill, sizeof(brushTemp)); 807 brushTemp.ptOrigin.x += RectBounds.left - Left; 808 brushTemp.ptOrigin.y += RectBounds.top - Top; 809 ret = IntFillRoundRect( dc, 810 RectBounds.left, 811 RectBounds.top, 812 RectBounds.right, 813 RectBounds.bottom, 814 xCurveDiameter, 815 yCurveDiameter, 816 &brushTemp); 817 BRUSH_ShareUnlockBrush(pbrFill); 818 819 if (ret) 820 { 821 ret = IntDrawRoundRect( dc, 822 RectBounds.left, 823 RectBounds.top, 824 RectBounds.right, 825 RectBounds.bottom, 826 xCurveDiameter, 827 yCurveDiameter, 828 pbrLine); 829 } 830 831 DC_vFinishBlit(dc, NULL); 832 } 833 834 835 pbrLine->lWidth = PenOrigWidth; 836 PEN_ShareUnlockPen(pbrLine); 837 return ret; 838 } 839 840 BOOL 841 APIENTRY 842 NtGdiRoundRect( 843 HDC hDC, 844 int LeftRect, 845 int TopRect, 846 int RightRect, 847 int BottomRect, 848 int Width, 849 int Height) 850 { 851 DC *dc = DC_LockDc(hDC); 852 BOOL ret = FALSE; /* Default to failure */ 853 854 DPRINT("NtGdiRoundRect(0x%p,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height); 855 if ( !dc ) 856 { 857 DPRINT1("NtGdiRoundRect() - hDC is invalid\n"); 858 EngSetLastError(ERROR_INVALID_HANDLE); 859 } 860 else 861 { 862 ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height ); 863 DC_UnlockDc ( dc ); 864 } 865 866 return ret; 867 } 868 869 BOOL 870 NTAPI 871 GreGradientFill( 872 HDC hdc, 873 PTRIVERTEX pVertex, 874 ULONG nVertex, 875 PVOID pMesh, 876 ULONG nMesh, 877 ULONG ulMode) 878 { 879 PDC pdc; 880 SURFACE *psurf; 881 EXLATEOBJ exlo; 882 RECTL rclExtent; 883 POINTL ptlDitherOrg; 884 ULONG i; 885 BOOL bRet; 886 887 /* Check parameters */ 888 if (ulMode & GRADIENT_FILL_TRIANGLE) 889 { 890 PGRADIENT_TRIANGLE pTriangle = (PGRADIENT_TRIANGLE)pMesh; 891 892 for (i = 0; i < nMesh; i++, pTriangle++) 893 { 894 if (pTriangle->Vertex1 >= nVertex || 895 pTriangle->Vertex2 >= nVertex || 896 pTriangle->Vertex3 >= nVertex) 897 { 898 EngSetLastError(ERROR_INVALID_PARAMETER); 899 return FALSE; 900 } 901 } 902 } 903 else 904 { 905 PGRADIENT_RECT pRect = (PGRADIENT_RECT)pMesh; 906 for (i = 0; i < nMesh; i++, pRect++) 907 { 908 if (pRect->UpperLeft >= nVertex || pRect->LowerRight >= nVertex) 909 { 910 EngSetLastError(ERROR_INVALID_PARAMETER); 911 return FALSE; 912 } 913 } 914 } 915 916 /* Lock the output DC */ 917 pdc = DC_LockDc(hdc); 918 if(!pdc) 919 { 920 EngSetLastError(ERROR_INVALID_HANDLE); 921 return FALSE; 922 } 923 924 if (!pdc->dclevel.pSurface) 925 { 926 /* Memory DC with no surface selected */ 927 DC_UnlockDc(pdc); 928 return TRUE; // CHECKME 929 } 930 931 /* Calculate extent */ 932 rclExtent.left = rclExtent.right = pVertex->x; 933 rclExtent.top = rclExtent.bottom = pVertex->y; 934 for (i = 0; i < nVertex; i++) 935 { 936 rclExtent.left = min(rclExtent.left, (pVertex + i)->x); 937 rclExtent.right = max(rclExtent.right, (pVertex + i)->x); 938 rclExtent.top = min(rclExtent.top, (pVertex + i)->y); 939 rclExtent.bottom = max(rclExtent.bottom, (pVertex + i)->y); 940 } 941 IntLPtoDP(pdc, (LPPOINT)&rclExtent, 2); 942 943 rclExtent.left += pdc->ptlDCOrig.x; 944 rclExtent.right += pdc->ptlDCOrig.x; 945 rclExtent.top += pdc->ptlDCOrig.y; 946 rclExtent.bottom += pdc->ptlDCOrig.y; 947 948 if (RECTL_bIsEmptyRect(&rclExtent)) 949 { 950 DC_UnlockDc(pdc); 951 return TRUE; 952 } 953 954 ptlDitherOrg.x = ptlDitherOrg.y = 0; 955 IntLPtoDP(pdc, (LPPOINT)&ptlDitherOrg, 1); 956 957 ptlDitherOrg.x += pdc->ptlDCOrig.x; 958 ptlDitherOrg.y += pdc->ptlDCOrig.y; 959 960 if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 961 { 962 IntUpdateBoundsRect(pdc, &rclExtent); 963 } 964 965 DC_vPrepareDCsForBlit(pdc, &rclExtent, NULL, NULL); 966 967 psurf = pdc->dclevel.pSurface; 968 969 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0, 0); 970 971 bRet = IntEngGradientFill(&psurf->SurfObj, 972 (CLIPOBJ *)&pdc->co, 973 &exlo.xlo, 974 pVertex, 975 nVertex, 976 pMesh, 977 nMesh, 978 &rclExtent, 979 &ptlDitherOrg, 980 ulMode); 981 982 EXLATEOBJ_vCleanup(&exlo); 983 DC_vFinishBlit(pdc, NULL); 984 DC_UnlockDc(pdc); 985 986 return bRet; 987 } 988 989 BOOL 990 APIENTRY 991 NtGdiGradientFill( 992 HDC hdc, 993 PTRIVERTEX pVertex, 994 ULONG nVertex, 995 PVOID pMesh, 996 ULONG nMesh, 997 ULONG ulMode) 998 { 999 BOOL bRet; 1000 PTRIVERTEX SafeVertex; 1001 PVOID SafeMesh; 1002 ULONG cbVertex, cbMesh; 1003 1004 /* Validate parameters */ 1005 if (!pVertex || !nVertex || !pMesh || !nMesh) 1006 { 1007 EngSetLastError(ERROR_INVALID_PARAMETER); 1008 return FALSE; 1009 } 1010 1011 switch (ulMode) 1012 { 1013 case GRADIENT_FILL_RECT_H: 1014 case GRADIENT_FILL_RECT_V: 1015 cbMesh = nMesh * sizeof(GRADIENT_RECT); 1016 break; 1017 case GRADIENT_FILL_TRIANGLE: 1018 cbMesh = nMesh * sizeof(GRADIENT_TRIANGLE); 1019 break; 1020 default: 1021 EngSetLastError(ERROR_INVALID_PARAMETER); 1022 return FALSE; 1023 } 1024 1025 cbVertex = nVertex * sizeof(TRIVERTEX) ; 1026 if(cbVertex + cbMesh <= cbVertex) 1027 { 1028 /* Overflow */ 1029 return FALSE ; 1030 } 1031 1032 /* Allocate a kernel mode buffer */ 1033 SafeVertex = ExAllocatePoolWithTag(PagedPool, cbVertex + cbMesh, TAG_SHAPE); 1034 if(!SafeVertex) 1035 { 1036 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 1037 return FALSE; 1038 } 1039 1040 SafeMesh = (PVOID)((ULONG_PTR)SafeVertex + cbVertex); 1041 1042 /* Copy the parameters to kernel mode */ 1043 _SEH2_TRY 1044 { 1045 ProbeForRead(pVertex, cbVertex, 1); 1046 ProbeForRead(pMesh, cbMesh, 1); 1047 RtlCopyMemory(SafeVertex, pVertex, cbVertex); 1048 RtlCopyMemory(SafeMesh, pMesh, cbMesh); 1049 } 1050 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1051 { 1052 ExFreePoolWithTag(SafeVertex, TAG_SHAPE); 1053 SetLastNtError(_SEH2_GetExceptionCode()); 1054 _SEH2_YIELD(return FALSE;) 1055 } 1056 _SEH2_END; 1057 1058 /* Call the internal function */ 1059 bRet = GreGradientFill(hdc, SafeVertex, nVertex, SafeMesh, nMesh, ulMode); 1060 1061 /* Cleanup and return result */ 1062 ExFreePoolWithTag(SafeVertex, TAG_SHAPE); 1063 return bRet; 1064 } 1065 1066 BOOL APIENTRY 1067 NtGdiExtFloodFill( 1068 HDC hDC, 1069 INT XStart, 1070 INT YStart, 1071 COLORREF Color, 1072 UINT FillType) 1073 { 1074 PDC dc; 1075 #if 0 1076 PDC_ATTR pdcattr; 1077 #endif 1078 SURFACE *psurf; 1079 EXLATEOBJ exlo; 1080 BOOL Ret = FALSE; 1081 RECTL DestRect; 1082 POINTL Pt; 1083 ULONG ConvColor; 1084 1085 dc = DC_LockDc(hDC); 1086 if (!dc) 1087 { 1088 EngSetLastError(ERROR_INVALID_HANDLE); 1089 return FALSE; 1090 } 1091 1092 if (!dc->dclevel.pSurface) 1093 { 1094 Ret = TRUE; 1095 goto cleanup; 1096 } 1097 1098 #if 0 1099 pdcattr = dc->pdcattr; 1100 #endif 1101 1102 Pt.x = XStart; 1103 Pt.y = YStart; 1104 IntLPtoDP(dc, (LPPOINT)&Pt, 1); 1105 1106 DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL); 1107 1108 /// FIXME: what about prgnVIS? And what about REAL clipping? 1109 psurf = dc->dclevel.pSurface; 1110 if (dc->prgnRao) 1111 { 1112 Ret = REGION_PtInRegion(dc->prgnRao, Pt.x, Pt.y); 1113 if (Ret) 1114 REGION_GetRgnBox(dc->prgnRao, (LPRECT)&DestRect); 1115 else 1116 { 1117 DC_vFinishBlit(dc, NULL); 1118 goto cleanup; 1119 } 1120 } 1121 else 1122 { 1123 RECTL_vSetRect(&DestRect, 0, 0, psurf->SurfObj.sizlBitmap.cx, psurf->SurfObj.sizlBitmap.cy); 1124 } 1125 1126 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 1127 { 1128 IntUpdateBoundsRect(dc, &DestRect); 1129 } 1130 1131 EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0xffffff, 0); 1132 1133 /* Only solid fills supported for now 1134 * How to support pattern brushes and non standard surfaces (not offering dib functions): 1135 * Version a (most likely slow): call DrvPatBlt for every pixel 1136 * Version b: create a flood mask and let MaskBlt blit a masked brush */ 1137 ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color); 1138 Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType); 1139 1140 DC_vFinishBlit(dc, NULL); 1141 1142 EXLATEOBJ_vCleanup(&exlo); 1143 1144 cleanup: 1145 DC_UnlockDc(dc); 1146 return Ret; 1147 } 1148 1149 /* EOF */ 1150