mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 02:13:29 +00:00
1044 lines
21 KiB
C
1044 lines
21 KiB
C
/*
|
|
* PROJECT: ReactOS GDI32
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Text drawing API.
|
|
* COPYRIGHT: Copyright 2014 Timo Kreuzer
|
|
* Copyright 2017 Katayama Hirofumi MZ
|
|
*/
|
|
|
|
#include <precomp.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
TextOutA(
|
|
_In_ HDC hdc,
|
|
_In_ INT nXStart,
|
|
_In_ INT nYStart,
|
|
_In_reads_(cchString) LPCSTR lpString,
|
|
_In_ INT cchString)
|
|
{
|
|
ANSI_STRING StringA;
|
|
UNICODE_STRING StringU;
|
|
BOOL bResult;
|
|
NTSTATUS Status;
|
|
|
|
if (lpString != NULL && cchString > 0)
|
|
{
|
|
if (cchString > MAXUSHORT)
|
|
cchString = MAXUSHORT;
|
|
|
|
StringA.Length = (USHORT)cchString;
|
|
StringA.MaximumLength = (USHORT)cchString;
|
|
StringA.Buffer = (PCHAR)lpString;
|
|
|
|
Status = RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
StringU.Buffer = NULL;
|
|
StringU.Length = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StringU.Buffer = NULL;
|
|
StringU.Length = 0;
|
|
}
|
|
|
|
bResult = TextOutW(hdc, nXStart, nYStart,
|
|
StringU.Buffer, StringU.Length / sizeof(WCHAR));
|
|
|
|
RtlFreeUnicodeString(&StringU);
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
TextOutW(
|
|
_In_ HDC hdc,
|
|
_In_ INT nXStart,
|
|
_In_ INT nYStart,
|
|
_In_reads_(cchString) LPCWSTR lpString,
|
|
_In_ INT cchString)
|
|
{
|
|
return ExtTextOutW(hdc, nXStart, nYStart, 0, NULL, (LPWSTR)lpString, cchString, NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
PolyTextOutA(
|
|
_In_ HDC hdc,
|
|
_In_reads_(cStrings) const POLYTEXTA *pptxt,
|
|
_In_ INT cStrings)
|
|
{
|
|
for (; cStrings>0; cStrings--, pptxt++)
|
|
{
|
|
if (!ExtTextOutA(hdc,
|
|
pptxt->x,
|
|
pptxt->y,
|
|
pptxt->uiFlags,
|
|
&pptxt->rcl,
|
|
pptxt->lpstr,
|
|
pptxt->n,
|
|
pptxt->pdx))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
PolyTextOutW(
|
|
_In_ HDC hdc,
|
|
_In_reads_(cStrings) const POLYTEXTW *pptxt,
|
|
_In_ INT cStrings)
|
|
{
|
|
for (; cStrings>0; cStrings--, pptxt++)
|
|
{
|
|
if (!ExtTextOutW(hdc,
|
|
pptxt->x,
|
|
pptxt->y,
|
|
pptxt->uiFlags,
|
|
&pptxt->rcl,
|
|
pptxt->lpstr,
|
|
pptxt->n,
|
|
pptxt->pdx))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
GdiGetCodePage(
|
|
_In_ HDC hdc)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
|
|
/* Get the DC attribute */
|
|
pdcattr = GdiGetDcAttr(hdc);
|
|
if (pdcattr == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (pdcattr->ulDirty_ & DIRTY_CHARSET)
|
|
return LOWORD(NtGdiGetCharSet(hdc));
|
|
|
|
return LOWORD(pdcattr->iCS_CP);
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
INT
|
|
WINAPI
|
|
GetTextCharacterExtra(
|
|
_In_ HDC hdc)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
|
|
/* Get the DC attribute */
|
|
pdcattr = GdiGetDcAttr(hdc);
|
|
if (pdcattr == NULL)
|
|
{
|
|
/* Do not set LastError here! */
|
|
return 0x8000000;
|
|
}
|
|
|
|
return pdcattr->lTextExtra;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
INT
|
|
WINAPI
|
|
GetTextCharset(
|
|
_In_ HDC hdc)
|
|
{
|
|
/* MSDN docs say this is equivalent */
|
|
return NtGdiGetTextCharsetInfo(hdc,NULL,0);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetTextMetricsA(
|
|
_In_ HDC hdc,
|
|
_Out_ LPTEXTMETRICA lptm)
|
|
{
|
|
TMW_INTERNAL tmwi;
|
|
|
|
if (!NtGdiGetTextMetricsW(hdc, &tmwi, sizeof(TMW_INTERNAL)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
FONT_TextMetricWToA(&tmwi.TextMetric, lptm);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetTextMetricsW(
|
|
_In_ HDC hdc,
|
|
_Out_ LPTEXTMETRICW lptm)
|
|
{
|
|
TMW_INTERNAL tmwi;
|
|
|
|
if (!NtGdiGetTextMetricsW(hdc, &tmwi, sizeof(TMW_INTERNAL)))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
*lptm = tmwi.TextMetric;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
APIENTRY
|
|
GetTextExtentPointA(
|
|
_In_ HDC hdc,
|
|
_In_reads_(cchString) LPCSTR lpString,
|
|
_In_ INT cchString,
|
|
_Out_ LPSIZE lpsz)
|
|
{
|
|
ANSI_STRING StringA;
|
|
UNICODE_STRING StringU;
|
|
BOOL ret;
|
|
|
|
RtlInitAnsiString(&StringA, (LPSTR)lpString);
|
|
RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
|
|
|
|
ret = GetTextExtentPointW(hdc, StringU.Buffer, cchString, lpsz);
|
|
|
|
RtlFreeUnicodeString(&StringU);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
APIENTRY
|
|
GetTextExtentPointW(
|
|
_In_ HDC hdc,
|
|
_In_reads_(cchString) LPCWSTR lpString,
|
|
_In_ INT cchString,
|
|
_Out_ LPSIZE lpsz)
|
|
{
|
|
return NtGdiGetTextExtent(hdc, (LPWSTR)lpString, cchString, lpsz, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
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)
|
|
{
|
|
|
|
/* Windows doesn't check nMaxExtent validity in unicode version */
|
|
if (nMaxExtent < -1)
|
|
{
|
|
DPRINT("nMaxExtent is invalid: %d\n", nMaxExtent);
|
|
}
|
|
|
|
if (LoadLPK(LPK_GTEP))
|
|
return LpkGetTextExtentExPoint(hdc, lpszString, cchString, nMaxExtent, lpnFit, lpnDx, lpSize, 0, 0);
|
|
|
|
return NtGdiGetTextExtentExW (
|
|
hdc, (LPWSTR)lpszString, cchString, nMaxExtent, (PULONG)lpnFit, (PULONG)lpnDx, lpSize, 0 );
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
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)
|
|
{
|
|
return NtGdiGetTextExtentExW(hdc, (LPWSTR)lpwsz, cwc, dxMax, (PULONG)pcCh, (PULONG)pdxOut, psize, 0);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
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)
|
|
{
|
|
NTSTATUS Status;
|
|
LPWSTR lpszStrW;
|
|
BOOL bResult = FALSE;
|
|
|
|
if (nMaxExtent < -1)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
Status = HEAP_strdupA2W(&lpszStrW, lpszStr);
|
|
if (!NT_SUCCESS (Status))
|
|
{
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
|
return FALSE;
|
|
}
|
|
|
|
bResult = NtGdiGetTextExtentExW(hdc,
|
|
lpszStrW,
|
|
cchString,
|
|
nMaxExtent,
|
|
(PULONG)lpnFit,
|
|
(PULONG)lpnDx,
|
|
lpSize,
|
|
0);
|
|
|
|
HEAP_free(lpszStrW);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetTextExtentPoint32A(
|
|
_In_ HDC hdc,
|
|
_In_reads_(cchString) LPCSTR lpString,
|
|
_In_ INT cchString,
|
|
_Out_ LPSIZE lpSize)
|
|
{
|
|
ANSI_STRING StringA;
|
|
UNICODE_STRING StringU;
|
|
BOOL ret;
|
|
|
|
StringA.Buffer = (LPSTR)lpString;
|
|
StringA.Length = cchString;
|
|
RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
|
|
|
|
ret = GetTextExtentPoint32W(hdc, StringU.Buffer, cchString, lpSize);
|
|
|
|
RtlFreeUnicodeString(&StringU);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetTextExtentPoint32W(
|
|
_In_ HDC hdc,
|
|
_In_reads_(cchString) LPCWSTR lpString,
|
|
_In_ int cchString,
|
|
_Out_ LPSIZE lpSize)
|
|
{
|
|
return NtGdiGetTextExtent(hdc, (LPWSTR)lpString, cchString, lpSize, 0);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
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)
|
|
{
|
|
return NtGdiGetTextExtentExW(hdc,
|
|
pgiIn,
|
|
cgi,
|
|
nMaxExtent,
|
|
(PULONG)lpnFit,
|
|
(PULONG)lpnDx,
|
|
lpSize,
|
|
GTEF_INDICES);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetTextExtentPointI(
|
|
_In_ HDC hdc,
|
|
_In_reads_(cgi) LPWORD pgiIn,
|
|
_In_ int cgi,
|
|
_Out_ LPSIZE lpSize)
|
|
{
|
|
return NtGdiGetTextExtent(hdc, pgiIn, cgi, lpSize, GTEF_INDICES);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
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)
|
|
{
|
|
ANSI_STRING StringA;
|
|
UNICODE_STRING StringU;
|
|
BOOL ret;
|
|
|
|
RtlInitAnsiString(&StringA, (LPSTR)lpString);
|
|
RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
|
|
|
|
ret = ExtTextOutW(hdc, x, y, fuOptions, lprc, StringU.Buffer, cch, lpDx);
|
|
|
|
RtlFreeUnicodeString(&StringU);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static BOOL bBypassETOWMF = FALSE;
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
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)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
|
|
if ( !bBypassETOWMF )
|
|
{
|
|
HANDLE_METADC(BOOL,
|
|
ExtTextOut,
|
|
FALSE,
|
|
hdc,
|
|
x,
|
|
y,
|
|
fuOptions,
|
|
lprc,
|
|
lpString,
|
|
cwc,
|
|
lpDx);
|
|
}
|
|
|
|
if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE;
|
|
|
|
if (!(fuOptions & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)))
|
|
{
|
|
bBypassETOWMF = TRUE;
|
|
|
|
if (LoadLPK(LPK_ETO))
|
|
return LpkExtTextOut(hdc, x, y, fuOptions, lprc, lpString, cwc , lpDx, 0);
|
|
}
|
|
else
|
|
{
|
|
bBypassETOWMF = FALSE;
|
|
}
|
|
|
|
/* Get the DC attribute */
|
|
pdcattr = GdiGetDcAttr(hdc);
|
|
if ( pdcattr &&
|
|
!(pdcattr->ulDirty_ & DC_DIBSECTION) &&
|
|
!(pdcattr->lTextAlign & TA_UPDATECP))
|
|
{
|
|
if ( lprc && !cwc )
|
|
{
|
|
if ( fuOptions & ETO_OPAQUE )
|
|
{
|
|
PGDIBSEXTTEXTOUT pgO;
|
|
|
|
pgO = GdiAllocBatchCommand(hdc, GdiBCExtTextOut);
|
|
if (pgO)
|
|
{
|
|
pdcattr->ulDirty_ |= DC_MODE_DIRTY;
|
|
pgO->Count = cwc;
|
|
pgO->Rect = *lprc;
|
|
pgO->Options = fuOptions;
|
|
/* Snapshot attribute */
|
|
pgO->ulBackgroundClr = pdcattr->ulBackgroundClr;
|
|
pgO->ptlViewportOrg = pdcattr->ptlViewportOrg;
|
|
return TRUE;
|
|
}
|
|
}
|
|
else // Do nothing, old explorer pops this off.
|
|
{
|
|
DPRINT1("GdiBCExtTextOut nothing\n");
|
|
return TRUE;
|
|
}
|
|
} // Max 580 wchars, if offset 0
|
|
else if ( cwc <= ((GDIBATCHBUFSIZE - sizeof(GDIBSTEXTOUT)) / sizeof(WCHAR)) )
|
|
{
|
|
PGDIBSTEXTOUT pgO;
|
|
PTEB pTeb = NtCurrentTeb();
|
|
|
|
pgO = GdiAllocBatchCommand(hdc, GdiBCTextOut);
|
|
if (pgO)
|
|
{
|
|
USHORT cjSize = 0;
|
|
ULONG DxSize = 0;
|
|
|
|
if (cwc > 2) cjSize = (cwc * sizeof(WCHAR)) - sizeof(pgO->String);
|
|
|
|
/* Calculate buffer size for string and Dx values */
|
|
if (lpDx)
|
|
{
|
|
/* If ETO_PDY is specified, we have pairs of INTs */
|
|
DxSize = (cwc * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
|
|
cjSize += DxSize;
|
|
// The structure buffer holds 4 bytes. Store Dx data then string.
|
|
// Result one wchar -> Buf[ Dx ]Str[wC], [4][2][X] one extra unused wchar
|
|
// to assure alignment of 4.
|
|
}
|
|
|
|
if ((pTeb->GdiTebBatch.Offset + cjSize ) <= GDIBATCHBUFSIZE)
|
|
{
|
|
pdcattr->ulDirty_ |= DC_MODE_DIRTY|DC_FONTTEXT_DIRTY;
|
|
pgO->cbCount = cwc;
|
|
pgO->x = x;
|
|
pgO->y = y;
|
|
pgO->Options = fuOptions;
|
|
pgO->iCS_CP = 0;
|
|
|
|
if (lprc) pgO->Rect = *lprc;
|
|
else
|
|
{
|
|
pgO->Options |= GDIBS_NORECT; // Tell the other side lprc is nill.
|
|
}
|
|
|
|
/* Snapshot attributes */
|
|
pgO->crForegroundClr = pdcattr->crForegroundClr;
|
|
pgO->crBackgroundClr = pdcattr->crBackgroundClr;
|
|
pgO->ulForegroundClr = pdcattr->ulForegroundClr;
|
|
pgO->ulBackgroundClr = pdcattr->ulBackgroundClr;
|
|
pgO->lBkMode = pdcattr->lBkMode == OPAQUE ? OPAQUE : TRANSPARENT;
|
|
pgO->hlfntNew = pdcattr->hlfntNew;
|
|
pgO->flTextAlign = pdcattr->flTextAlign;
|
|
pgO->ptlViewportOrg = pdcattr->ptlViewportOrg;
|
|
|
|
pgO->Size = DxSize; // of lpDx then string after.
|
|
/* Put the Dx before the String to assure alignment of 4 */
|
|
if (lpDx) RtlCopyMemory( &pgO->Buffer, lpDx, DxSize);
|
|
|
|
if (cwc) RtlCopyMemory( &pgO->String[DxSize/sizeof(WCHAR)], lpString, cwc * sizeof(WCHAR));
|
|
|
|
// Recompute offset and return size
|
|
pTeb->GdiTebBatch.Offset += cjSize;
|
|
((PGDIBATCHHDR)pgO)->Size += cjSize;
|
|
return TRUE;
|
|
}
|
|
// Reset offset and count then fall through
|
|
pTeb->GdiTebBatch.Offset -= sizeof(GDIBSTEXTOUT);
|
|
pTeb->GdiBatchCount--;
|
|
}
|
|
}
|
|
}
|
|
return NtGdiExtTextOutW(hdc,
|
|
x,
|
|
y,
|
|
fuOptions,
|
|
(LPRECT)lprc,
|
|
(LPWSTR)lpString,
|
|
cwc,
|
|
(LPINT)lpDx,
|
|
0);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
INT
|
|
WINAPI
|
|
GetTextFaceW(
|
|
_In_ HDC hdc,
|
|
_In_ INT cwcMax,
|
|
_Out_writes_to_opt_(cwcMax, return) LPWSTR pFaceName)
|
|
{
|
|
/* Validate parameters */
|
|
if (pFaceName && cwcMax <= 0)
|
|
{
|
|
/* Set last error and return failure */
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
/* Forward to kernel */
|
|
return NtGdiGetTextFaceW(hdc, cwcMax, pFaceName, FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
INT
|
|
WINAPI
|
|
GetTextFaceA(
|
|
_In_ HDC hdc,
|
|
_In_ INT cchMax,
|
|
_Out_writes_to_opt_(cchMax, return) LPSTR lpName)
|
|
{
|
|
INT res;
|
|
LPWSTR nameW;
|
|
|
|
/* Validate parameters */
|
|
if (lpName && cchMax <= 0)
|
|
{
|
|
/* Set last error and return failure */
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
res = GetTextFaceW(hdc, 0, NULL);
|
|
nameW = HeapAlloc( GetProcessHeap(), 0, res * 2 );
|
|
if (nameW == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
GetTextFaceW( hdc, res, nameW );
|
|
|
|
if (lpName)
|
|
{
|
|
if (cchMax && !WideCharToMultiByte( CP_ACP, 0, nameW, -1, lpName, cchMax, NULL, NULL))
|
|
lpName[cchMax-1] = 0;
|
|
res = strlen(lpName);
|
|
}
|
|
else
|
|
{
|
|
res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL);
|
|
}
|
|
|
|
HeapFree( GetProcessHeap(), 0, nameW );
|
|
return res;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
INT
|
|
WINAPI
|
|
GetTextFaceAliasW(
|
|
_In_ HDC hdc,
|
|
_In_ INT cwcMax,
|
|
_Out_writes_to_opt_(cwcMax, return) LPWSTR pszOut)
|
|
{
|
|
if (pszOut && !cwcMax)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
return NtGdiGetTextFaceW(hdc, cwcMax, pszOut, TRUE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
GetFontResourceInfoW(
|
|
_In_z_ LPCWSTR lpFileName,
|
|
_Inout_ DWORD *pdwBufSize,
|
|
_Out_writes_to_opt_(*pdwBufSize, 1) PVOID lpBuffer,
|
|
_In_ DWORD dwType)
|
|
{
|
|
BOOL bRet;
|
|
UNICODE_STRING NtFileName;
|
|
|
|
DPRINT("GetFontResourceInfoW: dwType = %lu\n", dwType);
|
|
|
|
if (!lpFileName || !pdwBufSize)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!RtlDosPathNameToNtPathName_U(lpFileName,
|
|
&NtFileName,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
|
|
bRet = NtGdiGetFontResourceInfoInternalW(
|
|
NtFileName.Buffer,
|
|
(NtFileName.Length / sizeof(WCHAR)) + 1,
|
|
1,
|
|
*pdwBufSize,
|
|
pdwBufSize,
|
|
lpBuffer,
|
|
dwType);
|
|
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, NtFileName.Buffer);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
INT
|
|
WINAPI
|
|
SetTextCharacterExtra(
|
|
_In_ HDC hdc,
|
|
_In_ INT nCharExtra)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
INT nOldCharExtra;
|
|
|
|
if (nCharExtra == 0x80000000)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0x80000000;
|
|
}
|
|
|
|
if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
|
|
{
|
|
HANDLE_METADC(INT, SetTextCharacterExtra, 0x80000000, hdc, nCharExtra);
|
|
}
|
|
|
|
/* Get the DC attribute */
|
|
pdcattr = GdiGetDcAttr(hdc);
|
|
if (pdcattr == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0x8000000;
|
|
}
|
|
|
|
if (NtCurrentTeb()->GdiTebBatch.HDC == hdc)
|
|
{
|
|
if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY)
|
|
{
|
|
NtGdiFlush(); // Sync up pdcattr from Kernel space.
|
|
pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY);
|
|
}
|
|
}
|
|
|
|
nOldCharExtra = pdcattr->lTextExtra;
|
|
pdcattr->lTextExtra = nCharExtra;
|
|
return nOldCharExtra;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*
|
|
*/
|
|
UINT
|
|
WINAPI
|
|
GetTextAlign(
|
|
_In_ HDC hdc)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
|
|
/* Get the DC attribute */
|
|
pdcattr = GdiGetDcAttr(hdc);
|
|
if (pdcattr == NULL)
|
|
{
|
|
/* Do not set LastError here! */
|
|
return GDI_ERROR;
|
|
}
|
|
|
|
return pdcattr->lTextAlign;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*
|
|
*/
|
|
COLORREF
|
|
WINAPI
|
|
GetTextColor(
|
|
_In_ HDC hdc)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
|
|
/* Get the DC attribute */
|
|
pdcattr = GdiGetDcAttr(hdc);
|
|
if (pdcattr == NULL)
|
|
{
|
|
/* Do not set LastError here! */
|
|
return CLR_INVALID;
|
|
}
|
|
|
|
return pdcattr->ulForegroundClr;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
UINT
|
|
WINAPI
|
|
SetTextAlign(
|
|
_In_ HDC hdc,
|
|
_In_ UINT fMode)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
UINT fOldMode;
|
|
|
|
HANDLE_METADC(BOOL, SetTextAlign, GDI_ERROR, hdc, fMode);
|
|
|
|
/* Get the DC attribute */
|
|
pdcattr = GdiGetDcAttr(hdc);
|
|
if (pdcattr == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return GDI_ERROR;
|
|
}
|
|
|
|
|
|
fOldMode = pdcattr->lTextAlign;
|
|
pdcattr->lTextAlign = fMode; // Raw
|
|
if (pdcattr->dwLayout & LAYOUT_RTL)
|
|
{
|
|
if ((fMode & TA_CENTER) != TA_CENTER) fMode ^= TA_RIGHT;
|
|
}
|
|
|
|
pdcattr->flTextAlign = fMode & TA_MASK;
|
|
return fOldMode;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
COLORREF
|
|
WINAPI
|
|
SetTextColor(
|
|
_In_ HDC hdc,
|
|
_In_ COLORREF crColor)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
COLORREF crOldColor;
|
|
|
|
HANDLE_METADC(COLORREF, SetTextColor, CLR_INVALID, hdc, crColor);
|
|
|
|
pdcattr = GdiGetDcAttr(hdc);
|
|
if (pdcattr == NULL)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return CLR_INVALID;
|
|
}
|
|
|
|
crOldColor = (COLORREF) pdcattr->ulForegroundClr;
|
|
pdcattr->ulForegroundClr = (ULONG)crColor;
|
|
|
|
if (pdcattr->crForegroundClr != crColor)
|
|
{
|
|
pdcattr->ulDirty_ |= (DIRTY_TEXT|DIRTY_LINE|DIRTY_FILL);
|
|
pdcattr->crForegroundClr = crColor;
|
|
}
|
|
|
|
return crOldColor;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
SetTextJustification(
|
|
_In_ HDC hdc,
|
|
_In_ INT nBreakExtra,
|
|
_In_ INT nBreakCount)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
|
|
if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
|
|
{
|
|
HANDLE_METADC(BOOL, SetTextJustification, FALSE, hdc, nBreakExtra, nBreakCount);
|
|
}
|
|
|
|
/* Get the DC attribute */
|
|
pdcattr = GdiGetDcAttr(hdc);
|
|
if (pdcattr == NULL)
|
|
{
|
|
/* Do not set LastError here! */
|
|
return GDI_ERROR;
|
|
}
|
|
|
|
|
|
if (NtCurrentTeb()->GdiTebBatch.HDC == hdc)
|
|
{
|
|
if (pdcattr->ulDirty_ & DC_FONTTEXT_DIRTY)
|
|
{
|
|
NtGdiFlush(); // Sync up pdcattr from Kernel space.
|
|
pdcattr->ulDirty_ &= ~(DC_MODE_DIRTY|DC_FONTTEXT_DIRTY);
|
|
}
|
|
}
|
|
|
|
pdcattr->cBreak = nBreakCount;
|
|
pdcattr->lBreakExtra = nBreakExtra;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
UINT
|
|
WINAPI
|
|
GetStringBitmapA(
|
|
_In_ HDC hdc,
|
|
_In_ LPSTR psz,
|
|
_In_ BOOL bDoCall,
|
|
_In_ UINT cj,
|
|
_Out_writes_(cj) BYTE *lpSB)
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
PWSTR pwsz;
|
|
UINT uResult = 0;
|
|
|
|
if (!bDoCall)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
Status = HEAP_strdupA2W(&pwsz, psz);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SetLastError (RtlNtStatusToDosError(Status));
|
|
}
|
|
else
|
|
{
|
|
uResult = NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj);
|
|
HEAP_free(pwsz);
|
|
}
|
|
|
|
return uResult;
|
|
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
UINT
|
|
WINAPI
|
|
GetStringBitmapW(
|
|
_In_ HDC hdc,
|
|
_In_ LPWSTR pwsz,
|
|
_In_ BOOL bDoCall,
|
|
_In_ UINT cj,
|
|
_Out_writes_(cj) BYTE *lpSB)
|
|
{
|
|
if (!bDoCall)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return NtGdiGetStringBitmapW(hdc, pwsz, 1, lpSB, cj);
|
|
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
GetETM(
|
|
_In_ HDC hdc,
|
|
_Out_ EXTTEXTMETRIC *petm)
|
|
{
|
|
BOOL bResult;
|
|
|
|
bResult = NtGdiGetETM(hdc, petm);
|
|
|
|
if (bResult && petm)
|
|
{
|
|
petm->emKernPairs = (WORD)GetKerningPairsA(hdc, 0, 0);
|
|
}
|
|
|
|
return bResult;
|
|
}
|