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