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 if ( !bBypassETOWMF ) 498 { 499 HANDLE_METADC(BOOL, 500 ExtTextOut, 501 FALSE, 502 hdc, 503 x, 504 y, 505 fuOptions, 506 lprc, 507 lpString, 508 cwc, 509 lpDx); 510 } 511 512 if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE; 513 514 if (!(fuOptions & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE))) 515 { 516 bBypassETOWMF = TRUE; 517 518 if (LoadLPK(LPK_ETO)) 519 return LpkExtTextOut(hdc, x, y, fuOptions, lprc, lpString, cwc , lpDx, 0); 520 } 521 else 522 { 523 bBypassETOWMF = FALSE; 524 } 525 526 /* Get the DC attribute */ 527 pdcattr = GdiGetDcAttr(hdc); 528 if ( pdcattr && 529 !(pdcattr->ulDirty_ & DC_DIBSECTION) && 530 !(pdcattr->lTextAlign & TA_UPDATECP)) 531 { 532 if ( lprc && !cwc ) 533 { 534 if ( fuOptions & ETO_OPAQUE ) 535 { 536 PGDIBSEXTTEXTOUT pgO; 537 538 pgO = GdiAllocBatchCommand(hdc, GdiBCExtTextOut); 539 if (pgO) 540 { 541 pdcattr->ulDirty_ |= DC_MODE_DIRTY; 542 pgO->Count = cwc; 543 pgO->Rect = *lprc; 544 pgO->Options = fuOptions; 545 /* Snapshot attribute */ 546 pgO->ulBackgroundClr = pdcattr->ulBackgroundClr; 547 pgO->ptlViewportOrg = pdcattr->ptlViewportOrg; 548 return TRUE; 549 } 550 } 551 else // Do nothing, old explorer pops this off. 552 { 553 DPRINT1("GdiBCExtTextOut nothing\n"); 554 return TRUE; 555 } 556 } // Max 580 wchars, if offset 0 557 else if ( cwc <= ((GDIBATCHBUFSIZE - sizeof(GDIBSTEXTOUT)) / sizeof(WCHAR)) ) 558 { 559 PGDIBSTEXTOUT pgO; 560 PTEB pTeb = NtCurrentTeb(); 561 562 pgO = GdiAllocBatchCommand(hdc, GdiBCTextOut); 563 if (pgO) 564 { 565 USHORT cjSize = 0; 566 ULONG DxSize = 0; 567 568 if (cwc > 2) cjSize = (cwc * sizeof(WCHAR)) - sizeof(pgO->String); 569 570 /* Calculate buffer size for string and Dx values */ 571 if (lpDx) 572 { 573 /* If ETO_PDY is specified, we have pairs of INTs */ 574 DxSize = (cwc * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1); 575 cjSize += DxSize; 576 // The structure buffer holds 4 bytes. Store Dx data then string. 577 // Result one wchar -> Buf[ Dx ]Str[wC], [4][2][X] one extra unused wchar 578 // to assure alignment of 4. 579 } 580 581 if ((pTeb->GdiTebBatch.Offset + cjSize ) <= GDIBATCHBUFSIZE) 582 { 583 pdcattr->ulDirty_ |= DC_MODE_DIRTY|DC_FONTTEXT_DIRTY; 584 pgO->cbCount = cwc; 585 pgO->x = x; 586 pgO->y = y; 587 pgO->Options = fuOptions; 588 pgO->iCS_CP = 0; 589 590 if (lprc) pgO->Rect = *lprc; 591 else 592 { 593 pgO->Options |= GDIBS_NORECT; // Tell the other side lprc is nill. 594 } 595 596 /* Snapshot attributes */ 597 pgO->crForegroundClr = pdcattr->crForegroundClr; 598 pgO->crBackgroundClr = pdcattr->crBackgroundClr; 599 pgO->ulForegroundClr = pdcattr->ulForegroundClr; 600 pgO->ulBackgroundClr = pdcattr->ulBackgroundClr; 601 pgO->lBkMode = pdcattr->lBkMode == OPAQUE ? OPAQUE : TRANSPARENT; 602 pgO->hlfntNew = pdcattr->hlfntNew; 603 pgO->flTextAlign = pdcattr->flTextAlign; 604 pgO->ptlViewportOrg = pdcattr->ptlViewportOrg; 605 606 pgO->Size = DxSize; // of lpDx then string after. 607 /* Put the Dx before the String to assure alignment of 4 */ 608 if (lpDx) RtlCopyMemory( &pgO->Buffer, lpDx, DxSize); 609 610 if (cwc) RtlCopyMemory( &pgO->String[DxSize/sizeof(WCHAR)], lpString, cwc * sizeof(WCHAR)); 611 612 // Recompute offset and return size 613 pTeb->GdiTebBatch.Offset += cjSize; 614 ((PGDIBATCHHDR)pgO)->Size += cjSize; 615 return TRUE; 616 } 617 // Reset offset and count then fall through 618 pTeb->GdiTebBatch.Offset -= sizeof(GDIBSTEXTOUT); 619 pTeb->GdiBatchCount--; 620 } 621 } 622 } 623 return NtGdiExtTextOutW(hdc, 624 x, 625 y, 626 fuOptions, 627 (LPRECT)lprc, 628 (LPWSTR)lpString, 629 cwc, 630 (LPINT)lpDx, 631 0); 632 } 633 634 635 /* 636 * @implemented 637 */ 638 INT 639 WINAPI 640 GetTextFaceW( 641 _In_ HDC hdc, 642 _In_ INT cwcMax, 643 _Out_writes_to_opt_(cwcMax, return) LPWSTR pFaceName) 644 { 645 /* Validate parameters */ 646 if (pFaceName && cwcMax <= 0) 647 { 648 /* Set last error and return failure */ 649 GdiSetLastError(ERROR_INVALID_PARAMETER); 650 return 0; 651 } 652 653 /* Forward to kernel */ 654 return NtGdiGetTextFaceW(hdc, cwcMax, pFaceName, FALSE); 655 } 656 657 658 /* 659 * @implemented 660 */ 661 INT 662 WINAPI 663 GetTextFaceA( 664 _In_ HDC hdc, 665 _In_ INT cchMax, 666 _Out_writes_to_opt_(cchMax, return) LPSTR lpName) 667 { 668 INT res; 669 LPWSTR nameW; 670 671 /* Validate parameters */ 672 if (lpName && cchMax <= 0) 673 { 674 /* Set last error and return failure */ 675 GdiSetLastError(ERROR_INVALID_PARAMETER); 676 return 0; 677 } 678 679 res = GetTextFaceW(hdc, 0, NULL); 680 nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 ); 681 if (nameW == NULL) 682 { 683 return 0; 684 } 685 686 GetTextFaceW( hdc, res, nameW ); 687 688 if (lpName) 689 { 690 if (cchMax && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, lpName, cchMax, NULL, NULL)) 691 lpName[cchMax-1] = 0; 692 res = strlen(lpName); 693 } 694 else 695 { 696 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL); 697 } 698 699 HeapFree( GetProcessHeap(), 0, nameW ); 700 return res; 701 } 702 703 704 /* 705 * @implemented 706 */ 707 INT 708 WINAPI 709 GetTextFaceAliasW( 710 _In_ HDC hdc, 711 _In_ INT cwcMax, 712 _Out_writes_to_opt_(cwcMax, return) LPWSTR pszOut) 713 { 714 if (pszOut && !cwcMax) 715 { 716 GdiSetLastError(ERROR_INVALID_PARAMETER); 717 return 0; 718 } 719 720 return NtGdiGetTextFaceW(hdc, cwcMax, pszOut, TRUE); 721 } 722 723 724 BOOL 725 WINAPI 726 GetFontResourceInfoW( 727 _In_z_ LPCWSTR lpFileName, 728 _Inout_ DWORD *pdwBufSize, 729 _Out_writes_to_opt_(*pdwBufSize, 1) PVOID lpBuffer, 730 _In_ DWORD dwType) 731 { 732 BOOL bRet; 733 UNICODE_STRING NtFileName; 734 735 DPRINT("GetFontResourceInfoW: dwType = %lu\n", dwType); 736 737 if (!lpFileName || !pdwBufSize) 738 { 739 SetLastError(ERROR_INVALID_PARAMETER); 740 return FALSE; 741 } 742 743 if (!RtlDosPathNameToNtPathName_U(lpFileName, 744 &NtFileName, 745 NULL, 746 NULL)) 747 { 748 SetLastError(ERROR_PATH_NOT_FOUND); 749 return FALSE; 750 } 751 752 bRet = NtGdiGetFontResourceInfoInternalW( 753 NtFileName.Buffer, 754 (NtFileName.Length / sizeof(WCHAR)) + 1, 755 1, 756 *pdwBufSize, 757 pdwBufSize, 758 lpBuffer, 759 dwType); 760 761 RtlFreeHeap(RtlGetProcessHeap(), 0, NtFileName.Buffer); 762 763 return bRet; 764 } 765 766 767 /* 768 * @unimplemented 769 */ 770 INT 771 WINAPI 772 SetTextCharacterExtra( 773 _In_ HDC hdc, 774 _In_ INT nCharExtra) 775 { 776 PDC_ATTR pdcattr; 777 INT nOldCharExtra; 778 779 if (nCharExtra == 0x80000000) 780 { 781 SetLastError(ERROR_INVALID_PARAMETER); 782 return 0x80000000; 783 } 784 785 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) 786 { 787 HANDLE_METADC(INT, SetTextCharacterExtra, 0x80000000, hdc, nCharExtra); 788 } 789 790 /* Get the DC attribute */ 791 pdcattr = GdiGetDcAttr(hdc); 792 if (pdcattr == NULL) 793 { 794 SetLastError(ERROR_INVALID_PARAMETER); 795 return 0x8000000; 796 } 797 798 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc) 799 { 800 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY) 801 { 802 NtGdiFlush(); // Sync up pdcattr from Kernel space. 803 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY); 804 } 805 } 806 807 nOldCharExtra = pdcattr->lTextExtra; 808 pdcattr->lTextExtra = nCharExtra; 809 return nOldCharExtra; 810 } 811 812 /* 813 * @implemented 814 * 815 */ 816 UINT 817 WINAPI 818 GetTextAlign( 819 _In_ HDC hdc) 820 { 821 PDC_ATTR pdcattr; 822 823 /* Get the DC attribute */ 824 pdcattr = GdiGetDcAttr(hdc); 825 if (pdcattr == NULL) 826 { 827 /* Do not set LastError here! */ 828 return GDI_ERROR; 829 } 830 831 return pdcattr->lTextAlign; 832 } 833 834 835 /* 836 * @implemented 837 * 838 */ 839 COLORREF 840 WINAPI 841 GetTextColor( 842 _In_ HDC hdc) 843 { 844 PDC_ATTR pdcattr; 845 846 /* Get the DC attribute */ 847 pdcattr = GdiGetDcAttr(hdc); 848 if (pdcattr == NULL) 849 { 850 /* Do not set LastError here! */ 851 return CLR_INVALID; 852 } 853 854 return pdcattr->ulForegroundClr; 855 } 856 857 858 /* 859 * @unimplemented 860 */ 861 UINT 862 WINAPI 863 SetTextAlign( 864 _In_ HDC hdc, 865 _In_ UINT fMode) 866 { 867 PDC_ATTR pdcattr; 868 UINT fOldMode; 869 870 HANDLE_METADC(BOOL, SetTextAlign, GDI_ERROR, hdc, fMode); 871 872 /* Get the DC attribute */ 873 pdcattr = GdiGetDcAttr(hdc); 874 if (pdcattr == NULL) 875 { 876 SetLastError(ERROR_INVALID_PARAMETER); 877 return GDI_ERROR; 878 } 879 880 881 fOldMode = pdcattr->lTextAlign; 882 pdcattr->lTextAlign = fMode; // Raw 883 if (pdcattr->dwLayout & LAYOUT_RTL) 884 { 885 if ((fMode & TA_CENTER) != TA_CENTER) fMode ^= TA_RIGHT; 886 } 887 888 pdcattr->flTextAlign = fMode & TA_MASK; 889 return fOldMode; 890 } 891 892 893 /* 894 * @implemented 895 */ 896 COLORREF 897 WINAPI 898 SetTextColor( 899 _In_ HDC hdc, 900 _In_ COLORREF crColor) 901 { 902 PDC_ATTR pdcattr; 903 COLORREF crOldColor; 904 905 HANDLE_METADC(COLORREF, SetTextColor, CLR_INVALID, hdc, crColor); 906 907 pdcattr = GdiGetDcAttr(hdc); 908 if (pdcattr == NULL) 909 { 910 SetLastError(ERROR_INVALID_PARAMETER); 911 return CLR_INVALID; 912 } 913 914 crOldColor = (COLORREF) pdcattr->ulForegroundClr; 915 pdcattr->ulForegroundClr = (ULONG)crColor; 916 917 if (pdcattr->crForegroundClr != crColor) 918 { 919 pdcattr->ulDirty_ |= (DIRTY_TEXT|DIRTY_LINE|DIRTY_FILL); 920 pdcattr->crForegroundClr = crColor; 921 } 922 923 return crOldColor; 924 } 925 926 /* 927 * @implemented 928 */ 929 BOOL 930 WINAPI 931 SetTextJustification( 932 _In_ HDC hdc, 933 _In_ INT nBreakExtra, 934 _In_ INT nBreakCount) 935 { 936 PDC_ATTR pdcattr; 937 938 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE) 939 { 940 HANDLE_METADC(BOOL, SetTextJustification, FALSE, hdc, nBreakExtra, nBreakCount); 941 } 942 943 /* Get the DC attribute */ 944 pdcattr = GdiGetDcAttr(hdc); 945 if (pdcattr == NULL) 946 { 947 /* Do not set LastError here! */ 948 return GDI_ERROR; 949 } 950 951 952 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc) 953 { 954 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY) 955 { 956 NtGdiFlush(); // Sync up pdcattr from Kernel space. 957 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY); 958 } 959 } 960 961 pdcattr->cBreak = nBreakCount; 962 pdcattr->lBreakExtra = nBreakExtra; 963 return TRUE; 964 } 965 966 /* 967 * @implemented 968 */ 969 UINT 970 WINAPI 971 GetStringBitmapA( 972 _In_ HDC hdc, 973 _In_ LPSTR psz, 974 _In_ BOOL bDoCall, 975 _In_ UINT cj, 976 _Out_writes_(cj) BYTE *lpSB) 977 { 978 979 NTSTATUS Status; 980 PWSTR pwsz; 981 UINT uResult = 0; 982 983 if (!bDoCall) 984 { 985 return 0; 986 } 987 988 Status = HEAP_strdupA2W(&pwsz, psz); 989 if (!NT_SUCCESS(Status)) 990 { 991 SetLastError (RtlNtStatusToDosError(Status)); 992 } 993 else 994 { 995 uResult = NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj); 996 HEAP_free(pwsz); 997 } 998 999 return uResult; 1000 1001 } 1002 1003 /* 1004 * @implemented 1005 */ 1006 UINT 1007 WINAPI 1008 GetStringBitmapW( 1009 _In_ HDC hdc, 1010 _In_ LPWSTR pwsz, 1011 _In_ BOOL bDoCall, 1012 _In_ UINT cj, 1013 _Out_writes_(cj) BYTE *lpSB) 1014 { 1015 if (!bDoCall) 1016 { 1017 return 0; 1018 } 1019 1020 return NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj); 1021 1022 } 1023 1024 /* 1025 * @implemented 1026 */ 1027 BOOL 1028 WINAPI 1029 GetETM( 1030 _In_ HDC hdc, 1031 _Out_ EXTTEXTMETRIC *petm) 1032 { 1033 BOOL bResult; 1034 1035 bResult = NtGdiGetETM(hdc, petm); 1036 1037 if (bResult && petm) 1038 { 1039 petm->emKernPairs = (WORD)GetKerningPairsA(hdc, 0, 0); 1040 } 1041 1042 return bResult; 1043 } 1044