xref: /reactos/win32ss/gdi/gdi32/objects/text.c (revision 34586814)
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
TextOutA(_In_ HDC hdc,_In_ INT nXStart,_In_ INT nYStart,_In_reads_ (cchString)LPCSTR lpString,_In_ INT cchString)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
TextOutW(_In_ HDC hdc,_In_ INT nXStart,_In_ INT nYStart,_In_reads_ (cchString)LPCWSTR lpString,_In_ INT cchString)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
PolyTextOutA(_In_ HDC hdc,_In_reads_ (cStrings)const POLYTEXTA * pptxt,_In_ INT cStrings)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
PolyTextOutW(_In_ HDC hdc,_In_reads_ (cStrings)const POLYTEXTW * pptxt,_In_ INT cStrings)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
GdiGetCodePage(_In_ HDC hdc)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
GetTextCharacterExtra(_In_ HDC hdc)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
GetTextCharset(_In_ HDC hdc)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
GetTextMetricsA(_In_ HDC hdc,_Out_ LPTEXTMETRICA lptm)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
GetTextMetricsW(_In_ HDC hdc,_Out_ LPTEXTMETRICW lptm)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
GetTextExtentPointA(_In_ HDC hdc,_In_reads_ (cchString)LPCSTR lpString,_In_ INT cchString,_Out_ LPSIZE lpsz)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
GetTextExtentPointW(_In_ HDC hdc,_In_reads_ (cchString)LPCWSTR lpString,_In_ INT cchString,_Out_ LPSIZE lpsz)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
GetTextExtentExPointW(_In_ HDC hdc,_In_reads_ (cchString)LPCWSTR lpszString,_In_ INT cchString,_In_ INT nMaxExtent,_Out_opt_ LPINT lpnFit,_Out_writes_to_opt_ (cchString,* lpnFit)LPINT lpnDx,_Out_ LPSIZE lpSize)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
GetTextExtentExPointWPri(_In_ HDC hdc,_In_reads_ (cwc)LPCWSTR lpwsz,_In_ INT cwc,_In_ INT dxMax,_Out_opt_ LPINT pcCh,_Out_writes_to_opt_ (cwc,* pcCh)LPINT pdxOut,_In_ LPSIZE psize)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
GetTextExtentExPointA(_In_ HDC hdc,_In_reads_ (cchString)LPCSTR lpszStr,_In_ INT cchString,_In_ INT nMaxExtent,_Out_opt_ LPINT lpnFit,_Out_writes_to_opt_ (cchString,* lpnFit)LPINT lpnDx,_Out_ LPSIZE lpSize)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
GetTextExtentPoint32A(_In_ HDC hdc,_In_reads_ (cchString)LPCSTR lpString,_In_ INT cchString,_Out_ LPSIZE lpSize)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
GetTextExtentPoint32W(_In_ HDC hdc,_In_reads_ (cchString)LPCWSTR lpString,_In_ int cchString,_Out_ LPSIZE lpSize)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
GetTextExtentExPointI(_In_ HDC hdc,_In_reads_ (cgi)LPWORD pgiIn,_In_ INT cgi,_In_ INT nMaxExtent,_Out_opt_ LPINT lpnFit,_Out_writes_to_opt_ (cwchString,* lpnFit)LPINT lpnDx,_Out_ LPSIZE lpSize)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
GetTextExtentPointI(_In_ HDC hdc,_In_reads_ (cgi)LPWORD pgiIn,_In_ int cgi,_Out_ LPSIZE lpSize)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
ExtTextOutA(_In_ HDC hdc,_In_ INT x,_In_ INT y,_In_ UINT fuOptions,_In_opt_ const RECT * lprc,_In_reads_opt_ (cch)LPCSTR lpString,_In_ UINT cch,_In_reads_opt_ (cch)const INT * lpDx)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
ExtTextOutW(_In_ HDC hdc,_In_ INT x,_In_ INT y,_In_ UINT fuOptions,_In_opt_ const RECT * lprc,_In_reads_opt_ (cwc)LPCWSTR lpString,_In_ UINT cwc,_In_reads_opt_ (cwc)const INT * lpDx)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                 DPRINT("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
GetTextFaceW(_In_ HDC hdc,_In_ INT cwcMax,_Out_writes_to_opt_ (cwcMax,return)LPWSTR pFaceName)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
GetTextFaceA(_In_ HDC hdc,_In_ INT cchMax,_Out_writes_to_opt_ (cchMax,return)LPSTR lpName)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
GetTextFaceAliasW(_In_ HDC hdc,_In_ INT cwcMax,_Out_writes_to_opt_ (cwcMax,return)LPWSTR pszOut)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
SetTextCharacterExtra(_In_ HDC hdc,_In_ INT nCharExtra)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
GetTextAlign(_In_ HDC hdc)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
GetTextColor(_In_ HDC hdc)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
SetTextAlign(_In_ HDC hdc,_In_ UINT fMode)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
SetTextColor(_In_ HDC hdc,_In_ COLORREF crColor)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
SetTextJustification(_In_ HDC hdc,_In_ INT nBreakExtra,_In_ INT nBreakCount)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
GetStringBitmapA(_In_ HDC hdc,_In_ LPSTR psz,_In_ BOOL bDoCall,_In_ UINT cj,_Out_writes_ (cj)BYTE * lpSB)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
GetStringBitmapW(_In_ HDC hdc,_In_ LPWSTR pwsz,_In_ BOOL bDoCall,_In_ UINT cj,_Out_writes_ (cj)BYTE * lpSB)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
GetETM(_In_ HDC hdc,_Out_ EXTTEXTMETRIC * petm)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