1 /* 2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Coordinate systems 5 * FILE: win32ss/gdi/ntgdi/coord.c 6 * PROGRAMERS: Timo Kreuzer (timo.kreuzer@rectos.org) 7 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 8 */ 9 10 /* Coordinate translation overview 11 * ------------------------------- 12 * 13 * Windows uses 3 different coordinate systems, referred to as world space, 14 * page space and device space. 15 * 16 * Device space: 17 * This is the coordinate system of the physical device that displays the 18 * graphics. One unit matches one pixel of the surface. The coordinate system 19 * is always orthogonal. 20 * 21 * Page space: 22 * This is the coordinate system on the screen or on the paper layout for 23 * printer devices. The coordinate system is also orthogonal but one unit 24 * does not necessarily match one pixel. Instead there are different mapping 25 * modes that can be set using SetMapMode() that specify how page space units 26 * are transformed into device space units. These mapping modes are: 27 * - MM_TEXT: One unit matches one unit in device space (one pixel) 28 * - MM_TWIPS One unit matches 1/20 point (1/1440 inch) 29 * - MM_LOMETRIC: One unit matches 0.1 millimeter 30 * - MM_HIMETRIC: One unit matches 0.01 millimeter 31 * - MM_LOENGLISH: One unit matches 0.01 inch 32 * - MM_HIENGLISH: One unit matches 0.001 inch 33 * - MM_ISOTROPIC: 34 * - MM_ANISOTROPIC: 35 * If the mapping mode is either MM_ISOTROPIC or MM_ANISOTROPIC, the actual 36 * transformation is calculated from the window and viewport extension. 37 * The window extension can be set using SetWindowExtEx() and describes the 38 * extents of an arbitrary window (not to confuse with the gui element!) in 39 * page space coordinates. 40 * The viewport extension can be set using SetViewportExtEx() and describes 41 * the extent of the same window in device space coordinates. If the mapping 42 * mode is MM_ISOTROPIC one of the viewport extensions can be adjusted by GDI 43 * to make sure the mapping stays isotropic, i.e. that it has the same x/y 44 * ratio as the window extension. 45 * 46 * World space: 47 * World space is the coordinate system that is used for all GDI drawing 48 * operations. The metrics of this coordinate system depend on the DCs 49 * graphics mode, which can be set using SetGraphicsMode(). 50 * If the graphics mode is GM_COMPATIBLE, world space is identical to page 51 * space and no additional transformation is applied. 52 * If the graphics mode is GM_ADVANCED, an arbitrary coordinate transformation 53 * can be set using SetWorldTransform(), which is applied to transform world 54 * space coordinates into page space coordinates. 55 * 56 * User mode data: 57 * All coordinate translation data is stored in the DC attribute, so the values 58 * might be invalid. This has to be taken into account. Values might also be 59 * zero, so when a division is made, the value has to be read first and then 60 * checked! This is true for both integer and floating point values, even if 61 * we cannot get floating point exceptions on x86, we can get them on all other 62 * architectures that use the FPU directly instead of emulation. 63 * The result of all operations might be completely random and invalid, if it was 64 * messed with in an illegal way in user mode. This is not a problem, since the 65 * result of coordinate transformations are never expected to be "valid" values. 66 * In the worst case, the drawing operation draws rubbish into the DC. 67 */ 68 69 /* INCLUDES ******************************************************************/ 70 71 #include <win32k.h> 72 73 #define NDEBUG 74 #include <debug.h> 75 C_ASSERT(sizeof(XFORML) == sizeof(XFORM)); 76 77 78 /* GLOBALS *******************************************************************/ 79 80 const MATRIX gmxIdentity = 81 { 82 FLOATOBJ_1, FLOATOBJ_0, 83 FLOATOBJ_0, FLOATOBJ_1, 84 FLOATOBJ_0, FLOATOBJ_0, 85 0, 0, XFORM_NO_TRANSLATION|XFORM_FORMAT_LTOL|XFORM_UNITY|XFORM_SCALE 86 }; 87 88 89 /* FUNCTIONS *****************************************************************/ 90 91 VOID 92 FASTCALL 93 DC_vFixIsotropicMapping(PDC pdc) 94 { 95 PDC_ATTR pdcattr; 96 LONG64 fx, fy; 97 LONG s; 98 SIZEL szlWindowExt, szlViewportExt; 99 ASSERT(pdc->pdcattr->iMapMode == MM_ISOTROPIC); 100 101 /* Get a pointer to the DC_ATTR */ 102 pdcattr = pdc->pdcattr; 103 104 /* Read the extents, we rely on non-null values */ 105 szlWindowExt = pdcattr->szlWindowExt; 106 szlViewportExt = pdcattr->szlViewportExt; 107 108 /* Check if all values are valid */ 109 if ((szlWindowExt.cx == 0) || (szlWindowExt.cy == 0) || 110 (szlViewportExt.cx == 0) || (szlViewportExt.cy == 0)) 111 { 112 /* Someone put rubbish into the fields, just ignore it. */ 113 return; 114 } 115 116 fx = abs((LONG64)szlWindowExt.cx * szlViewportExt.cy); 117 fy = abs((LONG64)szlWindowExt.cy * szlViewportExt.cx); 118 119 if (fx < fy) 120 { 121 s = (szlWindowExt.cy ^ szlViewportExt.cx) > 0 ? 1 : -1; 122 pdcattr->szlViewportExt.cx = (LONG)(fx * s / szlWindowExt.cy); 123 } 124 else if (fx > fy) 125 { 126 s = (szlWindowExt.cx ^ szlViewportExt.cy) > 0 ? 1 : -1; 127 pdcattr->szlViewportExt.cy = (LONG)(fy * s / szlWindowExt.cx); 128 } 129 130 /* Reset the flag */ 131 pdc->pdcattr->flXform &= ~PAGE_EXTENTS_CHANGED; 132 } 133 134 VOID 135 FASTCALL 136 DC_vGetPageToDevice(PDC pdc, MATRIX *pmx) 137 { 138 PDC_ATTR pdcattr = pdc->pdcattr; 139 PSIZEL pszlViewPortExt; 140 SIZEL szlWindowExt; 141 142 /* Get the viewport extension */ 143 pszlViewPortExt = DC_pszlViewportExt(pdc); 144 145 /* Copy the window extension, so no one can mess with it */ 146 szlWindowExt = pdcattr->szlWindowExt; 147 148 /* No shearing / rotation */ 149 FLOATOBJ_SetLong(&pmx->efM12, 0); 150 FLOATOBJ_SetLong(&pmx->efM21, 0); 151 152 /* Calculate scaling */ 153 if (szlWindowExt.cx != 0) 154 { 155 FLOATOBJ_SetLong(&pmx->efM11, pszlViewPortExt->cx); 156 FLOATOBJ_DivLong(&pmx->efM11, szlWindowExt.cx); 157 } 158 else 159 FLOATOBJ_SetLong(&pmx->efM11, 1); 160 161 if (szlWindowExt.cy != 0) 162 { 163 FLOATOBJ_SetLong(&pmx->efM22, pszlViewPortExt->cy); 164 FLOATOBJ_DivLong(&pmx->efM22, szlWindowExt.cy); 165 } 166 else 167 FLOATOBJ_SetLong(&pmx->efM22, 1); 168 169 /* Calculate x offset */ 170 FLOATOBJ_SetLong(&pmx->efDx, -pdcattr->ptlWindowOrg.x); 171 FLOATOBJ_Mul(&pmx->efDx, &pmx->efM11); 172 FLOATOBJ_AddLong(&pmx->efDx, pdcattr->ptlViewportOrg.x); 173 174 /* Calculate y offset */ 175 FLOATOBJ_SetLong(&pmx->efDy, -pdcattr->ptlWindowOrg.y); 176 FLOATOBJ_Mul(&pmx->efDy, &pmx->efM22); 177 FLOATOBJ_AddLong(&pmx->efDy, pdcattr->ptlViewportOrg.y); 178 } 179 180 VOID 181 FASTCALL 182 DC_vUpdateWorldToDevice(PDC pdc) 183 { 184 XFORMOBJ xoPageToDevice, xoWorldToPage, xoWorldToDevice; 185 MATRIX mxPageToDevice; 186 187 // FIXME: make sure world-to-page is valid! 188 189 /* Construct a transformation to do the page-to-device conversion */ 190 DC_vGetPageToDevice(pdc, &mxPageToDevice); 191 XFORMOBJ_vInit(&xoPageToDevice, &mxPageToDevice); 192 193 /* Recalculate the world-to-device xform */ 194 XFORMOBJ_vInit(&xoWorldToPage, &pdc->pdcattr->mxWorldToPage); 195 XFORMOBJ_vInit(&xoWorldToDevice, &pdc->pdcattr->mxWorldToDevice); 196 XFORMOBJ_iCombine(&xoWorldToDevice, &xoWorldToPage, &xoPageToDevice); 197 198 /* Reset the flags */ 199 pdc->pdcattr->flXform &= ~WORLD_XFORM_CHANGED; 200 } 201 202 VOID 203 FASTCALL 204 DC_vUpdateDeviceToWorld(PDC pdc) 205 { 206 XFORMOBJ xoWorldToDevice, xoDeviceToWorld; 207 PMATRIX pmxWorldToDevice; 208 209 /* Get the world-to-device translation */ 210 pmxWorldToDevice = DC_pmxWorldToDevice(pdc); 211 XFORMOBJ_vInit(&xoWorldToDevice, pmxWorldToDevice); 212 213 /* Create inverse of world-to-device transformation */ 214 XFORMOBJ_vInit(&xoDeviceToWorld, &pdc->pdcattr->mxDeviceToWorld); 215 if (XFORMOBJ_iInverse(&xoDeviceToWorld, &xoWorldToDevice) == DDI_ERROR) 216 { 217 MX_Set0(&pdc->pdcattr->mxDeviceToWorld); 218 return; 219 } 220 221 /* Reset the flag */ 222 pdc->pdcattr->flXform &= ~DEVICE_TO_WORLD_INVALID; 223 } 224 225 BOOL 226 NTAPI 227 GreCombineTransform( 228 XFORML *pxformDest, 229 XFORML *pxform1, 230 XFORML *pxform2) 231 { 232 MATRIX mxDest, mx1, mx2; 233 XFORMOBJ xoDest, xo1, xo2; 234 235 /* Check for illegal parameters */ 236 if (!pxformDest || !pxform1 || !pxform2) return FALSE; 237 238 /* Initialize XFORMOBJs */ 239 XFORMOBJ_vInit(&xoDest, &mxDest); 240 XFORMOBJ_vInit(&xo1, &mx1); 241 XFORMOBJ_vInit(&xo2, &mx2); 242 243 /* Convert the XFORMLs into XFORMOBJs */ 244 XFORMOBJ_iSetXform(&xo1, pxform1); 245 XFORMOBJ_iSetXform(&xo2, pxform2); 246 247 /* Combine them */ 248 XFORMOBJ_iCombine(&xoDest, &xo1, &xo2); 249 250 /* Translate back into XFORML */ 251 XFORMOBJ_iGetXform(&xoDest, pxformDest); 252 253 return TRUE; 254 } 255 256 BOOL 257 APIENTRY 258 NtGdiCombineTransform( 259 LPXFORM UnsafeXFormResult, 260 LPXFORM Unsafexform1, 261 LPXFORM Unsafexform2) 262 { 263 BOOL Ret; 264 265 _SEH2_TRY 266 { 267 ProbeForWrite(UnsafeXFormResult, sizeof(XFORM), 1); 268 ProbeForRead(Unsafexform1, sizeof(XFORM), 1); 269 ProbeForRead(Unsafexform2, sizeof(XFORM), 1); 270 Ret = GreCombineTransform((XFORML*)UnsafeXFormResult, 271 (XFORML*)Unsafexform1, 272 (XFORML*)Unsafexform2); 273 } 274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 275 { 276 Ret = FALSE; 277 } 278 _SEH2_END; 279 280 return Ret; 281 } 282 283 // FIXME: Should be XFORML and use XFORMOBJ functions directly 284 BOOL 285 APIENTRY 286 NtGdiGetTransform( 287 HDC hdc, 288 DWORD iXform, 289 LPXFORM pXForm) 290 { 291 PDC pdc; 292 BOOL ret = TRUE; 293 MATRIX mxPageToDevice; 294 XFORMOBJ xo; 295 PMATRIX pmx; 296 297 if (!pXForm) 298 { 299 EngSetLastError(ERROR_INVALID_PARAMETER); 300 return FALSE; 301 } 302 303 pdc = DC_LockDc(hdc); 304 if (!pdc) 305 { 306 EngSetLastError(ERROR_INVALID_HANDLE); 307 return FALSE; 308 } 309 310 switch (iXform) 311 { 312 case GdiWorldSpaceToPageSpace: 313 pmx = DC_pmxWorldToPage(pdc); 314 break; 315 316 case GdiWorldSpaceToDeviceSpace: 317 pmx = DC_pmxWorldToDevice(pdc); 318 break; 319 320 case GdiDeviceSpaceToWorldSpace: 321 pmx = DC_pmxDeviceToWorld(pdc); 322 break; 323 324 case GdiPageSpaceToDeviceSpace: 325 DC_vGetPageToDevice(pdc, &mxPageToDevice); 326 pmx = &mxPageToDevice; 327 break; 328 329 default: 330 DPRINT1("Unknown transform %lu\n", iXform); 331 ret = FALSE; 332 goto leave; 333 } 334 335 /* Initialize an XFORMOBJ */ 336 XFORMOBJ_vInit(&xo, pmx); 337 338 _SEH2_TRY 339 { 340 ProbeForWrite(pXForm, sizeof(XFORML), 1); 341 XFORMOBJ_iGetXform(&xo, (XFORML*)pXForm); 342 } 343 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 344 { 345 ret = FALSE; 346 } 347 _SEH2_END; 348 349 leave: 350 DC_UnlockDc(pdc); 351 return ret; 352 } 353 354 355 /*! 356 * Converts points from logical coordinates into device coordinates. 357 * Conversion depends on the mapping mode, 358 * world transfrom, viewport origin settings for the given device context. 359 * \param hDC device context. 360 * \param Points an array of POINT structures (in/out). 361 * \param Count number of elements in the array of POINT structures. 362 * \return TRUE if success, FALSE otherwise. 363 */ 364 BOOL 365 APIENTRY 366 NtGdiTransformPoints( 367 HDC hDC, 368 PPOINT UnsafePtsIn, 369 PPOINT UnsafePtOut, 370 INT Count, 371 INT iMode) 372 { 373 PDC pdc; 374 LPPOINT Points; 375 ULONG Size; 376 BOOL ret = TRUE; 377 378 if (Count <= 0) 379 return TRUE; 380 381 if (!UnsafePtsIn || !UnsafePtOut) 382 { 383 return FALSE; 384 } 385 386 pdc = DC_LockDc(hDC); 387 if (!pdc) 388 { 389 return FALSE; 390 } 391 392 Size = Count * sizeof(POINT); 393 394 // FIXME: It would be wise to have a small stack buffer as optimization 395 Points = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEMP); 396 if (!Points) 397 { 398 DC_UnlockDc(pdc); 399 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); 400 return FALSE; 401 } 402 403 _SEH2_TRY 404 { 405 ProbeForWrite(UnsafePtOut, Size, 1); 406 ProbeForRead(UnsafePtsIn, Size, 1); 407 RtlCopyMemory(Points, UnsafePtsIn, Size); 408 } 409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 410 { 411 /* Do not set last error */ 412 _SEH2_YIELD(goto leave;) 413 } 414 _SEH2_END; 415 416 switch (iMode) 417 { 418 case GdiDpToLp: 419 DC_vXformDeviceToWorld(pdc, Count, Points, Points); 420 break; 421 422 case GdiLpToDp: 423 DC_vXformWorldToDevice(pdc, Count, Points, Points); 424 break; 425 426 case 2: // Not supported yet. Need testing. 427 default: 428 { 429 EngSetLastError(ERROR_INVALID_PARAMETER); 430 ret = FALSE; 431 goto leave; 432 } 433 } 434 435 _SEH2_TRY 436 { 437 /* Pointer was already probed! */ 438 RtlCopyMemory(UnsafePtOut, Points, Size); 439 } 440 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 441 { 442 /* Do not set last error */ 443 ret = 0; 444 } 445 _SEH2_END; 446 447 // 448 // If we are getting called that means User XForms is a mess! 449 // 450 leave: 451 DC_UnlockDc(pdc); 452 ExFreePoolWithTag(Points, GDITAG_TEMP); 453 return ret; 454 } 455 456 BOOL 457 NTAPI 458 GreModifyWorldTransform( 459 PDC pdc, 460 const XFORML *pxform, 461 DWORD dwMode) 462 { 463 MATRIX mxSrc; 464 XFORMOBJ xoSrc, xoDC; 465 466 switch (dwMode) 467 { 468 case MWT_IDENTITY: 469 pdc->pdcattr->mxWorldToPage = gmxIdentity; 470 break; 471 472 case MWT_LEFTMULTIPLY: 473 XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage); 474 XFORMOBJ_vInit(&xoSrc, &mxSrc); 475 if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR) 476 return FALSE; 477 XFORMOBJ_iCombine(&xoDC, &xoSrc, &xoDC); 478 break; 479 480 case MWT_RIGHTMULTIPLY: 481 XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage); 482 XFORMOBJ_vInit(&xoSrc, &mxSrc); 483 if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR) 484 return FALSE; 485 XFORMOBJ_iCombine(&xoDC, &xoDC, &xoSrc); 486 break; 487 488 case MWT_SET: 489 XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage); 490 if (XFORMOBJ_iSetXform(&xoDC, pxform) == DDI_ERROR) 491 return FALSE; 492 break; 493 494 default: 495 return FALSE; 496 } 497 498 /*Set invalidation flags */ 499 pdc->pdcattr->flXform |= WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID; 500 501 return TRUE; 502 } 503 504 BOOL 505 APIENTRY 506 NtGdiModifyWorldTransform( 507 HDC hdc, 508 LPXFORM pxformUnsafe, 509 DWORD dwMode) 510 { 511 PDC pdc; 512 XFORML xformSafe; 513 BOOL Ret = TRUE; 514 515 pdc = DC_LockDc(hdc); 516 if (!pdc) 517 { 518 EngSetLastError(ERROR_INVALID_HANDLE); 519 return FALSE; 520 } 521 522 /* The xform is permitted to be NULL for MWT_IDENTITY. 523 * However, if it is not NULL, then it must be valid even 524 * though it is not used. */ 525 if ((dwMode != MWT_IDENTITY) && (pxformUnsafe == NULL)) 526 { 527 DC_UnlockDc(pdc); 528 return FALSE; 529 } 530 531 if (pxformUnsafe != NULL) 532 { 533 _SEH2_TRY 534 { 535 ProbeForRead(pxformUnsafe, sizeof(XFORML), 1); 536 RtlCopyMemory(&xformSafe, pxformUnsafe, sizeof(XFORML)); 537 } 538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 539 { 540 Ret = FALSE; 541 } 542 _SEH2_END; 543 } 544 545 /* Safe to handle kernel mode data. */ 546 if (Ret) Ret = GreModifyWorldTransform(pdc, &xformSafe, dwMode); 547 DC_UnlockDc(pdc); 548 return Ret; 549 } 550 551 BOOL 552 APIENTRY 553 NtGdiOffsetViewportOrgEx( 554 HDC hDC, 555 int XOffset, 556 int YOffset, 557 LPPOINT UnsafePoint) 558 { 559 PDC dc; 560 PDC_ATTR pdcattr; 561 NTSTATUS Status = STATUS_SUCCESS; 562 563 dc = DC_LockDc(hDC); 564 if (!dc) 565 { 566 EngSetLastError(ERROR_INVALID_HANDLE); 567 return FALSE; 568 } 569 pdcattr = dc->pdcattr; 570 571 if (UnsafePoint) 572 { 573 _SEH2_TRY 574 { 575 ProbeForWrite(UnsafePoint, sizeof(POINT), 1); 576 UnsafePoint->x = pdcattr->ptlViewportOrg.x; 577 UnsafePoint->y = pdcattr->ptlViewportOrg.y; 578 if (pdcattr->dwLayout & LAYOUT_RTL) 579 { 580 UnsafePoint->x = -UnsafePoint->x; 581 } 582 } 583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 584 { 585 Status = _SEH2_GetExceptionCode(); 586 } 587 _SEH2_END; 588 589 if (!NT_SUCCESS(Status)) 590 { 591 SetLastNtError(Status); 592 DC_UnlockDc(dc); 593 return FALSE; 594 } 595 } 596 597 if (pdcattr->dwLayout & LAYOUT_RTL) 598 { 599 XOffset = -XOffset; 600 } 601 pdcattr->ptlViewportOrg.x += XOffset; 602 pdcattr->ptlViewportOrg.y += YOffset; 603 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 604 605 DC_UnlockDc(dc); 606 607 return TRUE; 608 } 609 610 BOOL 611 APIENTRY 612 NtGdiOffsetWindowOrgEx( 613 HDC hDC, 614 int XOffset, 615 int YOffset, 616 LPPOINT Point) 617 { 618 PDC dc; 619 PDC_ATTR pdcattr; 620 621 dc = DC_LockDc(hDC); 622 if (!dc) 623 { 624 EngSetLastError(ERROR_INVALID_HANDLE); 625 return FALSE; 626 } 627 pdcattr = dc->pdcattr; 628 629 if (Point) 630 { 631 NTSTATUS Status = STATUS_SUCCESS; 632 633 _SEH2_TRY 634 { 635 ProbeForWrite(Point, sizeof(POINT), 1); 636 Point->x = pdcattr->ptlWindowOrg.x; 637 Point->y = pdcattr->ptlWindowOrg.y; 638 } 639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 640 { 641 Status = _SEH2_GetExceptionCode(); 642 } 643 _SEH2_END; 644 645 if (!NT_SUCCESS(Status)) 646 { 647 SetLastNtError(Status); 648 DC_UnlockDc(dc); 649 return FALSE; 650 } 651 } 652 653 pdcattr->ptlWindowOrg.x += XOffset; 654 pdcattr->ptlWindowOrg.y += YOffset; 655 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 656 657 DC_UnlockDc(dc); 658 659 return TRUE; 660 } 661 662 BOOL 663 APIENTRY 664 NtGdiScaleViewportExtEx( 665 HDC hDC, 666 int Xnum, 667 int Xdenom, 668 int Ynum, 669 int Ydenom, 670 LPSIZE pSize) 671 { 672 PDC pDC; 673 PDC_ATTR pdcattr; 674 BOOL Ret = FALSE; 675 LONG X, Y; 676 677 pDC = DC_LockDc(hDC); 678 if (!pDC) 679 { 680 EngSetLastError(ERROR_INVALID_HANDLE); 681 return FALSE; 682 } 683 pdcattr = pDC->pdcattr; 684 685 if (pdcattr->iMapMode > MM_TWIPS) 686 { 687 if (Xdenom && Ydenom) 688 { 689 DC_pszlViewportExt(pDC); 690 X = Xnum * pdcattr->szlViewportExt.cx / Xdenom; 691 if (X) 692 { 693 Y = Ynum * pdcattr->szlViewportExt.cy / Ydenom; 694 if (Y) 695 { 696 pdcattr->szlViewportExt.cx = X; 697 pdcattr->szlViewportExt.cy = Y; 698 pdcattr->flXform |= PAGE_XLATE_CHANGED; 699 700 IntMirrorWindowOrg(pDC); 701 702 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | 703 INVALIDATE_ATTRIBUTES | 704 WORLD_XFORM_CHANGED | 705 DEVICE_TO_WORLD_INVALID); 706 707 if (pdcattr->iMapMode == MM_ISOTROPIC) 708 { 709 DC_vFixIsotropicMapping(pDC); 710 } 711 712 Ret = TRUE; 713 } 714 } 715 } 716 } 717 else 718 Ret = TRUE; 719 720 if (pSize) 721 { 722 _SEH2_TRY 723 { 724 ProbeForWrite(pSize, sizeof(SIZE), 1); 725 726 pSize->cx = pdcattr->szlViewportExt.cx; 727 pSize->cy = pdcattr->szlViewportExt.cy; 728 } 729 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 730 { 731 SetLastNtError(_SEH2_GetExceptionCode()); 732 Ret = FALSE; 733 } 734 _SEH2_END; 735 } 736 737 DC_UnlockDc(pDC); 738 return Ret; 739 } 740 741 BOOL 742 APIENTRY 743 NtGdiScaleWindowExtEx( 744 HDC hDC, 745 int Xnum, 746 int Xdenom, 747 int Ynum, 748 int Ydenom, 749 LPSIZE pSize) 750 { 751 PDC pDC; 752 PDC_ATTR pdcattr; 753 BOOL Ret = FALSE; 754 LONG X, Y; 755 756 pDC = DC_LockDc(hDC); 757 if (!pDC) 758 { 759 EngSetLastError(ERROR_INVALID_HANDLE); 760 return FALSE; 761 } 762 pdcattr = pDC->pdcattr; 763 764 if (pSize) 765 { 766 NTSTATUS Status = STATUS_SUCCESS; 767 768 _SEH2_TRY 769 { 770 ProbeForWrite(pSize, sizeof(SIZE), 1); 771 772 X = pdcattr->szlWindowExt.cx; 773 if (pdcattr->dwLayout & LAYOUT_RTL) X = -X; 774 pSize->cx = X; 775 pSize->cy = pdcattr->szlWindowExt.cy; 776 } 777 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 778 { 779 Status = _SEH2_GetExceptionCode(); 780 } 781 _SEH2_END; 782 783 if (!NT_SUCCESS(Status)) 784 { 785 SetLastNtError(Status); 786 DC_UnlockDc(pDC); 787 return FALSE; 788 } 789 } 790 791 if (pdcattr->iMapMode > MM_TWIPS) 792 { 793 if (Xdenom && Ydenom) 794 { 795 X = Xnum * pdcattr->szlWindowExt.cx / Xdenom; 796 if (X) 797 { 798 Y = Ynum * pdcattr->szlWindowExt.cy / Ydenom; 799 if (Y) 800 { 801 pdcattr->szlWindowExt.cx = X; 802 pdcattr->szlWindowExt.cy = Y; 803 804 IntMirrorWindowOrg(pDC); 805 806 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | 807 INVALIDATE_ATTRIBUTES | 808 WORLD_XFORM_CHANGED | 809 DEVICE_TO_WORLD_INVALID); 810 811 Ret = TRUE; 812 } 813 } 814 } 815 } 816 else 817 Ret = TRUE; 818 819 DC_UnlockDc(pDC); 820 return Ret; 821 } 822 823 int 824 APIENTRY 825 IntGdiSetMapMode( 826 PDC dc, 827 int MapMode) 828 { 829 INT iPrevMapMode; 830 FLONG flXform; 831 PDC_ATTR pdcattr = dc->pdcattr; 832 833 if (MapMode == pdcattr->iMapMode) 834 return MapMode; 835 836 flXform = pdcattr->flXform & ~(ISO_OR_ANISO_MAP_MODE|PTOD_EFM22_NEGATIVE| 837 PTOD_EFM11_NEGATIVE|POSITIVE_Y_IS_UP|PAGE_TO_DEVICE_SCALE_IDENTITY| 838 PAGE_TO_DEVICE_IDENTITY); 839 840 switch (MapMode) 841 { 842 case MM_TEXT: 843 pdcattr->szlWindowExt.cx = 1; 844 pdcattr->szlWindowExt.cy = 1; 845 pdcattr->szlViewportExt.cx = 1; 846 pdcattr->szlViewportExt.cy = 1; 847 flXform |= PAGE_TO_DEVICE_SCALE_IDENTITY; 848 break; 849 850 case MM_ISOTROPIC: 851 flXform |= ISO_OR_ANISO_MAP_MODE; 852 /* Fall through */ 853 854 case MM_LOMETRIC: 855 pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 10; 856 pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 10; 857 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 858 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 859 break; 860 861 case MM_HIMETRIC: 862 pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 100; 863 pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 100; 864 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 865 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 866 break; 867 868 case MM_LOENGLISH: 869 pdcattr->szlWindowExt.cx = MulDiv(1000, pdcattr->szlVirtualDeviceMm.cx, 254); 870 pdcattr->szlWindowExt.cy = MulDiv(1000, pdcattr->szlVirtualDeviceMm.cy, 254); 871 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 872 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 873 break; 874 875 case MM_HIENGLISH: 876 pdcattr->szlWindowExt.cx = MulDiv(10000, pdcattr->szlVirtualDeviceMm.cx, 254); 877 pdcattr->szlWindowExt.cy = MulDiv(10000, pdcattr->szlVirtualDeviceMm.cy, 254); 878 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 879 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 880 break; 881 882 case MM_TWIPS: 883 pdcattr->szlWindowExt.cx = MulDiv(14400, pdcattr->szlVirtualDeviceMm.cx, 254); 884 pdcattr->szlWindowExt.cy = MulDiv(14400, pdcattr->szlVirtualDeviceMm.cy, 254); 885 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 886 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 887 break; 888 889 case MM_ANISOTROPIC: 890 flXform &= ~(PAGE_TO_DEVICE_IDENTITY|POSITIVE_Y_IS_UP); 891 flXform |= ISO_OR_ANISO_MAP_MODE; 892 break; 893 894 default: 895 return 0; 896 } 897 898 /* Save the old map mode and set the new one */ 899 iPrevMapMode = pdcattr->iMapMode; 900 pdcattr->iMapMode = MapMode; 901 902 /* Update xform flags */ 903 pdcattr->flXform = flXform | (PAGE_XLATE_CHANGED | PAGE_EXTENTS_CHANGED | 904 INVALIDATE_ATTRIBUTES | DEVICE_TO_PAGE_INVALID | 905 WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID); 906 907 return iPrevMapMode; 908 } 909 910 BOOL 911 FASTCALL 912 GreSetViewportOrgEx( 913 HDC hDC, 914 int X, 915 int Y, 916 LPPOINT Point) 917 { 918 PDC dc; 919 PDC_ATTR pdcattr; 920 921 dc = DC_LockDc(hDC); 922 if (!dc) 923 { 924 EngSetLastError(ERROR_INVALID_HANDLE); 925 return FALSE; 926 } 927 pdcattr = dc->pdcattr; 928 929 if (Point) 930 { 931 Point->x = pdcattr->ptlViewportOrg.x; 932 Point->y = pdcattr->ptlViewportOrg.y; 933 } 934 935 pdcattr->ptlViewportOrg.x = X; 936 pdcattr->ptlViewportOrg.y = Y; 937 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 938 939 DC_UnlockDc(dc); 940 return TRUE; 941 } 942 943 BOOL 944 APIENTRY 945 NtGdiSetViewportOrgEx( 946 HDC hDC, 947 int X, 948 int Y, 949 LPPOINT Point) 950 { 951 PDC dc; 952 PDC_ATTR pdcattr; 953 954 dc = DC_LockDc(hDC); 955 if (!dc) 956 { 957 EngSetLastError(ERROR_INVALID_HANDLE); 958 return FALSE; 959 } 960 pdcattr = dc->pdcattr; 961 962 if (Point) 963 { 964 NTSTATUS Status = STATUS_SUCCESS; 965 966 _SEH2_TRY 967 { 968 ProbeForWrite(Point, sizeof(POINT), 1); 969 Point->x = pdcattr->ptlViewportOrg.x; 970 Point->y = pdcattr->ptlViewportOrg.y; 971 } 972 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 973 { 974 Status = _SEH2_GetExceptionCode(); 975 } 976 _SEH2_END; 977 978 if (!NT_SUCCESS(Status)) 979 { 980 SetLastNtError(Status); 981 DC_UnlockDc(dc); 982 return FALSE; 983 } 984 } 985 986 pdcattr->ptlViewportOrg.x = X; 987 pdcattr->ptlViewportOrg.y = Y; 988 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 989 990 DC_UnlockDc(dc); 991 992 return TRUE; 993 } 994 995 BOOL 996 APIENTRY 997 NtGdiSetWindowOrgEx( 998 HDC hDC, 999 int X, 1000 int Y, 1001 LPPOINT Point) 1002 { 1003 PDC dc; 1004 PDC_ATTR pdcattr; 1005 1006 dc = DC_LockDc(hDC); 1007 if (!dc) 1008 { 1009 EngSetLastError(ERROR_INVALID_HANDLE); 1010 return FALSE; 1011 } 1012 pdcattr = dc->pdcattr; 1013 1014 if (Point) 1015 { 1016 NTSTATUS Status = STATUS_SUCCESS; 1017 1018 _SEH2_TRY 1019 { 1020 ProbeForWrite(Point, sizeof(POINT), 1); 1021 Point->x = pdcattr->ptlWindowOrg.x; 1022 Point->y = pdcattr->ptlWindowOrg.y; 1023 } 1024 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1025 { 1026 Status = _SEH2_GetExceptionCode(); 1027 } 1028 _SEH2_END; 1029 1030 if (!NT_SUCCESS(Status)) 1031 { 1032 SetLastNtError(Status); 1033 DC_UnlockDc(dc); 1034 return FALSE; 1035 } 1036 } 1037 1038 pdcattr->ptlWindowOrg.x = X; 1039 pdcattr->ptlWindowOrg.y = Y; 1040 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 1041 1042 DC_UnlockDc(dc); 1043 1044 return TRUE; 1045 } 1046 1047 // 1048 // Mirror Window function. 1049 // 1050 VOID 1051 FASTCALL 1052 IntMirrorWindowOrg(PDC dc) 1053 { 1054 PDC_ATTR pdcattr; 1055 LONG X, cx; 1056 1057 pdcattr = dc->pdcattr; 1058 1059 if (!(pdcattr->dwLayout & LAYOUT_RTL)) 1060 { 1061 pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx; // Flip it back. 1062 return; 1063 } 1064 1065 /* Copy the window extension, so no one can mess with it */ 1066 cx = pdcattr->szlViewportExt.cx; 1067 if (cx == 0) return; 1068 // 1069 // WOrgx = wox - (Width - 1) * WExtx / VExtx 1070 // 1071 X = (dc->erclWindow.right - dc->erclWindow.left) - 1; // Get device width - 1 1072 1073 X = (X * pdcattr->szlWindowExt.cx) / cx; 1074 1075 pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx - X; // Now set the inverted win origion. 1076 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 1077 1078 return; 1079 } 1080 1081 VOID 1082 NTAPI 1083 DC_vSetLayout( 1084 IN PDC pdc, 1085 IN LONG wox, 1086 IN DWORD dwLayout) 1087 { 1088 PDC_ATTR pdcattr = pdc->pdcattr; 1089 1090 pdcattr->dwLayout = dwLayout; 1091 1092 if (!(dwLayout & LAYOUT_ORIENTATIONMASK)) return; 1093 1094 if (dwLayout & LAYOUT_RTL) 1095 { 1096 pdcattr->iMapMode = MM_ANISOTROPIC; 1097 } 1098 1099 //pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy; 1100 //pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x; 1101 1102 //if (wox == -1) 1103 // IntMirrorWindowOrg(pdc); 1104 //else 1105 // pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x; 1106 1107 if (!(pdcattr->flTextAlign & TA_CENTER)) pdcattr->flTextAlign |= TA_RIGHT; 1108 1109 if (pdc->dclevel.flPath & DCPATH_CLOCKWISE) 1110 pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE; 1111 else 1112 pdc->dclevel.flPath |= DCPATH_CLOCKWISE; 1113 1114 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | 1115 INVALIDATE_ATTRIBUTES | 1116 WORLD_XFORM_CHANGED | 1117 DEVICE_TO_WORLD_INVALID); 1118 } 1119 1120 // NtGdiSetLayout 1121 // 1122 // The default is left to right. This function changes it to right to left, which 1123 // is the standard in Arabic and Hebrew cultures. 1124 // 1125 /* 1126 * @implemented 1127 */ 1128 DWORD 1129 APIENTRY 1130 NtGdiSetLayout( 1131 IN HDC hdc, 1132 IN LONG wox, 1133 IN DWORD dwLayout) 1134 { 1135 PDC pdc; 1136 DWORD dwOldLayout; 1137 1138 pdc = DC_LockDc(hdc); 1139 if (!pdc) 1140 { 1141 EngSetLastError(ERROR_INVALID_HANDLE); 1142 return GDI_ERROR; 1143 } 1144 1145 dwOldLayout = pdc->pdcattr->dwLayout; 1146 DC_vSetLayout(pdc, wox, dwLayout); 1147 1148 DC_UnlockDc(pdc); 1149 return dwOldLayout; 1150 } 1151 1152 /* 1153 * @implemented 1154 */ 1155 LONG 1156 APIENTRY 1157 NtGdiGetDeviceWidth( 1158 IN HDC hdc) 1159 { 1160 PDC dc; 1161 LONG Ret; 1162 dc = DC_LockDc(hdc); 1163 if (!dc) 1164 { 1165 EngSetLastError(ERROR_INVALID_HANDLE); 1166 return 0; 1167 } 1168 Ret = dc->erclWindow.right - dc->erclWindow.left; 1169 DC_UnlockDc(dc); 1170 return Ret; 1171 } 1172 1173 /* 1174 * @implemented 1175 */ 1176 BOOL 1177 APIENTRY 1178 NtGdiMirrorWindowOrg( 1179 IN HDC hdc) 1180 { 1181 PDC dc; 1182 dc = DC_LockDc(hdc); 1183 if (!dc) 1184 { 1185 EngSetLastError(ERROR_INVALID_HANDLE); 1186 return FALSE; 1187 } 1188 IntMirrorWindowOrg(dc); 1189 DC_UnlockDc(dc); 1190 return TRUE; 1191 } 1192 1193 /* 1194 * @implemented 1195 */ 1196 BOOL 1197 APIENTRY 1198 NtGdiSetSizeDevice( 1199 IN HDC hdc, 1200 IN INT cxVirtualDevice, 1201 IN INT cyVirtualDevice) 1202 { 1203 PDC dc; 1204 PDC_ATTR pdcattr; 1205 1206 if (!cxVirtualDevice || !cyVirtualDevice) 1207 { 1208 return FALSE; 1209 } 1210 1211 dc = DC_LockDc(hdc); 1212 if (!dc) return FALSE; 1213 1214 pdcattr = dc->pdcattr; 1215 1216 pdcattr->szlVirtualDeviceSize.cx = cxVirtualDevice; 1217 pdcattr->szlVirtualDeviceSize.cy = cyVirtualDevice; 1218 1219 DC_UnlockDc(dc); 1220 1221 return TRUE; 1222 } 1223 1224 /* 1225 * @implemented 1226 */ 1227 BOOL 1228 APIENTRY 1229 NtGdiSetVirtualResolution( 1230 IN HDC hdc, 1231 IN INT cxVirtualDevicePixel, 1232 IN INT cyVirtualDevicePixel, 1233 IN INT cxVirtualDeviceMm, 1234 IN INT cyVirtualDeviceMm) 1235 { 1236 PDC dc; 1237 PDC_ATTR pdcattr; 1238 1239 /* Check parameters (all zeroes resets to real resolution) */ 1240 if (cxVirtualDevicePixel == 0 && cyVirtualDevicePixel == 0 && 1241 cxVirtualDeviceMm == 0 && cyVirtualDeviceMm == 0) 1242 { 1243 cxVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, HORZRES); 1244 cyVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, VERTRES); 1245 cxVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, HORZSIZE); 1246 cyVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, VERTSIZE); 1247 } 1248 else if (cxVirtualDevicePixel == 0 || cyVirtualDevicePixel == 0 || 1249 cxVirtualDeviceMm == 0 || cyVirtualDeviceMm == 0) 1250 { 1251 return FALSE; 1252 } 1253 1254 dc = DC_LockDc(hdc); 1255 if (!dc) return FALSE; 1256 1257 pdcattr = dc->pdcattr; 1258 1259 pdcattr->szlVirtualDevicePixel.cx = cxVirtualDevicePixel; 1260 pdcattr->szlVirtualDevicePixel.cy = cyVirtualDevicePixel; 1261 pdcattr->szlVirtualDeviceMm.cx = cxVirtualDeviceMm; 1262 pdcattr->szlVirtualDeviceMm.cy = cyVirtualDeviceMm; 1263 1264 // DC_vUpdateXforms(dc); 1265 DC_UnlockDc(dc); 1266 return TRUE; 1267 } 1268 1269 static 1270 VOID FASTCALL 1271 DC_vGetAspectRatioFilter(PDC pDC, LPSIZE AspectRatio) 1272 { 1273 if (pDC->pdcattr->flFontMapper & 1) // TRUE assume 1. 1274 { 1275 // "This specifies that Windows should only match fonts that have the 1276 // same aspect ratio as the display.", Programming Windows, Fifth Ed. 1277 AspectRatio->cx = pDC->ppdev->gdiinfo.ulLogPixelsX; 1278 AspectRatio->cy = pDC->ppdev->gdiinfo.ulLogPixelsY; 1279 } 1280 else 1281 { 1282 AspectRatio->cx = 0; 1283 AspectRatio->cy = 0; 1284 } 1285 } 1286 1287 BOOL APIENTRY 1288 GreGetDCPoint( 1289 HDC hDC, 1290 UINT iPoint, 1291 PPOINTL Point) 1292 { 1293 BOOL Ret = TRUE; 1294 DC *pdc; 1295 SIZE Size; 1296 PSIZEL pszlViewportExt; 1297 1298 if (!Point) 1299 { 1300 EngSetLastError(ERROR_INVALID_PARAMETER); 1301 return FALSE; 1302 } 1303 1304 pdc = DC_LockDc(hDC); 1305 if (!pdc) 1306 { 1307 EngSetLastError(ERROR_INVALID_HANDLE); 1308 return FALSE; 1309 } 1310 1311 switch (iPoint) 1312 { 1313 case GdiGetViewPortExt: 1314 pszlViewportExt = DC_pszlViewportExt(pdc); 1315 Point->x = pszlViewportExt->cx; 1316 Point->y = pszlViewportExt->cy; 1317 break; 1318 1319 case GdiGetWindowExt: 1320 Point->x = pdc->pdcattr->szlWindowExt.cx; 1321 Point->y = pdc->pdcattr->szlWindowExt.cy; 1322 break; 1323 1324 case GdiGetViewPortOrg: 1325 *Point = pdc->pdcattr->ptlViewportOrg; 1326 break; 1327 1328 case GdiGetWindowOrg: 1329 *Point = pdc->pdcattr->ptlWindowOrg; 1330 break; 1331 1332 case GdiGetDCOrg: 1333 *Point = pdc->ptlDCOrig; 1334 break; 1335 1336 case GdiGetAspectRatioFilter: 1337 DC_vGetAspectRatioFilter(pdc, &Size); 1338 Point->x = Size.cx; 1339 Point->y = Size.cy; 1340 break; 1341 1342 default: 1343 EngSetLastError(ERROR_INVALID_PARAMETER); 1344 Ret = FALSE; 1345 break; 1346 } 1347 1348 DC_UnlockDc(pdc); 1349 return Ret; 1350 } 1351 1352 BOOL 1353 WINAPI 1354 GreSetDCOrg( 1355 _In_ HDC hdc, 1356 _In_ LONG x, 1357 _In_ LONG y, 1358 _In_opt_ PRECTL Rect) 1359 { 1360 PDC dc; 1361 1362 dc = DC_LockDc(hdc); 1363 if (!dc) return FALSE; 1364 1365 /* Set DC Origin */ 1366 dc->ptlDCOrig.x = x; 1367 dc->ptlDCOrig.y = y; 1368 1369 /* Recalculate Fill Origin */ 1370 dc->ptlFillOrigin.x = dc->dclevel.ptlBrushOrigin.x + x; 1371 dc->ptlFillOrigin.y = dc->dclevel.ptlBrushOrigin.y + y; 1372 1373 /* Set DC Window Rectangle */ 1374 if (Rect) 1375 dc->erclWindow = *Rect; 1376 1377 DC_UnlockDc(dc); 1378 return TRUE; 1379 } 1380 1381 BOOL 1382 WINAPI 1383 GreGetDCOrgEx( 1384 _In_ HDC hdc, 1385 _Out_ PPOINTL Point, 1386 _Out_ PRECTL Rect) 1387 { 1388 PDC dc; 1389 1390 dc = DC_LockDc(hdc); 1391 if (!dc) return FALSE; 1392 1393 /* Retrieve DC Window Rectangle without a check */ 1394 *Rect = dc->erclWindow; 1395 1396 DC_UnlockDc(dc); 1397 1398 /* Use default call for DC Origin and parameter checking */ 1399 return GreGetDCPoint( hdc, GdiGetDCOrg, Point); 1400 } 1401 1402 BOOL 1403 WINAPI 1404 GreGetWindowExtEx( 1405 _In_ HDC hdc, 1406 _Out_ LPSIZE lpSize) 1407 { 1408 return GreGetDCPoint(hdc, GdiGetWindowExt, (PPOINTL)lpSize); 1409 } 1410 1411 BOOL 1412 WINAPI 1413 GreGetViewportExtEx( 1414 _In_ HDC hdc, 1415 _Out_ LPSIZE lpSize) 1416 { 1417 return GreGetDCPoint(hdc, GdiGetViewPortExt, (PPOINTL)lpSize); 1418 } 1419 1420 BOOL APIENTRY 1421 NtGdiGetDCPoint( 1422 HDC hDC, 1423 UINT iPoint, 1424 PPOINTL Point) 1425 { 1426 BOOL Ret; 1427 POINTL SafePoint; 1428 1429 if (!Point) 1430 { 1431 EngSetLastError(ERROR_INVALID_PARAMETER); 1432 return FALSE; 1433 } 1434 1435 Ret = GreGetDCPoint(hDC, iPoint, &SafePoint); 1436 if (Ret) 1437 { 1438 _SEH2_TRY 1439 { 1440 ProbeForWrite(Point, sizeof(POINT), 1); 1441 *Point = SafePoint; 1442 } 1443 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1444 { 1445 Ret = FALSE; 1446 } 1447 _SEH2_END; 1448 } 1449 1450 return Ret; 1451 } 1452 1453 /* EOF */ 1454