1 /* 2 * PROJECT: ReactOS Win32k Subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/line.c 5 * PURPOSE: Line functions 6 * PROGRAMMERS: ... 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 DBG_DEFAULT_CHANNEL(GdiLine); 15 16 // Some code from the WINE project source (www.winehq.com) 17 18 VOID FASTCALL 19 AddPenLinesBounds(PDC dc, int count, POINT *points) 20 { 21 DWORD join, endcap; 22 RECTL bounds, rect; 23 LONG lWidth; 24 PBRUSH pbrLine; 25 26 /* Get BRUSH from current pen. */ 27 pbrLine = dc->dclevel.pbrLine; 28 ASSERT(pbrLine); 29 30 lWidth = 0; 31 32 // Setup bounds 33 bounds.left = bounds.top = INT_MAX; 34 bounds.right = bounds.bottom = INT_MIN; 35 36 if (((pbrLine->ulPenStyle & PS_TYPE_MASK) & PS_GEOMETRIC) || pbrLine->lWidth > 1) 37 { 38 /* Windows uses some heuristics to estimate the distance from the point that will be painted */ 39 lWidth = pbrLine->lWidth + 2; 40 endcap = (PS_ENDCAP_MASK & pbrLine->ulPenStyle); 41 join = (PS_JOIN_MASK & pbrLine->ulPenStyle); 42 if (join == PS_JOIN_MITER) 43 { 44 lWidth *= 5; 45 if (endcap == PS_ENDCAP_SQUARE) lWidth = (lWidth * 3 + 1) / 2; 46 } 47 else 48 { 49 if (endcap == PS_ENDCAP_SQUARE) lWidth -= lWidth / 4; 50 else lWidth = (lWidth + 1) / 2; 51 } 52 } 53 54 while (count-- > 0) 55 { 56 rect.left = points->x - lWidth; 57 rect.top = points->y - lWidth; 58 rect.right = points->x + lWidth + 1; 59 rect.bottom = points->y + lWidth + 1; 60 RECTL_bUnionRect(&bounds, &bounds, &rect); 61 points++; 62 } 63 64 DPRINT("APLB dc %p l %d t %d\n",dc,rect.left,rect.top); 65 DPRINT(" r %d b %d\n",rect.right,rect.bottom); 66 67 { 68 RECTL rcRgn = dc->erclClip; // Use the clip box for now. 69 70 if (RECTL_bIntersectRect( &rcRgn, &rcRgn, &bounds )) 71 IntUpdateBoundsRect(dc, &rcRgn); 72 else 73 IntUpdateBoundsRect(dc, &bounds); 74 } 75 } 76 77 // Should use Fx in Point 78 // 79 BOOL FASTCALL 80 IntGdiMoveToEx(DC *dc, 81 int X, 82 int Y, 83 LPPOINT Point) 84 { 85 PDC_ATTR pdcattr = dc->pdcattr; 86 if ( Point ) 87 { 88 if ( pdcattr->ulDirty_ & DIRTY_PTLCURRENT ) // Double hit! 89 { 90 Point->x = pdcattr->ptfxCurrent.x; // ret prev before change. 91 Point->y = pdcattr->ptfxCurrent.y; 92 IntDPtoLP ( dc, Point, 1); // Reconvert back. 93 } 94 else 95 { 96 Point->x = pdcattr->ptlCurrent.x; 97 Point->y = pdcattr->ptlCurrent.y; 98 } 99 } 100 pdcattr->ptlCurrent.x = X; 101 pdcattr->ptlCurrent.y = Y; 102 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 103 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 104 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 105 106 return TRUE; 107 } 108 109 BOOL FASTCALL 110 GreMoveTo( HDC hdc, 111 INT x, 112 INT y, 113 LPPOINT pptOut) 114 { 115 BOOL Ret; 116 PDC dc; 117 if (!(dc = DC_LockDc(hdc))) 118 { 119 EngSetLastError(ERROR_INVALID_HANDLE); 120 return FALSE; 121 } 122 Ret = IntGdiMoveToEx(dc, x, y, pptOut); 123 DC_UnlockDc(dc); 124 return Ret; 125 } 126 127 // Should use Fx in pt 128 // 129 VOID FASTCALL 130 IntGetCurrentPositionEx(PDC dc, LPPOINT pt) 131 { 132 PDC_ATTR pdcattr = dc->pdcattr; 133 134 if ( pt ) 135 { 136 if (pdcattr->ulDirty_ & DIRTY_PTFXCURRENT) 137 { 138 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 139 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 140 pdcattr->ulDirty_ &= ~(DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 141 } 142 pt->x = pdcattr->ptlCurrent.x; 143 pt->y = pdcattr->ptlCurrent.y; 144 } 145 } 146 147 BOOL FASTCALL 148 IntGdiLineTo(DC *dc, 149 int XEnd, 150 int YEnd) 151 { 152 SURFACE *psurf; 153 BOOL Ret = TRUE; 154 PBRUSH pbrLine; 155 RECTL Bounds; 156 POINT Points[2]; 157 PDC_ATTR pdcattr; 158 PPATH pPath; 159 160 ASSERT_DC_PREPARED(dc); 161 162 pdcattr = dc->pdcattr; 163 164 if (PATH_IsPathOpen(dc->dclevel)) 165 { 166 Ret = PATH_LineTo(dc, XEnd, YEnd); 167 } 168 else 169 { 170 psurf = dc->dclevel.pSurface; 171 if (NULL == psurf) 172 { 173 EngSetLastError(ERROR_INVALID_HANDLE); 174 return FALSE; 175 } 176 177 Points[0].x = pdcattr->ptlCurrent.x; 178 Points[0].y = pdcattr->ptlCurrent.y; 179 Points[1].x = XEnd; 180 Points[1].y = YEnd; 181 182 IntLPtoDP(dc, Points, 2); 183 184 /* The DCOrg is in device coordinates */ 185 Points[0].x += dc->ptlDCOrig.x; 186 Points[0].y += dc->ptlDCOrig.y; 187 Points[1].x += dc->ptlDCOrig.x; 188 Points[1].y += dc->ptlDCOrig.y; 189 190 Bounds.left = min(Points[0].x, Points[1].x); 191 Bounds.top = min(Points[0].y, Points[1].y); 192 Bounds.right = max(Points[0].x, Points[1].x); 193 Bounds.bottom = max(Points[0].y, Points[1].y); 194 195 /* Get BRUSH from current pen. */ 196 pbrLine = dc->dclevel.pbrLine; 197 ASSERT(pbrLine); 198 199 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 200 { 201 DPRINT("Bounds dc %p l %d t %d\n",dc,Bounds.left,Bounds.top); 202 DPRINT(" r %d b %d\n",Bounds.right,Bounds.bottom); 203 AddPenLinesBounds(dc, 2, Points); 204 } 205 206 if (!(pbrLine->flAttrs & BR_IS_NULL)) 207 { 208 if (IntIsEffectiveWidePen(pbrLine)) 209 { 210 /* Clear the path */ 211 PATH_Delete(dc->dclevel.hPath); 212 dc->dclevel.hPath = NULL; 213 214 /* Begin a path */ 215 pPath = PATH_CreatePath(2); 216 dc->dclevel.flPath |= DCPATH_ACTIVE; 217 dc->dclevel.hPath = pPath->BaseObject.hHmgr; 218 IntGetCurrentPositionEx(dc, &pPath->pos); 219 IntLPtoDP(dc, &pPath->pos, 1); 220 221 PATH_MoveTo(dc, pPath); 222 PATH_LineTo(dc, XEnd, YEnd); 223 224 /* Close the path */ 225 pPath->state = PATH_Closed; 226 dc->dclevel.flPath &= ~DCPATH_ACTIVE; 227 228 /* Actually stroke a path */ 229 Ret = PATH_StrokePath(dc, pPath); 230 231 /* Clear the path */ 232 PATH_UnlockPath(pPath); 233 PATH_Delete(dc->dclevel.hPath); 234 dc->dclevel.hPath = NULL; 235 } 236 else 237 { 238 Ret = IntEngLineTo(&psurf->SurfObj, 239 (CLIPOBJ *)&dc->co, 240 &dc->eboLine.BrushObject, 241 Points[0].x, Points[0].y, 242 Points[1].x, Points[1].y, 243 &Bounds, 244 ROP2_TO_MIX(pdcattr->jROP2)); 245 } 246 } 247 } 248 249 if (Ret) 250 { 251 pdcattr->ptlCurrent.x = XEnd; 252 pdcattr->ptlCurrent.y = YEnd; 253 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 254 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 255 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 256 } 257 258 return Ret; 259 } 260 261 BOOL FASTCALL 262 IntGdiPolyBezier(DC *dc, 263 LPPOINT pt, 264 DWORD Count) 265 { 266 BOOL ret = FALSE; // Default to FAILURE 267 268 if ( PATH_IsPathOpen(dc->dclevel) ) 269 { 270 return PATH_PolyBezier ( dc, pt, Count ); 271 } 272 273 /* We'll convert it into line segments and draw them using Polyline */ 274 { 275 POINT *Pts; 276 INT nOut; 277 278 Pts = GDI_Bezier ( pt, Count, &nOut ); 279 if ( Pts ) 280 { 281 ret = IntGdiPolyline(dc, Pts, nOut); 282 ExFreePoolWithTag(Pts, TAG_BEZIER); 283 } 284 } 285 286 return ret; 287 } 288 289 BOOL FASTCALL 290 IntGdiPolyBezierTo(DC *dc, 291 LPPOINT pt, 292 DWORD Count) 293 { 294 BOOL ret = FALSE; // Default to failure 295 PDC_ATTR pdcattr = dc->pdcattr; 296 297 if ( PATH_IsPathOpen(dc->dclevel) ) 298 ret = PATH_PolyBezierTo ( dc, pt, Count ); 299 else /* We'll do it using PolyBezier */ 300 { 301 POINT *npt; 302 npt = ExAllocatePoolWithTag(PagedPool, 303 sizeof(POINT) * (Count + 1), 304 TAG_BEZIER); 305 if ( npt ) 306 { 307 npt[0].x = pdcattr->ptlCurrent.x; 308 npt[0].y = pdcattr->ptlCurrent.y; 309 memcpy(npt + 1, pt, sizeof(POINT) * Count); 310 ret = IntGdiPolyBezier(dc, npt, Count+1); 311 ExFreePoolWithTag(npt, TAG_BEZIER); 312 } 313 } 314 if ( ret ) 315 { 316 pdcattr->ptlCurrent.x = pt[Count-1].x; 317 pdcattr->ptlCurrent.y = pt[Count-1].y; 318 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 319 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 320 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 321 } 322 323 return ret; 324 } 325 326 BOOL FASTCALL 327 IntGdiPolyline(DC *dc, 328 LPPOINT pt, 329 int Count) 330 { 331 SURFACE *psurf; 332 BRUSH *pbrLine; 333 LPPOINT Points; 334 BOOL Ret = TRUE; 335 LONG i; 336 PDC_ATTR pdcattr = dc->pdcattr; 337 PPATH pPath; 338 339 if (!dc->dclevel.pSurface) 340 { 341 return TRUE; 342 } 343 344 DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL); 345 psurf = dc->dclevel.pSurface; 346 347 /* Get BRUSHOBJ from current pen. */ 348 pbrLine = dc->dclevel.pbrLine; 349 ASSERT(pbrLine); 350 351 if (!(pbrLine->flAttrs & BR_IS_NULL)) 352 { 353 Points = EngAllocMem(0, Count * sizeof(POINT), GDITAG_TEMP); 354 if (Points != NULL) 355 { 356 RtlCopyMemory(Points, pt, Count * sizeof(POINT)); 357 IntLPtoDP(dc, Points, Count); 358 359 /* Offset the array of points by the DC origin */ 360 for (i = 0; i < Count; i++) 361 { 362 Points[i].x += dc->ptlDCOrig.x; 363 Points[i].y += dc->ptlDCOrig.y; 364 } 365 366 if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR)) 367 { 368 AddPenLinesBounds(dc, Count, Points); 369 } 370 371 if (IntIsEffectiveWidePen(pbrLine)) 372 { 373 /* Clear the path */ 374 PATH_Delete(dc->dclevel.hPath); 375 dc->dclevel.hPath = NULL; 376 377 /* Begin a path */ 378 pPath = PATH_CreatePath(Count); 379 dc->dclevel.flPath |= DCPATH_ACTIVE; 380 dc->dclevel.hPath = pPath->BaseObject.hHmgr; 381 pPath->pos = pt[0]; 382 IntLPtoDP(dc, &pPath->pos, 1); 383 384 PATH_MoveTo(dc, pPath); 385 for (i = 1; i < Count; ++i) 386 { 387 PATH_LineTo(dc, pt[i].x, pt[i].y); 388 } 389 390 /* Close the path */ 391 pPath->state = PATH_Closed; 392 dc->dclevel.flPath &= ~DCPATH_ACTIVE; 393 394 /* Actually stroke a path */ 395 Ret = PATH_StrokePath(dc, pPath); 396 397 /* Clear the path */ 398 PATH_UnlockPath(pPath); 399 PATH_Delete(dc->dclevel.hPath); 400 dc->dclevel.hPath = NULL; 401 } 402 else 403 { 404 Ret = IntEngPolyline(&psurf->SurfObj, 405 (CLIPOBJ *)&dc->co, 406 &dc->eboLine.BrushObject, 407 Points, 408 Count, 409 ROP2_TO_MIX(pdcattr->jROP2)); 410 } 411 EngFreeMem(Points); 412 } 413 else 414 { 415 Ret = FALSE; 416 } 417 } 418 419 DC_vFinishBlit(dc, NULL); 420 421 return Ret; 422 } 423 424 BOOL FASTCALL 425 IntGdiPolylineTo(DC *dc, 426 LPPOINT pt, 427 DWORD Count) 428 { 429 BOOL ret = FALSE; // Default to failure 430 PDC_ATTR pdcattr = dc->pdcattr; 431 432 if (PATH_IsPathOpen(dc->dclevel)) 433 { 434 ret = PATH_PolylineTo(dc, pt, Count); 435 } 436 else /* Do it using Polyline */ 437 { 438 POINT *pts = ExAllocatePoolWithTag(PagedPool, 439 sizeof(POINT) * (Count + 1), 440 TAG_SHAPE); 441 if ( pts ) 442 { 443 pts[0].x = pdcattr->ptlCurrent.x; 444 pts[0].y = pdcattr->ptlCurrent.y; 445 memcpy( pts + 1, pt, sizeof(POINT) * Count); 446 ret = IntGdiPolyline(dc, pts, Count + 1); 447 ExFreePoolWithTag(pts, TAG_SHAPE); 448 } 449 } 450 if ( ret ) 451 { 452 pdcattr->ptlCurrent.x = pt[Count-1].x; 453 pdcattr->ptlCurrent.y = pt[Count-1].y; 454 pdcattr->ptfxCurrent = pdcattr->ptlCurrent; 455 CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx 456 pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE); 457 } 458 459 return ret; 460 } 461 462 463 BOOL FASTCALL 464 IntGdiPolyPolyline(DC *dc, 465 LPPOINT pt, 466 PULONG PolyPoints, 467 DWORD Count) 468 { 469 ULONG i; 470 LPPOINT pts; 471 PULONG pc; 472 BOOL ret = FALSE; // Default to failure 473 pts = pt; 474 pc = PolyPoints; 475 476 if (PATH_IsPathOpen(dc->dclevel)) 477 { 478 return PATH_PolyPolyline( dc, pt, PolyPoints, Count ); 479 } 480 for (i = 0; i < Count; i++) 481 { 482 ret = IntGdiPolyline ( dc, pts, *pc ); 483 if (ret == FALSE) 484 { 485 return ret; 486 } 487 pts+=*pc++; 488 } 489 490 return ret; 491 } 492 493 /******************************************************************************/ 494 495 BOOL 496 APIENTRY 497 NtGdiLineTo(HDC hDC, 498 int XEnd, 499 int YEnd) 500 { 501 DC *dc; 502 BOOL Ret; 503 RECT rcLockRect ; 504 505 dc = DC_LockDc(hDC); 506 if (!dc) 507 { 508 EngSetLastError(ERROR_INVALID_HANDLE); 509 return FALSE; 510 } 511 512 rcLockRect.left = dc->pdcattr->ptlCurrent.x; 513 rcLockRect.top = dc->pdcattr->ptlCurrent.y; 514 rcLockRect.right = XEnd; 515 rcLockRect.bottom = YEnd; 516 517 IntLPtoDP(dc, (PPOINT)&rcLockRect, 2); 518 519 /* The DCOrg is in device coordinates */ 520 rcLockRect.left += dc->ptlDCOrig.x; 521 rcLockRect.top += dc->ptlDCOrig.y; 522 rcLockRect.right += dc->ptlDCOrig.x; 523 rcLockRect.bottom += dc->ptlDCOrig.y; 524 525 DC_vPrepareDCsForBlit(dc, &rcLockRect, NULL, NULL); 526 527 Ret = IntGdiLineTo(dc, XEnd, YEnd); 528 529 DC_vFinishBlit(dc, NULL); 530 531 DC_UnlockDc(dc); 532 return Ret; 533 } 534 535 // FIXME: This function is completely broken 536 static 537 BOOL 538 GdiPolyDraw( 539 IN HDC hdc, 540 IN LPPOINT lppt, 541 IN LPBYTE lpbTypes, 542 IN ULONG cCount) 543 { 544 PDC dc; 545 PDC_ATTR pdcattr; 546 POINT bzr[4]; 547 volatile PPOINT line_pts, line_pts_old, bzr_pts; 548 INT num_pts, num_bzr_pts, space, space_old, size; 549 ULONG i; 550 BOOL result = FALSE; 551 552 dc = DC_LockDc(hdc); 553 if (!dc) return FALSE; 554 pdcattr = dc->pdcattr; 555 556 if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)) 557 DC_vUpdateFillBrush(dc); 558 559 if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY)) 560 DC_vUpdateLineBrush(dc); 561 562 if (!cCount) 563 { 564 DC_UnlockDc(dc); 565 return TRUE; 566 } 567 568 line_pts = NULL; 569 line_pts_old = NULL; 570 bzr_pts = NULL; 571 572 { 573 if (PATH_IsPathOpen(dc->dclevel)) 574 { 575 result = PATH_PolyDraw(dc, (const POINT *)lppt, (const BYTE *)lpbTypes, cCount); 576 goto Cleanup; 577 } 578 579 /* Check for valid point types */ 580 for (i = 0; i < cCount; i++) 581 { 582 switch (lpbTypes[i]) 583 { 584 case PT_MOVETO: 585 case PT_LINETO | PT_CLOSEFIGURE: 586 case PT_LINETO: 587 break; 588 case PT_BEZIERTO: 589 if((i + 2 < cCount) && (lpbTypes[i + 1] == PT_BEZIERTO) && 590 ((lpbTypes[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)) 591 { 592 i += 2; 593 break; 594 } 595 default: 596 goto Cleanup; 597 } 598 } 599 600 space = cCount + 300; 601 line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE); 602 if (line_pts == NULL) 603 { 604 result = FALSE; 605 goto Cleanup; 606 } 607 608 num_pts = 1; 609 610 line_pts[0].x = pdcattr->ptlCurrent.x; 611 line_pts[0].y = pdcattr->ptlCurrent.y; 612 613 for ( i = 0; i < cCount; i++ ) 614 { 615 switch (lpbTypes[i]) 616 { 617 case PT_MOVETO: 618 if (num_pts >= 2) IntGdiPolyline( dc, line_pts, num_pts ); 619 num_pts = 0; 620 line_pts[num_pts++] = lppt[i]; 621 break; 622 case PT_LINETO: 623 case (PT_LINETO | PT_CLOSEFIGURE): 624 line_pts[num_pts++] = lppt[i]; 625 break; 626 case PT_BEZIERTO: 627 bzr[0].x = line_pts[num_pts - 1].x; 628 bzr[0].y = line_pts[num_pts - 1].y; 629 RtlCopyMemory( &bzr[1], &lppt[i], 3 * sizeof(POINT) ); 630 631 if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts ))) 632 { 633 size = num_pts + (cCount - i) + num_bzr_pts; 634 if (space < size) 635 { 636 space_old = space; 637 space = size * 2; 638 line_pts_old = line_pts; 639 line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE); 640 if (!line_pts) goto Cleanup; 641 RtlCopyMemory(line_pts, line_pts_old, space_old * sizeof(POINT)); 642 ExFreePoolWithTag(line_pts_old, TAG_SHAPE); 643 line_pts_old = NULL; 644 } 645 RtlCopyMemory( &line_pts[num_pts], &bzr_pts[1], (num_bzr_pts - 1) * sizeof(POINT) ); 646 num_pts += num_bzr_pts - 1; 647 ExFreePoolWithTag(bzr_pts, TAG_BEZIER); 648 bzr_pts = NULL; 649 } 650 i += 2; 651 break; 652 } 653 if (lpbTypes[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0]; 654 } 655 656 if (num_pts >= 2) IntGdiPolyline( dc, line_pts, num_pts ); 657 IntGdiMoveToEx( dc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL ); 658 result = TRUE; 659 } 660 661 Cleanup: 662 663 if (line_pts != NULL) 664 { 665 ExFreePoolWithTag(line_pts, TAG_SHAPE); 666 } 667 668 if ((line_pts_old != NULL) && (line_pts_old != line_pts)) 669 { 670 ExFreePoolWithTag(line_pts_old, TAG_SHAPE); 671 } 672 673 if (bzr_pts != NULL) 674 { 675 ExFreePoolWithTag(bzr_pts, TAG_BEZIER); 676 } 677 678 DC_UnlockDc(dc); 679 680 return result; 681 } 682 683 __kernel_entry 684 W32KAPI 685 BOOL 686 APIENTRY 687 NtGdiPolyDraw( 688 _In_ HDC hdc, 689 _In_reads_(cpt) LPPOINT ppt, 690 _In_reads_(cpt) LPBYTE pjAttr, 691 _In_ ULONG cpt) 692 { 693 PBYTE pjBuffer; 694 PPOINT pptSafe; 695 PBYTE pjSafe; 696 SIZE_T cjSizePt; 697 BOOL bResult; 698 699 if (cpt == 0) 700 { 701 ERR("cpt is 0\n"); 702 return FALSE; 703 } 704 705 /* Validate that cpt isn't too large */ 706 if (cpt > ((MAXULONG - cpt) / sizeof(*ppt))) 707 { 708 ERR("cpt is too large\n", cpt); 709 return FALSE; 710 } 711 712 /* Calculate size for a buffer */ 713 cjSizePt = cpt * sizeof(*ppt); 714 ASSERT(cjSizePt + cpt > cjSizePt); 715 716 /* Allocate a buffer for all data */ 717 pjBuffer = ExAllocatePoolWithTag(PagedPool, cjSizePt + cpt, TAG_SHAPE); 718 if (pjBuffer == NULL) 719 { 720 ERR("Failed to allocate buffer\n"); 721 return FALSE; 722 } 723 724 pptSafe = (PPOINT)pjBuffer; 725 pjSafe = pjBuffer + cjSizePt; 726 727 _SEH2_TRY 728 { 729 ProbeArrayForRead(ppt, sizeof(*ppt), cpt, sizeof(ULONG)); 730 ProbeArrayForRead(pjAttr, sizeof(*pjAttr), cpt, sizeof(BYTE)); 731 732 /* Copy the arrays */ 733 RtlCopyMemory(pptSafe, ppt, cjSizePt); 734 RtlCopyMemory(pjSafe, pjAttr, cpt); 735 } 736 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 737 { 738 SetLastNtError(_SEH2_GetExceptionCode()); 739 bResult = FALSE; 740 goto Cleanup; 741 } 742 _SEH2_END; 743 744 /* Call the internal function */ 745 bResult = GdiPolyDraw(hdc, pptSafe, pjSafe, cpt); 746 747 Cleanup: 748 749 /* Free the buffer */ 750 ExFreePoolWithTag(pjBuffer, TAG_SHAPE); 751 752 return bResult; 753 } 754 755 /* 756 * @implemented 757 */ 758 _Success_(return != FALSE) 759 BOOL 760 APIENTRY 761 NtGdiMoveTo( 762 IN HDC hdc, 763 IN INT x, 764 IN INT y, 765 OUT OPTIONAL LPPOINT pptOut) 766 { 767 PDC pdc; 768 BOOL Ret; 769 POINT Point; 770 771 pdc = DC_LockDc(hdc); 772 if (!pdc) return FALSE; 773 774 Ret = IntGdiMoveToEx(pdc, x, y, &Point); 775 776 if (Ret && pptOut) 777 { 778 _SEH2_TRY 779 { 780 ProbeForWrite(pptOut, sizeof(POINT), 1); 781 RtlCopyMemory(pptOut, &Point, sizeof(POINT)); 782 } 783 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 784 { 785 SetLastNtError(_SEH2_GetExceptionCode()); 786 Ret = FALSE; // CHECKME: is this correct? 787 } 788 _SEH2_END; 789 } 790 791 DC_UnlockDc(pdc); 792 793 return Ret; 794 } 795 796 /* EOF */ 797