mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
[NTGDI][FREETYPE] FontLink: Request sub-font sizes (#8806)
A bug fix of FontLink'ed glyph size. JIRA issue: CORE-20470 - Add FONTLINK_ENTRY structure and g_FontLinkEntries variable. - Delete font-link cache mechanism. - Don't access the registry while rendering is in progress. - Request sub-font sizes while drawing FontLink text.
This commit is contained in:
+267
-230
@@ -39,24 +39,25 @@ typedef struct _FONTLINK
|
||||
PSHARED_FACE SharedFace;
|
||||
} FONTLINK, *PFONTLINK;
|
||||
|
||||
typedef struct _FONTLINK_ENTRY
|
||||
{
|
||||
LIST_ENTRY ListEntry;
|
||||
WCHAR lfFaceName[LF_FACESIZE];
|
||||
PZZWSTR pszzFontLink;
|
||||
} FONTLINK_ENTRY, *PFONTLINK_ENTRY;
|
||||
|
||||
typedef struct _FONTLINK_CHAIN
|
||||
{
|
||||
LIST_ENTRY FontLinkList; //< List of FONTLINK's
|
||||
LOGFONTW LogFont;
|
||||
PZZWSTR pszzFontLink;
|
||||
PCZZWSTR pszzFontLink;
|
||||
PTEXTOBJ pBaseTextObj;
|
||||
FT_Face pDefFace;
|
||||
} FONTLINK_CHAIN, *PFONTLINK_CHAIN;
|
||||
|
||||
typedef struct _FONTLINK_CACHE
|
||||
{
|
||||
LIST_ENTRY ListEntry;
|
||||
LOGFONTW LogFont;
|
||||
FONTLINK_CHAIN Chain;
|
||||
} FONTLINK_CACHE, *PFONTLINK_CACHE;
|
||||
|
||||
#define FONTLINK_DEFAULT_CHAR 0x30FB // U+30FB (KATAKANA MIDDLE DOT)
|
||||
|
||||
static RTL_STATIC_LIST_HEAD(g_FontLinkEntries); // The list of FONTLINK_ENTRY
|
||||
static DWORD s_chFontLinkDefaultChar = FONTLINK_DEFAULT_CHAR;
|
||||
static WCHAR s_szDefFontLinkFileName[MAX_PATH] = L"";
|
||||
static WCHAR s_szDefFontLinkFontName[MAX_PATH] = L"";
|
||||
@@ -64,10 +65,6 @@ static BOOL s_fFontLinkUseAnsi = FALSE;
|
||||
static BOOL s_fFontLinkUseOem = FALSE;
|
||||
static BOOL s_fFontLinkUseSymbol = FALSE;
|
||||
|
||||
#define MAX_FONTLINK_CACHE 128
|
||||
static RTL_STATIC_LIST_HEAD(g_FontLinkCache); // The list of FONTLINK_CACHE
|
||||
static LONG g_nFontLinkCacheCount = 0;
|
||||
|
||||
static inline NTSTATUS
|
||||
FontLink_LoadSettings(VOID)
|
||||
{
|
||||
@@ -190,103 +187,6 @@ FontLink_Chain_IsPopulated(const FONTLINK_CHAIN *pChain)
|
||||
return pChain->LogFont.lfFaceName[0];
|
||||
}
|
||||
|
||||
static VOID
|
||||
FontLink_Chain_Free(
|
||||
_Inout_ PFONTLINK_CHAIN pChain)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
PFONTLINK pLink;
|
||||
|
||||
if (!FontLink_Chain_IsPopulated(pChain)) // The chain is not populated yet
|
||||
return;
|
||||
|
||||
if (pChain->pszzFontLink)
|
||||
ExFreePoolWithTag(pChain->pszzFontLink, TAG_FONT);
|
||||
|
||||
while (!IsListEmpty(&pChain->FontLinkList))
|
||||
{
|
||||
Entry = RemoveHeadList(&pChain->FontLinkList);
|
||||
pLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
|
||||
FontLink_Destroy(pLink);
|
||||
}
|
||||
}
|
||||
|
||||
static inline VOID
|
||||
FontLink_AddCache(
|
||||
_In_ PFONTLINK_CACHE pCache)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
|
||||
/* Add the new cache entry to the top of the cache list */
|
||||
++g_nFontLinkCacheCount;
|
||||
InsertHeadList(&g_FontLinkCache, &pCache->ListEntry);
|
||||
|
||||
/* If there are too many cache entries in the list, remove the oldest one at the bottom */
|
||||
if (g_nFontLinkCacheCount > MAX_FONTLINK_CACHE)
|
||||
{
|
||||
ASSERT(!IsListEmpty(&g_FontLinkCache));
|
||||
Entry = RemoveTailList(&g_FontLinkCache);
|
||||
--g_nFontLinkCacheCount;
|
||||
pCache = CONTAINING_RECORD(Entry, FONTLINK_CACHE, ListEntry);
|
||||
FontLink_Chain_Free(&pCache->Chain);
|
||||
ExFreePoolWithTag(pCache, TAG_FONT);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the chain to the cache (g_FontLinkCache) if the chain had been populated.
|
||||
/// @param pChain The chain.
|
||||
static inline VOID
|
||||
FontLink_Chain_Finish(
|
||||
_Inout_ PFONTLINK_CHAIN pChain)
|
||||
{
|
||||
PFONTLINK_CACHE pCache;
|
||||
|
||||
if (!FontLink_Chain_IsPopulated(pChain))
|
||||
return; // The chain is not populated yet
|
||||
|
||||
pCache = ExAllocatePoolWithTag(PagedPool, sizeof(FONTLINK_CACHE), TAG_FONT);
|
||||
if (!pCache)
|
||||
return; // Out of memory
|
||||
|
||||
pCache->LogFont = pChain->LogFont;
|
||||
pCache->Chain = *pChain;
|
||||
IntRebaseList(&pCache->Chain.FontLinkList, &pChain->FontLinkList);
|
||||
|
||||
FontLink_AddCache(pCache);
|
||||
}
|
||||
|
||||
static inline PFONTLINK_CACHE
|
||||
FontLink_FindCache(
|
||||
_In_ const LOGFONTW* pLogFont)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
PFONTLINK_CACHE pLinkCache;
|
||||
for (Entry = g_FontLinkCache.Flink; Entry != &g_FontLinkCache; Entry = Entry->Flink)
|
||||
{
|
||||
pLinkCache = CONTAINING_RECORD(Entry, FONTLINK_CACHE, ListEntry);
|
||||
if (RtlEqualMemory(&pLinkCache->LogFont, pLogFont, sizeof(LOGFONTW)))
|
||||
return pLinkCache;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline VOID
|
||||
FontLink_CleanupCache(VOID)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
PFONTLINK_CACHE pLinkCache;
|
||||
|
||||
while (!IsListEmpty(&g_FontLinkCache))
|
||||
{
|
||||
Entry = RemoveHeadList(&g_FontLinkCache);
|
||||
pLinkCache = CONTAINING_RECORD(Entry, FONTLINK_CACHE, ListEntry);
|
||||
FontLink_Chain_Free(&pLinkCache->Chain);
|
||||
ExFreePoolWithTag(pLinkCache, TAG_FONT);
|
||||
}
|
||||
|
||||
g_nFontLinkCacheCount = 0;
|
||||
}
|
||||
|
||||
/* TPMF_FIXED_PITCH is confusing; brain-dead api */
|
||||
#ifndef _TMPF_VARIABLE_PITCH
|
||||
#define _TMPF_VARIABLE_PITCH TMPF_FIXED_PITCH
|
||||
@@ -972,6 +872,78 @@ IntLoadFontSubstList(PLIST_ENTRY pHead)
|
||||
return NT_SUCCESS(Status);
|
||||
}
|
||||
|
||||
static NTSTATUS FontLink_AddEntry(LPCWSTR lfFaceName, PZZWSTR pszzFontLink)
|
||||
{
|
||||
SIZE_T FontLinkSize = SZZ_GetSize(pszzFontLink);
|
||||
PZZWSTR pszz = ExAllocatePoolWithTag(PagedPool, FontLinkSize, TAG_FONT);
|
||||
if (!pszz)
|
||||
return STATUS_NO_MEMORY;
|
||||
RtlCopyMemory(pszz, pszzFontLink, FontLinkSize);
|
||||
|
||||
PFONTLINK_ENTRY pEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONTLINK_ENTRY), TAG_FONT);
|
||||
if (!pEntry)
|
||||
{
|
||||
ExFreePoolWithTag(pszz, TAG_FONT);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
pEntry->pszzFontLink = pszz;
|
||||
RtlStringCchCopyW(pEntry->lfFaceName, _countof(pEntry->lfFaceName), lfFaceName);
|
||||
InsertHeadList(&g_FontLinkEntries, &pEntry->ListEntry);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void FontLink_DeleteEntries(VOID)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
PFONTLINK_ENTRY pEntry;
|
||||
|
||||
for (Entry = g_FontLinkEntries.Flink; Entry != &g_FontLinkEntries; Entry = Entry->Flink)
|
||||
{
|
||||
pEntry = CONTAINING_RECORD(Entry, FONTLINK_ENTRY, ListEntry);
|
||||
ExFreePoolWithTag(pEntry->pszzFontLink, TAG_FONT);
|
||||
ExFreePoolWithTag(pEntry, TAG_FONT);
|
||||
}
|
||||
}
|
||||
|
||||
static NTSTATUS FontLink_PopulateEntries(VOID)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HKEY hKey;
|
||||
DWORD cchName, cbData, dwType;
|
||||
WCHAR szName[LF_FACESIZE], szzFontLink[300];
|
||||
|
||||
// Open the registry key
|
||||
Status = RegOpenKey(
|
||||
L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink",
|
||||
&hKey);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
for (DWORD dwIndex = 0;; ++dwIndex)
|
||||
{
|
||||
cchName = _countof(szName);
|
||||
cbData = sizeof(szzFontLink);
|
||||
Status = RegEnumValueW(hKey, dwIndex, szName, &cchName, &dwType, szzFontLink, &cbData);
|
||||
if (!NT_SUCCESS(Status))
|
||||
break;
|
||||
if (dwType != REG_MULTI_SZ)
|
||||
continue;
|
||||
|
||||
// Ensure double-NUL-terminated
|
||||
szzFontLink[_countof(szzFontLink) - 1] = UNICODE_NULL;
|
||||
szzFontLink[_countof(szzFontLink) - 2] = UNICODE_NULL;
|
||||
|
||||
DPRINT1("szName: %S\n", szName);
|
||||
DPRINT1("szzFontLink: %S\n", szzFontLink);
|
||||
|
||||
FontLink_AddEntry(szName, szzFontLink);
|
||||
}
|
||||
|
||||
ZwClose(hKey); // Close the registry key
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOL FASTCALL
|
||||
InitFontSupport(VOID)
|
||||
{
|
||||
@@ -1010,6 +982,7 @@ InitFontSupport(VOID)
|
||||
FontLink_LoadSettings();
|
||||
FontLink_LoadDefaultFonts();
|
||||
FontLink_LoadDefaultCharset();
|
||||
FontLink_PopulateEntries();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1022,9 +995,6 @@ FreeFontSupport(VOID)
|
||||
PFONTSUBST_ENTRY pSubstEntry;
|
||||
PFONT_ENTRY pFontEntry;
|
||||
|
||||
// Cleanup the FontLink cache
|
||||
FontLink_CleanupCache();
|
||||
|
||||
// Free font cache list
|
||||
pHead = &g_FontCacheListHead;
|
||||
while (!IsListEmpty(pHead))
|
||||
@@ -1052,6 +1022,8 @@ FreeFontSupport(VOID)
|
||||
CleanupFontEntry(pFontEntry);
|
||||
}
|
||||
|
||||
FontLink_DeleteEntries();
|
||||
|
||||
if (g_FreeTypeLibrary)
|
||||
{
|
||||
FT_Done_Library(g_FreeTypeLibrary);
|
||||
@@ -1229,97 +1201,6 @@ static const WCHAR s_szzDefFixedFontLink[] =
|
||||
L"gulim.ttc,GulimChe\0"
|
||||
L"\0";
|
||||
|
||||
static NTSTATUS
|
||||
FontLink_Chain_LoadReg(
|
||||
_Inout_ PFONTLINK_CHAIN pChain,
|
||||
_Inout_ PLOGFONTW pLF)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
HKEY hKey;
|
||||
DWORD cbData;
|
||||
WCHAR szzFontLink[512];
|
||||
SIZE_T FontLinkSize;
|
||||
PZZWSTR pszzFontLink = NULL;
|
||||
|
||||
ASSERT(pLF->lfFaceName[0]);
|
||||
|
||||
// Open the registry key
|
||||
Status = RegOpenKey(
|
||||
L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink",
|
||||
&hKey);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
// Load the FontLink entry
|
||||
cbData = sizeof(szzFontLink);
|
||||
Status = RegQueryValue(hKey, pLF->lfFaceName, REG_MULTI_SZ, szzFontLink, &cbData);
|
||||
if (!NT_SUCCESS(Status) &&
|
||||
(Status != STATUS_BUFFER_OVERFLOW) && (Status != STATUS_BUFFER_TOO_SMALL))
|
||||
{
|
||||
// Retry with substituted
|
||||
SubstituteFontRecurse(pLF);
|
||||
cbData = sizeof(szzFontLink);
|
||||
Status = RegQueryValue(hKey, pLF->lfFaceName, REG_MULTI_SZ, szzFontLink, &cbData);
|
||||
}
|
||||
|
||||
if ((Status == STATUS_BUFFER_OVERFLOW) || (Status == STATUS_BUFFER_TOO_SMALL))
|
||||
{
|
||||
// Buffer is too small. Retry with larger buffer
|
||||
if (cbData >= 2 * sizeof(WCHAR)) // Sanity check
|
||||
{
|
||||
FontLinkSize = cbData;
|
||||
pszzFontLink = ExAllocatePoolWithTag(PagedPool, FontLinkSize, TAG_FONT);
|
||||
if (!pszzFontLink)
|
||||
{
|
||||
ZwClose(hKey); // Close the registry key
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
Status = RegQueryValue(hKey, pLF->lfFaceName, REG_MULTI_SZ, pszzFontLink, &cbData);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePoolWithTag(pszzFontLink, TAG_FONT);
|
||||
pszzFontLink = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZwClose(hKey); // Close the registry key
|
||||
|
||||
if (!NT_SUCCESS(Status)) // Failed to get registry value
|
||||
{
|
||||
// Use default value
|
||||
ASSERT(sizeof(szzFontLink) >= sizeof(s_szzDefFontLink));
|
||||
ASSERT(sizeof(szzFontLink) >= sizeof(s_szzDefFixedFontLink));
|
||||
if (!(pLF->lfPitchAndFamily & FIXED_PITCH))
|
||||
RtlCopyMemory(szzFontLink, s_szzDefFontLink, sizeof(s_szzDefFontLink));
|
||||
else
|
||||
RtlCopyMemory(szzFontLink, s_szzDefFixedFontLink, sizeof(s_szzDefFixedFontLink));
|
||||
}
|
||||
|
||||
if (pszzFontLink)
|
||||
{
|
||||
// Ensure double-NUL-terminated
|
||||
ASSERT(FontLinkSize / sizeof(WCHAR) >= 2);
|
||||
pszzFontLink[FontLinkSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
|
||||
pszzFontLink[FontLinkSize / sizeof(WCHAR) - 2] = UNICODE_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure double-NUL-terminated
|
||||
szzFontLink[_countof(szzFontLink) - 1] = UNICODE_NULL;
|
||||
szzFontLink[_countof(szzFontLink) - 2] = UNICODE_NULL;
|
||||
|
||||
FontLinkSize = SZZ_GetSize(szzFontLink);
|
||||
pszzFontLink = ExAllocatePoolWithTag(PagedPool, FontLinkSize, TAG_FONT);
|
||||
if (!pszzFontLink)
|
||||
return STATUS_NO_MEMORY;
|
||||
RtlCopyMemory(pszzFontLink, szzFontLink, FontLinkSize);
|
||||
}
|
||||
pChain->pszzFontLink = pszzFontLink;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static inline PFONTLINK
|
||||
FontLink_Chain_FindLink(
|
||||
PFONTLINK_CHAIN pChain,
|
||||
@@ -1379,6 +1260,44 @@ FontLink_Create(
|
||||
return pLink;
|
||||
}
|
||||
|
||||
static PFONTLINK_ENTRY
|
||||
FontLink_FindEntry(const LOGFONTW *pLogFont)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
PFONTLINK_ENTRY pEntry;
|
||||
LOGFONTW lf = *pLogFont;
|
||||
|
||||
SubstituteFontRecurse(&lf);
|
||||
|
||||
for (Entry = g_FontLinkEntries.Flink; Entry != &g_FontLinkEntries; Entry = Entry->Flink)
|
||||
{
|
||||
pEntry = CONTAINING_RECORD(Entry, FONTLINK_ENTRY, ListEntry);
|
||||
if (!_wcsicmp(pEntry->lfFaceName, lf.lfFaceName))
|
||||
return pEntry;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
FontLink_Chain_FindEntry(
|
||||
_Inout_ PFONTLINK_CHAIN pChain,
|
||||
_Inout_ PLOGFONTW pLF)
|
||||
{
|
||||
PFONTLINK_ENTRY pEntry = FontLink_FindEntry(pLF);
|
||||
if (!pEntry)
|
||||
{
|
||||
if (!(pLF->lfPitchAndFamily & FIXED_PITCH))
|
||||
pChain->pszzFontLink = s_szzDefFontLink;
|
||||
else
|
||||
pChain->pszzFontLink = s_szzDefFixedFontLink;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
pChain->pszzFontLink = pEntry->pszzFontLink;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
FontLink_Chain_Populate(
|
||||
_Inout_ PFONTLINK_CHAIN pChain)
|
||||
@@ -1388,8 +1307,7 @@ FontLink_Chain_Populate(
|
||||
LOGFONTW lfBase;
|
||||
PTEXTOBJ pTextObj = pChain->pBaseTextObj;
|
||||
PFONTGDI pFontGDI;
|
||||
PWSTR pszLink;
|
||||
PFONTLINK_CACHE pLinkCache;
|
||||
PCWSTR pszLink;
|
||||
WCHAR szEntry[MAX_PATH];
|
||||
BOOL bFixCharSet;
|
||||
|
||||
@@ -1418,21 +1336,10 @@ FontLink_Chain_Populate(
|
||||
if (bFixCharSet)
|
||||
lfBase.lfCharSet = DEFAULT_CHARSET;
|
||||
|
||||
// Use cache if any
|
||||
pLinkCache = FontLink_FindCache(&lfBase);
|
||||
if (pLinkCache)
|
||||
{
|
||||
RemoveEntryList(&pLinkCache->ListEntry);
|
||||
*pChain = pLinkCache->Chain;
|
||||
IntRebaseList(&pChain->FontLinkList, &pLinkCache->Chain.FontLinkList);
|
||||
ExFreePoolWithTag(pLinkCache, TAG_FONT);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
pChain->LogFont = lfBase;
|
||||
|
||||
// Load FontLink entry from registry
|
||||
Status = FontLink_Chain_LoadReg(pChain, &pChain->LogFont);
|
||||
// Load FontLink entry
|
||||
Status = FontLink_Chain_FindEntry(pChain, &pChain->LogFont);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
@@ -4076,13 +3983,6 @@ IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
|
||||
if (lfHeight == -1)
|
||||
lfHeight = -2;
|
||||
|
||||
if (FontGDI->Magic == FONTGDI_MAGIC &&
|
||||
FontGDI->lfHeight == lfHeight &&
|
||||
FontGDI->lfWidth == lfWidth)
|
||||
{
|
||||
return 0; /* Cached */
|
||||
}
|
||||
|
||||
ASSERT_FREETYPE_LOCK_HELD();
|
||||
pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
|
||||
pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
|
||||
@@ -4187,6 +4087,127 @@ IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG lfHeight)
|
||||
return FT_Request_Size(face, &req);
|
||||
}
|
||||
|
||||
static FT_Error
|
||||
IntRequestFontSizeEx(FT_Face face, const LOGFONTW *plf)
|
||||
{
|
||||
FT_Error error;
|
||||
FT_Size_RequestRec req;
|
||||
TT_OS2 *pOS2;
|
||||
TT_HoriHeader *pHori;
|
||||
LONG lfHeight = plf->lfHeight, lfWidth = plf->lfWidth;
|
||||
FT_WinFNT_HeaderRec WinFNT;
|
||||
LONG Ascent, Descent, Sum, EmHeight;
|
||||
LONG tmAscent, tmDescent, tmHeight, tmInternalLeading;
|
||||
|
||||
lfWidth = abs(lfWidth);
|
||||
if (lfHeight == 0)
|
||||
{
|
||||
if (lfWidth == 0)
|
||||
{
|
||||
DPRINT("lfHeight and lfWidth are zero.\n");
|
||||
lfHeight = -16;
|
||||
}
|
||||
else
|
||||
{
|
||||
lfHeight = lfWidth;
|
||||
}
|
||||
}
|
||||
|
||||
if (lfHeight == -1)
|
||||
lfHeight = -2;
|
||||
|
||||
ASSERT_FREETYPE_LOCK_HELD();
|
||||
pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
|
||||
pHori = (TT_HoriHeader *)FT_Get_Sfnt_Table(face, FT_SFNT_HHEA);
|
||||
|
||||
if (!pOS2 || !pHori)
|
||||
{
|
||||
error = FT_Get_WinFNT_Header(face, &WinFNT);
|
||||
if (error)
|
||||
{
|
||||
DPRINT1("%s: Failed to request font size.\n", face->family_name);
|
||||
return error;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: We cast TT_OS2.usWinAscent and TT_OS2.usWinDescent to signed FT_Short.
|
||||
* Why? See: https://learn.microsoft.com/en-us/typography/opentype/spec/os2#uswindescent
|
||||
*
|
||||
* > usWinDescent is "usually" a positive value ...
|
||||
*
|
||||
* We can read it as "not always". See CORE-14994.
|
||||
* See also: https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection
|
||||
*/
|
||||
#define FM_SEL_USE_TYPO_METRICS 0x80
|
||||
if (lfHeight > 0)
|
||||
{
|
||||
/* case (A): lfHeight is positive */
|
||||
Sum = (FT_Short)pOS2->usWinAscent + (FT_Short)pOS2->usWinDescent;
|
||||
if (Sum == 0 || (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS))
|
||||
{
|
||||
Ascent = pHori->Ascender;
|
||||
Descent = -pHori->Descender;
|
||||
Sum = Ascent + Descent;
|
||||
}
|
||||
else
|
||||
{
|
||||
Ascent = (FT_Short)pOS2->usWinAscent;
|
||||
Descent = (FT_Short)pOS2->usWinDescent;
|
||||
}
|
||||
|
||||
tmAscent = FT_MulDiv(lfHeight, Ascent, Sum);
|
||||
tmDescent = FT_MulDiv(lfHeight, Descent, Sum);
|
||||
tmHeight = tmAscent + tmDescent;
|
||||
tmInternalLeading = tmHeight - FT_MulDiv(lfHeight, face->units_per_EM, Sum);
|
||||
}
|
||||
else if (lfHeight < 0)
|
||||
{
|
||||
/* case (B): lfHeight is negative */
|
||||
if (pOS2->fsSelection & FM_SEL_USE_TYPO_METRICS)
|
||||
{
|
||||
tmAscent = FT_MulDiv(-lfHeight, pHori->Ascender, face->units_per_EM);
|
||||
tmDescent = FT_MulDiv(-lfHeight, -pHori->Descender, face->units_per_EM);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmAscent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinAscent, face->units_per_EM);
|
||||
tmDescent = FT_MulDiv(-lfHeight, (FT_Short)pOS2->usWinDescent, face->units_per_EM);
|
||||
}
|
||||
tmHeight = tmAscent + tmDescent;
|
||||
tmInternalLeading = tmHeight + lfHeight;
|
||||
}
|
||||
#undef FM_SEL_USE_TYPO_METRICS
|
||||
|
||||
EmHeight = tmHeight - tmInternalLeading;
|
||||
EmHeight = max(EmHeight, 1);
|
||||
EmHeight = min(EmHeight, USHORT_MAX);
|
||||
|
||||
#if 1
|
||||
/* I think this is wrong implementation but its test result is better. */
|
||||
if (lfWidth != 0)
|
||||
req.width = FT_MulDiv(lfWidth, face->units_per_EM, pOS2->xAvgCharWidth) << 6;
|
||||
#else
|
||||
/* I think this is correct implementation but it is mismatching to the
|
||||
other metric functions. The test result is bad. */
|
||||
if (lfWidth != 0)
|
||||
req.width = (FT_MulDiv(lfWidth, 96 * 5, 72 * 3) << 6); /* ??? FIXME */
|
||||
#endif
|
||||
else
|
||||
req.width = 0;
|
||||
|
||||
/* HACK: We do not handle small widths well, so just use zero for these. See CORE-19870. */
|
||||
if (lfWidth < 10)
|
||||
req.width = 0;
|
||||
|
||||
req.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
|
||||
req.height = (EmHeight << 6);
|
||||
req.horiResolution = 0;
|
||||
req.vertResolution = 0;
|
||||
return FT_Request_Size(face, &req);
|
||||
}
|
||||
|
||||
BOOL FASTCALL
|
||||
TextIntUpdateSize(PDC dc,
|
||||
PTEXTOBJ TextObj,
|
||||
@@ -4336,6 +4357,25 @@ FontLink_Chain_Dump(
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOL
|
||||
IntNeedRequestFontSize(PFONTLINK_CHAIN pChain, FT_Face face, PLIST_ENTRY TargetEntry)
|
||||
{
|
||||
PLIST_ENTRY Entry, Head = &pChain->FontLinkList;
|
||||
PFONTLINK pFontLink;
|
||||
|
||||
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
|
||||
{
|
||||
pFontLink = CONTAINING_RECORD(Entry, FONTLINK, ListEntry);
|
||||
if (!FontLink_PrepareFontInfo(pFontLink))
|
||||
continue; // This link is not useful, check the next one
|
||||
|
||||
if (pFontLink->SharedFace->Face == face || Entry == TargetEntry)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/// Search the target glyph and update the current font info.
|
||||
/// @return The glyph index
|
||||
static UINT
|
||||
@@ -4382,6 +4422,8 @@ FontLink_Chain_FindGlyph(
|
||||
// The target glyph is found in the chain
|
||||
DPRINT("code: 0x%08X, index: 0x%08X\n", code, index);
|
||||
pCache->Hashed.Face = *pFace = face;
|
||||
if (IntNeedRequestFontSize(pChain, face, Entry))
|
||||
IntRequestFontSizeEx(face, &pChain->LogFont);
|
||||
FT_Set_Transform(face, &pCache->Hashed.matTransform, NULL);
|
||||
return index;
|
||||
}
|
||||
@@ -5042,8 +5084,6 @@ TextIntGetTextExtentPoint(
|
||||
Size->cy = ascender + descender;
|
||||
}
|
||||
|
||||
FontLink_Chain_Finish(&Chain);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -6840,7 +6880,6 @@ IntExtTextOutW(
|
||||
if (!IntGetTextDisposition(&DeltaX64, &DeltaY64, String, Count, Dx, &Cache,
|
||||
fuOptions, bNoTransform, &Chain))
|
||||
{
|
||||
FontLink_Chain_Finish(&Chain);
|
||||
IntUnLockFreeType();
|
||||
bResult = FALSE;
|
||||
goto Cleanup;
|
||||
@@ -7160,8 +7199,6 @@ IntExtTextOutW(
|
||||
}
|
||||
}
|
||||
|
||||
FontLink_Chain_Finish(&Chain);
|
||||
|
||||
IntUnLockFreeType();
|
||||
|
||||
EXLATEOBJ_vCleanup(&exloRGB2Dst);
|
||||
|
||||
Reference in New Issue
Block a user