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