[GDI32] Integrate LpkGetTextExtentExPoint(). (#1362)
[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 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 }