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