[Win32SS] Add TextOut to GDI Batch
[reactos.git] / win32ss / gdi / gdi32 / objects / text.c
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 return NtGdiGetTextExtentExW (
300 hdc, (LPWSTR)lpszString, cchString, nMaxExtent, (PULONG)lpnFit, (PULONG)lpnDx, lpSize, 0 );
301 }
302
303
304 /*
305 * @implemented
306 */
307 BOOL
308 WINAPI
309 GetTextExtentExPointWPri(
310 _In_ HDC hdc,
311 _In_reads_(cwc) LPWSTR lpwsz,
312 _In_ ULONG cwc,
313 _In_ ULONG dxMax,
314 _Out_opt_ ULONG *pcCh,
315 _Out_writes_to_opt_(cwc, *pcCh) PULONG pdxOut,
316 _In_ LPSIZE psize)
317 {
318 return NtGdiGetTextExtentExW(hdc, lpwsz, cwc, dxMax, pcCh, pdxOut, psize, 0);
319 }
320
321 /*
322 * @implemented
323 */
324 BOOL
325 WINAPI
326 GetTextExtentExPointA(
327 _In_ HDC hdc,
328 _In_reads_(cchString) LPCSTR lpszStr,
329 _In_ INT cchString,
330 _In_ INT nMaxExtent,
331 _Out_opt_ LPINT lpnFit,
332 _Out_writes_to_opt_ (cchString, *lpnFit) LPINT lpnDx,
333 _Out_ LPSIZE lpSize)
334 {
335 NTSTATUS Status;
336 LPWSTR lpszStrW;
337 BOOL bResult = FALSE;
338
339 if (nMaxExtent < -1)
340 {
341 SetLastError(ERROR_INVALID_PARAMETER);
342 return FALSE;
343 }
344
345 Status = HEAP_strdupA2W(&lpszStrW, lpszStr);
346 if (!NT_SUCCESS (Status))
347 {
348 SetLastError(RtlNtStatusToDosError(Status));
349 return FALSE;
350 }
351
352 bResult = NtGdiGetTextExtentExW(hdc,
353 lpszStrW,
354 cchString,
355 nMaxExtent,
356 (PULONG)lpnFit,
357 (PULONG)lpnDx,
358 lpSize,
359 0);
360
361 HEAP_free(lpszStrW);
362
363 return bResult;
364 }
365
366
367 /*
368 * @implemented
369 */
370 BOOL
371 WINAPI
372 GetTextExtentPoint32A(
373 _In_ HDC hdc,
374 _In_reads_(cchString) LPCSTR lpString,
375 _In_ INT cchString,
376 _Out_ LPSIZE lpSize)
377 {
378 ANSI_STRING StringA;
379 UNICODE_STRING StringU;
380 BOOL ret;
381
382 StringA.Buffer = (LPSTR)lpString;
383 StringA.Length = cchString;
384 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
385
386 ret = GetTextExtentPoint32W(hdc, StringU.Buffer, cchString, lpSize);
387
388 RtlFreeUnicodeString(&StringU);
389
390 return ret;
391 }
392
393
394 /*
395 * @implemented
396 */
397 BOOL
398 WINAPI
399 GetTextExtentPoint32W(
400 _In_ HDC hdc,
401 _In_reads_(cchString) LPCWSTR lpString,
402 _In_ int cchString,
403 _Out_ LPSIZE lpSize)
404 {
405 return NtGdiGetTextExtent(hdc, (LPWSTR)lpString, cchString, lpSize, 0);
406 }
407
408 /*
409 * @implemented
410 */
411 BOOL
412 WINAPI
413 GetTextExtentExPointI(
414 _In_ HDC hdc,
415 _In_reads_(cgi) LPWORD pgiIn,
416 _In_ INT cgi,
417 _In_ INT nMaxExtent,
418 _Out_opt_ LPINT lpnFit,
419 _Out_writes_to_opt_(cwchString, *lpnFit) LPINT lpnDx,
420 _Out_ LPSIZE lpSize)
421 {
422 return NtGdiGetTextExtentExW(hdc,
423 pgiIn,
424 cgi,
425 nMaxExtent,
426 (PULONG)lpnFit,
427 (PULONG)lpnDx,
428 lpSize,
429 GTEF_INDICES);
430 }
431
432 /*
433 * @implemented
434 */
435 BOOL
436 WINAPI
437 GetTextExtentPointI(
438 _In_ HDC hdc,
439 _In_reads_(cgi) LPWORD pgiIn,
440 _In_ int cgi,
441 _Out_ LPSIZE lpSize)
442 {
443 return NtGdiGetTextExtent(hdc, pgiIn, cgi, lpSize, GTEF_INDICES);
444 }
445
446 /*
447 * @implemented
448 */
449 BOOL
450 WINAPI
451 ExtTextOutA(
452 _In_ HDC hdc,
453 _In_ INT x,
454 _In_ INT y,
455 _In_ UINT fuOptions,
456 _In_opt_ const RECT *lprc,
457 _In_reads_opt_(cch) LPCSTR lpString,
458 _In_ UINT cch,
459 _In_reads_opt_(cch) const INT *lpDx)
460 {
461 ANSI_STRING StringA;
462 UNICODE_STRING StringU;
463 BOOL ret;
464
465 RtlInitAnsiString(&StringA, (LPSTR)lpString);
466 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
467
468 ret = ExtTextOutW(hdc, x, y, fuOptions, lprc, StringU.Buffer, cch, lpDx);
469
470 RtlFreeUnicodeString(&StringU);
471
472 return ret;
473 }
474
475
476 /*
477 * @implemented
478 */
479 BOOL
480 WINAPI
481 ExtTextOutW(
482 _In_ HDC hdc,
483 _In_ INT x,
484 _In_ INT y,
485 _In_ UINT fuOptions,
486 _In_opt_ const RECT *lprc,
487 _In_reads_opt_(cwc) LPCWSTR lpString,
488 _In_ UINT cwc,
489 _In_reads_opt_(cwc) const INT *lpDx)
490 {
491 PDC_ATTR pdcattr;
492
493 HANDLE_METADC(BOOL,
494 ExtTextOut,
495 FALSE,
496 hdc,
497 x,
498 y,
499 fuOptions,
500 lprc,
501 lpString,
502 cwc,
503 lpDx);
504
505 if (!(fuOptions & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)))
506 {
507 if (LoadLPK(LPK_ETO))
508 return LpkExtTextOut(hdc, x, y, fuOptions, lprc, lpString, cwc , lpDx, 0);
509 }
510
511 /* Get the DC attribute */
512 pdcattr = GdiGetDcAttr(hdc);
513 if ( pdcattr &&
514 !(pdcattr->ulDirty_ & DC_DIBSECTION) &&
515 !(pdcattr->lTextAlign & TA_UPDATECP))
516 {
517 if ( lprc && !cwc )
518 {
519 if ( fuOptions & ETO_OPAQUE )
520 {
521 PGDIBSEXTTEXTOUT pgO;
522
523 pgO = GdiAllocBatchCommand(hdc, GdiBCExtTextOut);
524 if (pgO)
525 {
526 pgO->Count = cwc;
527 pgO->Rect = *lprc;
528 pgO->Options = fuOptions;
529 /* Snapshot attribute */
530 pgO->ulBackgroundClr = pdcattr->ulBackgroundClr;
531 pgO->ptlViewportOrg = pdcattr->ptlViewportOrg;
532 return TRUE;
533 }
534 }
535 else // Do nothing, old explorer pops this off.
536 {
537 DPRINT1("GdiBCExtTextOut nothing\n");
538 return TRUE;
539 }
540 } // Max 580 wchars, if offset 0
541 else if ( cwc <= ((GDIBATCHBUFSIZE - sizeof(GDIBSTEXTOUT)) / sizeof(WCHAR)) )
542 {
543 PGDIBSTEXTOUT pgO;
544 PTEB pTeb = NtCurrentTeb();
545
546 pgO = GdiAllocBatchCommand(hdc, GdiBCTextOut);
547 if (pgO)
548 {
549 USHORT cjSize = 0;
550 ULONG DxSize = 0;
551
552 if (cwc > 2) cjSize = (cwc * sizeof(WCHAR)) - sizeof(pgO->String);
553
554 /* Calculate buffer size for string and Dx values */
555 if (lpDx)
556 {
557 /* If ETO_PDY is specified, we have pairs of INTs */
558 DxSize = (cwc * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
559 cjSize += DxSize;
560 // The structure buffer holds 4 bytes. Store Dx data then string.
561 // Result one wchar -> Buf[ Dx ]Str[wC], [4][2][X] one extra unused wchar
562 // to assure alignment of 4.
563 }
564
565 if ((pTeb->GdiTebBatch.Offset + cjSize ) <= GDIBATCHBUFSIZE)
566 {
567 pgO->cbCount = cwc;
568 pgO->x = x;
569 pgO->y = y;
570 pgO->Options = fuOptions;
571 pgO->iCS_CP = 0;
572
573 if (lprc) pgO->Rect = *lprc;
574 else
575 {
576 pgO->Options |= GDIBS_NORECT; // Tell the other side lprc is nill.
577 }
578
579 /* Snapshot attributes */
580 pgO->crForegroundClr = pdcattr->crForegroundClr;
581 pgO->crBackgroundClr = pdcattr->crBackgroundClr;
582 pgO->ulForegroundClr = pdcattr->ulForegroundClr;
583 pgO->ulBackgroundClr = pdcattr->ulBackgroundClr;
584 pgO->lBkMode = pdcattr->lBkMode == OPAQUE ? OPAQUE : TRANSPARENT;
585 pgO->hlfntNew = pdcattr->hlfntNew;
586 pgO->flTextAlign = pdcattr->flTextAlign;
587 pgO->ptlViewportOrg = pdcattr->ptlViewportOrg;
588
589 pgO->Size = DxSize; // of lpDx then string after.
590 /* Put the Dx before the String to assure alignment of 4 */
591 if (lpDx) RtlCopyMemory( &pgO->Buffer, lpDx, DxSize);
592
593 if (cwc) RtlCopyMemory( &pgO->String[DxSize/sizeof(WCHAR)], lpString, cwc * sizeof(WCHAR));
594
595 // Recompute offset and return size
596 pTeb->GdiTebBatch.Offset += cjSize;
597 ((PGDIBATCHHDR)pgO)->Size += cjSize;
598 return TRUE;
599 }
600 // Reset offset and count then fall through
601 pTeb->GdiTebBatch.Offset -= sizeof(GDIBSTEXTOUT);
602 pTeb->GdiBatchCount--;
603 }
604 }
605 }
606 return NtGdiExtTextOutW(hdc,
607 x,
608 y,
609 fuOptions,
610 (LPRECT)lprc,
611 (LPWSTR)lpString,
612 cwc,
613 (LPINT)lpDx,
614 0);
615 }
616
617
618 /*
619 * @implemented
620 */
621 INT
622 WINAPI
623 GetTextFaceW(
624 _In_ HDC hdc,
625 _In_ INT cwcMax,
626 _Out_writes_to_opt_(cwcMax, return) LPWSTR pFaceName)
627 {
628 /* Validate parameters */
629 if (pFaceName && cwcMax <= 0)
630 {
631 /* Set last error and return failure */
632 GdiSetLastError(ERROR_INVALID_PARAMETER);
633 return 0;
634 }
635
636 /* Forward to kernel */
637 return NtGdiGetTextFaceW(hdc, cwcMax, pFaceName, FALSE);
638 }
639
640
641 /*
642 * @implemented
643 */
644 INT
645 WINAPI
646 GetTextFaceA(
647 _In_ HDC hdc,
648 _In_ INT cchMax,
649 _Out_writes_to_opt_(cchMax, return) LPSTR lpName)
650 {
651 INT res;
652 LPWSTR nameW;
653
654 /* Validate parameters */
655 if (lpName && cchMax <= 0)
656 {
657 /* Set last error and return failure */
658 GdiSetLastError(ERROR_INVALID_PARAMETER);
659 return 0;
660 }
661
662 res = GetTextFaceW(hdc, 0, NULL);
663 nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
664 if (nameW == NULL)
665 {
666 return 0;
667 }
668
669 GetTextFaceW( hdc, res, nameW );
670
671 if (lpName)
672 {
673 if (cchMax && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, lpName, cchMax, NULL, NULL))
674 lpName[cchMax-1] = 0;
675 res = strlen(lpName);
676 }
677 else
678 {
679 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
680 }
681
682 HeapFree( GetProcessHeap(), 0, nameW );
683 return res;
684 }
685
686
687 /*
688 * @implemented
689 */
690 INT
691 WINAPI
692 GetTextFaceAliasW(
693 _In_ HDC hdc,
694 _In_ INT cwcMax,
695 _Out_writes_to_opt_(cwcMax, return) LPWSTR pszOut)
696 {
697 if (pszOut && !cwcMax)
698 {
699 GdiSetLastError(ERROR_INVALID_PARAMETER);
700 return 0;
701 }
702
703 return NtGdiGetTextFaceW(hdc, cwcMax, pszOut, TRUE);
704 }
705
706
707 BOOL
708 WINAPI
709 GetFontResourceInfoW(
710 _In_z_ LPCWSTR lpFileName,
711 _Inout_ DWORD *pdwBufSize,
712 _Out_writes_to_opt_(*pdwBufSize, 1) PVOID lpBuffer,
713 _In_ DWORD dwType)
714 {
715 BOOL bRet;
716 UNICODE_STRING NtFileName;
717
718 DPRINT("GetFontResourceInfoW: dwType = %lu\n", dwType);
719
720 if (!lpFileName || !pdwBufSize)
721 {
722 SetLastError(ERROR_INVALID_PARAMETER);
723 return FALSE;
724 }
725
726 if (!RtlDosPathNameToNtPathName_U(lpFileName,
727 &NtFileName,
728 NULL,
729 NULL))
730 {
731 SetLastError(ERROR_PATH_NOT_FOUND);
732 return FALSE;
733 }
734
735 bRet = NtGdiGetFontResourceInfoInternalW(
736 NtFileName.Buffer,
737 (NtFileName.Length / sizeof(WCHAR)) + 1,
738 1,
739 *pdwBufSize,
740 pdwBufSize,
741 lpBuffer,
742 dwType);
743
744 RtlFreeHeap(RtlGetProcessHeap(), 0, NtFileName.Buffer);
745
746 return bRet;
747 }
748
749
750 /*
751 * @unimplemented
752 */
753 INT
754 WINAPI
755 SetTextCharacterExtra(
756 _In_ HDC hdc,
757 _In_ INT nCharExtra)
758 {
759 PDC_ATTR pdcattr;
760 INT nOldCharExtra;
761
762 if (nCharExtra == 0x80000000)
763 {
764 SetLastError(ERROR_INVALID_PARAMETER);
765 return 0x80000000;
766 }
767
768 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
769 {
770 HANDLE_METADC(INT, SetTextCharacterExtra, 0x80000000, hdc, nCharExtra);
771 }
772
773 /* Get the DC attribute */
774 pdcattr = GdiGetDcAttr(hdc);
775 if (pdcattr == NULL)
776 {
777 SetLastError(ERROR_INVALID_PARAMETER);
778 return 0x8000000;
779 }
780
781 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc)
782 {
783 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY)
784 {
785 NtGdiFlush(); // Sync up pdcattr from Kernel space.
786 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY);
787 }
788 }
789
790 nOldCharExtra = pdcattr->lTextExtra;
791 pdcattr->lTextExtra = nCharExtra;
792 return nOldCharExtra;
793 }
794
795 /*
796 * @implemented
797 *
798 */
799 UINT
800 WINAPI
801 GetTextAlign(
802 _In_ HDC hdc)
803 {
804 PDC_ATTR pdcattr;
805
806 /* Get the DC attribute */
807 pdcattr = GdiGetDcAttr(hdc);
808 if (pdcattr == NULL)
809 {
810 /* Do not set LastError here! */
811 return GDI_ERROR;
812 }
813
814 return pdcattr->lTextAlign;
815 }
816
817
818 /*
819 * @implemented
820 *
821 */
822 COLORREF
823 WINAPI
824 GetTextColor(
825 _In_ HDC hdc)
826 {
827 PDC_ATTR pdcattr;
828
829 /* Get the DC attribute */
830 pdcattr = GdiGetDcAttr(hdc);
831 if (pdcattr == NULL)
832 {
833 /* Do not set LastError here! */
834 return CLR_INVALID;
835 }
836
837 return pdcattr->ulForegroundClr;
838 }
839
840
841 /*
842 * @unimplemented
843 */
844 UINT
845 WINAPI
846 SetTextAlign(
847 _In_ HDC hdc,
848 _In_ UINT fMode)
849 {
850 PDC_ATTR pdcattr;
851 UINT fOldMode;
852
853 HANDLE_METADC(BOOL, SetTextAlign, GDI_ERROR, hdc, fMode);
854
855 /* Get the DC attribute */
856 pdcattr = GdiGetDcAttr(hdc);
857 if (pdcattr == NULL)
858 {
859 SetLastError(ERROR_INVALID_PARAMETER);
860 return GDI_ERROR;
861 }
862
863
864 fOldMode = pdcattr->lTextAlign;
865 pdcattr->lTextAlign = fMode; // Raw
866 if (pdcattr->dwLayout & LAYOUT_RTL)
867 {
868 if ((fMode & TA_CENTER) != TA_CENTER) fMode ^= TA_RIGHT;
869 }
870
871 pdcattr->flTextAlign = fMode & TA_MASK;
872 return fOldMode;
873 }
874
875
876 /*
877 * @implemented
878 */
879 COLORREF
880 WINAPI
881 SetTextColor(
882 _In_ HDC hdc,
883 _In_ COLORREF crColor)
884 {
885 PDC_ATTR pdcattr;
886 COLORREF crOldColor;
887
888 HANDLE_METADC(COLORREF, SetTextColor, CLR_INVALID, hdc, crColor);
889
890 pdcattr = GdiGetDcAttr(hdc);
891 if (pdcattr == NULL)
892 {
893 SetLastError(ERROR_INVALID_PARAMETER);
894 return CLR_INVALID;
895 }
896
897 crOldColor = (COLORREF) pdcattr->ulForegroundClr;
898 pdcattr->ulForegroundClr = (ULONG)crColor;
899
900 if (pdcattr->crForegroundClr != crColor)
901 {
902 pdcattr->ulDirty_ |= (DIRTY_TEXT|DIRTY_LINE|DIRTY_FILL);
903 pdcattr->crForegroundClr = crColor;
904 }
905
906 return crOldColor;
907 }
908
909 /*
910 * @implemented
911 */
912 BOOL
913 WINAPI
914 SetTextJustification(
915 _In_ HDC hdc,
916 _In_ INT nBreakExtra,
917 _In_ INT nBreakCount)
918 {
919 PDC_ATTR pdcattr;
920
921 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
922 {
923 HANDLE_METADC(BOOL, SetTextJustification, FALSE, hdc, nBreakExtra, nBreakCount);
924 }
925
926 /* Get the DC attribute */
927 pdcattr = GdiGetDcAttr(hdc);
928 if (pdcattr == NULL)
929 {
930 /* Do not set LastError here! */
931 return GDI_ERROR;
932 }
933
934
935 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc)
936 {
937 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY)
938 {
939 NtGdiFlush(); // Sync up pdcattr from Kernel space.
940 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY);
941 }
942 }
943
944 pdcattr->cBreak = nBreakCount;
945 pdcattr->lBreakExtra = nBreakExtra;
946 return TRUE;
947 }
948
949 /*
950 * @implemented
951 */
952 UINT
953 WINAPI
954 GetStringBitmapA(
955 _In_ HDC hdc,
956 _In_ LPSTR psz,
957 _In_ BOOL bDoCall,
958 _In_ UINT cj,
959 _Out_writes_(cj) BYTE *lpSB)
960 {
961
962 NTSTATUS Status;
963 PWSTR pwsz;
964 UINT uResult = 0;
965
966 if (!bDoCall)
967 {
968 return 0;
969 }
970
971 Status = HEAP_strdupA2W(&pwsz, psz);
972 if (!NT_SUCCESS(Status))
973 {
974 SetLastError (RtlNtStatusToDosError(Status));
975 }
976 else
977 {
978 uResult = NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj);
979 HEAP_free(pwsz);
980 }
981
982 return uResult;
983
984 }
985
986 /*
987 * @implemented
988 */
989 UINT
990 WINAPI
991 GetStringBitmapW(
992 _In_ HDC hdc,
993 _In_ LPWSTR pwsz,
994 _In_ BOOL bDoCall,
995 _In_ UINT cj,
996 _Out_writes_(cj) BYTE *lpSB)
997 {
998 if (!bDoCall)
999 {
1000 return 0;
1001 }
1002
1003 return NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj);
1004
1005 }
1006
1007 /*
1008 * @implemented
1009 */
1010 BOOL
1011 WINAPI
1012 GetETM(
1013 _In_ HDC hdc,
1014 _Out_ EXTTEXTMETRIC *petm)
1015 {
1016 BOOL bResult;
1017
1018 bResult = NtGdiGetETM(hdc, petm);
1019
1020 if (bResult && petm)
1021 {
1022 petm->emKernPairs = (WORD)GetKerningPairsA(hdc, 0, 0);
1023 }
1024
1025 return bResult;
1026 }