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