Optimize CFX_FolderFontInfo::FindFont() for an exact match case.
Avoid a linear search where possible.
-- Make some free functions be methods of FontFaceInfo.
Fixed: pdfium:2135
Change-Id: I3185c59ef347996ea46792a5d67e0be8f4c787ef
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/117232
Reviewed-by: Thomas Sepez <tsepez@google.com>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxge/cfx_folderfontinfo.cpp b/core/fxge/cfx_folderfontinfo.cpp
index 6985bb3..b7eec78 100644
--- a/core/fxge/cfx_folderfontinfo.cpp
+++ b/core/fxge/cfx_folderfontinfo.cpp
@@ -12,6 +12,7 @@
#include "build/build_config.h"
#include "core/fxcrt/byteorder.h"
+#include "core/fxcrt/check_op.h"
#include "core/fxcrt/containers/contains.h"
#include "core/fxcrt/fx_codepage.h"
#include "core/fxcrt/fx_extension.h"
@@ -123,29 +124,6 @@
return 0;
}
-int32_t GetSimilarValue(int weight,
- bool bItalic,
- int pitch_family,
- uint32_t style,
- bool bMatchName,
- size_t familyNameLength,
- size_t bsNameLength) {
- int32_t iSimilarValue = 0;
- if (bMatchName && (familyNameLength == bsNameLength))
- iSimilarValue += 4;
- if (FontStyleIsForceBold(style) == (weight > 400))
- iSimilarValue += 16;
- if (FontStyleIsItalic(style) == bItalic)
- iSimilarValue += 16;
- if (FontStyleIsSerif(style) == FontFamilyIsRoman(pitch_family))
- iSimilarValue += 16;
- if (FontStyleIsScript(style) == FontFamilyIsScript(pitch_family))
- iSimilarValue += 8;
- if (FontStyleIsFixedPitch(style) == FontFamilyIsFixedPitch(pitch_family))
- iSimilarValue += 8;
- return iSimilarValue;
-}
-
} // namespace
CFX_FolderFontInfo::CFX_FolderFontInfo() = default;
@@ -324,23 +302,41 @@
const ByteString& family,
bool bMatchName) {
FontFaceInfo* pFind = nullptr;
-
- ByteStringView bsFamily = family.AsStringView();
uint32_t charset_flag = GetCharset(charset);
+
int32_t iBestSimilar = 0;
+ if (bMatchName) {
+ // Try a direct lookup for either a perfect score or to determine a
+ // baseline similarity score.
+ auto direct_it = m_FontList.find(family);
+ if (direct_it != m_FontList.end()) {
+ FontFaceInfo* pFont = direct_it->second.get();
+ if (pFont->IsEligibleForFindFont(charset_flag, charset)) {
+ iBestSimilar =
+ pFont->SimilarityScore(weight, bItalic, pitch_family, bMatchName);
+ if (iBestSimilar == FontFaceInfo::kSimilarityScoreMax) {
+ return pFont;
+ }
+ pFind = pFont;
+ }
+ }
+ }
+ // Try and find a better match. Since FindFamilyNameMatch() is expensive,
+ // avoid calling it unless there might be a better match.
+ ByteStringView bsFamily = family.AsStringView();
for (const auto& it : m_FontList) {
const ByteString& bsName = it.first;
FontFaceInfo* pFont = it.second.get();
- if (!(pFont->m_Charsets & charset_flag) && charset != FX_Charset::kDefault)
+ if (!pFont->IsEligibleForFindFont(charset_flag, charset)) {
continue;
-
- if (bMatchName && !FindFamilyNameMatch(bsFamily, bsName))
- continue;
-
- int32_t iSimilarValue =
- GetSimilarValue(weight, bItalic, pitch_family, pFont->m_Styles,
- bMatchName, bsFamily.GetLength(), bsName.GetLength());
+ }
+ int32_t iSimilarValue = pFont->SimilarityScore(
+ weight, bItalic, pitch_family,
+ bMatchName && bsFamily.GetLength() == bsName.GetLength());
if (iSimilarValue > iBestSimilar) {
+ if (bMatchName && !FindFamilyNameMatch(bsFamily, bsName)) {
+ continue;
+ }
iBestSimilar = iSimilarValue;
pFind = pFont;
}
@@ -436,3 +432,37 @@
m_FontTables(fontTables),
m_FontOffset(fontOffset),
m_FileSize(fileSize) {}
+
+bool CFX_FolderFontInfo::FontFaceInfo::IsEligibleForFindFont(
+ uint32_t flag,
+ FX_Charset charset) const {
+ return (m_Charsets & flag) || charset == FX_Charset::kDefault;
+}
+
+int32_t CFX_FolderFontInfo::FontFaceInfo::SimilarityScore(
+ int weight,
+ bool italic,
+ int pitch_family,
+ bool exact_match_bonus) const {
+ int32_t score = 0;
+ if (FontStyleIsForceBold(m_Styles) == (weight > 400)) {
+ score += 16;
+ }
+ if (FontStyleIsItalic(m_Styles) == italic) {
+ score += 16;
+ }
+ if (FontStyleIsSerif(m_Styles) == FontFamilyIsRoman(pitch_family)) {
+ score += 16;
+ }
+ if (FontStyleIsScript(m_Styles) == FontFamilyIsScript(pitch_family)) {
+ score += 8;
+ }
+ if (FontStyleIsFixedPitch(m_Styles) == FontFamilyIsFixedPitch(pitch_family)) {
+ score += 8;
+ }
+ if (exact_match_bonus) {
+ score += 4;
+ }
+ DCHECK_LE(score, kSimilarityScoreMax);
+ return score;
+}
diff --git a/core/fxge/cfx_folderfontinfo.h b/core/fxge/cfx_folderfontinfo.h
index 63d73c3..ec53226 100644
--- a/core/fxge/cfx_folderfontinfo.h
+++ b/core/fxge/cfx_folderfontinfo.h
@@ -50,12 +50,20 @@
class FontFaceInfo {
public:
+ static constexpr int32_t kSimilarityScoreMax = 68;
+
FontFaceInfo(ByteString filePath,
ByteString faceName,
ByteString fontTables,
uint32_t fontOffset,
uint32_t fileSize);
+ bool IsEligibleForFindFont(uint32_t flag, FX_Charset charset) const;
+ int32_t SimilarityScore(int weight,
+ bool italic,
+ int pitch_family,
+ bool exact_match_bonus) const;
+
const ByteString m_FilePath;
const ByteString m_FaceName;
const ByteString m_FontTables;