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