7#include "core/fxge/cfx_fontmapper.h"
15#include "build/build_config.h"
16#include "core/fxcrt/check_op.h"
17#include "core/fxcrt/containers/adapters.h"
18#include "core/fxcrt/containers/contains.h"
19#include "core/fxcrt/data_vector.h"
20#include "core/fxcrt/fx_codepage.h"
21#include "core/fxcrt/fx_extension.h"
22#include "core/fxcrt/fx_memory.h"
23#include "core/fxcrt/unowned_ptr_exclusion.h"
24#include "core/fxge/cfx_fontmgr.h"
25#include "core/fxge/cfx_substfont.h"
26#include "core/fxge/fx_font.h"
27#include "core/fxge/systemfontinfo_iface.h"
32 "StandardFont enum count mismatch");
38 "Courier-BoldOblique",
42 "Helvetica-BoldOblique",
57constexpr AltFontName kAltFontNames[] = {
149struct AltFontFamily {
150 const char* m_pFontName;
151 const char* m_pFontFamily;
154constexpr AltFontFamily kAltFontFamilies[] = {
155 {
"AGaramondPro",
"Adobe Garamond Pro"},
156 {
"BankGothicBT-Medium",
"BankGothic Md BT"},
157 {
"ForteMT",
"Forte"},
160#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || defined(OS_ASMJS)
161const char kNarrowFamily[] =
"LiberationSansNarrow";
162#elif BUILDFLAG(IS_ANDROID)
163const char kNarrowFamily[] =
"RobotoCondensed";
165const char kNarrowFamily[] =
"ArialNarrow";
172 auto pos = norm.Find(
'+');
173 if (pos.has_value() && pos.value() != 0)
174 norm = norm.First(pos.value());
179const char* GetFontFamily(uint32_t nStyle,
const ByteString& fontname) {
180 if (fontname.Contains(
"Script")) {
182 return "ScriptMTBold";
184 if (fontname.Contains(
"Palace")) {
185 return "PalaceScriptMT";
186 }
else if (fontname.Contains(
"French")) {
187 return "FrenchScriptMT";
188 }
else if (fontname.Contains(
"FreeStyle")) {
189 return "FreeStyleScript";
193 for (
const auto& alternate : kAltFontFamilies) {
194 if (fontname.Contains(alternate.m_pFontName)) {
195 return alternate.m_pFontFamily;
203 size_t iIndex = bsRegion.Find(
',').value_or(bsRegion.GetLength());
213constexpr FX_FontStyle kFontStyles[] = {
222 bool reverse_search) {
223 if (font_name.IsEmpty())
226 for (
const FX_FontStyle& style : kFontStyles) {
227 if (style.len > font_name.GetLength())
230 ByteStringView style_view =
231 reverse_search ? font_name.Last(style.len) : font_name.First(style.len);
232 if (style_view == style.name)
239 bool* is_style_available,
242 if (style_str.IsEmpty())
246 bool is_first_item =
true;
247 while (i < style_str.GetLength()) {
249 const FX_FontStyle* style_result =
250 GetStyleType(buf.AsStringView(),
false);
251 if ((i && !*is_style_available) || (!i && !style_result))
254 uint32_t parsed_style;
256 *is_style_available =
true;
257 parsed_style = style_result->style;
271 is_first_item =
false;
282 i += buf.GetLength() + 1;
287bool CheckSupportThirdPartFont(
const ByteString& name,
int* pitch_family) {
288 if (name
!= "MyriadPro")
294uint32_t GetStyleFromBaseFont(
int base_font) {
295 int pos = base_font % 4;
297 if (pos == 1 || pos == 2)
304int GetPitchFamilyFromBaseFont(
int base_font) {
312int GetPitchFamilyFromFlags(uint32_t flags) {
313 int pitch_family = 0;
323int AdjustBaseFontForStyle(
int base_font, uint32_t style) {
324 if (!style || (base_font % 4))
347 for (size_t i = 0; i < str.GetLength(); ++i) {
348 if (!FXSYS_IsUpperASCII(str[i]))
354void RemoveSubsettedFontPrefix(
ByteString* subst_name) {
355 constexpr size_t kPrefixLength = 6;
356 if (subst_name->GetLength() > kPrefixLength &&
357 (*subst_name)[kPrefixLength] ==
'+' &&
358 IsStrUpper(subst_name->First(kPrefixLength))) {
360 subst_name->Last(subst_name->GetLength() - (kPrefixLength + 1));
366 if (is_truetype && name.Front() ==
'@')
367 subst_name.Delete(0);
369 subst_name.Remove(
' ');
370 RemoveSubsettedFontPrefix(&subst_name);
375bool IsNarrowFontName(
const ByteString& name) {
376 static const char kNarrowFonts[][10] = {
"Narrow",
"Condensed"};
377 for (
const char* font : kNarrowFonts) {
378 std::optional<size_t> pos = name.Find(font);
379 if (pos.has_value() && pos.value() != 0)
385class ScopedFontDeleter {
387 FX_STACK_ALLOCATED();
390 : font_info_(font_info), font_(font) {}
391 ~ScopedFontDeleter() { font_info_->DeleteFont(font_); }
405 std::unique_ptr<SystemFontInfoIface> pFontInfo) {
409 m_bListLoaded =
false;
410 m_pFontInfo = std::move(pFontInfo);
414 return std::move(m_pFontInfo);
418 uint32_t buffer[256];
419 m_pFontInfo->GetFontData(font_handle, kTableTTCF,
420 pdfium::as_writable_byte_span(buffer));
422 uint32_t checksum = 0;
423 for (
auto x : buffer) {
430 size_t size = m_pFontInfo->GetFontData(font_handle, kTableNAME, {});
434 DataVector<uint8_t> buffer(size);
435 size_t bytes_read = m_pFontInfo->GetFontData(font_handle, kTableNAME, buffer);
436 return bytes_read == size ? GetNameFromTT(buffer, 6) : ByteString();
444 m_FaceArray.push_back({name,
static_cast<uint32_t>(charset)});
445 if (name == m_LastFamily)
448 bool is_localized =
std::any_of(name.begin(), name.end(), [](
const char& c) {
449 return static_cast<uint8_t>(c) > 0x80;
453 void* font_handle = m_pFontInfo->GetFont(name);
456 m_pFontInfo->MapFont(0,
false, FX_Charset::kDefault, 0, name);
461 ScopedFontDeleter scoped_font(m_pFontInfo.get(), font_handle);
462 ByteString new_name = GetPSNameFromTT(font_handle);
463 if (!new_name.IsEmpty())
464 m_LocalizedTTFonts.emplace_back(new_name, name);
466 m_InstalledTTFonts.push_back(name);
471 if (!m_pFontInfo || m_bListLoaded)
474 m_pFontInfo->EnumFontList(
this);
475 m_bListLoaded =
true;
480 for (
const ByteString& font : pdfium::Reversed(m_InstalledTTFonts)) {
481 if (TT_NormalizeName(font) == norm_name) {
485 for (
const auto& font_data : pdfium::Reversed(m_LocalizedTTFonts)) {
486 if (TT_NormalizeName(font_data.first) == norm_name) {
487 return font_data.second;
500 if (!m_StandardFaces[base_font]) {
501 m_StandardFaces[base_font] = m_pFontMgr->NewFixedFace(
502 nullptr, m_pFontMgr->GetStandardFont(base_font), 0);
504 return m_StandardFaces[base_font];
513 if (!m_GenericSerifFace) {
514 m_GenericSerifFace = m_pFontMgr->NewFixedFace(
515 nullptr, m_pFontMgr->GetGenericSerifFont(), 0);
517 return m_GenericSerifFace;
519 subst_font->m_Family =
"Chrome Sans";
520 if (!m_GenericSansFace) {
522 m_pFontMgr->NewFixedFace(
nullptr, m_pFontMgr->GetGenericSansFont(), 0);
524 return m_GenericSansFace;
537 ScopedFontDeleter scoped_font(m_pFontInfo.get(), font_handle);
538 m_pFontInfo->GetFaceName(font_handle, &face_name);
539 if (charset == FX_Charset::kDefault)
540 m_pFontInfo->GetFontCharset(font_handle, &charset);
541 size_t ttc_size = m_pFontInfo->GetFontData(font_handle, kTableTTCF, {});
542 size_t font_size = m_pFontInfo->GetFontData(font_handle, 0, {});
543 if (font_size == 0 && ttc_size == 0)
548 ? GetCachedTTCFace(font_handle, ttc_size, font_size)
549 : GetCachedFace(font_handle, face_name, weight, is_italic, font_size);
553 subst_font->m_Family = face_name;
556 if (weight != face_weight)
558 if (is_italic && !face->IsItalic()) {
559 if (italic_angle == 0)
561 else if (abs(italic_angle) < 5)
582 const ByteString subst_name = GetSubstName(name, is_truetype);
583 if (subst_name
== "Symbol" && !is_truetype) {
584 subst_font->m_Family =
"Chrome Symbol";
586 return UseInternalSubst(kSymbol, weight, italic_angle, 0, subst_font);
588 if (subst_name
== "ZapfDingbats") {
589 subst_font->m_Family =
"Chrome Dingbats";
591 return UseInternalSubst(kDingbats, weight, italic_angle, 0, subst_font);
596 bool has_comma =
false;
597 bool has_hyphen =
false;
599 std::optional<size_t> pos = subst_name.Find(
",");
600 if (pos.has_value()) {
601 family = subst_name.First(pos.value());
603 style = subst_name.Last(subst_name.GetLength() - (pos.value() + 1));
609 for (; base_font <
kSymbol; base_font++) {
610 if (family == kBase14FontNames[base_font])
615 bool is_style_available =
false;
617 nStyle = GetStyleFromBaseFont(base_font);
618 pitch_family = GetPitchFamilyFromBaseFont(base_font);
623 std::optional<size_t> pos = family.ReverseFind(
'-');
624 if (pos.has_value()) {
625 style = family.Last(family.GetLength() - (pos.value() + 1));
626 family = family.First(pos.value());
631 size_t nLen = family.GetLength();
632 const FX_FontStyle* style_result =
633 GetStyleType(family.AsStringView(),
true);
635 family = family.First(nLen - style_result->len);
636 nStyle |= style_result->style;
639 pitch_family = GetPitchFamilyFromFlags(flags);
642 const int old_weight = weight;
646 if (ParseStyles(style, &is_style_available, &weight, &nStyle)) {
652 return UseInternalSubst(base_font, old_weight, italic_angle, pitch_family,
656 const FX_Charset Charset = GetCharset(code_page, base_font, flags);
660 const char* maybe_family = GetFontFamily(nStyle, family);
665 ByteString match = MatchInstalledFonts(TT_NormalizeName(family));
666 if (match.IsEmpty() && family
!= subst_name &&
667 (!has_comma && (!has_hyphen || (has_hyphen && !is_style_available)))) {
668 match
= MatchInstalledFonts(TT_NormalizeName(subst_name));
672 if (!CheckSupportThirdPartFont(family, &pitch_family)) {
673 is_italic = italic_angle != 0;
676 if (IsNarrowFontName(subst_name))
677 family
= kNarrowFamily;
692 if (!match.IsEmpty())
695 base_font = AdjustBaseFontForStyle(base_font, nStyle);
696 family = kBase14FontNames[base_font];
702 m_pFontInfo->MapFont(weight, is_italic, Charset, pitch_family, family);
704 return UseExternalSubst(font_handle, subst_name, weight, is_italic,
705 italic_angle, Charset, subst_font);
709 is_italic = italic_angle != 0;
712 if (!match.IsEmpty()) {
713 font_handle = m_pFontInfo->GetFont(match);
715 return UseInternalSubst(base_font, old_weight, italic_angle, pitch_family,
718 return UseExternalSubst(font_handle, subst_name, weight, is_italic,
719 italic_angle, Charset, subst_font);
723#if !BUILDFLAG(IS_WIN)
724 if (subst_name ==
"Symbol") {
725 subst_font->m_Family =
"Chrome Symbol";
726 subst_font->m_Charset = FX_Charset::kSymbol;
727 return UseInternalSubst(kSymbol, old_weight, italic_angle, pitch_family,
731 return FindSubstFont(family, is_truetype, flags & ~
FXFONT_SYMBOLIC, weight,
732 italic_angle, FX_CodePage::kDefANSI, subst_font);
736 return UseInternalSubst(base_font, old_weight, italic_angle, pitch_family,
740 auto it = std::find_if(
741 m_FaceArray.begin(), m_FaceArray.end(), [Charset](
const FaceData& face) {
742 return face.charset ==
static_cast<uint32_t>(Charset);
744 if (it == m_FaceArray.end()) {
745 return UseInternalSubst(base_font, old_weight, italic_angle, pitch_family,
748 font_handle = m_pFontInfo->GetFont(it->name);
751 return UseExternalSubst(font_handle, subst_name, weight, is_italic,
752 italic_angle, Charset, subst_font);
756 return m_FaceArray.size();
760 CHECK_LT(index, m_FaceArray.size());
761 return m_FaceArray[index].name;
765 for (
const auto& font : m_InstalledTTFonts) {
773 for (
const auto& fontPair : m_LocalizedTTFonts) {
774 if (fontPair.first == name)
781std::optional<ByteString> CFX_FontMapper::InstalledFontNameStartingWith(
782 const ByteString& name)
const {
783 for (
const auto& thisname : m_InstalledTTFonts) {
784 if (thisname.First(name.GetLength()) == name)
790std::optional<ByteString> CFX_FontMapper::LocalizedFontNameStartingWith(
791 const ByteString& name)
const {
792 for (
const auto& thispair : m_LocalizedTTFonts) {
793 if (thispair.first.First(name.GetLength()) == name)
794 return thispair.second;
801FixedSizeDataVector<uint8_t> CFX_FontMapper::RawBytesForIndex(size_t index) {
802 CHECK_LT(index, m_FaceArray.size());
804 void* font_handle = m_pFontInfo->MapFont(0,
false, FX_Charset::kDefault, 0,
807 return FixedSizeDataVector<uint8_t>();
809 ScopedFontDeleter scoped_font(m_pFontInfo.get(), font_handle);
810 size_t required_size = m_pFontInfo->GetFontData(font_handle, 0, {});
811 if (required_size == 0) {
812 return FixedSizeDataVector<uint8_t>();
814 auto result = FixedSizeDataVector<uint8_t>::Uninit(required_size);
815 size_t actual_size = m_pFontInfo->GetFontData(font_handle, 0, result.span());
816 if (actual_size != required_size) {
817 return FixedSizeDataVector<uint8_t>();
827 uint32_t checksum = GetChecksumFromTT(font_handle);
829 m_pFontMgr->GetCachedTTCFontDesc(ttc_size, checksum);
831 auto font_data = FixedSizeDataVector<uint8_t>::Uninit(ttc_size);
833 m_pFontInfo->GetFontData(font_handle, kTableTTCF, font_data.span());
834 if (size != ttc_size)
837 pFontDesc = m_pFontMgr->AddCachedTTCFontDesc(ttc_size, checksum,
838 std::move(font_data));
840 size_t font_offset = ttc_size - data_size;
842 GetTTCIndex(pFontDesc->FontData().first(ttc_size), font_offset);
843 RetainPtr<CFX_Face> pFace(pFontDesc->GetFace(face_index));
847 pFace = m_pFontMgr->NewFixedFace(
848 pFontDesc, pFontDesc->FontData().first(ttc_size), face_index);
852 pFontDesc->SetFace(face_index, pFace.Get());
862 m_pFontMgr->GetCachedFontDesc(subst_name, weight, is_italic);
864 auto font_data = FixedSizeDataVector<uint8_t>::Uninit(data_size);
865 size_t size = m_pFontInfo->GetFontData(font_handle, 0, font_data.span());
866 if (size != data_size)
869 pFontDesc = m_pFontMgr->AddCachedFontDesc(subst_name, weight, is_italic,
870 std::move(font_data));
872 RetainPtr<CFX_Face> pFace(pFontDesc->GetFace(0));
876 pFace = m_pFontMgr->NewFixedFace(pFontDesc,
877 pFontDesc->FontData().first(data_size), 0);
881 pFontDesc->SetFace(0, pFace.Get());
888 const auto* end =
std::end(kAltFontNames);
890 std::lower_bound(
std::begin(kAltFontNames), end, name->c_str(),
891 [](
const AltFontName& element,
const char* name) {
894 if (found == end || FXSYS_stricmp(found->m_pName, name->c_str()))
897 *name = kBase14FontNames[
static_cast<size_t>(found->m_Index)];
898 return found->m_Index;
903 return pdfium::Contains(kBase14FontNames, name);
fxcrt::ByteString ByteString
void AddInstalledFont(const ByteString &name, FX_Charset charset)
void SetSystemFontInfo(std::unique_ptr< SystemFontInfoIface > pFontInfo)
bool HasLocalizedFont(ByteStringView name) const
static bool IsFixedFont(StandardFont font)
static constexpr int kNumStandardFonts
bool HasInstalledFont(ByteStringView name) const
CFX_FontMapper(CFX_FontMgr *mgr)
void LoadInstalledFonts()
size_t GetFaceSize() const
static bool IsStandardFontName(const ByteString &name)
static std::optional< StandardFont > GetStandardFontName(ByteString *name)
ByteString GetFaceName(size_t index) const
static bool IsSymbolicFont(StandardFont font)
RetainPtr< CFX_Face > FindSubstFont(const ByteString &face_name, bool is_truetype, uint32_t flags, int weight, int italic_angle, FX_CodePage code_page, CFX_SubstFont *subst_font)
std::unique_ptr< SystemFontInfoIface > TakeSystemFontInfo()
void SetIsBuiltInGenericFont()
ByteString(const char *ptr)
bool operator==(const char *ptr) const
bool operator!=(const ByteString &other) const
ByteString & operator=(const char *str)
ByteString & operator=(const ByteString &that)
ByteString & operator=(ByteString &&that) noexcept
bool operator!=(const char *ptr) const
FX_Charset FX_GetCharsetFromCodePage(FX_CodePage codepage)
bool FX_CharSetIsCJK(FX_Charset uCharset)
#define FXFONT_USEEXTERNATTR
bool FontStyleIsSerif(uint32_t style)
bool FontStyleIsFixedPitch(uint32_t style)
bool FontStyleIsSymbolic(uint32_t style)
bool FontFamilyIsRoman(uint32_t family)
bool FontStyleIsItalic(uint32_t style)
#define FXFONT_FORCE_BOLD
#define FXFONT_FW_BOLD_BOLD
#define FXFONT_FF_FIXEDPITCH
bool FontStyleIsScript(uint32_t style)
bool FontStyleIsForceBold(uint32_t style)
int FXSYS_stricmp(const char *str1, const char *str2)
fxcrt::ByteStringView ByteStringView
#define UNOWNED_PTR_EXCLUSION