/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
- * FILE: lib/gdi32/object/font.c
+ * FILE: win32ss/gdi/gdi32/objects/font.c
* PURPOSE:
* PROGRAMMER:
*
#include <precomp.h>
+#include <math.h>
+#include <strsafe.h>
+
#define NDEBUG
#include <debug.h>
+/* Rounds a floating point number to integer. The world-to-viewport
+ * transformation process is done in floating point internally. This function
+ * is then used to round these coordinates to integer values.
+ */
+static __inline INT GDI_ROUND(FLOAT val)
+{
+ return (int)floor(val + 0.5);
+}
+
/*
* For TranslateCharsetInfo
*/
strW = HeapAlloc(GetProcessHeap(), 0, lenW*sizeof(WCHAR));
if (!strW)
return NULL;
- MultiByteToWideChar(cp, 0, str, count, strW, lenW);
+ if(!MultiByteToWideChar(cp, 0, str, count, strW, lenW))
+ {
+ HeapFree(GetProcessHeap(), 0, strW);
+ return NULL;
+ }
DPRINT("mapped %s -> %S\n", str, strW);
if(plenW) *plenW = lenW;
if(pCP) *pCP = cp;
tma->ntmFontSig = tmw->ntmFontSig;
}
+// IntFontFamilyCompareEx's flags
+#define IFFCX_CHARSET 1
+#define IFFCX_STYLE 2
+
+FORCEINLINE int FASTCALL
+IntFontFamilyCompareEx(const FONTFAMILYINFO *ffi1,
+ const FONTFAMILYINFO *ffi2, DWORD dwCompareFlags)
+{
+ const LOGFONTW *plf1 = &ffi1->EnumLogFontEx.elfLogFont;
+ const LOGFONTW *plf2 = &ffi2->EnumLogFontEx.elfLogFont;
+ ULONG WeightDiff1, WeightDiff2;
+ int cmp = _wcsicmp(plf1->lfFaceName, plf2->lfFaceName);
+ if (cmp)
+ return cmp;
+ if (dwCompareFlags & IFFCX_CHARSET)
+ {
+ if (plf1->lfCharSet < plf2->lfCharSet)
+ return -1;
+ if (plf1->lfCharSet > plf2->lfCharSet)
+ return 1;
+ }
+ if (dwCompareFlags & IFFCX_STYLE)
+ {
+ WeightDiff1 = labs(plf1->lfWeight - FW_NORMAL);
+ WeightDiff2 = labs(plf2->lfWeight - FW_NORMAL);
+ if (WeightDiff1 < WeightDiff2)
+ return -1;
+ if (WeightDiff1 > WeightDiff2)
+ return 1;
+ if (plf1->lfItalic < plf2->lfItalic)
+ return -1;
+ if (plf1->lfItalic > plf2->lfItalic)
+ return 1;
+ }
+ return 0;
+}
+
+static int __cdecl
+IntFontFamilyCompare(const void *ffi1, const void *ffi2)
+{
+ return IntFontFamilyCompareEx(ffi1, ffi2, IFFCX_STYLE | IFFCX_CHARSET);
+}
+
+// IntEnumFontFamilies' flags:
+#define IEFF_UNICODE 1
+#define IEFF_EXTENDED 2
+
+int FASTCALL
+IntFontFamilyListUnique(FONTFAMILYINFO *InfoList, INT nCount,
+ const LOGFONTW *plf, DWORD dwFlags)
+{
+ FONTFAMILYINFO *first, *last, *result;
+ DWORD dwCompareFlags = 0;
+
+ if (plf->lfFaceName[0])
+ dwCompareFlags |= IFFCX_STYLE;
+
+ if ((dwFlags & IEFF_EXTENDED) && plf->lfCharSet == DEFAULT_CHARSET)
+ dwCompareFlags |= IFFCX_CHARSET;
+
+ first = InfoList;
+ last = &InfoList[nCount];
+
+ /* std::unique(first, last, IntFontFamilyCompareEx); */
+ if (first == last)
+ return 0;
+
+ result = first;
+ while (++first != last)
+ {
+ if (IntFontFamilyCompareEx(result, first, dwCompareFlags) != 0)
+ {
+ *(++result) = *first;
+ }
+ }
+ nCount = (int)(++result - InfoList);
+
+ return nCount;
+}
+
static int FASTCALL
-IntEnumFontFamilies(HDC Dc, LPLOGFONTW LogFont, PVOID EnumProc, LPARAM lParam,
- BOOL Unicode)
+IntEnumFontFamilies(HDC Dc, const LOGFONTW *LogFont, PVOID EnumProc, LPARAM lParam,
+ DWORD dwFlags)
{
int FontFamilyCount;
- int FontFamilySize;
PFONTFAMILYINFO Info;
- int Ret = 0;
+ int Ret = 1;
int i;
ENUMLOGFONTEXA EnumLogFontExA;
NEWTEXTMETRICEXA NewTextMetricExA;
LOGFONTW lfW;
+ LONG InfoCount;
+ ULONG DataSize;
+ NTSTATUS Status;
- Info = RtlAllocateHeap(GetProcessHeap(), 0,
- INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO));
- if (NULL == Info)
+ DataSize = INITIAL_FAMILY_COUNT * sizeof(FONTFAMILYINFO);
+ Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize);
+ if (Info == NULL)
{
- return 0;
+ return 1;
}
+ /* Initialize the LOGFONT structure */
+ ZeroMemory(&lfW, sizeof(lfW));
if (!LogFont)
{
lfW.lfCharSet = DEFAULT_CHARSET;
- lfW.lfPitchAndFamily = 0;
- lfW.lfFaceName[0] = 0;
- LogFont = &lfW;
+ }
+ else
+ {
+ lfW.lfCharSet = LogFont->lfCharSet;
+ lfW.lfPitchAndFamily = LogFont->lfPitchAndFamily;
+ StringCbCopyW(lfW.lfFaceName, sizeof(lfW.lfFaceName), LogFont->lfFaceName);
}
- FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, INITIAL_FAMILY_COUNT);
+ /* Retrieve the font information */
+ InfoCount = INITIAL_FAMILY_COUNT;
+ FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, &lfW, Info, &InfoCount);
if (FontFamilyCount < 0)
{
RtlFreeHeap(GetProcessHeap(), 0, Info);
- return 0;
+ return 1;
}
- if (INITIAL_FAMILY_COUNT < FontFamilyCount)
+
+ /* Resize the buffer if the buffer is too small */
+ if (INITIAL_FAMILY_COUNT < InfoCount)
{
- FontFamilySize = FontFamilyCount;
RtlFreeHeap(GetProcessHeap(), 0, Info);
- Info = RtlAllocateHeap(GetProcessHeap(), 0,
- FontFamilyCount * sizeof(FONTFAMILYINFO));
- if (NULL == Info)
+
+ Status = RtlULongMult(InfoCount, sizeof(FONTFAMILYINFO), &DataSize);
+ if (!NT_SUCCESS(Status) || DataSize > LONG_MAX)
{
- return 0;
+ DPRINT1("Overflowed.\n");
+ return 1;
+ }
+ Info = RtlAllocateHeap(GetProcessHeap(), 0, DataSize);
+ if (Info == NULL)
+ {
+ return 1;
}
- FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, LogFont, Info, FontFamilySize);
- if (FontFamilyCount < 0 || FontFamilySize < FontFamilyCount)
+ FontFamilyCount = NtGdiGetFontFamilyInfo(Dc, &lfW, Info, &InfoCount);
+ if (FontFamilyCount < 0 || FontFamilyCount < InfoCount)
{
RtlFreeHeap(GetProcessHeap(), 0, Info);
- return 0;
+ return 1;
}
}
+ /* Sort and remove redundant information */
+ qsort(Info, FontFamilyCount, sizeof(*Info), IntFontFamilyCompare);
+ FontFamilyCount = IntFontFamilyListUnique(Info, FontFamilyCount, &lfW, dwFlags);
+
+ /* call the callback */
for (i = 0; i < FontFamilyCount; i++)
{
- if (Unicode)
+ if (dwFlags & IEFF_UNICODE)
{
Ret = ((FONTENUMPROCW) EnumProc)(
(VOID*)&Info[i].EnumLogFontEx,
(VOID*)&NewTextMetricExA,
Info[i].FontType, lParam);
}
+
+ if(Ret == 0)
+ break;
}
RtlFreeHeap(GetProcessHeap(), 0, Info);
EnumFontFamiliesExW(HDC hdc, LPLOGFONTW lpLogfont, FONTENUMPROCW lpEnumFontFamExProc,
LPARAM lParam, DWORD dwFlags)
{
- return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam, TRUE);
+ if (lpLogfont)
+ {
+ DPRINT("EnumFontFamiliesExW(%p, %p(%S, %u, %u), %p, %p, 0x%08lX)\n",
+ hdc, lpLogfont, lpLogfont->lfFaceName, lpLogfont->lfCharSet,
+ lpLogfont->lfPitchAndFamily, lpEnumFontFamExProc, lParam, dwFlags);
+ }
+ else
+ {
+ DPRINT("EnumFontFamiliesExW(%p, NULL, %p, %p, 0x%08lX)\n",
+ hdc, lpEnumFontFamExProc, lParam, dwFlags);
+ }
+ return IntEnumFontFamilies(hdc, lpLogfont, lpEnumFontFamExProc, lParam,
+ IEFF_UNICODE | IEFF_EXTENDED);
}
{
LOGFONTW LogFont;
+ DPRINT("EnumFontFamiliesW(%p, %S, %p, %p)\n",
+ hdc, lpszFamily, lpEnumFontFamProc, lParam);
+
ZeroMemory(&LogFont, sizeof(LOGFONTW));
LogFont.lfCharSet = DEFAULT_CHARSET;
if (NULL != lpszFamily)
lstrcpynW(LogFont.lfFaceName, lpszFamily, LF_FACESIZE);
}
- return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, TRUE);
+ return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, IEFF_UNICODE);
}
{
LOGFONTW LogFontW, *pLogFontW;
+ if (lpLogfont)
+ {
+ DPRINT("EnumFontFamiliesExA(%p, %p(%s, %u, %u), %p, %p, 0x%08lX)\n",
+ hdc, lpLogfont, lpLogfont->lfFaceName, lpLogfont->lfCharSet,
+ lpLogfont->lfPitchAndFamily, lpEnumFontFamExProc, lParam, dwFlags);
+ }
+ else
+ {
+ DPRINT("EnumFontFamiliesExA(%p, NULL, %p, %p, 0x%08lX)\n",
+ hdc, lpEnumFontFamExProc, lParam, dwFlags);
+ }
+
if (lpLogfont)
{
LogFontA2W(&LogFontW,lpLogfont);
else pLogFontW = NULL;
/* no need to convert LogFontW back to lpLogFont b/c it's an [in] parameter only */
- return IntEnumFontFamilies(hdc, pLogFontW, lpEnumFontFamExProc, lParam, FALSE);
+ return IntEnumFontFamilies(hdc, pLogFontW, lpEnumFontFamExProc, lParam, IEFF_EXTENDED);
}
{
LOGFONTW LogFont;
+ DPRINT("EnumFontFamiliesA(%p, %s, %p, %p)\n",
+ hdc, lpszFamily, lpEnumFontFamProc, lParam);
+
ZeroMemory(&LogFont, sizeof(LOGFONTW));
LogFont.lfCharSet = DEFAULT_CHARSET;
if (NULL != lpszFamily)
MultiByteToWideChar(CP_THREAD_ACP, 0, lpszFamily, -1, LogFont.lfFaceName, LF_FACESIZE);
}
- return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, FALSE);
+ return IntEnumFontFamilies(hdc, &LogFont, lpEnumFontFamProc, lParam, 0);
}
DWORD ret;
UINT font_cp;
- if ( !lpString || uCount <= 0 || (nMaxExtent < 0 && nMaxExtent != -1 ) )
+ if ( !lpString || uCount <= 0 || !lpResults || (nMaxExtent < 0 && nMaxExtent != -1 ) )
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
UINT i, nSet;
DPRINT("GetCharacterPlacementW\n");
- if(dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
- if(lpResults->lpClass) DPRINT("classes not implemented\n");
- if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
- DPRINT("Caret positions for complex scripts not implemented\n");
+ if (dwFlags&(~GCP_REORDER)) DPRINT("flags 0x%08lx ignored\n", dwFlags);
+ if (lpResults->lpClass) DPRINT("classes not implemented\n");
nSet = (UINT)uCount;
- if(nSet > lpResults->nGlyphs)
+ if (nSet > lpResults->nGlyphs)
nSet = lpResults->nGlyphs;
/* return number of initialized fields */
lpResults->nGlyphs = nSet;
- /*if((dwFlags&GCP_REORDER)==0 || !BidiAvail)
- {*/
+ if (dwFlags & GCP_REORDER)
+ {
+ if (LoadLPK(LPK_GCP))
+ return LpkGetCharacterPlacement(hdc, lpString, uCount, nMaxExtent, lpResults, dwFlags, 0);
+ }
+
/* Treat the case where no special handling was requested in a fastpath way */
- /* copy will do if the GCP_REORDER flag is not set */
- if(lpResults->lpOutString)
+ /* copy will do if the GCP_REORDER flag is not set */
+ if (lpResults->lpOutString)
lstrcpynW( lpResults->lpOutString, lpString, nSet );
- if(lpResults->lpGlyphs)
- lstrcpynW( lpResults->lpGlyphs, lpString, nSet );
-
- if(lpResults->lpOrder)
+ if (lpResults->lpOrder)
{
- for(i = 0; i < nSet; i++)
+ for (i = 0; i < nSet; i++)
lpResults->lpOrder[i] = i;
}
- /*} else
- {
- BIDI_Reorder( lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
- nSet, lpResults->lpOrder );
- }*/
/* FIXME: Will use the placement chars */
if (lpResults->lpDx)
lpResults->lpCaretPos[i] = (pos += size.cx);
}
- /*if(lpResults->lpGlyphs)
- NtGdiGetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);*/
+ if (lpResults->lpGlyphs)
+ NtGdiGetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
ret = MAKELONG(size.cx, size.cy);
ret = NtGdiGetCharABCWidthsW( hdc,
wstr[0],
- (ULONG)count,
+ wlen - 1,
(PWCHAR)wstr,
GCABCW_NOFLOAT,
(PVOID)lpabc);
mbchs[0] = (uChar & 0xff);
}
p = FONT_mbtowc(hdc, mbchs, len, NULL, NULL);
+ if(!p)
+ return GDI_ERROR;
c = p[0];
}
else
return NtGdiGetGlyphOutline ( hdc, uChar, uFormat, lpgm, cbBuffer, lpvBuffer, (CONST LPMAT2)lpmat2, TRUE);
}
+/*
+ * @unimplemented
+ */
+DWORD
+WINAPI
+GetGlyphOutlineWow(
+ DWORD a0,
+ DWORD a1,
+ DWORD a2,
+ DWORD a3,
+ DWORD a4,
+ DWORD a5,
+ DWORD a6
+)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
/*
* @implemented
needed = sizeof(OUTLINETEXTMETRICA);
if(lpOTMW->otmpFamilyName)
needed += WideCharToMultiByte(CP_ACP, 0,
- (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFamilyName), -1,
+ (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFamilyName), -1,
NULL, 0, NULL, NULL);
if(lpOTMW->otmpFaceName)
needed += WideCharToMultiByte(CP_ACP, 0,
- (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFaceName), -1,
+ (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFaceName), -1,
NULL, 0, NULL, NULL);
if(lpOTMW->otmpStyleName)
needed += WideCharToMultiByte(CP_ACP, 0,
- (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpStyleName), -1,
+ (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpStyleName), -1,
NULL, 0, NULL, NULL);
if(lpOTMW->otmpFullName)
needed += WideCharToMultiByte(CP_ACP, 0,
- (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFullName), -1,
+ (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFullName), -1,
NULL, 0, NULL, NULL);
if(!lpOTM)
{
output->otmpFamilyName = (LPSTR)(ptr - (char*)output);
len = WideCharToMultiByte(CP_ACP, 0,
- (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFamilyName), -1,
+ (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFamilyName), -1,
ptr, left, NULL, NULL);
left -= len;
ptr += len;
{
output->otmpFaceName = (LPSTR)(ptr - (char*)output);
len = WideCharToMultiByte(CP_ACP, 0,
- (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFaceName), -1,
+ (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFaceName), -1,
ptr, left, NULL, NULL);
left -= len;
ptr += len;
{
output->otmpStyleName = (LPSTR)(ptr - (char*)output);
len = WideCharToMultiByte(CP_ACP, 0,
- (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpStyleName), -1,
+ (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpStyleName), -1,
ptr, left, NULL, NULL);
left -= len;
ptr += len;
{
output->otmpFullName = (LPSTR)(ptr - (char*)output);
len = WideCharToMultiByte(CP_ACP, 0,
- (WCHAR*)((char*)lpOTMW + (int)lpOTMW->otmpFullName), -1,
+ (WCHAR*)((char*)lpOTMW + (intptr_t)lpOTMW->otmpFullName), -1,
ptr, left, NULL, NULL);
left -= len;
}
else
output->otmpFullName = 0;
- assert(left == 0);
+ ASSERT(left == 0);
if(output != lpOTM)
{
return ret;
}
+/* Performs a device to world transformation on the specified size (which
+ * is in integer format).
+ */
+static inline INT INTERNAL_YDSTOWS(XFORM *xForm, INT height)
+{
+ double floatHeight;
+
+ /* Perform operation with floating point */
+ floatHeight = (double)height * xForm->eM22;
+ /* Round to integers */
+ return GDI_ROUND(floatHeight);
+}
+
+/* scale width and height but don't mirror them */
+static inline INT width_to_LP( XFORM *xForm, INT width )
+{
+ return GDI_ROUND( (double)width * fabs( xForm->eM11));
+}
+
+static inline INT height_to_LP( XFORM *xForm, INT height )
+{
+ return GDI_ROUND( (double)height * fabs( xForm->eM22 ));
+}
/*
* @implemented
)
{
TMDIFF Tmd; // Should not be zero.
+ UINT Size, AvailableSize = 0, StringSize;
+ XFORM DevToWorld;
+ OUTLINETEXTMETRICW* LocalOTM;
+ WCHAR* Str;
+ BYTE* Ptr;
+
+ /* Get the structure */
+ Size = NtGdiGetOutlineTextMetricsInternalW(hdc, 0, NULL, &Tmd);
+ if (!Size)
+ return 0;
+ if (!lpOTM || (cbData < sizeof(*lpOTM)))
+ return Size;
+
+ LocalOTM = HeapAlloc(GetProcessHeap(), 0, Size);
+ LocalOTM->otmSize = Size;
+ Size = NtGdiGetOutlineTextMetricsInternalW(hdc, Size, LocalOTM, &Tmd);
+ if (!Size)
+ {
+ HeapFree(GetProcessHeap(), 0, LocalOTM);
+ return 0;
+ }
+
+ if (!NtGdiGetTransform(hdc, GdiDeviceSpaceToWorldSpace, &DevToWorld))
+ {
+ DPRINT1("NtGdiGetTransform failed!\n");
+ HeapFree(GetProcessHeap(), 0, LocalOTM);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return 0;
+ }
- return NtGdiGetOutlineTextMetricsInternalW(hdc, cbData, lpOTM, &Tmd);
+ /* Fill in DC specific data */
+ LocalOTM->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
+ LocalOTM->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
+ LocalOTM->otmTextMetrics.tmHeight = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmHeight );
+ LocalOTM->otmTextMetrics.tmAscent = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmAscent );
+ LocalOTM->otmTextMetrics.tmDescent = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmDescent );
+ LocalOTM->otmTextMetrics.tmInternalLeading = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmInternalLeading );
+ LocalOTM->otmTextMetrics.tmExternalLeading = height_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmExternalLeading );
+ LocalOTM->otmTextMetrics.tmAveCharWidth = width_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmAveCharWidth );
+ LocalOTM->otmTextMetrics.tmMaxCharWidth = width_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmMaxCharWidth );
+ LocalOTM->otmTextMetrics.tmOverhang = width_to_LP( &DevToWorld, LocalOTM->otmTextMetrics.tmOverhang );
+ LocalOTM->otmAscent = height_to_LP( &DevToWorld, LocalOTM->otmAscent);
+ LocalOTM->otmDescent = height_to_LP( &DevToWorld, LocalOTM->otmDescent);
+ LocalOTM->otmLineGap = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmLineGap));
+ LocalOTM->otmsCapEmHeight = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmsCapEmHeight));
+ LocalOTM->otmsXHeight = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmsXHeight));
+ LocalOTM->otmrcFontBox.top = height_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.top);
+ LocalOTM->otmrcFontBox.bottom = height_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.bottom);
+ LocalOTM->otmrcFontBox.left = width_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.left);
+ LocalOTM->otmrcFontBox.right = width_to_LP( &DevToWorld, LocalOTM->otmrcFontBox.right);
+ LocalOTM->otmMacAscent = height_to_LP( &DevToWorld, LocalOTM->otmMacAscent);
+ LocalOTM->otmMacDescent = height_to_LP( &DevToWorld, LocalOTM->otmMacDescent);
+ LocalOTM->otmMacLineGap = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmMacLineGap));
+ LocalOTM->otmptSubscriptSize.x = width_to_LP( &DevToWorld, LocalOTM->otmptSubscriptSize.x);
+ LocalOTM->otmptSubscriptSize.y = height_to_LP( &DevToWorld, LocalOTM->otmptSubscriptSize.y);
+ LocalOTM->otmptSubscriptOffset.x = width_to_LP( &DevToWorld, LocalOTM->otmptSubscriptOffset.x);
+ LocalOTM->otmptSubscriptOffset.y = height_to_LP( &DevToWorld, LocalOTM->otmptSubscriptOffset.y);
+ LocalOTM->otmptSuperscriptSize.x = width_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptSize.x);
+ LocalOTM->otmptSuperscriptSize.y = height_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptSize.y);
+ LocalOTM->otmptSuperscriptOffset.x = width_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptOffset.x);
+ LocalOTM->otmptSuperscriptOffset.y = height_to_LP( &DevToWorld, LocalOTM->otmptSuperscriptOffset.y);
+ LocalOTM->otmsStrikeoutSize = abs(INTERNAL_YDSTOWS(&DevToWorld,LocalOTM->otmsStrikeoutSize));
+ LocalOTM->otmsStrikeoutPosition = height_to_LP( &DevToWorld, LocalOTM->otmsStrikeoutPosition);
+ LocalOTM->otmsUnderscoreSize = height_to_LP( &DevToWorld, LocalOTM->otmsUnderscoreSize);
+ LocalOTM->otmsUnderscorePosition = height_to_LP( &DevToWorld, LocalOTM->otmsUnderscorePosition);
+
+ /* Copy what we can */
+ CopyMemory(lpOTM, LocalOTM, min(Size, cbData));
+
+ lpOTM->otmpFamilyName = NULL;
+ lpOTM->otmpFaceName = NULL;
+ lpOTM->otmpStyleName = NULL;
+ lpOTM->otmpFullName = NULL;
+
+ Size = sizeof(*lpOTM);
+ AvailableSize = cbData - Size;
+ Ptr = (BYTE*)lpOTM + sizeof(*lpOTM);
+
+ /* Fix string values up */
+ if (LocalOTM->otmpFamilyName)
+ {
+ Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpFamilyName);
+ StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
+ if (AvailableSize >= StringSize)
+ {
+ CopyMemory(Ptr, Str, StringSize);
+ lpOTM->otmpFamilyName = (PSTR)(Ptr - (BYTE*)lpOTM);
+ Ptr += StringSize;
+ AvailableSize -= StringSize;
+ Size += StringSize;
+ }
+ }
+
+ if (LocalOTM->otmpFaceName)
+ {
+ Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpFaceName);
+ StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
+ if (AvailableSize >= StringSize)
+ {
+ CopyMemory(Ptr, Str, StringSize);
+ lpOTM->otmpFaceName = (PSTR)(Ptr - (BYTE*)lpOTM);
+ Ptr += StringSize;
+ AvailableSize -= StringSize;
+ Size += StringSize;
+ }
+ }
+
+ if (LocalOTM->otmpStyleName)
+ {
+ Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpStyleName);
+ StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
+ if (AvailableSize >= StringSize)
+ {
+ CopyMemory(Ptr, Str, StringSize);
+ lpOTM->otmpStyleName = (PSTR)(Ptr - (BYTE*)lpOTM);
+ Ptr += StringSize;
+ AvailableSize -= StringSize;
+ Size += StringSize;
+ }
+ }
+
+ if (LocalOTM->otmpFullName)
+ {
+ Str = (WCHAR*)((char*)LocalOTM + (ptrdiff_t)LocalOTM->otmpFullName);
+ StringSize = (wcslen(Str) + 1) * sizeof(WCHAR);
+ if (AvailableSize >= StringSize)
+ {
+ CopyMemory(Ptr, Str, StringSize);
+ lpOTM->otmpFullName = (PSTR)(Ptr - (BYTE*)lpOTM);
+ Ptr += StringSize;
+ AvailableSize -= StringSize;
+ Size += StringSize;
+ }
+ }
+
+ lpOTM->otmSize = Size;
+
+ HeapFree(GetProcessHeap(), 0, LocalOTM);
+
+ return Size;
}
/*
}
+#if DBG
+VOID DumpFamilyInfo(const FONTFAMILYINFO *Info, LONG Count)
+{
+ LONG i;
+ const LOGFONTW *plf;
+
+ DPRINT1("---\n");
+ DPRINT1("Count: %d\n", Count);
+ for (i = 0; i < Count; ++i)
+ {
+ plf = &Info[i].EnumLogFontEx.elfLogFont;
+ DPRINT1("%d: '%S',%u,'%S', %ld:%ld, %ld, %d, %d\n", i,
+ plf->lfFaceName, plf->lfCharSet, Info[i].EnumLogFontEx.elfFullName,
+ plf->lfHeight, plf->lfWidth, plf->lfWeight, plf->lfItalic, plf->lfPitchAndFamily);
+ }
+}
+
+VOID DoFontSystemUnittest(VOID)
+{
+#ifndef RTL_SOFT_ASSERT
+#define RTL_SOFT_ASSERT(exp) \
+ (void)((!(exp)) ? \
+ DbgPrint("%s(%d): Soft assertion failed\n Expression: %s\n", __FILE__, __LINE__, #exp), FALSE : TRUE)
+#define RTL_SOFT_ASSERT_defined
+#endif
+
+ LOGFONTW LogFont;
+ FONTFAMILYINFO Info[4];
+ UNICODE_STRING Str1, Str2;
+ LONG ret, InfoCount;
+
+ //DumpFontInfo(TRUE);
+
+ /* L"" DEFAULT_CHARSET */
+ RtlZeroMemory(&LogFont, sizeof(LogFont));
+ LogFont.lfCharSet = DEFAULT_CHARSET;
+ InfoCount = RTL_NUMBER_OF(Info);
+ ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount);
+ DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount);
+ DumpFamilyInfo(Info, ret);
+ RTL_SOFT_ASSERT(ret == RTL_NUMBER_OF(Info));
+ RTL_SOFT_ASSERT(InfoCount > 32);
+
+ /* L"Microsoft Sans Serif" ANSI_CHARSET */
+ RtlZeroMemory(&LogFont, sizeof(LogFont));
+ LogFont.lfCharSet = ANSI_CHARSET;
+ StringCbCopyW(LogFont.lfFaceName, sizeof(LogFont.lfFaceName), L"Microsoft Sans Serif");
+ InfoCount = RTL_NUMBER_OF(Info);
+ ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount);
+ DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount);
+ DumpFamilyInfo(Info, ret);
+ RTL_SOFT_ASSERT(ret != -1);
+ RTL_SOFT_ASSERT(InfoCount > 0);
+ RTL_SOFT_ASSERT(InfoCount < 16);
+
+ RtlInitUnicodeString(&Str1, Info[0].EnumLogFontEx.elfLogFont.lfFaceName);
+ RtlInitUnicodeString(&Str2, L"Microsoft Sans Serif");
+ ret = RtlCompareUnicodeString(&Str1, &Str2, TRUE);
+ RTL_SOFT_ASSERT(ret == 0);
+
+ RtlInitUnicodeString(&Str1, Info[0].EnumLogFontEx.elfFullName);
+ RtlInitUnicodeString(&Str2, L"Tahoma");
+ ret = RtlCompareUnicodeString(&Str1, &Str2, TRUE);
+ RTL_SOFT_ASSERT(ret == 0);
+
+ /* L"Non-Existent" DEFAULT_CHARSET */
+ RtlZeroMemory(&LogFont, sizeof(LogFont));
+ LogFont.lfCharSet = ANSI_CHARSET;
+ StringCbCopyW(LogFont.lfFaceName, sizeof(LogFont.lfFaceName), L"Non-Existent");
+ InfoCount = RTL_NUMBER_OF(Info);
+ ret = NtGdiGetFontFamilyInfo(NULL, &LogFont, Info, &InfoCount);
+ DPRINT1("ret: %ld, InfoCount: %ld\n", ret, InfoCount);
+ DumpFamilyInfo(Info, ret);
+ RTL_SOFT_ASSERT(ret == 0);
+ RTL_SOFT_ASSERT(InfoCount == 0);
+
+#ifdef RTL_SOFT_ASSERT_defined
+#undef RTL_SOFT_ASSERT_defined
+#undef RTL_SOFT_ASSERT
+#endif
+}
+#endif
+
+/* EOF */
/*
* @implemented
*/
CONST LOGFONTW *lplf
)
{
+#if 0
+ static BOOL bDidTest = FALSE;
+ if (!bDidTest)
+ {
+ bDidTest = TRUE;
+ DoFontSystemUnittest();
+ }
+#endif
if (lplf)
{
ENUMLOGFONTEXDVW Logfont;
/* FIXME the flags */
/* FIXME the pdv */
/* FIXME NtGdiRemoveFontResource handle flags and pdv */
+ DPRINT("RemoveFontResourceExW\n");
return 0;
}
LPARAM lParam,
DWORD dwFlags)
{
- ULONG_PTR idEnum, cbDataSize, cbRetSize;
+ ULONG_PTR idEnum;
+ ULONG cbDataSize, cbRetSize;
PENUMFONTDATAW pEfdw;
PBYTE pBuffer;
PBYTE pMax;
return ret;
}
+
+/*
+ * @implemented
+ */
+int
+WINAPI
+GdiAddFontResourceW(
+ LPCWSTR lpszFilename,
+ FLONG fl,
+ DESIGNVECTOR *pdv)
+{
+ INT Ret;
+ WCHAR lpszBuffer[MAX_PATH];
+ WCHAR lpszAbsPath[MAX_PATH];
+ UNICODE_STRING NtAbsPath;
+
+ /* FIXME: We don't support multiple files passed in lpszFilename
+ * as L"abcxxxxx.pfm|abcxxxxx.pfb"
+ */
+
+ /* Does the file exist in CurrentDirectory or in the Absolute Path passed? */
+ GetCurrentDirectoryW(MAX_PATH, lpszBuffer);
+
+ if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
+ {
+ /* Nope. Then let's check Fonts folder */
+ GetWindowsDirectoryW(lpszBuffer, MAX_PATH);
+ StringCbCatW(lpszBuffer, sizeof(lpszBuffer), L"\\Fonts");
+
+ if (!SearchPathW(lpszBuffer, lpszFilename, NULL, MAX_PATH, lpszAbsPath, NULL))
+ {
+ DPRINT1("Font not found. The Buffer is: %ls, the FileName is: %S\n", lpszBuffer, lpszFilename);
+ return 0;
+ }
+ }
+
+ /* We found the font file so: */
+ if (!RtlDosPathNameToNtPathName_U(lpszAbsPath, &NtAbsPath, NULL, NULL))
+ {
+ DPRINT1("Can't convert Path! Path: %ls\n", lpszAbsPath);
+ return 0;
+ }
+
+ /* The Nt call expects a null-terminator included in cwc param. */
+ ASSERT(NtAbsPath.Buffer[NtAbsPath.Length / sizeof(WCHAR)] == UNICODE_NULL);
+ Ret = NtGdiAddFontResourceW(NtAbsPath.Buffer, NtAbsPath.Length / sizeof(WCHAR) + 1, 1, fl, 0, pdv);
+
+ RtlFreeUnicodeString(&NtAbsPath);
+
+ return Ret;
+}
+
+/*
+ * @implemented
+ */
+HANDLE
+WINAPI
+AddFontMemResourceEx(
+ PVOID pbFont,
+ DWORD cbFont,
+ PVOID pdv,
+ DWORD *pcFonts
+)
+{
+ if ( pbFont && cbFont && pcFonts)
+ {
+ return NtGdiAddFontMemResourceEx(pbFont, cbFont, NULL, 0, pcFonts);
+ }
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+WINAPI
+RemoveFontMemResourceEx(HANDLE fh)
+{
+ if (fh)
+ {
+ return NtGdiRemoveFontMemResourceEx(fh);
+ }
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+}
+
+
+/*
+ * @unimplemented
+ */
+int
+WINAPI
+AddFontResourceTracking(
+ LPCSTR lpString,
+ int unknown
+)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
+
+/*
+ * @unimplemented
+ */
+int
+WINAPI
+RemoveFontResourceTracking(LPCSTR lpString,int unknown)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
+
+BOOL
+WINAPI
+CreateScalableFontResourceW(
+ DWORD fdwHidden,
+ LPCWSTR lpszFontRes,
+ LPCWSTR lpszFontFile,
+ LPCWSTR lpszCurrentPath
+)
+{
+ HANDLE f;
+
+ UNIMPLEMENTED;
+
+ /* fHidden=1 - only visible for the calling app, read-only, not
+ * enumerated with EnumFonts/EnumFontFamilies
+ * lpszCurrentPath can be NULL
+ */
+
+ /* If the output file already exists, return the ERROR_FILE_EXISTS error as specified in MSDN */
+ if ((f = CreateFileW(lpszFontRes, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(f);
+ SetLastError(ERROR_FILE_EXISTS);
+ return FALSE;
+ }
+ return FALSE; /* create failed */
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+bInitSystemAndFontsDirectoriesW(LPWSTR *SystemDir,LPWSTR *FontsDir)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+EudcLoadLinkW(LPCWSTR pBaseFaceName,LPCWSTR pEudcFontPath,INT iPriority,INT iFontLinkType)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
+
+/*
+ * @unimplemented
+ */
+BOOL
+WINAPI
+EudcUnloadLinkW(LPCWSTR pBaseFaceName,LPCWSTR pEudcFontPath)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+WINAPI
+GetEUDCTimeStamp(VOID)
+{
+ return NtGdiGetEudcTimeStampEx(NULL,0,TRUE);
+}
+
+/*
+ * @implemented
+ */
+DWORD
+WINAPI
+GetEUDCTimeStampExW(LPWSTR lpBaseFaceName)
+{
+ DWORD retValue = 0;
+
+ if (!lpBaseFaceName)
+ {
+ retValue = NtGdiGetEudcTimeStampEx(NULL,0,FALSE);
+ }
+ else
+ {
+ retValue = NtGdiGetEudcTimeStampEx(lpBaseFaceName, wcslen(lpBaseFaceName), FALSE);
+ }
+
+ return retValue;
+}
+
+/*
+ * @implemented
+ */
+ULONG
+WINAPI
+GetFontAssocStatus(HDC hdc)
+{
+ ULONG retValue = 0;
+
+ if (hdc)
+ {
+ retValue = NtGdiQueryFontAssocInfo(hdc);
+ }
+
+ return retValue;
+}
+
+/*
+ * @unimplemented
+ */
+DWORD
+WINAPI
+QueryFontAssocStatus(VOID)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+WINAPI
+UnloadNetworkFonts(DWORD unknown)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+}
+
+/*
+ * @implemented
+ *
+ */
+DWORD
+WINAPI
+GetFontData(HDC hdc,
+ DWORD dwTable,
+ DWORD dwOffset,
+ LPVOID lpvBuffer,
+ DWORD cbData)
+{
+ if (!lpvBuffer)
+ {
+ cbData = 0;
+ }
+ return NtGdiGetFontData(hdc, dwTable, dwOffset, lpvBuffer, cbData);
+}
+
+DWORD
+WINAPI
+cGetTTFFromFOT(DWORD x1 ,DWORD x2 ,DWORD x3, DWORD x4, DWORD x5, DWORD x6, DWORD x7)
+{
+ UNIMPLEMENTED;
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return 0;
+}
+