From ede43e5e39fe2b574c66b0ddb2c7010b7b507394 Mon Sep 17 00:00:00 2001 From: gongheng Date: Wed, 21 Oct 2026 16:39:43 +0800 Subject: [PATCH] fix(pdfium): resolve installed CJK fonts referenced by PostScript name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register each enumerated font in m_FontList before notifying the mapper so that GetFont() succeeds during enumeration and PostScript names get read. 字体枚举时先注册进 m_FontList 再通知 mapper,保证枚举期间 GetFont() 成功, 使已安装字体的 PostScript 名可被读取索引。 Index the PostScript name of every installed font whose PS name differs from its family name, not only localized names, so /BaseFont entries like "FZXBSJW--GB1-0" can resolve to the installed font family. 为所有 PS 名与族名不同的已安装字体建立 PostScript 名索引(不再仅限本地化名), 使 /BaseFont 条目(如 "FZXBSJW--GB1-0")能解析到已安装字族。 Prefer an exact family-name match in MapFont for CJK charsets over the hardcoded fallback lists, which previously ignored the requested family. MapFont 对 CJK 字符集优先按请求族名精确匹配,而非直接落入硬编码回退列表。 Log: 修复PDF按PostScript字体名无法匹配已安装中文字体的问题 PMS: BUG-380413 Influence: PDF中引用已安装中文字体的PostScript名(如方正小标宋)时能正确 匹配对应字体,不再被无关替代字体替换,中文显示恢复正确。 --- .../pdfium/core/fxge/cfx_folderfontinfo.cpp | 38 +++++++++++-------- .../pdfium/core/fxge/cfx_fontmapper.cpp | 30 +++++++++------ .../pdfium/pdfium/core/fxge/fx_ge_linux.cpp | 15 ++++++++ 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/cfx_folderfontinfo.cpp b/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/cfx_folderfontinfo.cpp index 75c4de9bd..26c1171c6 100644 --- a/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/cfx_folderfontinfo.cpp +++ b/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/cfx_folderfontinfo.cpp @@ -245,6 +245,23 @@ void CFX_FolderFontInfo::ReportFace(const ByteString& path, auto pInfo = std::make_unique(path, facename, tables, offset, filesize); + pInfo->m_Styles = 0; + if (style.Contains("Bold")) + pInfo->m_Styles |= FXFONT_FORCE_BOLD; + if (style.Contains("Italic") || style.Contains("Oblique")) + pInfo->m_Styles |= FXFONT_ITALIC; + if (facename.Contains("Serif")) + pInfo->m_Styles |= FXFONT_SERIF; + + // 必须先把该字体注册进 m_FontList,再通知 mapper:在字体枚举期间, + // CFX_FontMapper::AddInstalledFont() 会调用 GetFont(facename) 打开该字体 + // 以读取其 PostScript 名。若像原先那样在调用之后再注册,枚举期间 + // GetFont() 必然失败,已安装字体的 PostScript 名永远不会被索引,导致 + // 后续按 PostScript 名的请求(如 PDF /BaseFont 中的 "FZXBSJW--GB1-0") + // 无法解析到已安装的字族。 + FontFaceInfo* pFace = pInfo.get(); + m_FontList[facename] = std::move(pInfo); + ByteString os2 = LoadTableFromTT(pFile, tables.raw_str(), nTables, 0x4f532f32, filesize); if (os2.GetLength() >= 86) { @@ -252,36 +269,27 @@ void CFX_FolderFontInfo::ReportFace(const ByteString& path, uint32_t codepages = GET_TT_LONG(p); if (codepages & (1U << 17)) { m_pMapper->AddInstalledFont(facename, FX_CHARSET_ShiftJIS); - pInfo->m_Charsets |= CHARSET_FLAG_SHIFTJIS; + pFace->m_Charsets |= CHARSET_FLAG_SHIFTJIS; } if (codepages & (1U << 18)) { m_pMapper->AddInstalledFont(facename, FX_CHARSET_ChineseSimplified); - pInfo->m_Charsets |= CHARSET_FLAG_GB; + pFace->m_Charsets |= CHARSET_FLAG_GB; } if (codepages & (1U << 20)) { m_pMapper->AddInstalledFont(facename, FX_CHARSET_ChineseTraditional); - pInfo->m_Charsets |= CHARSET_FLAG_BIG5; + pFace->m_Charsets |= CHARSET_FLAG_BIG5; } if ((codepages & (1U << 19)) || (codepages & (1U << 21))) { m_pMapper->AddInstalledFont(facename, FX_CHARSET_Hangul); - pInfo->m_Charsets |= CHARSET_FLAG_KOREAN; + pFace->m_Charsets |= CHARSET_FLAG_KOREAN; } if (codepages & (1U << 31)) { m_pMapper->AddInstalledFont(facename, FX_CHARSET_Symbol); - pInfo->m_Charsets |= CHARSET_FLAG_SYMBOL; + pFace->m_Charsets |= CHARSET_FLAG_SYMBOL; } } m_pMapper->AddInstalledFont(facename, FX_CHARSET_ANSI); - pInfo->m_Charsets |= CHARSET_FLAG_ANSI; - pInfo->m_Styles = 0; - if (style.Contains("Bold")) - pInfo->m_Styles |= FXFONT_FORCE_BOLD; - if (style.Contains("Italic") || style.Contains("Oblique")) - pInfo->m_Styles |= FXFONT_ITALIC; - if (facename.Contains("Serif")) - pInfo->m_Styles |= FXFONT_SERIF; - - m_FontList[facename] = std::move(pInfo); + pFace->m_Charsets |= CHARSET_FLAG_ANSI; } void* CFX_FolderFontInfo::GetSubstFont(const ByteString& face) { diff --git a/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/cfx_fontmapper.cpp b/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/cfx_fontmapper.cpp index 2ac33dd78..60c9ec230 100644 --- a/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/cfx_fontmapper.cpp +++ b/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/cfx_fontmapper.cpp @@ -323,18 +323,26 @@ void CFX_FontMapper::AddInstalledFont(const ByteString& name, int charset) { return static_cast(c) > 0x80; }); - if (bLocalized) { - void* hFont = m_pFontInfo->GetFont(name.c_str()); - if (!hFont) { + // 字体既可能通过族名(family name)引用,也可能通过 PostScript 名引用; + // 而 PDF 的 /BaseFont 条目通常携带的是 PostScript 名(例如族名 + // "FZXiaoBiaoSong-B05S" 对应的 "FZXBSJW--GB1-0")。此处为每台已安装 + // 字体中 PostScript 名与族名不同的字体建立 PostScript 名索引,使 + // MatchInstalledFonts() 能把 PostScript 名请求解析到已安装的字体族上。 + // 原先仅对本地化(含非 ASCII 字符)的族名做该索引,导致 ASCII 族名字体 + // 的 PostScript 名请求永远无法匹配已安装字体,总会被无关的替代字体替换。 + void* hFont = m_pFontInfo->GetFont(name.c_str()); + if (!hFont && bLocalized) { hFont = m_pFontInfo->MapFont(0, 0, FX_CHARSET_Default, 0, name.c_str()); - if (!hFont) - return; - } - - ByteString new_name = GetPSNameFromTT(hFont); - if (!new_name.IsEmpty()) - m_LocalizedTTFonts.push_back(std::make_pair(new_name, name)); - m_pFontInfo->DeleteFont(hFont); + } + if (hFont) { + ByteString ps_name = GetPSNameFromTT(hFont); + if (!ps_name.IsEmpty() && + TT_NormalizeName(ps_name.c_str()) != TT_NormalizeName(name.c_str())) { + m_LocalizedTTFonts.push_back(std::make_pair(ps_name, name)); + } + m_pFontInfo->DeleteFont(hFont); + } else if (bLocalized) { + return; } m_InstalledTTFonts.push_back(name); m_LastFamily = name; diff --git a/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/fx_ge_linux.cpp b/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/fx_ge_linux.cpp index d56881352..de25b76e7 100644 --- a/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/fx_ge_linux.cpp +++ b/3rdparty/deepin-pdfium/src/3rdparty/pdfium/pdfium/core/fxge/fx_ge_linux.cpp @@ -114,6 +114,13 @@ void* CFX_LinuxFontInfo::MapFont(int weight, break; } case FX_CHARSET_ChineseSimplified: { + // 优先按请求的族名精确匹配,而不是直接落入硬编码回退列表:PDF 常以 + // 某个已安装 CJK 字体的族名引用它(例如 "FZXiaoBiaoSong-B05S"), + // 该名字往往不在下方任何旧回退列表中;若不先做精确匹配,下方列表 + // 会无条件替换为列表中第一个找到的字体,完全忽略请求的族名。 + auto exact_it = m_FontList.find(family); + if (exact_it != m_FontList.end()) + return exact_it->second.get(); for (const char* name : g_LinuxGbFontList) { auto it = m_FontList.find(name); if (it != m_FontList.end()) @@ -122,6 +129,10 @@ void* CFX_LinuxFontInfo::MapFont(int weight, break; } case FX_CHARSET_ChineseTraditional: { + // 参见上方 FX_CHARSET_ChineseSimplified 分支的注释。 + auto exact_it = m_FontList.find(family); + if (exact_it != m_FontList.end()) + return exact_it->second.get(); for (const char* name : g_LinuxB5FontList) { auto it = m_FontList.find(name); if (it != m_FontList.end()) @@ -130,6 +141,10 @@ void* CFX_LinuxFontInfo::MapFont(int weight, break; } case FX_CHARSET_Hangul: { + // 参见上方 FX_CHARSET_ChineseSimplified 分支的注释。 + auto exact_it = m_FontList.find(family); + if (exact_it != m_FontList.end()) + return exact_it->second.get(); for (const char* name : g_LinuxHGFontList) { auto it = m_FontList.find(name); if (it != m_FontList.end())