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
23 _In_reads_(cchString
) LPCSTR lpString
,
27 UNICODE_STRING StringU
;
31 if (lpString
!= NULL
&& cchString
> 0)
33 if (cchString
> MAXUSHORT
)
34 cchString
= MAXUSHORT
;
36 StringA
.Length
= (USHORT
)cchString
;
37 StringA
.MaximumLength
= (USHORT
)cchString
;
38 StringA
.Buffer
= (PCHAR
)lpString
;
40 Status
= RtlAnsiStringToUnicodeString(&StringU
, &StringA
, TRUE
);
41 if (!NT_SUCCESS(Status
))
43 StringU
.Buffer
= NULL
;
49 StringU
.Buffer
= NULL
;
53 bResult
= TextOutW(hdc
, nXStart
, nYStart
,
54 StringU
.Buffer
, StringU
.Length
/ sizeof(WCHAR
));
56 RtlFreeUnicodeString(&StringU
);
70 _In_reads_(cchString
) LPCWSTR lpString
,
73 return ExtTextOutW(hdc
, nXStart
, nYStart
, 0, NULL
, (LPWSTR
)lpString
, cchString
, NULL
);
84 _In_reads_(cStrings
) const POLYTEXTA
*pptxt
,
87 for (; cStrings
>0; cStrings
--, pptxt
++)
113 _In_reads_(cStrings
) const POLYTEXTW
*pptxt
,
116 for (; cStrings
>0; cStrings
--, pptxt
++)
118 if (!ExtTextOutW(hdc
,
145 /* Get the DC attribute */
146 pdcattr
= GdiGetDcAttr(hdc
);
149 SetLastError(ERROR_INVALID_PARAMETER
);
153 if (pdcattr
->ulDirty_
& DIRTY_CHARSET
)
154 return LOWORD(NtGdiGetCharSet(hdc
));
156 return LOWORD(pdcattr
->iCS_CP
);
165 GetTextCharacterExtra(
170 /* Get the DC attribute */
171 pdcattr
= GdiGetDcAttr(hdc
);
174 /* Do not set LastError here! */
178 return pdcattr
->lTextExtra
;
190 /* MSDN docs say this is equivalent */
191 return NtGdiGetTextCharsetInfo(hdc
,NULL
,0);
202 _Out_ LPTEXTMETRICA lptm
)
206 if (!NtGdiGetTextMetricsW(hdc
, &tmwi
, sizeof(TMW_INTERNAL
)))
211 FONT_TextMetricWToA(&tmwi
.TextMetric
, lptm
);
223 _Out_ LPTEXTMETRICW lptm
)
227 if (!NtGdiGetTextMetricsW(hdc
, &tmwi
, sizeof(TMW_INTERNAL
)))
232 *lptm
= tmwi
.TextMetric
;
244 _In_reads_(cchString
) LPCSTR lpString
,
249 UNICODE_STRING StringU
;
252 RtlInitAnsiString(&StringA
, (LPSTR
)lpString
);
253 RtlAnsiStringToUnicodeString(&StringU
, &StringA
, TRUE
);
255 ret
= GetTextExtentPointW(hdc
, StringU
.Buffer
, cchString
, lpsz
);
257 RtlFreeUnicodeString(&StringU
);
270 _In_reads_(cchString
) LPCWSTR lpString
,
274 return NtGdiGetTextExtent(hdc
, (LPWSTR
)lpString
, cchString
, lpsz
, 0);
283 GetTextExtentExPointW(
285 _In_reads_(cchString
) LPCWSTR lpszString
,
288 _Out_opt_ LPINT lpnFit
,
289 _Out_writes_to_opt_(cchString
, *lpnFit
) LPINT lpnDx
,
293 /* Windows doesn't check nMaxExtent validity in unicode version */
296 DPRINT("nMaxExtent is invalid: %d\n", nMaxExtent
);
299 return NtGdiGetTextExtentExW (
300 hdc
, (LPWSTR
)lpszString
, cchString
, nMaxExtent
, (PULONG
)lpnFit
, (PULONG
)lpnDx
, lpSize
, 0 );
309 GetTextExtentExPointWPri(
311 _In_reads_(cwc
) LPWSTR lpwsz
,
314 _Out_opt_ ULONG
*pcCh
,
315 _Out_writes_to_opt_(cwc
, *pcCh
) PULONG pdxOut
,
318 return NtGdiGetTextExtentExW(hdc
, lpwsz
, cwc
, dxMax
, pcCh
, pdxOut
, psize
, 0);
326 GetTextExtentExPointA(
328 _In_reads_(cchString
) LPCSTR lpszStr
,
331 _Out_opt_ LPINT lpnFit
,
332 _Out_writes_to_opt_ (cchString
, *lpnFit
) LPINT lpnDx
,
337 BOOL bResult
= FALSE
;
341 SetLastError(ERROR_INVALID_PARAMETER
);
345 Status
= HEAP_strdupA2W(&lpszStrW
, lpszStr
);
346 if (!NT_SUCCESS (Status
))
348 SetLastError(RtlNtStatusToDosError(Status
));
352 bResult
= NtGdiGetTextExtentExW(hdc
,
372 GetTextExtentPoint32A(
374 _In_reads_(cchString
) LPCSTR lpString
,
379 UNICODE_STRING StringU
;
382 StringA
.Buffer
= (LPSTR
)lpString
;
383 StringA
.Length
= cchString
;
384 RtlAnsiStringToUnicodeString(&StringU
, &StringA
, TRUE
);
386 ret
= GetTextExtentPoint32W(hdc
, StringU
.Buffer
, cchString
, lpSize
);
388 RtlFreeUnicodeString(&StringU
);
399 GetTextExtentPoint32W(
401 _In_reads_(cchString
) LPCWSTR lpString
,
405 return NtGdiGetTextExtent(hdc
, (LPWSTR
)lpString
, cchString
, lpSize
, 0);
413 GetTextExtentExPointI(
415 _In_reads_(cgi
) LPWORD pgiIn
,
418 _Out_opt_ LPINT lpnFit
,
419 _Out_writes_to_opt_(cwchString
, *lpnFit
) LPINT lpnDx
,
422 return NtGdiGetTextExtentExW(hdc
,
439 _In_reads_(cgi
) LPWORD pgiIn
,
443 return NtGdiGetTextExtent(hdc
, pgiIn
, cgi
, lpSize
, GTEF_INDICES
);
456 _In_opt_
const RECT
*lprc
,
457 _In_reads_opt_(cch
) LPCSTR lpString
,
459 _In_reads_opt_(cch
) const INT
*lpDx
)
462 UNICODE_STRING StringU
;
465 RtlInitAnsiString(&StringA
, (LPSTR
)lpString
);
466 RtlAnsiStringToUnicodeString(&StringU
, &StringA
, TRUE
);
468 ret
= ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, StringU
.Buffer
, cch
, lpDx
);
470 RtlFreeUnicodeString(&StringU
);
486 _In_opt_
const RECT
*lprc
,
487 _In_reads_opt_(cwc
) LPCWSTR lpString
,
489 _In_reads_opt_(cwc
) const INT
*lpDx
)
505 if (!(fuOptions
& (ETO_GLYPH_INDEX
| ETO_IGNORELANGUAGE
)))
507 if (LoadLPK(LPK_ETO
))
508 return LpkExtTextOut(hdc
, x
, y
, fuOptions
, lprc
, lpString
, cwc
, lpDx
, 0);
511 /* Get the DC attribute */
512 pdcattr
= GdiGetDcAttr(hdc
);
514 !(pdcattr
->ulDirty_
& DC_DIBSECTION
) &&
515 !(pdcattr
->lTextAlign
& TA_UPDATECP
))
519 if ( fuOptions
& ETO_OPAQUE
)
521 PGDIBSEXTTEXTOUT pgO
;
523 pgO
= GdiAllocBatchCommand(hdc
, GdiBCExtTextOut
);
528 pgO
->Options
= fuOptions
;
529 /* Snapshot attribute */
530 pgO
->ulBackgroundClr
= pdcattr
->ulBackgroundClr
;
531 pgO
->ptlViewportOrg
= pdcattr
->ptlViewportOrg
;
535 else // Do nothing, old explorer pops this off.
537 DPRINT1("GdiBCExtTextOut nothing\n");
540 } // Max 580 wchars, if offset 0
541 else if ( cwc
<= ((GDIBATCHBUFSIZE
- sizeof(GDIBSTEXTOUT
)) / sizeof(WCHAR
)) )
544 PTEB pTeb
= NtCurrentTeb();
546 pgO
= GdiAllocBatchCommand(hdc
, GdiBCTextOut
);
552 if (cwc
> 2) cjSize
= (cwc
* sizeof(WCHAR
)) - sizeof(pgO
->String
);
554 /* Calculate buffer size for string and Dx values */
557 /* If ETO_PDY is specified, we have pairs of INTs */
558 DxSize
= (cwc
* sizeof(INT
)) * (fuOptions
& ETO_PDY
? 2 : 1);
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.
565 if ((pTeb
->GdiTebBatch
.Offset
+ cjSize
) <= GDIBATCHBUFSIZE
)
570 pgO
->Options
= fuOptions
;
573 if (lprc
) pgO
->Rect
= *lprc
;
576 pgO
->Options
|= GDIBS_NORECT
; // Tell the other side lprc is nill.
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
;
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
);
593 if (cwc
) RtlCopyMemory( &pgO
->String
[DxSize
/sizeof(WCHAR
)], lpString
, cwc
* sizeof(WCHAR
));
595 // Recompute offset and return size
596 pTeb
->GdiTebBatch
.Offset
+= cjSize
;
597 ((PGDIBATCHHDR
)pgO
)->Size
+= cjSize
;
600 // Reset offset and count then fall through
601 pTeb
->GdiTebBatch
.Offset
-= sizeof(GDIBSTEXTOUT
);
602 pTeb
->GdiBatchCount
--;
606 return NtGdiExtTextOutW(hdc
,
626 _Out_writes_to_opt_(cwcMax
, return) LPWSTR pFaceName
)
628 /* Validate parameters */
629 if (pFaceName
&& cwcMax
<= 0)
631 /* Set last error and return failure */
632 GdiSetLastError(ERROR_INVALID_PARAMETER
);
636 /* Forward to kernel */
637 return NtGdiGetTextFaceW(hdc
, cwcMax
, pFaceName
, FALSE
);
649 _Out_writes_to_opt_(cchMax
, return) LPSTR lpName
)
654 /* Validate parameters */
655 if (lpName
&& cchMax
<= 0)
657 /* Set last error and return failure */
658 GdiSetLastError(ERROR_INVALID_PARAMETER
);
662 res
= GetTextFaceW(hdc
, 0, NULL
);
663 nameW
= HeapAlloc( GetProcessHeap(), 0, res
* 2 );
669 GetTextFaceW( hdc
, res
, nameW
);
673 if (cchMax
&& !WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, lpName
, cchMax
, NULL
, NULL
))
674 lpName
[cchMax
-1] = 0;
675 res
= strlen(lpName
);
679 res
= WideCharToMultiByte( CP_ACP
, 0, nameW
, -1, NULL
, 0, NULL
, NULL
);
682 HeapFree( GetProcessHeap(), 0, nameW
);
695 _Out_writes_to_opt_(cwcMax
, return) LPWSTR pszOut
)
697 if (pszOut
&& !cwcMax
)
699 GdiSetLastError(ERROR_INVALID_PARAMETER
);
703 return NtGdiGetTextFaceW(hdc
, cwcMax
, pszOut
, TRUE
);
709 GetFontResourceInfoW(
710 _In_z_ LPCWSTR lpFileName
,
711 _Inout_ DWORD
*pdwBufSize
,
712 _Out_writes_to_opt_(*pdwBufSize
, 1) PVOID lpBuffer
,
716 UNICODE_STRING NtFileName
;
718 DPRINT("GetFontResourceInfoW: dwType = %lu\n", dwType
);
720 if (!lpFileName
|| !pdwBufSize
)
722 SetLastError(ERROR_INVALID_PARAMETER
);
726 if (!RtlDosPathNameToNtPathName_U(lpFileName
,
731 SetLastError(ERROR_PATH_NOT_FOUND
);
735 bRet
= NtGdiGetFontResourceInfoInternalW(
737 (NtFileName
.Length
/ sizeof(WCHAR
)) + 1,
744 RtlFreeHeap(RtlGetProcessHeap(), 0, NtFileName
.Buffer
);
755 SetTextCharacterExtra(
762 if (nCharExtra
== 0x80000000)
764 SetLastError(ERROR_INVALID_PARAMETER
);
768 if (GDI_HANDLE_GET_TYPE(hdc
) == GDILoObjType_LO_METADC16_TYPE
)
770 HANDLE_METADC(INT
, SetTextCharacterExtra
, 0x80000000, hdc
, nCharExtra
);
773 /* Get the DC attribute */
774 pdcattr
= GdiGetDcAttr(hdc
);
777 SetLastError(ERROR_INVALID_PARAMETER
);
781 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
783 if (pdcattr
->ulDirty_
& DC_FONTTEXT_DIRTY
)
785 NtGdiFlush(); // Sync up pdcattr from Kernel space.
786 pdcattr
->ulDirty_
&= ~(DC_MODE_DIRTY
|DC_FONTTEXT_DIRTY
);
790 nOldCharExtra
= pdcattr
->lTextExtra
;
791 pdcattr
->lTextExtra
= nCharExtra
;
792 return nOldCharExtra
;
806 /* Get the DC attribute */
807 pdcattr
= GdiGetDcAttr(hdc
);
810 /* Do not set LastError here! */
814 return pdcattr
->lTextAlign
;
829 /* Get the DC attribute */
830 pdcattr
= GdiGetDcAttr(hdc
);
833 /* Do not set LastError here! */
837 return pdcattr
->ulForegroundClr
;
853 HANDLE_METADC(BOOL
, SetTextAlign
, GDI_ERROR
, hdc
, fMode
);
855 /* Get the DC attribute */
856 pdcattr
= GdiGetDcAttr(hdc
);
859 SetLastError(ERROR_INVALID_PARAMETER
);
864 fOldMode
= pdcattr
->lTextAlign
;
865 pdcattr
->lTextAlign
= fMode
; // Raw
866 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
868 if ((fMode
& TA_CENTER
) != TA_CENTER
) fMode
^= TA_RIGHT
;
871 pdcattr
->flTextAlign
= fMode
& TA_MASK
;
883 _In_ COLORREF crColor
)
888 HANDLE_METADC(COLORREF
, SetTextColor
, CLR_INVALID
, hdc
, crColor
);
890 pdcattr
= GdiGetDcAttr(hdc
);
893 SetLastError(ERROR_INVALID_PARAMETER
);
897 crOldColor
= (COLORREF
) pdcattr
->ulForegroundClr
;
898 pdcattr
->ulForegroundClr
= (ULONG
)crColor
;
900 if (pdcattr
->crForegroundClr
!= crColor
)
902 pdcattr
->ulDirty_
|= (DIRTY_TEXT
|DIRTY_LINE
|DIRTY_FILL
);
903 pdcattr
->crForegroundClr
= crColor
;
914 SetTextJustification(
916 _In_ INT nBreakExtra
,
917 _In_ INT nBreakCount
)
921 if (GDI_HANDLE_GET_TYPE(hdc
) == GDILoObjType_LO_METADC16_TYPE
)
923 HANDLE_METADC(BOOL
, SetTextJustification
, FALSE
, hdc
, nBreakExtra
, nBreakCount
);
926 /* Get the DC attribute */
927 pdcattr
= GdiGetDcAttr(hdc
);
930 /* Do not set LastError here! */
935 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
937 if (pdcattr
->ulDirty_
& DC_FONTTEXT_DIRTY
)
939 NtGdiFlush(); // Sync up pdcattr from Kernel space.
940 pdcattr
->ulDirty_
&= ~(DC_MODE_DIRTY
|DC_FONTTEXT_DIRTY
);
944 pdcattr
->cBreak
= nBreakCount
;
945 pdcattr
->lBreakExtra
= nBreakExtra
;
959 _Out_writes_(cj
) BYTE
*lpSB
)
971 Status
= HEAP_strdupA2W(&pwsz
, psz
);
972 if (!NT_SUCCESS(Status
))
974 SetLastError (RtlNtStatusToDosError(Status
));
978 uResult
= NtGdiGetStringBitmapW(hdc
, pwsz
, 1, lpSB
, cj
);
996 _Out_writes_(cj
) BYTE
*lpSB
)
1003 return NtGdiGetStringBitmapW(hdc
, pwsz
, 1, lpSB
, cj
);
1014 _Out_ EXTTEXTMETRIC
*petm
)
1018 bResult
= NtGdiGetETM(hdc
, petm
);
1020 if (bResult
&& petm
)
1022 petm
->emKernPairs
= (WORD
)GetKerningPairsA(hdc
, 0, 0);