1 /* 2 * PROJECT: ReactOS GDI32 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Text drawing API. 5 * COPYRIGHT: Copyright 2014 Timo Kreuzer 6 * Copyright 2017 Katayama Hirofumi MZ 7 */ 8 9 #include <precomp.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 /* 15 * @implemented 16 */ 17 BOOL 18 WINAPI 19 TextOutA( 20 _In_ HDC hdc, 21 _In_ INT nXStart, 22 _In_ INT nYStart, 23 _In_reads_(cchString) LPCSTR lpString, 24 _In_ INT cchString) 25 { 26 ANSI_STRING StringA; 27 UNICODE_STRING StringU; 28 BOOL bResult; 29 NTSTATUS Status; 30 31 if (lpString != NULL && cchString > 0) 32 { 33 if (cchString > MAXUSHORT) 34 cchString = MAXUSHORT; 35 36 StringA.Length = (USHORT)cchString; 37 StringA.MaximumLength = (USHORT)cchString; 38 StringA.Buffer = (PCHAR)lpString; 39 40 Status = RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE); 41 if (!NT_SUCCESS(Status)) 42 { 43 StringU.Buffer = NULL; 44 StringU.Length = 0; 45 } 46 } 47 else 48 { 49 StringU.Buffer = NULL; 50 StringU.Length = 0; 51 } 52 53 bResult = TextOutW(hdc, nXStart, nYStart, 54 StringU.Buffer, StringU.Length / sizeof(WCHAR)); 55 56 RtlFreeUnicodeString(&StringU); 57 return bResult; 58 } 59 60 61 /* 62 * @implemented 63 */ 64 BOOL 65 WINAPI 66 TextOutW( 67 _In_ HDC hdc, 68 _In_ INT nXStart, 69 _In_ INT nYStart, 70 _In_reads_(cchString) LPCWSTR lpString, 71 _In_ INT cchString) 72 { 73 return ExtTextOutW(hdc, nXStart, nYStart, 0, NULL, (LPWSTR)lpString, cchString, NULL); 74 } 75 76 77 /* 78 * @unimplemented 79 */ 80 BOOL 81 WINAPI 82 PolyTextOutA( 83 _In_ HDC hdc, 84 _In_reads_(cStrings) const POLYTEXTA *pptxt, 85 _In_ INT cStrings) 86 { 87 for (; cStrings>0; cStrings--, pptxt++) 88 { 89 if (!ExtTextOutA(hdc, 90 pptxt->x, 91 pptxt->y, 92 pptxt->uiFlags, 93 &pptxt->rcl, 94 pptxt->lpstr, 95 pptxt->n, 96 pptxt->pdx)) 97 { 98 return FALSE; 99 } 100 } 101 102 return TRUE; 103 } 104 105 106 /* 107 * @unimplemented 108 */ 109 BOOL 110 WINAPI 111 PolyTextOutW( 112 _In_ HDC hdc, 113 _In_reads_(cStrings) const POLYTEXTW *pptxt, 114 _In_ INT cStrings) 115 { 116 for (; cStrings>0; cStrings--, pptxt++) 117 { 118 if (!ExtTextOutW(hdc, 119 pptxt->x, 120 pptxt->y, 121 pptxt->uiFlags, 122 &pptxt->rcl, 123 pptxt->lpstr, 124 pptxt->n, 125 pptxt->pdx)) 126 { 127 return FALSE; 128 } 129 } 130 131 return TRUE; 132 } 133 134 135 /* 136 * @implemented 137 */ 138 DWORD 139 WINAPI 140 GdiGetCodePage( 141 _In_ HDC hdc) 142 { 143 PDC_ATTR pdcattr; 144 145 /* Get the DC attribute */ 146 pdcattr = GdiGetDcAttr(hdc); 147 if (pdcattr == NULL) 148 { 149 SetLastError(ERROR_INVALID_PARAMETER); 150 return 0; 151 } 152 153 if (pdcattr->ulDirty_ & DIRTY_CHARSET) 154 return LOWORD(NtGdiGetCharSet(hdc)); 155 156 return LOWORD(pdcattr->iCS_CP); 157 } 158 159 160 /* 161 * @unimplemented 162 */ 163 INT 164 WINAPI 165 GetTextCharacterExtra( 166 _In_ HDC hdc) 167 { 168 PDC_ATTR pdcattr; 169 170 /* Get the DC attribute */ 171 pdcattr = GdiGetDcAttr(hdc); 172 if (pdcattr == NULL) 173 { 174 /* Do not set LastError here! */ 175 return 0x8000000; 176 } 177 178 return pdcattr->lTextExtra; 179 } 180 181 182 /* 183 * @implemented 184 */ 185 INT 186 WINAPI 187 GetTextCharset( 188 _In_ HDC hdc) 189 { 190 /* MSDN docs say this is equivalent */ 191 return NtGdiGetTextCharsetInfo(hdc,NULL,0); 192 } 193 194 195 /* 196 * @implemented 197 */ 198 BOOL 199 WINAPI 200 GetTextMetricsA( 201 _In_ HDC hdc, 202 _Out_ LPTEXTMETRICA lptm) 203 { 204 TMW_INTERNAL tmwi; 205 206 if (!NtGdiGetTextMetricsW(hdc, &tmwi, sizeof(TMW_INTERNAL))) 207 { 208 return FALSE; 209 } 210 211 FONT_TextMetricWToA(&tmwi.TextMetric, lptm); 212 return TRUE; 213 } 214 215 216 /* 217 * @implemented 218 */ 219 BOOL 220 WINAPI 221 GetTextMetricsW( 222 _In_ HDC hdc, 223 _Out_ LPTEXTMETRICW lptm) 224 { 225 TMW_INTERNAL tmwi; 226 227 if (!NtGdiGetTextMetricsW(hdc, &tmwi, sizeof(TMW_INTERNAL))) 228 { 229 return FALSE; 230 } 231 232 *lptm = tmwi.TextMetric; 233 return TRUE; 234 } 235 236 237 /* 238 * @implemented 239 */ 240 BOOL 241 APIENTRY 242 GetTextExtentPointA( 243 _In_ HDC hdc, 244 _In_reads_(cchString) LPCSTR lpString, 245 _In_ INT cchString, 246 _Out_ LPSIZE lpsz) 247 { 248 ANSI_STRING StringA; 249 UNICODE_STRING StringU; 250 BOOL ret; 251 252 RtlInitAnsiString(&StringA, (LPSTR)lpString); 253 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE); 254 255 ret = GetTextExtentPointW(hdc, StringU.Buffer, cchString, lpsz); 256 257 RtlFreeUnicodeString(&StringU); 258 259 return ret; 260 } 261 262 263 /* 264 * @implemented 265 */ 266 BOOL 267 APIENTRY 268 GetTextExtentPointW( 269 _In_ HDC hdc, 270 _In_reads_(cchString) LPCWSTR lpString, 271 _In_ INT cchString, 272 _Out_ LPSIZE lpsz) 273 { 274 return NtGdiGetTextExtent(hdc, (LPWSTR)lpString, cchString, lpsz, 0); 275 } 276 277 278 /* 279 * @implemented 280 */ 281 BOOL 282 WINAPI 283 GetTextExtentExPointW( 284 _In_ HDC hdc, 285 _In_reads_(cchString) LPCWSTR lpszString, 286 _In_ INT cchString, 287 _In_ INT nMaxExtent, 288 _Out_opt_ LPINT lpnFit, 289 _Out_writes_to_opt_(cchString, *lpnFit) LPINT lpnDx, 290 _Out_ LPSIZE lpSize) 291 { 292 293 /* Windows doesn't check nMaxExtent validity in unicode version */ 294 if (nMaxExtent < -1) 295 { 296 DPRINT("nMaxExtent is invalid: %d\n", nMaxExtent); 297 } 298 299 if (LoadLPK(LPK_GTEP)) 300 return LpkGetTextExtentExPoint(hdc, lpszString, cchString, nMaxExtent, lpnFit, lpnDx, lpSize, 0, 0); 301 302 return NtGdiGetTextExtentExW ( 303 hdc, (LPWSTR)lpszString, cchString, nMaxExtent, (PULONG)lpnFit, (PULONG)lpnDx, lpSize, 0 ); 304 } 305 306 307 /* 308 * @implemented 309 */ 310 BOOL 311 WINAPI 312 GetTextExtentExPointWPri( 313 _In_ HDC hdc, 314 _In_reads_(cwc) LPCWSTR lpwsz, 315 _In_ INT cwc, 316 _In_ INT dxMax, 317 _Out_opt_ LPINT pcCh, 318 _Out_writes_to_opt_(cwc, *pcCh) LPINT pdxOut, 319 _In_ LPSIZE psize) 320 { 321 return NtGdiGetTextExtentExW(hdc, (LPWSTR)lpwsz, cwc, dxMax, (PULONG)pcCh, (PULONG)pdxOut, psize, 0); 322 } 323 324 /* 325 * @implemented 326 */ 327 BOOL 328 WINAPI 329 GetTextExtentExPointA( 330 _In_ HDC hdc, 331 _In_reads_(cchString) LPCSTR lpszStr, 332 _In_ INT cchString, 333 _In_ INT nMaxExtent, 334 _Out_opt_ LPINT lpnFit, 335 _Out_writes_to_opt_ (cchString, *lpnFit) LPINT lpnDx, 336 _Out_ LPSIZE lpSize) 337 { 338 NTSTATUS Status; 339 LPWSTR lpszStrW; 340 BOOL bResult = FALSE; 341 342 if (nMaxExtent < -1) 343 { 344 SetLastError(ERROR_INVALID_PARAMETER); 345 return FALSE; 346 } 347 348 Status = HEAP_strdupA2W(&lpszStrW, lpszStr); 349 if (!NT_SUCCESS (Status)) 350 { 351 SetLastError(RtlNtStatusToDosError(Status)); 352 return FALSE; 353 } 354 355 bResult = NtGdiGetTextExtentExW(hdc, 356 lpszStrW, 357 cchString, 358 nMaxExtent, 359 (PULONG)lpnFit, 360 (PULONG)lpnDx, 361 lpSize, 362 0); 363 364 HEAP_free(lpszStrW); 365 366 return bResult; 367 } 368 369 370 /* 371 * @implemented 372 */ 373 BOOL 374 WINAPI 375 GetTextExtentPoint32A( 376 _In_ HDC hdc, 377 _In_reads_(cchString) LPCSTR lpString, 378 _In_ INT cchString, 379 _Out_ LPSIZE lpSize) 380 { 381 ANSI_STRING StringA; 382 UNICODE_STRING StringU; 383 BOOL ret; 384 385 StringA.Buffer = (LPSTR)lpString; 386 StringA.Length = cchString; 387 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE); 388 389 ret = GetTextExtentPoint32W(hdc, StringU.Buffer, cchString, lpSize); 390 391 RtlFreeUnicodeString(&StringU); 392 393 return ret; 394 } 395 396 397 /* 398 * @implemented 399 */ 400 BOOL 401 WINAPI 402 GetTextExtentPoint32W( 403 _In_ HDC hdc, 404 _In_reads_(cchString) LPCWSTR lpString, 405 _In_ int cchString, 406 _Out_ LPSIZE lpSize) 407 { 408 return NtGdiGetTextExtent(hdc, (LPWSTR)lpString, cchString, lpSize, 0); 409 } 410 411 /* 412 * @implemented 413 */ 414 BOOL 415 WINAPI 416 GetTextExtentExPointI( 417 _In_ HDC hdc, 418 _In_reads_(cgi) LPWORD pgiIn, 419 _In_ INT cgi, 420 _In_ INT nMaxExtent, 421 _Out_opt_ LPINT lpnFit, 422 _Out_writes_to_opt_(cwchString, *lpnFit) LPINT lpnDx, 423 _Out_ LPSIZE lpSize) 424 { 425 return NtGdiGetTextExtentExW(hdc, 426 pgiIn, 427 cgi, 428 nMaxExtent, 429 (PULONG)lpnFit, 430 (PULONG)lpnDx, 431 lpSize, 432 GTEF_INDICES); 433 } 434 435 /* 436 * @implemented 437 */ 438 BOOL 439 WINAPI 440 GetTextExtentPointI( 441 _In_ HDC hdc, 442 _In_reads_(cgi) LPWORD pgiIn, 443 _In_ int cgi, 444 _Out_ LPSIZE lpSize) 445 { 446 return NtGdiGetTextExtent(hdc, pgiIn, cgi, lpSize, GTEF_INDICES); 447 } 448 449 /* 450 * @implemented 451 */ 452 BOOL 453 WINAPI 454 ExtTextOutA( 455 _In_ HDC hdc, 456 _In_ INT x, 457 _In_ INT y, 458 _In_ UINT fuOptions, 459 _In_opt_ const RECT *lprc, 460 _In_reads_opt_(cch) LPCSTR lpString, 461 _In_ UINT cch, 462 _In_reads_opt_(cch) const INT *lpDx) 463 { 464 ANSI_STRING StringA; 465 UNICODE_STRING StringU; 466 BOOL ret; 467 468 RtlInitAnsiString(&StringA, (LPSTR)lpString); 469 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE); 470 471 ret = ExtTextOutW(hdc, x, y, fuOptions, lprc, StringU.Buffer, cch, lpDx); 472 473 RtlFreeUnicodeString(&StringU); 474 475 return ret; 476 } 477 478 static BOOL bBypassETOWMF = FALSE; 479 480 /* 481 * @implemented 482 */ 483 BOOL 484 WINAPI 485 ExtTextOutW( 486 _In_ HDC hdc, 487 _In_ INT x, 488 _In_ INT y, 489 _In_ UINT fuOptions, 490 _In_opt_ const RECT *lprc, 491 _In_reads_opt_(cwc) LPCWSTR lpString, 492 _In_ UINT cwc, 493 _In_reads_opt_(cwc) const INT *lpDx) 494 { 495 PDC_ATTR pdcattr; 496 497 // Need both, should return a parameter error? No they don't! 498 if ( !lpDx && fuOptions & ETO_PDY ) 499 return FALSE; 500 501 // Now sorting out rectangle. 502 503 // Here again, need both. 504 if ( lprc && !(fuOptions & (ETO_CLIPPED|ETO_OPAQUE)) ) 505 { 506 lprc = NULL; // No flags, no rectangle. 507 } 508 else if (!lprc) // No rectangle, force clear flags if set and continue. 509 { 510 fuOptions &= ~(ETO_CLIPPED|ETO_OPAQUE); 511 } 512 513 if ( !bBypassETOWMF ) 514 { 515 HANDLE_METADC(BOOL, 516 ExtTextOut, 517 FALSE, 518 hdc, 519 x, 520 y, 521 fuOptions, 522 lprc, 523 lpString, 524 cwc, 525 lpDx); 526 } 527 528 if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE; 529 530 if (!(fuOptions & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE))) 531 { 532 bBypassETOWMF = TRUE; 533 534 if (LoadLPK(LPK_ETO)) 535 return LpkExtTextOut(hdc, x, y, fuOptions, lprc, lpString, cwc , lpDx, 0); 536 } 537 else 538 { 539 bBypassETOWMF = FALSE; 540 } 541 542 /* Get the DC attribute */ 543 pdcattr = GdiGetDcAttr(hdc); 544 if ( pdcattr && 545 !(pdcattr->ulDirty_ & DC_DIBSECTION) && 546 !(pdcattr->lTextAlign & TA_UPDATECP)) 547 { 548 if ( lprc && !cwc ) 549 { 550 if ( fuOptions & ETO_OPAQUE ) 551 { 552 PGDIBSEXTTEXTOUT pgO; 553 554 pgO = GdiAllocBatchCommand(hdc, GdiBCExtTextOut); 555 if (pgO) 556 { 557 pdcattr->ulDirty_ |= DC_MODE_DIRTY; 558 pgO->Count = cwc; 559 pgO->Rect = *lprc; 560 pgO->Options = fuOptions; 561 /* Snapshot attribute */ 562 pgO->ulBackgroundClr = pdcattr->ulBackgroundClr; 563 pgO->ptlViewportOrg = pdcattr->ptlViewportOrg; 564 return TRUE; 565 } 566 } 567 else // Do nothing, old explorer pops this off. 568 { 569 DPRINT1("GdiBCExtTextOut nothing\n"); 570 return TRUE; 571 } 572 } // Max 580 wchars, if offset 0 573 else if ( cwc <= ((GDIBATCHBUFSIZE - sizeof(GDIBSTEXTOUT)) / sizeof(WCHAR)) ) 574 { 575 PGDIBSTEXTOUT pgO; 576 PTEB pTeb = NtCurrentTeb(); 577 578 pgO = GdiAllocBatchCommand(hdc, GdiBCTextOut); 579 if (pgO) 580 { 581 USHORT cjSize = 0; 582 ULONG DxSize = 0; 583 584 if (cwc > 2) cjSize = (cwc * sizeof(WCHAR)) - sizeof(pgO->String); 585 586 /* Calculate buffer size for string and Dx values */ 587 if (lpDx) 588 { 589 /* If ETO_PDY is specified, we have pairs of INTs */ 590 DxSize = (cwc * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1); 591 cjSize += DxSize; 592 // The structure buffer holds 4 bytes. Store Dx data then string. 593 // Result one wchar -> Buf[ Dx ]Str[wC], [4][2][X] one extra unused wchar 594 // to assure alignment of 4. 595 } 596 597 if ((pTeb->GdiTebBatch.Offset + cjSize ) <= GDIBATCHBUFSIZE) 598 { 599 pdcattr->ulDirty_ |= DC_MODE_DIRTY|DC_FONTTEXT_DIRTY; 600 pgO->cbCount = cwc; 601 pgO->x = x; 602 pgO->y = y; 603 pgO->Options = fuOptions; 604 pgO->iCS_CP = 0; 605 606 if (lprc) pgO->Rect = *lprc; 607 else 608 { 609 pgO->Options |= GDIBS_NORECT; // Tell the other side lprc is nill. 610 } 611 612 /* Snapshot attributes */ 613 pgO->crForegroundClr = pdcattr->crForegroundClr; 614 pgO->crBackgroundClr = pdcattr->crBackgroundClr; 615 pgO->ulForegroundClr = pdcattr->ulForegroundClr; 616 pgO->ulBackgroundClr = pdcattr->ulBackgroundClr; 617 pgO->lBkMode = pdcattr->lBkMode == OPAQUE ? OPAQUE : TRANSPARENT; 618 pgO->hlfntNew = pdcattr->hlfntNew; 619 pgO->flTextAlign = pdcattr->flTextAlign; 620 pgO->ptlViewportOrg = pdcattr->ptlViewportOrg; 621 622 pgO->Size = DxSize; // of lpDx then string after. 623 /* Put the Dx before the String to assure alignment of 4 */ 624 if (lpDx) RtlCopyMemory( &pgO->Buffer, lpDx, DxSize); 625 626 if (cwc) RtlCopyMemory( &pgO->String[DxSize/sizeof(WCHAR)], lpString, cwc * sizeof(WCHAR)); 627 628 // Recompute offset and return size 629 pTeb->GdiTebBatch.Offset += cjSize; 630 ((PGDIBATCHHDR)pgO)->Size += cjSize; 631 return TRUE; 632 } 633 // Reset offset and count then fall through 634 pTeb->GdiTebBatch.Offset -= sizeof(GDIBSTEXTOUT); 635 pTeb->GdiBatchCount--; 636 } 637 } 638 } 639 return NtGdiExtTextOutW(hdc, 640 x, 641 y, 642 fuOptions, 643 (LPRECT)lprc, 644 (LPWSTR)lpString, 645 cwc, 646 (LPINT)lpDx, 647 0); 648 } 649 650 651 /* 652 * @implemented 653 */ 654 INT 655 WINAPI 656 GetTextFaceW( 657 _In_ HDC hdc, 658 _In_ INT cwcMax, 659 _Out_writes_to_opt_(cwcMax, return) LPWSTR pFaceName) 660 { 661 /* Validate parameters */ 662 if (pFaceName && cwcMax <= 0) 663 { 664 /* Set last error and return failure */ 665 GdiSetLastError(ERROR_INVALID_PARAMETER); 666 return 0; 667 } 668 669 /* Forward to kernel */ 670 return NtGdiGetTextFaceW(hdc, cwcMax, pFaceName, FALSE); 671 } 672 673 674 /* 675 * @implemented 676 */ 677 INT 678 WINAPI 679 GetTextFaceA( 680 _In_ HDC hdc, 681 _In_ INT cchMax, 682 _Out_writes_to_opt_(cchMax, return) LPSTR lpName) 683 { 684 INT res; 685 LPWSTR nameW; 686 687 /* Validate parameters */ 688 if (lpName && cchMax <= 0) 689 { 690 /* Set last error and return failure */ 691 GdiSetLastError(ERROR_INVALID_PARAMETER); 692 return 0; 693 } 694 695 res = GetTextFaceW(hdc, 0, NULL); 696 nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 ); 697 if (nameW == NULL) 698 { 699 return 0; 700 } 701 702 GetTextFaceW( hdc, res, nameW ); 703 704 if (lpName) 705 { 706 if (cchMax && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, lpName, cchMax, NULL, NULL)) 707 lpName[cchMax-1] = 0; 708 res = strlen(lpName); 709 } 710 else 711 { 712 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL); 713 } 714 715 HeapFree( GetProcessHeap(), 0, nameW ); 716 return res; 717 } 718 719 720 /* 721 * @implemented 722 */ 723 INT 724 WINAPI 725 GetTextFaceAliasW( 726 _In_ HDC hdc, 727 _In_ INT cwcMax, 728 _Out_writes_to_opt_(cwcMax, return) LPWSTR pszOut) 729 { 730 if (pszOut && !cwcMax) 731 { 732 GdiSetLastError(ERROR_INVALID_PARAMETER); 733 return 0; 734 } 735 736 return NtGdiGetTextFaceW(hdc, cwcMax, pszOut, TRUE); 737 } 738 739 740 BOOL 741 WINAPI 742 GetFontResourceInfoW( 743 _In_z_ LPCWSTR lpFileName, 744 _Inout_ DWORD *pdwBufSize, 745 _Out_writes_to_opt_(*pdwBufSize, 1) PVOID lpBuffer, 746 _In_ DWORD dwType) 747 { 748 BOOL bRet; 749 UNICODE_STRING NtFileName; 750 751 DPRINT("GetFontResourceInfoW: dwType = %lu\n", dwType); 752 753 if (!lpFileName || !pdwBufSize) 754 { 755 SetLastError(ERROR_INVALID_PARAMETER); 756 return FALSE; 757 } 758 759 if (!RtlDosPathNameToNtPathName_U(lpFileName, 760 &NtFileName, 761 NULL, 762 NULL)) 763 { 764 SetLastError(ERROR_PATH_NOT_FOUND); 765 return FALSE; 766 } 767 768 bRet = NtGdiGetFontResourceInfoInternalW( 769 NtFileName.Buffer, 770 (NtFileName.Length / sizeof(WCHAR)) + 1, 771 1, 772 *pdwBufSize, 773 pdwBufSize, 774 lpBuffer, 775 dwType); 776 777 RtlFreeHeap(RtlGetProcessHeap(), 0, NtFileName.Buffer); 778 779 return bRet; 780 } 781 782 783 /* 784 * @unimplemented 785 */ 786 INT 787 WINAPI 788 SetTextCharacterExtra( 789 _In_ HDC hdc, 790 _In_ INT nCharExtra) 791 { 792 PDC_ATTR pdcattr; 793 INT nOldCharExtra; 794 795 if (nCharExtra == 0x80000000) 796 { 797 SetLastError(ERROR_INVALID_PARAMETER); 798 return 0x80000000; 799 } 800 801 HANDLE_METADC16(INT, SetTextCharacterExtra, 0x80000000, hdc, nCharExtra); 802 803 /* Get the DC attribute */ 804 pdcattr = GdiGetDcAttr(hdc); 805 if (pdcattr == NULL) 806 { 807 SetLastError(ERROR_INVALID_PARAMETER); 808 return 0x8000000; 809 } 810 811 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc) 812 { 813 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY) 814 { 815 NtGdiFlush(); // Sync up pdcattr from Kernel space. 816 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY); 817 } 818 } 819 820 nOldCharExtra = pdcattr->lTextExtra; 821 pdcattr->lTextExtra = nCharExtra; 822 return nOldCharExtra; 823 } 824 825 /* 826 * @implemented 827 * 828 */ 829 UINT 830 WINAPI 831 GetTextAlign( 832 _In_ HDC hdc) 833 { 834 PDC_ATTR pdcattr; 835 836 /* Get the DC attribute */ 837 pdcattr = GdiGetDcAttr(hdc); 838 if (pdcattr == NULL) 839 { 840 /* Do not set LastError here! */ 841 return GDI_ERROR; 842 } 843 844 return pdcattr->lTextAlign; 845 } 846 847 848 /* 849 * @implemented 850 * 851 */ 852 COLORREF 853 WINAPI 854 GetTextColor( 855 _In_ HDC hdc) 856 { 857 PDC_ATTR pdcattr; 858 859 /* Get the DC attribute */ 860 pdcattr = GdiGetDcAttr(hdc); 861 if (pdcattr == NULL) 862 { 863 /* Do not set LastError here! */ 864 return CLR_INVALID; 865 } 866 867 return pdcattr->ulForegroundClr; 868 } 869 870 871 /* 872 * @unimplemented 873 */ 874 UINT 875 WINAPI 876 SetTextAlign( 877 _In_ HDC hdc, 878 _In_ UINT fMode) 879 { 880 PDC_ATTR pdcattr; 881 UINT fOldMode; 882 883 HANDLE_METADC(BOOL, SetTextAlign, GDI_ERROR, hdc, fMode); 884 885 /* Get the DC attribute */ 886 pdcattr = GdiGetDcAttr(hdc); 887 if (pdcattr == NULL) 888 { 889 SetLastError(ERROR_INVALID_PARAMETER); 890 return GDI_ERROR; 891 } 892 893 894 fOldMode = pdcattr->lTextAlign; 895 pdcattr->lTextAlign = fMode; // Raw 896 if (pdcattr->dwLayout & LAYOUT_RTL) 897 { 898 if ((fMode & TA_CENTER) != TA_CENTER) fMode ^= TA_RIGHT; 899 } 900 901 pdcattr->flTextAlign = fMode & TA_MASK; 902 return fOldMode; 903 } 904 905 906 /* 907 * @implemented 908 */ 909 COLORREF 910 WINAPI 911 SetTextColor( 912 _In_ HDC hdc, 913 _In_ COLORREF crColor) 914 { 915 PDC_ATTR pdcattr; 916 COLORREF crOldColor; 917 918 HANDLE_METADC(COLORREF, SetTextColor, CLR_INVALID, hdc, crColor); 919 920 pdcattr = GdiGetDcAttr(hdc); 921 if (pdcattr == NULL) 922 { 923 SetLastError(ERROR_INVALID_PARAMETER); 924 return CLR_INVALID; 925 } 926 927 crOldColor = (COLORREF) pdcattr->ulForegroundClr; 928 pdcattr->ulForegroundClr = (ULONG)crColor; 929 930 if (pdcattr->crForegroundClr != crColor) 931 { 932 pdcattr->ulDirty_ |= (DIRTY_TEXT|DIRTY_LINE|DIRTY_FILL); 933 pdcattr->crForegroundClr = crColor; 934 } 935 936 return crOldColor; 937 } 938 939 /* 940 * @implemented 941 */ 942 BOOL 943 WINAPI 944 SetTextJustification( 945 _In_ HDC hdc, 946 _In_ INT nBreakExtra, 947 _In_ INT nBreakCount) 948 { 949 PDC_ATTR pdcattr; 950 951 HANDLE_METADC16(BOOL, SetTextJustification, FALSE, hdc, nBreakExtra, nBreakCount); 952 953 /* Get the DC attribute */ 954 pdcattr = GdiGetDcAttr(hdc); 955 if (pdcattr == NULL) 956 { 957 /* Do not set LastError here! */ 958 return GDI_ERROR; 959 } 960 961 962 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc) 963 { 964 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY) 965 { 966 NtGdiFlush(); // Sync up pdcattr from Kernel space. 967 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY); 968 } 969 } 970 971 pdcattr->cBreak = nBreakCount; 972 pdcattr->lBreakExtra = nBreakExtra; 973 return TRUE; 974 } 975 976 /* 977 * @implemented 978 */ 979 UINT 980 WINAPI 981 GetStringBitmapA( 982 _In_ HDC hdc, 983 _In_ LPSTR psz, 984 _In_ BOOL bDoCall, 985 _In_ UINT cj, 986 _Out_writes_(cj) BYTE *lpSB) 987 { 988 989 NTSTATUS Status; 990 PWSTR pwsz; 991 UINT uResult = 0; 992 993 if (!bDoCall) 994 { 995 return 0; 996 } 997 998 Status = HEAP_strdupA2W(&pwsz, psz); 999 if (!NT_SUCCESS(Status)) 1000 { 1001 SetLastError (RtlNtStatusToDosError(Status)); 1002 } 1003 else 1004 { 1005 uResult = NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj); 1006 HEAP_free(pwsz); 1007 } 1008 1009 return uResult; 1010 1011 } 1012 1013 /* 1014 * @implemented 1015 */ 1016 UINT 1017 WINAPI 1018 GetStringBitmapW( 1019 _In_ HDC hdc, 1020 _In_ LPWSTR pwsz, 1021 _In_ BOOL bDoCall, 1022 _In_ UINT cj, 1023 _Out_writes_(cj) BYTE *lpSB) 1024 { 1025 if (!bDoCall) 1026 { 1027 return 0; 1028 } 1029 1030 return NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj); 1031 1032 } 1033 1034 /* 1035 * @implemented 1036 */ 1037 BOOL 1038 WINAPI 1039 GetETM( 1040 _In_ HDC hdc, 1041 _Out_ EXTTEXTMETRIC *petm) 1042 { 1043 BOOL bResult; 1044 1045 bResult = NtGdiGetETM(hdc, petm); 1046 1047 if (bResult && petm) 1048 { 1049 petm->emKernPairs = (WORD)GetKerningPairsA(hdc, 0, 0); 1050 } 1051 1052 return bResult; 1053 } 1054