reactos/win32ss/gdi/gdi32/objects/text.c
Joachim Henze ea05d36496 [0.4.13][PARPORT] Fix I/O port length check, [REACTOS] Logging & formatting, e.g. CORE-14388 CORE-19105
Ports back a real fix:
0.4.15-dev-1173-g ba09834c5e [PARPORT] Fix I/O port length check

Ports back logging and formatting:
0.4.15-dev-6794-g 4eace8d762 [IPHLPAPI] Silence obsolete FIXME in GetAdaptersAddresses (#5834) CORE-14388
0.4.15-dev-6438-g b12ab486d8 [MUP] Mute DPRINT1's that slow down shared folder accesses (#5545) CORE-19105

And mutes some other loggings as well for stuff, that I either never want to port back, e.g. the IMM-implementations,
or which is not really helpful in the older branches:
fixme:(win32ss/user/user32/misc/imm.c:446) WINNLSEnableIME is UNIMPLEMENTED!
fixme:(../dll/win32/iphlpapi/address.c:290) GetAdaptersAddresses - Semi Stub: Family 2, Flags 0x0000002e, Reserved 00000000, pAdapterAddress 00000000, pOutBufLen 0143EBD4.
(dll/ntdll/ldr/ldrinit.c:1649) LdrpInitializeProcessCompat: Not applying automatic fix for winver 0xa00 due to policy
(win32ss/gdi/gdi32/objects/text.c:543) GdiBCExtTextOut nothing

when browsing the startmenu:
fixme:(dll/win32/comctl32/toolbar.c:394) [00080086] TBSTYLE_REGISTERDROP not implemented
fixme:(dll/win32/comctl32/toolbar.c:5636) [00080086] response 2045774661 not handled to NM_CUSTOMDRAW (CDDS_PREERASE)
fixme:(dll/win32/comctl32/toolbar.c:5673) [00080086] response 3225142 not handled to NM_CUSTOMDRAW (CDDS_POSTERASE)
fixme:(dll/win32/comctl32/toolbar.c:5636) [000200BA] response 9 not handled to NM_CUSTOMDRAW (CDDS_PREERASE)
fixme:(dll/win32/comctl32/toolbar.c:5636) [00080086] response 2288892 not handled to NM_CUSTOMDRAW (CDDS_PREERASE)
fixme:(dll/win32/comctl32/toolbar.c:5673) [00080086] response 3291448 not handled to NM_CUSTOMDRAW (CDDS_POSTERASE)

and a bigger block regarding the parallel port during booting:
(drivers/parallel/parport/parport.c:127) Parport DriverEntry
(drivers/parallel/parport/fdo.c:391) AddDevice(B0B50548 B0FED980)
(drivers/parallel/parport/fdo.c:25) AddDeviceInternal()
(drivers/parallel/parport/fdo.c:513) FdoPnp()
(drivers/parallel/parport/fdo.c:582) IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS
(drivers/parallel/parport/fdo.c:513) FdoPnp()
(drivers/parallel/parport/fdo.c:546) IRP_MJ_PNP / IRP_MN_START_DEVICE
(drivers/parallel/parport/misc.c:42) Calling lower device B0FED980
(drivers/parallel/parport/fdo.c:116) FdoStartDevice ()
(drivers/parallel/parport/fdo.c:160) Port: BaseAddress 0x378  Length 8
(drivers/parallel/parport/fdo.c:160) Port: BaseAddress 0x778  Length 8
(drivers/parallel/parport/fdo.c:174) Interrupt: Level 20  Vector 55
(drivers/parallel/parport/fdo.c:195) New LPT port: Base 0x378
(drivers/parallel/parport/fdo.c:513) FdoPnp()
(drivers/parallel/parport/fdo.c:586) Unknown minor function 0x9
(drivers/parallel/parport/fdo.c:513) FdoPnp()
(drivers/parallel/parport/fdo.c:586) Unknown minor function 0x14
(drivers/parallel/parport/fdo.c:513) FdoPnp()
(drivers/parallel/parport/fdo.c:564) IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations
(drivers/parallel/parport/fdo.c:351) FdoQueryBusRelations()
(drivers/parallel/parport/fdo.c:233) FdoCreateRawParallelPdo()
(drivers/parallel/parport/fdo.c:378) Done
(drivers/parallel/parport/pdo.c:165) PdoPnp()
2023-11-05 13:24:34 +01:00

1034 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;
}
/*
* @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;
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)))
{
if (LoadLPK(LPK_ETO))
return LpkExtTextOut(hdc, x, y, fuOptions, lprc, lpString, cwc , lpDx, 0);
}
/* 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.
{
DPRINT("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;
}