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 ret = INTERNAL_APPLY_MATRIX(DC_pmxDeviceToWorld(pdc), Points, Count); 420 break; 421 422 case GdiLpToDp: 423 ret = INTERNAL_APPLY_MATRIX(DC_pmxWorldToDevice(pdc), Points, Count); 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 if (ret) 436 { 437 _SEH2_TRY 438 { 439 /* Pointer was already probed! */ 440 RtlCopyMemory(UnsafePtOut, Points, Size); 441 } 442 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 443 { 444 /* Do not set last error */ 445 ret = FALSE; 446 } 447 _SEH2_END; 448 } 449 450 // 451 // If we are getting called that means User XForms is a mess! 452 // 453 leave: 454 DC_UnlockDc(pdc); 455 ExFreePoolWithTag(Points, GDITAG_TEMP); 456 return ret; 457 } 458 459 BOOL 460 NTAPI 461 GreModifyWorldTransform( 462 PDC pdc, 463 const XFORML *pxform, 464 DWORD dwMode) 465 { 466 MATRIX mxSrc; 467 XFORMOBJ xoSrc, xoDC; 468 469 switch (dwMode) 470 { 471 case MWT_IDENTITY: 472 pdc->pdcattr->mxWorldToPage = gmxIdentity; 473 break; 474 475 case MWT_LEFTMULTIPLY: 476 XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage); 477 XFORMOBJ_vInit(&xoSrc, &mxSrc); 478 if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR) 479 return FALSE; 480 XFORMOBJ_iCombine(&xoDC, &xoSrc, &xoDC); 481 break; 482 483 case MWT_RIGHTMULTIPLY: 484 XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage); 485 XFORMOBJ_vInit(&xoSrc, &mxSrc); 486 if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR) 487 return FALSE; 488 XFORMOBJ_iCombine(&xoDC, &xoDC, &xoSrc); 489 break; 490 491 case MWT_SET: 492 XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage); 493 if (XFORMOBJ_iSetXform(&xoDC, pxform) == DDI_ERROR) 494 return FALSE; 495 break; 496 497 default: 498 return FALSE; 499 } 500 501 /*Set invalidation flags */ 502 pdc->pdcattr->flXform |= WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID; 503 504 return TRUE; 505 } 506 507 BOOL 508 APIENTRY 509 NtGdiModifyWorldTransform( 510 HDC hdc, 511 LPXFORM pxformUnsafe, 512 DWORD dwMode) 513 { 514 PDC pdc; 515 XFORML xformSafe; 516 BOOL Ret = TRUE; 517 518 pdc = DC_LockDc(hdc); 519 if (!pdc) 520 { 521 EngSetLastError(ERROR_INVALID_HANDLE); 522 return FALSE; 523 } 524 525 /* The xform is permitted to be NULL for MWT_IDENTITY. 526 * However, if it is not NULL, then it must be valid even 527 * though it is not used. */ 528 if ((dwMode != MWT_IDENTITY) && (pxformUnsafe == NULL)) 529 { 530 DC_UnlockDc(pdc); 531 return FALSE; 532 } 533 534 if (pxformUnsafe != NULL) 535 { 536 _SEH2_TRY 537 { 538 ProbeForRead(pxformUnsafe, sizeof(XFORML), 1); 539 RtlCopyMemory(&xformSafe, pxformUnsafe, sizeof(XFORML)); 540 } 541 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 542 { 543 Ret = FALSE; 544 } 545 _SEH2_END; 546 } 547 548 /* Safe to handle kernel mode data. */ 549 if (Ret) Ret = GreModifyWorldTransform(pdc, &xformSafe, dwMode); 550 DC_UnlockDc(pdc); 551 return Ret; 552 } 553 554 BOOL 555 APIENTRY 556 NtGdiOffsetViewportOrgEx( 557 HDC hDC, 558 int XOffset, 559 int YOffset, 560 LPPOINT UnsafePoint) 561 { 562 PDC dc; 563 PDC_ATTR pdcattr; 564 NTSTATUS Status = STATUS_SUCCESS; 565 566 dc = DC_LockDc(hDC); 567 if (!dc) 568 { 569 EngSetLastError(ERROR_INVALID_HANDLE); 570 return FALSE; 571 } 572 pdcattr = dc->pdcattr; 573 574 if (UnsafePoint) 575 { 576 _SEH2_TRY 577 { 578 ProbeForWrite(UnsafePoint, sizeof(POINT), 1); 579 UnsafePoint->x = pdcattr->ptlViewportOrg.x; 580 UnsafePoint->y = pdcattr->ptlViewportOrg.y; 581 if (pdcattr->dwLayout & LAYOUT_RTL) 582 { 583 UnsafePoint->x = -UnsafePoint->x; 584 } 585 } 586 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 587 { 588 Status = _SEH2_GetExceptionCode(); 589 } 590 _SEH2_END; 591 592 if (!NT_SUCCESS(Status)) 593 { 594 SetLastNtError(Status); 595 DC_UnlockDc(dc); 596 return FALSE; 597 } 598 } 599 600 if (pdcattr->dwLayout & LAYOUT_RTL) 601 { 602 XOffset = -XOffset; 603 } 604 pdcattr->ptlViewportOrg.x += XOffset; 605 pdcattr->ptlViewportOrg.y += YOffset; 606 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 607 608 DC_UnlockDc(dc); 609 610 return TRUE; 611 } 612 613 BOOL 614 APIENTRY 615 NtGdiOffsetWindowOrgEx( 616 HDC hDC, 617 int XOffset, 618 int YOffset, 619 LPPOINT Point) 620 { 621 PDC dc; 622 PDC_ATTR pdcattr; 623 624 dc = DC_LockDc(hDC); 625 if (!dc) 626 { 627 EngSetLastError(ERROR_INVALID_HANDLE); 628 return FALSE; 629 } 630 pdcattr = dc->pdcattr; 631 632 if (Point) 633 { 634 NTSTATUS Status = STATUS_SUCCESS; 635 636 _SEH2_TRY 637 { 638 ProbeForWrite(Point, sizeof(POINT), 1); 639 Point->x = pdcattr->ptlWindowOrg.x; 640 Point->y = pdcattr->ptlWindowOrg.y; 641 } 642 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 643 { 644 Status = _SEH2_GetExceptionCode(); 645 } 646 _SEH2_END; 647 648 if (!NT_SUCCESS(Status)) 649 { 650 SetLastNtError(Status); 651 DC_UnlockDc(dc); 652 return FALSE; 653 } 654 } 655 656 pdcattr->ptlWindowOrg.x += XOffset; 657 pdcattr->ptlWindowOrg.y += YOffset; 658 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 659 660 DC_UnlockDc(dc); 661 662 return TRUE; 663 } 664 665 BOOL 666 APIENTRY 667 NtGdiScaleViewportExtEx( 668 HDC hDC, 669 int Xnum, 670 int Xdenom, 671 int Ynum, 672 int Ydenom, 673 LPSIZE pSize) 674 { 675 PDC pDC; 676 PDC_ATTR pdcattr; 677 BOOL Ret = FALSE; 678 LONG X, Y; 679 680 pDC = DC_LockDc(hDC); 681 if (!pDC) 682 { 683 EngSetLastError(ERROR_INVALID_HANDLE); 684 return FALSE; 685 } 686 pdcattr = pDC->pdcattr; 687 688 if (pdcattr->iMapMode > MM_TWIPS) 689 { 690 if (Xdenom && Ydenom) 691 { 692 DC_pszlViewportExt(pDC); 693 X = Xnum * pdcattr->szlViewportExt.cx / Xdenom; 694 if (X) 695 { 696 Y = Ynum * pdcattr->szlViewportExt.cy / Ydenom; 697 if (Y) 698 { 699 pdcattr->szlViewportExt.cx = X; 700 pdcattr->szlViewportExt.cy = Y; 701 pdcattr->flXform |= PAGE_XLATE_CHANGED; 702 703 IntMirrorWindowOrg(pDC); 704 705 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | 706 INVALIDATE_ATTRIBUTES | 707 WORLD_XFORM_CHANGED | 708 DEVICE_TO_WORLD_INVALID); 709 710 if (pdcattr->iMapMode == MM_ISOTROPIC) 711 { 712 DC_vFixIsotropicMapping(pDC); 713 } 714 715 Ret = TRUE; 716 } 717 } 718 } 719 } 720 else 721 Ret = TRUE; 722 723 if (pSize) 724 { 725 _SEH2_TRY 726 { 727 ProbeForWrite(pSize, sizeof(SIZE), 1); 728 729 pSize->cx = pdcattr->szlViewportExt.cx; 730 pSize->cy = pdcattr->szlViewportExt.cy; 731 } 732 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 733 { 734 SetLastNtError(_SEH2_GetExceptionCode()); 735 Ret = FALSE; 736 } 737 _SEH2_END; 738 } 739 740 DC_UnlockDc(pDC); 741 return Ret; 742 } 743 744 BOOL 745 APIENTRY 746 NtGdiScaleWindowExtEx( 747 HDC hDC, 748 int Xnum, 749 int Xdenom, 750 int Ynum, 751 int Ydenom, 752 LPSIZE pSize) 753 { 754 PDC pDC; 755 PDC_ATTR pdcattr; 756 BOOL Ret = FALSE; 757 LONG X, Y; 758 759 pDC = DC_LockDc(hDC); 760 if (!pDC) 761 { 762 EngSetLastError(ERROR_INVALID_HANDLE); 763 return FALSE; 764 } 765 pdcattr = pDC->pdcattr; 766 767 if (pSize) 768 { 769 NTSTATUS Status = STATUS_SUCCESS; 770 771 _SEH2_TRY 772 { 773 ProbeForWrite(pSize, sizeof(SIZE), 1); 774 775 X = pdcattr->szlWindowExt.cx; 776 if (pdcattr->dwLayout & LAYOUT_RTL) X = -X; 777 pSize->cx = X; 778 pSize->cy = pdcattr->szlWindowExt.cy; 779 } 780 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 781 { 782 Status = _SEH2_GetExceptionCode(); 783 } 784 _SEH2_END; 785 786 if (!NT_SUCCESS(Status)) 787 { 788 SetLastNtError(Status); 789 DC_UnlockDc(pDC); 790 return FALSE; 791 } 792 } 793 794 if (pdcattr->iMapMode > MM_TWIPS) 795 { 796 if (Xdenom && Ydenom) 797 { 798 X = Xnum * pdcattr->szlWindowExt.cx / Xdenom; 799 if (X) 800 { 801 Y = Ynum * pdcattr->szlWindowExt.cy / Ydenom; 802 if (Y) 803 { 804 pdcattr->szlWindowExt.cx = X; 805 pdcattr->szlWindowExt.cy = Y; 806 807 IntMirrorWindowOrg(pDC); 808 809 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | 810 INVALIDATE_ATTRIBUTES | 811 WORLD_XFORM_CHANGED | 812 DEVICE_TO_WORLD_INVALID); 813 814 Ret = TRUE; 815 } 816 } 817 } 818 } 819 else 820 Ret = TRUE; 821 822 DC_UnlockDc(pDC); 823 return Ret; 824 } 825 826 int 827 APIENTRY 828 IntGdiSetMapMode( 829 PDC dc, 830 int MapMode) 831 { 832 INT iPrevMapMode; 833 FLONG flXform; 834 PDC_ATTR pdcattr = dc->pdcattr; 835 836 if (MapMode == pdcattr->iMapMode) 837 return MapMode; 838 839 flXform = pdcattr->flXform & ~(ISO_OR_ANISO_MAP_MODE|PTOD_EFM22_NEGATIVE| 840 PTOD_EFM11_NEGATIVE|POSITIVE_Y_IS_UP|PAGE_TO_DEVICE_SCALE_IDENTITY| 841 PAGE_TO_DEVICE_IDENTITY); 842 843 switch (MapMode) 844 { 845 case MM_TEXT: 846 pdcattr->szlWindowExt.cx = 1; 847 pdcattr->szlWindowExt.cy = 1; 848 pdcattr->szlViewportExt.cx = 1; 849 pdcattr->szlViewportExt.cy = 1; 850 flXform |= PAGE_TO_DEVICE_SCALE_IDENTITY; 851 break; 852 853 case MM_ISOTROPIC: 854 flXform |= ISO_OR_ANISO_MAP_MODE; 855 /* Fall through */ 856 857 case MM_LOMETRIC: 858 pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 10; 859 pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 10; 860 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 861 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 862 break; 863 864 case MM_HIMETRIC: 865 pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 100; 866 pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 100; 867 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 868 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 869 break; 870 871 case MM_LOENGLISH: 872 pdcattr->szlWindowExt.cx = EngMulDiv(1000, pdcattr->szlVirtualDeviceMm.cx, 254); 873 pdcattr->szlWindowExt.cy = EngMulDiv(1000, pdcattr->szlVirtualDeviceMm.cy, 254); 874 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 875 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 876 break; 877 878 case MM_HIENGLISH: 879 pdcattr->szlWindowExt.cx = EngMulDiv(10000, pdcattr->szlVirtualDeviceMm.cx, 254); 880 pdcattr->szlWindowExt.cy = EngMulDiv(10000, pdcattr->szlVirtualDeviceMm.cy, 254); 881 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 882 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 883 break; 884 885 case MM_TWIPS: 886 pdcattr->szlWindowExt.cx = EngMulDiv(14400, pdcattr->szlVirtualDeviceMm.cx, 254); 887 pdcattr->szlWindowExt.cy = EngMulDiv(14400, pdcattr->szlVirtualDeviceMm.cy, 254); 888 pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; 889 pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; 890 break; 891 892 case MM_ANISOTROPIC: 893 flXform &= ~(PAGE_TO_DEVICE_IDENTITY|POSITIVE_Y_IS_UP); 894 flXform |= ISO_OR_ANISO_MAP_MODE; 895 break; 896 897 default: 898 return 0; 899 } 900 901 /* Save the old map mode and set the new one */ 902 iPrevMapMode = pdcattr->iMapMode; 903 pdcattr->iMapMode = MapMode; 904 905 /* Update xform flags */ 906 pdcattr->flXform = flXform | (PAGE_XLATE_CHANGED | PAGE_EXTENTS_CHANGED | 907 INVALIDATE_ATTRIBUTES | DEVICE_TO_PAGE_INVALID | 908 WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID); 909 910 return iPrevMapMode; 911 } 912 913 BOOL 914 FASTCALL 915 GreSetViewportOrgEx( 916 HDC hDC, 917 int X, 918 int Y, 919 LPPOINT Point) 920 { 921 PDC dc; 922 PDC_ATTR pdcattr; 923 924 dc = DC_LockDc(hDC); 925 if (!dc) 926 { 927 EngSetLastError(ERROR_INVALID_HANDLE); 928 return FALSE; 929 } 930 pdcattr = dc->pdcattr; 931 932 if (Point) 933 { 934 Point->x = pdcattr->ptlViewportOrg.x; 935 Point->y = pdcattr->ptlViewportOrg.y; 936 } 937 938 pdcattr->ptlViewportOrg.x = X; 939 pdcattr->ptlViewportOrg.y = Y; 940 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 941 942 DC_UnlockDc(dc); 943 return TRUE; 944 } 945 946 BOOL 947 APIENTRY 948 NtGdiSetViewportOrgEx( 949 HDC hDC, 950 int X, 951 int Y, 952 LPPOINT Point) 953 { 954 PDC dc; 955 PDC_ATTR pdcattr; 956 957 dc = DC_LockDc(hDC); 958 if (!dc) 959 { 960 EngSetLastError(ERROR_INVALID_HANDLE); 961 return FALSE; 962 } 963 pdcattr = dc->pdcattr; 964 965 if (Point) 966 { 967 NTSTATUS Status = STATUS_SUCCESS; 968 969 _SEH2_TRY 970 { 971 ProbeForWrite(Point, sizeof(POINT), 1); 972 Point->x = pdcattr->ptlViewportOrg.x; 973 Point->y = pdcattr->ptlViewportOrg.y; 974 } 975 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 976 { 977 Status = _SEH2_GetExceptionCode(); 978 } 979 _SEH2_END; 980 981 if (!NT_SUCCESS(Status)) 982 { 983 SetLastNtError(Status); 984 DC_UnlockDc(dc); 985 return FALSE; 986 } 987 } 988 989 pdcattr->ptlViewportOrg.x = X; 990 pdcattr->ptlViewportOrg.y = Y; 991 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 992 993 DC_UnlockDc(dc); 994 995 return TRUE; 996 } 997 998 BOOL 999 APIENTRY 1000 NtGdiSetWindowOrgEx( 1001 HDC hDC, 1002 int X, 1003 int Y, 1004 LPPOINT Point) 1005 { 1006 PDC dc; 1007 PDC_ATTR pdcattr; 1008 1009 dc = DC_LockDc(hDC); 1010 if (!dc) 1011 { 1012 EngSetLastError(ERROR_INVALID_HANDLE); 1013 return FALSE; 1014 } 1015 pdcattr = dc->pdcattr; 1016 1017 if (Point) 1018 { 1019 NTSTATUS Status = STATUS_SUCCESS; 1020 1021 _SEH2_TRY 1022 { 1023 ProbeForWrite(Point, sizeof(POINT), 1); 1024 Point->x = pdcattr->ptlWindowOrg.x; 1025 Point->y = pdcattr->ptlWindowOrg.y; 1026 } 1027 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1028 { 1029 Status = _SEH2_GetExceptionCode(); 1030 } 1031 _SEH2_END; 1032 1033 if (!NT_SUCCESS(Status)) 1034 { 1035 SetLastNtError(Status); 1036 DC_UnlockDc(dc); 1037 return FALSE; 1038 } 1039 } 1040 1041 pdcattr->ptlWindowOrg.x = X; 1042 pdcattr->ptlWindowOrg.y = Y; 1043 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 1044 1045 DC_UnlockDc(dc); 1046 1047 return TRUE; 1048 } 1049 1050 // 1051 // Mirror Window function. 1052 // 1053 VOID 1054 FASTCALL 1055 IntMirrorWindowOrg(PDC dc) 1056 { 1057 PDC_ATTR pdcattr; 1058 LONG X, cx; 1059 1060 pdcattr = dc->pdcattr; 1061 1062 if (!(pdcattr->dwLayout & LAYOUT_RTL)) 1063 { 1064 pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx; // Flip it back. 1065 return; 1066 } 1067 1068 /* Copy the window extension, so no one can mess with it */ 1069 cx = pdcattr->szlViewportExt.cx; 1070 if (cx == 0) return; 1071 // 1072 // WOrgx = wox - (Width - 1) * WExtx / VExtx 1073 // 1074 X = (dc->erclWindow.right - dc->erclWindow.left) - 1; // Get device width - 1 1075 1076 X = (X * pdcattr->szlWindowExt.cx) / cx; 1077 1078 pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx - X; // Now set the inverted win origion. 1079 pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID; 1080 1081 return; 1082 } 1083 1084 VOID 1085 NTAPI 1086 DC_vSetLayout( 1087 IN PDC pdc, 1088 IN LONG wox, 1089 IN DWORD dwLayout) 1090 { 1091 PDC_ATTR pdcattr = pdc->pdcattr; 1092 1093 pdcattr->dwLayout = dwLayout; 1094 1095 if (!(dwLayout & LAYOUT_ORIENTATIONMASK)) return; 1096 1097 if (dwLayout & LAYOUT_RTL) 1098 { 1099 pdcattr->iMapMode = MM_ANISOTROPIC; 1100 } 1101 1102 //pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy; 1103 //pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x; 1104 1105 //if (wox == -1) 1106 // IntMirrorWindowOrg(pdc); 1107 //else 1108 // pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x; 1109 1110 if (!(pdcattr->flTextAlign & TA_CENTER)) pdcattr->flTextAlign |= TA_RIGHT; 1111 1112 if (pdc->dclevel.flPath & DCPATH_CLOCKWISE) 1113 pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE; 1114 else 1115 pdc->dclevel.flPath |= DCPATH_CLOCKWISE; 1116 1117 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | 1118 INVALIDATE_ATTRIBUTES | 1119 WORLD_XFORM_CHANGED | 1120 DEVICE_TO_WORLD_INVALID); 1121 } 1122 1123 // NtGdiSetLayout 1124 // 1125 // The default is left to right. This function changes it to right to left, which 1126 // is the standard in Arabic and Hebrew cultures. 1127 // 1128 /* 1129 * @implemented 1130 */ 1131 DWORD 1132 APIENTRY 1133 NtGdiSetLayout( 1134 IN HDC hdc, 1135 IN LONG wox, 1136 IN DWORD dwLayout) 1137 { 1138 PDC pdc; 1139 DWORD dwOldLayout; 1140 1141 pdc = DC_LockDc(hdc); 1142 if (!pdc) 1143 { 1144 EngSetLastError(ERROR_INVALID_HANDLE); 1145 return GDI_ERROR; 1146 } 1147 1148 dwOldLayout = pdc->pdcattr->dwLayout; 1149 DC_vSetLayout(pdc, wox, dwLayout); 1150 1151 DC_UnlockDc(pdc); 1152 return dwOldLayout; 1153 } 1154 1155 /* 1156 * @implemented 1157 */ 1158 LONG 1159 APIENTRY 1160 NtGdiGetDeviceWidth( 1161 IN HDC hdc) 1162 { 1163 PDC dc; 1164 LONG Ret; 1165 dc = DC_LockDc(hdc); 1166 if (!dc) 1167 { 1168 EngSetLastError(ERROR_INVALID_HANDLE); 1169 return 0; 1170 } 1171 Ret = dc->erclWindow.right - dc->erclWindow.left; 1172 DC_UnlockDc(dc); 1173 return Ret; 1174 } 1175 1176 /* 1177 * @implemented 1178 */ 1179 BOOL 1180 APIENTRY 1181 NtGdiMirrorWindowOrg( 1182 IN HDC hdc) 1183 { 1184 PDC dc; 1185 dc = DC_LockDc(hdc); 1186 if (!dc) 1187 { 1188 EngSetLastError(ERROR_INVALID_HANDLE); 1189 return FALSE; 1190 } 1191 IntMirrorWindowOrg(dc); 1192 DC_UnlockDc(dc); 1193 return TRUE; 1194 } 1195 1196 /* 1197 * @implemented 1198 */ 1199 BOOL 1200 APIENTRY 1201 NtGdiSetSizeDevice( 1202 IN HDC hdc, 1203 IN INT cxVirtualDevice, 1204 IN INT cyVirtualDevice) 1205 { 1206 PDC dc; 1207 PDC_ATTR pdcattr; 1208 1209 if (!cxVirtualDevice || !cyVirtualDevice) 1210 { 1211 return FALSE; 1212 } 1213 1214 dc = DC_LockDc(hdc); 1215 if (!dc) return FALSE; 1216 1217 pdcattr = dc->pdcattr; 1218 1219 pdcattr->szlVirtualDeviceSize.cx = cxVirtualDevice; 1220 pdcattr->szlVirtualDeviceSize.cy = cyVirtualDevice; 1221 1222 DC_UnlockDc(dc); 1223 1224 return TRUE; 1225 } 1226 1227 /* 1228 * @implemented 1229 */ 1230 BOOL 1231 APIENTRY 1232 NtGdiSetVirtualResolution( 1233 IN HDC hdc, 1234 IN INT cxVirtualDevicePixel, 1235 IN INT cyVirtualDevicePixel, 1236 IN INT cxVirtualDeviceMm, 1237 IN INT cyVirtualDeviceMm) 1238 { 1239 PDC dc; 1240 PDC_ATTR pdcattr; 1241 1242 /* Check parameters (all zeroes resets to real resolution) */ 1243 if (cxVirtualDevicePixel == 0 && cyVirtualDevicePixel == 0 && 1244 cxVirtualDeviceMm == 0 && cyVirtualDeviceMm == 0) 1245 { 1246 cxVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, HORZRES); 1247 cyVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, VERTRES); 1248 cxVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, HORZSIZE); 1249 cyVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, VERTSIZE); 1250 } 1251 else if (cxVirtualDevicePixel == 0 || cyVirtualDevicePixel == 0 || 1252 cxVirtualDeviceMm == 0 || cyVirtualDeviceMm == 0) 1253 { 1254 return FALSE; 1255 } 1256 1257 dc = DC_LockDc(hdc); 1258 if (!dc) return FALSE; 1259 1260 pdcattr = dc->pdcattr; 1261 1262 pdcattr->szlVirtualDevicePixel.cx = cxVirtualDevicePixel; 1263 pdcattr->szlVirtualDevicePixel.cy = cyVirtualDevicePixel; 1264 pdcattr->szlVirtualDeviceMm.cx = cxVirtualDeviceMm; 1265 pdcattr->szlVirtualDeviceMm.cy = cyVirtualDeviceMm; 1266 1267 // DC_vUpdateXforms(dc); 1268 DC_UnlockDc(dc); 1269 return TRUE; 1270 } 1271 1272 static 1273 VOID FASTCALL 1274 DC_vGetAspectRatioFilter(PDC pDC, LPSIZE AspectRatio) 1275 { 1276 if (pDC->pdcattr->flFontMapper & 1) // TRUE assume 1. 1277 { 1278 // "This specifies that Windows should only match fonts that have the 1279 // same aspect ratio as the display.", Programming Windows, Fifth Ed. 1280 AspectRatio->cx = pDC->ppdev->gdiinfo.ulLogPixelsX; 1281 AspectRatio->cy = pDC->ppdev->gdiinfo.ulLogPixelsY; 1282 } 1283 else 1284 { 1285 AspectRatio->cx = 0; 1286 AspectRatio->cy = 0; 1287 } 1288 } 1289 1290 BOOL APIENTRY 1291 GreGetDCPoint( 1292 HDC hDC, 1293 UINT iPoint, 1294 PPOINTL Point) 1295 { 1296 BOOL Ret = TRUE; 1297 DC *pdc; 1298 SIZE Size; 1299 PSIZEL pszlViewportExt; 1300 1301 if (!Point) 1302 { 1303 EngSetLastError(ERROR_INVALID_PARAMETER); 1304 return FALSE; 1305 } 1306 1307 pdc = DC_LockDc(hDC); 1308 if (!pdc) 1309 { 1310 EngSetLastError(ERROR_INVALID_HANDLE); 1311 return FALSE; 1312 } 1313 1314 switch (iPoint) 1315 { 1316 case GdiGetViewPortExt: 1317 pszlViewportExt = DC_pszlViewportExt(pdc); 1318 Point->x = pszlViewportExt->cx; 1319 Point->y = pszlViewportExt->cy; 1320 break; 1321 1322 case GdiGetWindowExt: 1323 Point->x = pdc->pdcattr->szlWindowExt.cx; 1324 Point->y = pdc->pdcattr->szlWindowExt.cy; 1325 break; 1326 1327 case GdiGetViewPortOrg: 1328 *Point = pdc->pdcattr->ptlViewportOrg; 1329 break; 1330 1331 case GdiGetWindowOrg: 1332 *Point = pdc->pdcattr->ptlWindowOrg; 1333 break; 1334 1335 case GdiGetDCOrg: 1336 *Point = pdc->ptlDCOrig; 1337 break; 1338 1339 case GdiGetAspectRatioFilter: 1340 DC_vGetAspectRatioFilter(pdc, &Size); 1341 Point->x = Size.cx; 1342 Point->y = Size.cy; 1343 break; 1344 1345 default: 1346 EngSetLastError(ERROR_INVALID_PARAMETER); 1347 Ret = FALSE; 1348 break; 1349 } 1350 1351 DC_UnlockDc(pdc); 1352 return Ret; 1353 } 1354 1355 BOOL 1356 WINAPI 1357 GreSetDCOrg( 1358 _In_ HDC hdc, 1359 _In_ LONG x, 1360 _In_ LONG y, 1361 _In_opt_ PRECTL Rect) 1362 { 1363 PDC dc; 1364 1365 dc = DC_LockDc(hdc); 1366 if (!dc) return FALSE; 1367 1368 /* Set DC Origin */ 1369 dc->ptlDCOrig.x = x; 1370 dc->ptlDCOrig.y = y; 1371 1372 /* Recalculate Fill Origin */ 1373 dc->ptlFillOrigin.x = dc->dclevel.ptlBrushOrigin.x + x; 1374 dc->ptlFillOrigin.y = dc->dclevel.ptlBrushOrigin.y + y; 1375 1376 /* Set DC Window Rectangle */ 1377 if (Rect) 1378 dc->erclWindow = *Rect; 1379 1380 DC_UnlockDc(dc); 1381 return TRUE; 1382 } 1383 1384 BOOL 1385 WINAPI 1386 GreGetDCOrgEx( 1387 _In_ HDC hdc, 1388 _Out_ PPOINTL Point, 1389 _Out_ PRECTL Rect) 1390 { 1391 PDC dc; 1392 1393 dc = DC_LockDc(hdc); 1394 if (!dc) return FALSE; 1395 1396 /* Retrieve DC Window Rectangle without a check */ 1397 *Rect = dc->erclWindow; 1398 1399 DC_UnlockDc(dc); 1400 1401 /* Use default call for DC Origin and parameter checking */ 1402 return GreGetDCPoint( hdc, GdiGetDCOrg, Point); 1403 } 1404 1405 BOOL 1406 WINAPI 1407 GreGetWindowExtEx( 1408 _In_ HDC hdc, 1409 _Out_ LPSIZE lpSize) 1410 { 1411 return GreGetDCPoint(hdc, GdiGetWindowExt, (PPOINTL)lpSize); 1412 } 1413 1414 BOOL 1415 WINAPI 1416 GreGetViewportExtEx( 1417 _In_ HDC hdc, 1418 _Out_ LPSIZE lpSize) 1419 { 1420 return GreGetDCPoint(hdc, GdiGetViewPortExt, (PPOINTL)lpSize); 1421 } 1422 1423 BOOL APIENTRY 1424 NtGdiGetDCPoint( 1425 HDC hDC, 1426 UINT iPoint, 1427 PPOINTL Point) 1428 { 1429 BOOL Ret; 1430 POINTL SafePoint; 1431 1432 if (!Point) 1433 { 1434 EngSetLastError(ERROR_INVALID_PARAMETER); 1435 return FALSE; 1436 } 1437 1438 Ret = GreGetDCPoint(hDC, iPoint, &SafePoint); 1439 if (Ret) 1440 { 1441 _SEH2_TRY 1442 { 1443 ProbeForWrite(Point, sizeof(POINT), 1); 1444 *Point = SafePoint; 1445 } 1446 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1447 { 1448 Ret = FALSE; 1449 } 1450 _SEH2_END; 1451 } 1452 1453 return Ret; 1454 } 1455 1456 /* EOF */ 1457