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