Merge the following revisions from kernel-fun branch:
[reactos.git] / reactos / win32ss / gdi / gdi32 / objects / text.c
1 #include <precomp.h>
2
3 #define NDEBUG
4 #include <debug.h>
5
6 /*
7 * @implemented
8 */
9 BOOL
10 WINAPI
11 TextOutA(
12 _In_ HDC hdc,
13 _In_ INT nXStart,
14 _In_ INT nYStart,
15 _In_reads_(cchString) LPCSTR lpString,
16 _In_ INT cchString)
17 {
18 ANSI_STRING StringA;
19 UNICODE_STRING StringU;
20 BOOL bResult;
21
22 if (lpString != NULL)
23 {
24 RtlInitAnsiString(&StringA, (LPSTR)lpString);
25 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
26 }
27 else
28 {
29 StringU.Buffer = NULL;
30 }
31
32 bResult = TextOutW(hdc, nXStart, nYStart, StringU.Buffer, cchString);
33
34 RtlFreeUnicodeString(&StringU);
35 return bResult;
36 }
37
38
39 /*
40 * @implemented
41 */
42 BOOL
43 WINAPI
44 TextOutW(
45 _In_ HDC hdc,
46 _In_ INT nXStart,
47 _In_ INT nYStart,
48 _In_reads_(cchString) LPCWSTR lpString,
49 _In_ INT cchString)
50 {
51 return ExtTextOutW(hdc, nXStart, nYStart, 0, NULL, (LPWSTR)lpString, cchString, NULL);
52 }
53
54
55 /*
56 * @unimplemented
57 */
58 BOOL
59 WINAPI
60 PolyTextOutA(
61 _In_ HDC hdc,
62 _In_reads_(cStrings) const POLYTEXTA *pptxt,
63 _In_ INT cStrings)
64 {
65 for (; cStrings>0; cStrings--, pptxt++)
66 {
67 if (!ExtTextOutA(hdc,
68 pptxt->x,
69 pptxt->y,
70 pptxt->uiFlags,
71 &pptxt->rcl,
72 pptxt->lpstr,
73 pptxt->n,
74 pptxt->pdx))
75 {
76 return FALSE;
77 }
78 }
79
80 return TRUE;
81 }
82
83
84 /*
85 * @unimplemented
86 */
87 BOOL
88 WINAPI
89 PolyTextOutW(
90 _In_ HDC hdc,
91 _In_reads_(cStrings) const POLYTEXTW *pptxt,
92 _In_ INT cStrings)
93 {
94 for (; cStrings>0; cStrings--, pptxt++)
95 {
96 if (!ExtTextOutW(hdc,
97 pptxt->x,
98 pptxt->y,
99 pptxt->uiFlags,
100 &pptxt->rcl,
101 pptxt->lpstr,
102 pptxt->n,
103 pptxt->pdx))
104 {
105 return FALSE;
106 }
107 }
108
109 return TRUE;
110 }
111
112
113 /*
114 * @implemented
115 */
116 DWORD
117 WINAPI
118 GdiGetCodePage(
119 _In_ HDC hdc)
120 {
121 PDC_ATTR pdcattr;
122
123 /* Get the DC attribute */
124 pdcattr = GdiGetDcAttr(hdc);
125 if (pdcattr == NULL)
126 {
127 SetLastError(ERROR_INVALID_PARAMETER);
128 return 0;
129 }
130
131 if (pdcattr->ulDirty_ & DIRTY_CHARSET)
132 return LOWORD(NtGdiGetCharSet(hdc));
133
134 return LOWORD(pdcattr->iCS_CP);
135 }
136
137
138 /*
139 * @unimplemented
140 */
141 INT
142 WINAPI
143 GetTextCharacterExtra(
144 _In_ HDC hdc)
145 {
146 PDC_ATTR pdcattr;
147
148 /* Get the DC attribute */
149 pdcattr = GdiGetDcAttr(hdc);
150 if (pdcattr == NULL)
151 {
152 /* Do not set LastError here! */
153 return 0x8000000;
154 }
155
156 return pdcattr->lTextExtra;
157 }
158
159
160 /*
161 * @implemented
162 */
163 INT
164 WINAPI
165 GetTextCharset(
166 _In_ HDC hdc)
167 {
168 /* MSDN docs say this is equivalent */
169 return NtGdiGetTextCharsetInfo(hdc,NULL,0);
170 }
171
172
173 /*
174 * @implemented
175 */
176 BOOL
177 WINAPI
178 GetTextMetricsA(
179 _In_ HDC hdc,
180 _Out_ LPTEXTMETRICA lptm)
181 {
182 TMW_INTERNAL tmwi;
183
184 if (!NtGdiGetTextMetricsW(hdc, &tmwi, sizeof(TMW_INTERNAL)))
185 {
186 return FALSE;
187 }
188
189 FONT_TextMetricWToA(&tmwi.TextMetric, lptm);
190 return TRUE;
191 }
192
193
194 /*
195 * @implemented
196 */
197 BOOL
198 WINAPI
199 GetTextMetricsW(
200 _In_ HDC hdc,
201 _Out_ LPTEXTMETRICW lptm)
202 {
203 TMW_INTERNAL tmwi;
204
205 if (!NtGdiGetTextMetricsW(hdc, &tmwi, sizeof(TMW_INTERNAL)))
206 {
207 return FALSE;
208 }
209
210 *lptm = tmwi.TextMetric;
211 return TRUE;
212 }
213
214
215 /*
216 * @implemented
217 */
218 BOOL
219 APIENTRY
220 GetTextExtentPointA(
221 _In_ HDC hdc,
222 _In_reads_(cchString) LPCSTR lpString,
223 _In_ INT cchString,
224 _Out_ LPSIZE lpsz)
225 {
226 ANSI_STRING StringA;
227 UNICODE_STRING StringU;
228 BOOL ret;
229
230 RtlInitAnsiString(&StringA, (LPSTR)lpString);
231 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
232
233 ret = GetTextExtentPointW(hdc, StringU.Buffer, cchString, lpsz);
234
235 RtlFreeUnicodeString(&StringU);
236
237 return ret;
238 }
239
240
241 /*
242 * @implemented
243 */
244 BOOL
245 APIENTRY
246 GetTextExtentPointW(
247 _In_ HDC hdc,
248 _In_reads_(cchString) LPCWSTR lpString,
249 _In_ INT cchString,
250 _Out_ LPSIZE lpsz)
251 {
252 return NtGdiGetTextExtent(hdc, (LPWSTR)lpString, cchString, lpsz, 0);
253 }
254
255
256 /*
257 * @implemented
258 */
259 BOOL
260 WINAPI
261 GetTextExtentExPointW(
262 _In_ HDC hdc,
263 _In_reads_(cchString) LPCWSTR lpszString,
264 _In_ INT cchString,
265 _In_ INT nMaxExtent,
266 _Out_opt_ LPINT lpnFit,
267 _Out_writes_to_opt_(cchString, *lpnFit) LPINT lpnDx,
268 _Out_ LPSIZE lpSize)
269 {
270
271 /* Windows doesn't check nMaxExtent validity in unicode version */
272 if (nMaxExtent < -1)
273 {
274 DPRINT("nMaxExtent is invalid: %d\n", nMaxExtent);
275 }
276
277 return NtGdiGetTextExtentExW (
278 hdc, (LPWSTR)lpszString, cchString, nMaxExtent, (PULONG)lpnFit, (PULONG)lpnDx, lpSize, 0 );
279 }
280
281
282 /*
283 * @implemented
284 */
285 BOOL
286 WINAPI
287 GetTextExtentExPointWPri(
288 _In_ HDC hdc,
289 _In_reads_(cwc) LPWSTR lpwsz,
290 _In_ ULONG cwc,
291 _In_ ULONG dxMax,
292 _Out_opt_ ULONG *pcCh,
293 _Out_writes_to_opt_(cwc, *pcCh) PULONG pdxOut,
294 _In_ LPSIZE psize)
295 {
296 return NtGdiGetTextExtentExW(hdc, lpwsz, cwc, dxMax, pcCh, pdxOut, psize, 0);
297 }
298
299 /*
300 * @implemented
301 */
302 BOOL
303 WINAPI
304 GetTextExtentExPointA(
305 _In_ HDC hdc,
306 _In_reads_(cchString) LPCSTR lpszStr,
307 _In_ INT cchString,
308 _In_ INT nMaxExtent,
309 _Out_opt_ LPINT lpnFit,
310 _Out_writes_to_opt_ (cchString, *lpnFit) LPINT lpnDx,
311 _Out_ LPSIZE lpSize)
312 {
313 NTSTATUS Status;
314 LPWSTR lpszStrW;
315 BOOL bResult = FALSE;
316
317 if (nMaxExtent < -1)
318 {
319 SetLastError(ERROR_INVALID_PARAMETER);
320 return FALSE;
321 }
322
323 Status = HEAP_strdupA2W(&lpszStrW, lpszStr);
324 if (!NT_SUCCESS (Status))
325 {
326 SetLastError(RtlNtStatusToDosError(Status));
327 return FALSE;
328 }
329
330 bResult = NtGdiGetTextExtentExW(hdc,
331 lpszStrW,
332 cchString,
333 nMaxExtent,
334 (PULONG)lpnFit,
335 (PULONG)lpnDx,
336 lpSize,
337 0);
338
339 HEAP_free(lpszStrW);
340
341 return bResult;
342 }
343
344
345 /*
346 * @implemented
347 */
348 BOOL
349 WINAPI
350 GetTextExtentPoint32A(
351 _In_ HDC hdc,
352 _In_reads_(cchString) LPCSTR lpString,
353 _In_ INT cchString,
354 _Out_ LPSIZE lpSize)
355 {
356 ANSI_STRING StringA;
357 UNICODE_STRING StringU;
358 BOOL ret;
359
360 StringA.Buffer = (LPSTR)lpString;
361 StringA.Length = cchString;
362 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
363
364 ret = GetTextExtentPoint32W(hdc, StringU.Buffer, cchString, lpSize);
365
366 RtlFreeUnicodeString(&StringU);
367
368 return ret;
369 }
370
371
372 /*
373 * @implemented
374 */
375 BOOL
376 WINAPI
377 GetTextExtentPoint32W(
378 _In_ HDC hdc,
379 _In_reads_(cchString) LPCWSTR lpString,
380 _In_ int cchString,
381 _Out_ LPSIZE lpSize)
382 {
383 return NtGdiGetTextExtent(hdc, (LPWSTR)lpString, cchString, lpSize, 0);
384 }
385
386 /*
387 * @implemented
388 */
389 BOOL
390 WINAPI
391 GetTextExtentExPointI(
392 _In_ HDC hdc,
393 _In_reads_(cgi) LPWORD pgiIn,
394 _In_ INT cgi,
395 _In_ INT nMaxExtent,
396 _Out_opt_ LPINT lpnFit,
397 _Out_writes_to_opt_(cwchString, *lpnFit) LPINT lpnDx,
398 _Out_ LPSIZE lpSize)
399 {
400 return NtGdiGetTextExtentExW(hdc,
401 pgiIn,
402 cgi,
403 nMaxExtent,
404 (PULONG)lpnFit,
405 (PULONG)lpnDx,
406 lpSize,
407 GTEF_INDICES);
408 }
409
410 /*
411 * @implemented
412 */
413 BOOL
414 WINAPI
415 GetTextExtentPointI(
416 _In_ HDC hdc,
417 _In_reads_(cgi) LPWORD pgiIn,
418 _In_ int cgi,
419 _Out_ LPSIZE lpSize)
420 {
421 return NtGdiGetTextExtent(hdc, pgiIn, cgi, lpSize, GTEF_INDICES);
422 }
423
424 /*
425 * @implemented
426 */
427 BOOL
428 WINAPI
429 ExtTextOutA(
430 _In_ HDC hdc,
431 _In_ INT x,
432 _In_ INT y,
433 _In_ UINT fuOptions,
434 _In_opt_ const RECT *lprc,
435 _In_reads_opt_(cch) LPCSTR lpString,
436 _In_ UINT cch,
437 _In_reads_opt_(cch) const INT *lpDx)
438 {
439 ANSI_STRING StringA;
440 UNICODE_STRING StringU;
441 BOOL ret;
442
443 RtlInitAnsiString(&StringA, (LPSTR)lpString);
444 RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
445
446 ret = ExtTextOutW(hdc, x, y, fuOptions, lprc, StringU.Buffer, cch, lpDx);
447
448 RtlFreeUnicodeString(&StringU);
449
450 return ret;
451 }
452
453
454 /*
455 * @implemented
456 */
457 BOOL
458 WINAPI
459 ExtTextOutW(
460 _In_ HDC hdc,
461 _In_ INT x,
462 _In_ INT y,
463 _In_ UINT fuOptions,
464 _In_opt_ const RECT *lprc,
465 _In_reads_opt_(cwc) LPCWSTR lpString,
466 _In_ UINT cwc,
467 _In_reads_opt_(cwc) const INT *lpDx)
468 {
469 HANDLE_METADC(BOOL,
470 ExtTextOut,
471 FALSE,
472 hdc,
473 x,
474 y,
475 fuOptions,
476 lprc,
477 lpString,
478 cwc,
479 lpDx);
480
481 return NtGdiExtTextOutW(hdc,
482 x,
483 y,
484 fuOptions,
485 (LPRECT)lprc,
486 (LPWSTR)lpString,
487 cwc,
488 (LPINT)lpDx,
489 0);
490 }
491
492
493 /*
494 * @implemented
495 */
496 INT
497 WINAPI
498 GetTextFaceW(
499 _In_ HDC hdc,
500 _In_ INT cwcMax,
501 _Out_writes_to_opt_(cwcMax, return) LPWSTR pFaceName)
502 {
503 /* Validate parameters */
504 if (pFaceName && cwcMax <= 0)
505 {
506 /* Set last error and return failure */
507 GdiSetLastError(ERROR_INVALID_PARAMETER);
508 return 0;
509 }
510
511 /* Forward to kernel */
512 return NtGdiGetTextFaceW(hdc, cwcMax, pFaceName, FALSE);
513 }
514
515
516 /*
517 * @implemented
518 */
519 INT
520 WINAPI
521 GetTextFaceA(
522 _In_ HDC hdc,
523 _In_ INT cchMax,
524 _Out_writes_to_opt_(cchMax, return) LPSTR lpName)
525 {
526 INT res;
527 LPWSTR nameW;
528
529 /* Validate parameters */
530 if (lpName && cchMax <= 0)
531 {
532 /* Set last error and return failure */
533 GdiSetLastError(ERROR_INVALID_PARAMETER);
534 return 0;
535 }
536
537 res = GetTextFaceW(hdc, 0, NULL);
538 nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
539 if (nameW == NULL)
540 {
541 return 0;
542 }
543
544 GetTextFaceW( hdc, res, nameW );
545
546 if (lpName)
547 {
548 if (cchMax && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, lpName, cchMax, NULL, NULL))
549 lpName[cchMax-1] = 0;
550 res = strlen(lpName);
551 }
552 else
553 {
554 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
555 }
556
557 HeapFree( GetProcessHeap(), 0, nameW );
558 return res;
559 }
560
561
562 /*
563 * @implemented
564 */
565 INT
566 WINAPI
567 GetTextFaceAliasW(
568 _In_ HDC hdc,
569 _In_ INT cwcMax,
570 _Out_writes_to_opt_(cwcMax, return) LPWSTR pszOut)
571 {
572 if (pszOut && !cwcMax)
573 {
574 GdiSetLastError(ERROR_INVALID_PARAMETER);
575 return 0;
576 }
577
578 return NtGdiGetTextFaceW(hdc, cwcMax, pszOut, TRUE);
579 }
580
581
582 BOOL
583 WINAPI
584 GetFontResourceInfoW(
585 _In_z_ LPCWSTR lpFileName,
586 _Inout_ DWORD *pdwBufSize,
587 _Out_writes_to_(*pdwBufSize, *pdwBufSize) PVOID lpBuffer,
588 _In_ DWORD dwType)
589 {
590 BOOL bRet;
591 UNICODE_STRING NtFileName;
592
593 if (!lpFileName || !pdwBufSize || !lpBuffer)
594 {
595 SetLastError(ERROR_INVALID_PARAMETER);
596 return FALSE;
597 }
598
599 if (!RtlDosPathNameToNtPathName_U(lpFileName,
600 &NtFileName,
601 NULL,
602 NULL))
603 {
604 SetLastError(ERROR_PATH_NOT_FOUND);
605 return FALSE;
606 }
607
608 bRet = NtGdiGetFontResourceInfoInternalW(
609 NtFileName.Buffer,
610 (NtFileName.Length / sizeof(WCHAR)) + 1,
611 1,
612 *pdwBufSize,
613 pdwBufSize,
614 lpBuffer,
615 dwType);
616
617 RtlFreeHeap(RtlGetProcessHeap(), 0, NtFileName.Buffer);
618
619 return bRet;
620 }
621
622
623 /*
624 * @unimplemented
625 */
626 INT
627 WINAPI
628 SetTextCharacterExtra(
629 _In_ HDC hdc,
630 _In_ INT nCharExtra)
631 {
632 PDC_ATTR pdcattr;
633 INT nOldCharExtra;
634
635 if (nCharExtra == 0x80000000)
636 {
637 SetLastError(ERROR_INVALID_PARAMETER);
638 return 0x80000000;
639 }
640
641 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
642 {
643 HANDLE_METADC(INT, SetTextCharacterExtra, 0x80000000, hdc, nCharExtra);
644 }
645
646 /* Get the DC attribute */
647 pdcattr = GdiGetDcAttr(hdc);
648 if (pdcattr == NULL)
649 {
650 SetLastError(ERROR_INVALID_PARAMETER);
651 return 0x8000000;
652 }
653
654 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc)
655 {
656 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY)
657 {
658 NtGdiFlush(); // Sync up pdcattr from Kernel space.
659 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY);
660 }
661 }
662
663 nOldCharExtra = pdcattr->lTextExtra;
664 pdcattr->lTextExtra = nCharExtra;
665 return nOldCharExtra;
666 }
667
668 /*
669 * @implemented
670 *
671 */
672 UINT
673 WINAPI
674 GetTextAlign(
675 _In_ HDC hdc)
676 {
677 PDC_ATTR pdcattr;
678
679 /* Get the DC attribute */
680 pdcattr = GdiGetDcAttr(hdc);
681 if (pdcattr == NULL)
682 {
683 /* Do not set LastError here! */
684 return GDI_ERROR;
685 }
686
687 return pdcattr->lTextAlign;
688 }
689
690
691 /*
692 * @implemented
693 *
694 */
695 COLORREF
696 WINAPI
697 GetTextColor(
698 _In_ HDC hdc)
699 {
700 PDC_ATTR pdcattr;
701
702 /* Get the DC attribute */
703 pdcattr = GdiGetDcAttr(hdc);
704 if (pdcattr == NULL)
705 {
706 /* Do not set LastError here! */
707 return CLR_INVALID;
708 }
709
710 return pdcattr->ulForegroundClr;
711 }
712
713
714 /*
715 * @unimplemented
716 */
717 UINT
718 WINAPI
719 SetTextAlign(
720 _In_ HDC hdc,
721 _In_ UINT fMode)
722 {
723 PDC_ATTR pdcattr;
724 UINT fOldMode;
725
726 HANDLE_METADC(BOOL, SetTextAlign, GDI_ERROR, hdc, fMode);
727
728 /* Get the DC attribute */
729 pdcattr = GdiGetDcAttr(hdc);
730 if (pdcattr == NULL)
731 {
732 SetLastError(ERROR_INVALID_PARAMETER);
733 return GDI_ERROR;
734 }
735
736
737 fOldMode = pdcattr->lTextAlign;
738 pdcattr->lTextAlign = fMode; // Raw
739 if (pdcattr->dwLayout & LAYOUT_RTL)
740 {
741 if ((fMode & TA_CENTER) != TA_CENTER) fMode ^= TA_RIGHT;
742 }
743
744 pdcattr->flTextAlign = fMode & TA_MASK;
745 return fOldMode;
746 }
747
748
749 /*
750 * @implemented
751 */
752 COLORREF
753 WINAPI
754 SetTextColor(
755 _In_ HDC hdc,
756 _In_ COLORREF crColor)
757 {
758 PDC_ATTR pdcattr;
759 COLORREF crOldColor;
760
761 HANDLE_METADC(COLORREF, SetTextColor, CLR_INVALID, hdc, crColor);
762
763 pdcattr = GdiGetDcAttr(hdc);
764 if (pdcattr == NULL)
765 {
766 SetLastError(ERROR_INVALID_PARAMETER);
767 return CLR_INVALID;
768 }
769
770 crOldColor = (COLORREF) pdcattr->ulForegroundClr;
771 pdcattr->ulForegroundClr = (ULONG)crColor;
772
773 if (pdcattr->crForegroundClr != crColor)
774 {
775 pdcattr->ulDirty_ |= (DIRTY_TEXT|DIRTY_LINE|DIRTY_FILL);
776 pdcattr->crForegroundClr = crColor;
777 }
778
779 return crOldColor;
780 }
781
782 /*
783 * @implemented
784 */
785 BOOL
786 WINAPI
787 SetTextJustification(
788 _In_ HDC hdc,
789 _In_ INT nBreakExtra,
790 _In_ INT nBreakCount)
791 {
792 PDC_ATTR pdcattr;
793
794 if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
795 {
796 HANDLE_METADC(BOOL, SetTextJustification, FALSE, hdc, nBreakExtra, nBreakCount);
797 }
798
799 /* Get the DC attribute */
800 pdcattr = GdiGetDcAttr(hdc);
801 if (pdcattr == NULL)
802 {
803 /* Do not set LastError here! */
804 return GDI_ERROR;
805 }
806
807
808 if (NtCurrentTeb()->GdiTebBatch.HDC == hdc)
809 {
810 if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY)
811 {
812 NtGdiFlush(); // Sync up pdcattr from Kernel space.
813 pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY);
814 }
815 }
816
817 pdcattr->cBreak = nBreakCount;
818 pdcattr->lBreakExtra = nBreakExtra;
819 return TRUE;
820 }
821
822 /*
823 * @implemented
824 */
825 UINT
826 WINAPI
827 GetStringBitmapA(
828 _In_ HDC hdc,
829 _In_ LPSTR psz,
830 _In_ BOOL bDoCall,
831 _In_ UINT cj,
832 _Out_writes_(cj) BYTE *lpSB)
833 {
834
835 NTSTATUS Status;
836 PWSTR pwsz;
837 UINT uResult = 0;
838
839 if (!bDoCall)
840 {
841 return 0;
842 }
843
844 Status = HEAP_strdupA2W(&pwsz, psz);
845 if (!NT_SUCCESS(Status))
846 {
847 SetLastError (RtlNtStatusToDosError(Status));
848 }
849 else
850 {
851 uResult = NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj);
852 HEAP_free(pwsz);
853 }
854
855 return uResult;
856
857 }
858
859 /*
860 * @implemented
861 */
862 UINT
863 WINAPI
864 GetStringBitmapW(
865 _In_ HDC hdc,
866 _In_ LPWSTR pwsz,
867 _In_ BOOL bDoCall,
868 _In_ UINT cj,
869 _Out_writes_(cj) BYTE *lpSB)
870 {
871 if (!bDoCall)
872 {
873 return 0;
874 }
875
876 return NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj);
877
878 }
879
880 /*
881 * @implemented
882 */
883 BOOL
884 WINAPI
885 GetETM(
886 _In_ HDC hdc,
887 _Out_ EXTTEXTMETRIC *petm)
888 {
889 BOOL bResult;
890
891 bResult = NtGdiGetETM(hdc, petm);
892
893 if (bResult && petm)
894 {
895 petm->emKernPairs = (WORD)GetKerningPairsA(hdc, 0, 0);
896 }
897
898 return bResult;
899 }