7#include "core/fxge/cfx_fontmapper.h"
15#include "build/build_config.h"
16#include "core/fxcrt/data_vector.h"
17#include "core/fxcrt/fx_codepage.h"
18#include "core/fxcrt/fx_extension.h"
19#include "core/fxcrt/fx_memory.h"
20#include "core/fxcrt/fx_memory_wrappers.h"
21#include "core/fxcrt/unowned_ptr_exclusion.h"
22#include "core/fxge/cfx_fontmgr.h"
23#include "core/fxge/cfx_substfont.h"
24#include "core/fxge/fx_font.h"
25#include "core/fxge/systemfontinfo_iface.h"
26#include "third_party/base/check_op.h"
27#include "third_party/base/containers/adapters.h"
28#include "third_party/base/containers/contains.h"
33 "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";
168ByteString TT_NormalizeName(ByteString norm) {
172 auto pos = norm.Find(
'+');
173 if (pos.has_value() && pos.value() != 0)
174 norm = norm.First(pos.value());
179void GetFontFamily(uint32_t nStyle, ByteString* fontName) {
180 if (fontName->Contains(
"Script")) {
182 *fontName
= "ScriptMTBold";
183 else if (fontName->Contains(
"Palace"))
184 *fontName
= "PalaceScriptMT";
185 else if (fontName->Contains(
"French"))
186 *fontName
= "FrenchScriptMT";
187 else if (fontName->Contains(
"FreeStyle"))
188 *fontName
= "FreeStyleScript";
191 for (
const auto& alternate : kAltFontFamilies) {
192 if (fontName->Contains(alternate.m_pFontName)) {
193 *fontName
= alternate.m_pFontFamily;
199ByteString ParseStyle(
const ByteString& bsStyle, size_t iStart) {
200 ByteStringView bsRegion = bsStyle.AsStringView().Substr(iStart);
201 size_t iIndex = bsRegion.Find(
',').value_or(bsRegion.GetLength());
202 return ByteString(bsRegion.First(iIndex));
211constexpr FX_FontStyle kFontStyles[] = {
219const FX_FontStyle* GetStyleType(ByteStringView font_name,
220 bool reverse_search) {
221 if (font_name.IsEmpty())
224 for (
const FX_FontStyle& style : kFontStyles) {
225 if (style.len > font_name.GetLength())
228 ByteStringView style_view =
229 reverse_search ? font_name.Last(style.len) : font_name.First(style.len);
230 if (style_view == style.name)
236bool ParseStyles(
const ByteString& style_str,
237 bool* is_style_available,
244 bool is_first_item =
true;
245 while (i < style_str.GetLength()) {
246 ByteString buf = ParseStyle(style_str, i);
247 const FX_FontStyle* style_result =
248 GetStyleType(buf.AsStringView(),
false);
249 if ((i && !*is_style_available) || (!i && !style_result))
252 uint32_t parsed_style;
254 *is_style_available =
true;
255 parsed_style = style_result->style;
269 is_first_item =
false;
280 i += buf.GetLength() + 1;
285bool CheckSupportThirdPartFont(
const ByteString& name,
int* pitch_family) {
286 if (name
!= "MyriadPro")
292uint32_t GetStyleFromBaseFont(
int base_font) {
293 int pos = base_font % 4;
295 if (pos == 1 || pos == 2)
302int GetPitchFamilyFromBaseFont(
int base_font) {
310int GetPitchFamilyFromFlags(uint32_t flags) {
311 int pitch_family = 0;
321int AdjustBaseFontForStyle(
int base_font, uint32_t style) {
322 if (!style || (base_font % 4))
344bool IsStrUpper(
const ByteString& str) {
345 for (size_t i = 0; i < str.GetLength(); ++i) {
346 if (!FXSYS_IsUpperASCII(str[i]))
352void RemoveSubsettedFontPrefix(ByteString* subst_name) {
353 constexpr size_t kPrefixLength = 6;
354 if (subst_name->GetLength() > kPrefixLength &&
355 (*subst_name)[kPrefixLength] ==
'+' &&
356 IsStrUpper(subst_name->First(kPrefixLength))) {
358 subst_name->Last(subst_name->GetLength() - (kPrefixLength + 1));
362ByteString GetSubstName(
const ByteString& name,
bool is_truetype) {
363 ByteString subst_name = name;
364 if (is_truetype && name
.Front() ==
'@')
365 subst_name.Delete(0);
367 subst_name.Remove(
' ');
368 RemoveSubsettedFontPrefix(&subst_name);
369 CFX_FontMapper::GetStandardFontName(&subst_name);
373bool IsNarrowFontName(
const ByteString& name) {
374 static const char kNarrowFonts[][10] = {
"Narrow",
"Condensed"};
375 for (
const char* font : kNarrowFonts) {
376 absl::optional<size_t> pos = name.Find(font);
377 if (pos.has_value() && pos.value() != 0)
383class ScopedFontDeleter {
385 FX_STACK_ALLOCATED();
388 : font_info_(font_info), font_(font) {}
389 ~ScopedFontDeleter() { font_info_->DeleteFont(font_); }
403 std::unique_ptr<SystemFontInfoIface> pFontInfo) {
407 m_bListLoaded =
false;
408 m_pFontInfo = std::move(pFontInfo);
412 return std::move(m_pFontInfo);
416 uint32_t buffer[256];
417 m_pFontInfo->GetFontData(
418 font_handle, kTableTTCF,
419 pdfium::as_writable_bytes(pdfium::make_span(buffer)));
421 uint32_t checksum = 0;
422 for (
auto x : buffer)
429 size_t size = m_pFontInfo->GetFontData(font_handle, kTableNAME, {});
433 DataVector<uint8_t> buffer(size);
434 size_t bytes_read = m_pFontInfo->GetFontData(font_handle, kTableNAME, buffer);
435 return bytes_read == size ? GetNameFromTT(buffer, 6) : ByteString();
443 m_FaceArray.push_back({name,
static_cast<uint32_t>(charset)});
444 if (name == m_LastFamily)
448 return static_cast<uint8_t>(c) > 0x80;
452 void* font_handle = m_pFontInfo->GetFont(name);
455 m_pFontInfo->MapFont(0,
false, FX_Charset::kDefault, 0, name);
460 ScopedFontDeleter scoped_font(m_pFontInfo.get(), font_handle);
461 ByteString new_name = GetPSNameFromTT(font_handle);
462 if (!new_name.IsEmpty())
463 m_LocalizedTTFonts.emplace_back(new_name, name);
465 m_InstalledTTFonts.push_back(name);
470 if (!m_pFontInfo || m_bListLoaded)
473 m_pFontInfo->EnumFontList(
this);
474 m_bListLoaded =
true;
477ByteString
CFX_FontMapper::MatchInstalledFonts(
const ByteString& norm_name) {
479 for (
const ByteString& font : pdfium::base::Reversed(m_InstalledTTFonts)) {
480 if (TT_NormalizeName(font) == norm_name) {
484 for (
const auto& font_data : pdfium::base::Reversed(m_LocalizedTTFonts)) {
485 if (TT_NormalizeName(font_data.first) == norm_name) {
486 return font_data.second;
499 if (!m_StandardFaces[base_font]) {
500 m_StandardFaces[base_font] = m_pFontMgr->NewFixedFace(
501 nullptr, m_pFontMgr->GetStandardFont(base_font), 0);
503 return m_StandardFaces[base_font];
512 if (!m_GenericSerifFace) {
513 m_GenericSerifFace = m_pFontMgr->NewFixedFace(
514 nullptr, m_pFontMgr->GetGenericSerifFont(), 0);
516 return m_GenericSerifFace;
518 subst_font->m_Family =
"Chrome Sans";
519 if (!m_GenericSansFace) {
521 m_pFontMgr->NewFixedFace(
nullptr, m_pFontMgr->GetGenericSansFont(), 0);
523 return m_GenericSansFace;
528 ByteString face_name,
536 ScopedFontDeleter scoped_font(m_pFontInfo.get(), font_handle);
537 m_pFontInfo->GetFaceName(font_handle, &face_name);
538 if (charset == FX_Charset::kDefault)
539 m_pFontInfo->GetFontCharset(font_handle, &charset);
540 size_t ttc_size = m_pFontInfo->GetFontData(font_handle, kTableTTCF, {});
541 size_t font_size = m_pFontInfo->GetFontData(font_handle, 0, {});
542 if (font_size == 0 && ttc_size == 0)
547 ? GetCachedTTCFace(font_handle, ttc_size, font_size)
548 : GetCachedFace(font_handle, face_name, weight, is_italic, font_size);
552 subst_font->m_Family = face_name;
555 if (weight != face_weight)
557 if (is_italic && !face->IsItalic()) {
558 if (italic_angle == 0)
560 else if (abs(italic_angle) < 5)
581 const ByteString subst_name = GetSubstName(name, is_truetype);
582 if (subst_name
== "Symbol" && !is_truetype) {
583 subst_font->m_Family =
"Chrome Symbol";
585 return UseInternalSubst(kSymbol, weight, italic_angle, 0, subst_font);
587 if (subst_name
== "ZapfDingbats") {
588 subst_font->m_Family =
"Chrome Dingbats";
590 return UseInternalSubst(kDingbats, weight, italic_angle, 0, subst_font);
595 bool has_comma =
false;
596 bool has_hyphen =
false;
598 absl::optional<size_t> pos = subst_name.Find(
",");
599 if (pos.has_value()) {
600 family = subst_name.First(pos.value());
601 GetStandardFontName(&family);
602 style = subst_name.Last(subst_name.GetLength() - (pos.value() + 1));
608 for (; base_font <
kSymbol; base_font++) {
609 if (family
== kBase14FontNames[base_font])
614 bool is_style_available =
false;
616 nStyle = GetStyleFromBaseFont(base_font);
617 pitch_family = GetPitchFamilyFromBaseFont(base_font);
622 absl::optional<size_t> pos = family.ReverseFind(
'-');
623 if (pos.has_value()) {
624 style = family.Last(family.GetLength() - (pos.value() + 1));
625 family = family.First(pos.value());
630 size_t nLen = family.GetLength();
631 const FX_FontStyle* style_result =
632 GetStyleType(family.AsStringView(),
true);
634 family = family.First(nLen - style_result->len);
635 nStyle |= style_result->style;
638 pitch_family = GetPitchFamilyFromFlags(flags);
641 const int old_weight = weight;
645 if (ParseStyles(style, &is_style_available, &weight, &nStyle)) {
651 return UseInternalSubst(base_font, old_weight, italic_angle, pitch_family,
655 const FX_Charset Charset = GetCharset(code_page, base_font, flags);
659 GetFontFamily(nStyle, &family);
660 ByteString match = MatchInstalledFonts(TT_NormalizeName(family));
662 (!has_comma && (!has_hyphen || (has_hyphen && !is_style_available)))) {
663 match
= MatchInstalledFonts(TT_NormalizeName(subst_name));
667 if (!CheckSupportThirdPartFont(family, &pitch_family)) {
668 is_italic = italic_angle != 0;
671 if (IsNarrowFontName(subst_name))
672 family
= kNarrowFamily;
690 base_font = AdjustBaseFontForStyle(base_font, nStyle);
691 family
= kBase14FontNames[base_font];
697 m_pFontInfo->MapFont(weight, is_italic, Charset, pitch_family, family);
699 return UseExternalSubst(font_handle, subst_name, weight, is_italic,
700 italic_angle, Charset, subst_font);
704 is_italic = italic_angle != 0;
708 font_handle = m_pFontInfo->GetFont(match);
710 return UseInternalSubst(base_font, old_weight, italic_angle, pitch_family,
713 return UseExternalSubst(font_handle, subst_name, weight, is_italic,
714 italic_angle, Charset, subst_font);
718#if !BUILDFLAG(IS_WIN)
719 if (subst_name ==
"Symbol") {
720 subst_font->m_Family =
"Chrome Symbol";
721 subst_font->m_Charset = FX_Charset::kSymbol;
722 return UseInternalSubst(kSymbol, old_weight, italic_angle, pitch_family,
726 return FindSubstFont(family, is_truetype, flags & ~
FXFONT_SYMBOLIC, weight,
727 italic_angle, FX_CodePage::kDefANSI, subst_font);
731 return UseInternalSubst(base_font, old_weight, italic_angle, pitch_family,
735 auto it = std::find_if(
736 m_FaceArray.begin(), m_FaceArray.end(), [Charset](
const FaceData& face) {
737 return face.charset ==
static_cast<uint32_t>(Charset);
739 if (it == m_FaceArray.end()) {
740 return UseInternalSubst(base_font, old_weight, italic_angle, pitch_family,
743 font_handle = m_pFontInfo->GetFont(it->name);
746 return UseExternalSubst(font_handle, subst_name, weight, is_italic,
747 italic_angle, Charset, subst_font);
751 return m_FaceArray.size();
755 CHECK_LT(index, m_FaceArray.size());
756 return m_FaceArray[index].name;
760 for (
const auto& font : m_InstalledTTFonts) {
768 for (
const auto& fontPair : m_LocalizedTTFonts) {
769 if (fontPair.first == name)
776absl::optional<ByteString> CFX_FontMapper::InstalledFontNameStartingWith(
777 const ByteString& name)
const {
778 for (
const auto& thisname : m_InstalledTTFonts) {
779 if (thisname.First(name.GetLength()) == name)
782 return absl::nullopt;
785absl::optional<ByteString> CFX_FontMapper::LocalizedFontNameStartingWith(
786 const ByteString& name)
const {
787 for (
const auto& thispair : m_LocalizedTTFonts) {
788 if (thispair.first.First(name.GetLength()) == name)
789 return thispair.second;
791 return absl::nullopt;
796FixedSizeDataVector<uint8_t> CFX_FontMapper::RawBytesForIndex(size_t index) {
797 CHECK_LT(index, m_FaceArray.size());
799 void* font_handle = m_pFontInfo->MapFont(0,
false, FX_Charset::kDefault, 0,
802 return FixedSizeDataVector<uint8_t>();
804 ScopedFontDeleter scoped_font(m_pFontInfo.get(), font_handle);
805 size_t required_size = m_pFontInfo->GetFontData(font_handle, 0, {});
806 if (required_size == 0) {
807 return FixedSizeDataVector<uint8_t>();
809 auto result = FixedSizeDataVector<uint8_t>::Uninit(required_size);
810 size_t actual_size = m_pFontInfo->GetFontData(font_handle, 0, result.span());
811 if (actual_size != required_size) {
812 return FixedSizeDataVector<uint8_t>();
821 CHECK_GE(ttc_size, data_size);
822 uint32_t checksum = GetChecksumFromTT(font_handle);
824 m_pFontMgr->GetCachedTTCFontDesc(ttc_size, checksum);
826 auto font_data = FixedSizeDataVector<uint8_t>::Uninit(ttc_size);
828 m_pFontInfo->GetFontData(font_handle, kTableTTCF, font_data.span());
829 if (size != ttc_size)
832 pFontDesc = m_pFontMgr->AddCachedTTCFontDesc(ttc_size, checksum,
833 std::move(font_data));
835 size_t font_offset = ttc_size - data_size;
837 GetTTCIndex(pFontDesc->FontData().first(ttc_size), font_offset);
838 RetainPtr<CFX_Face> pFace(pFontDesc->GetFace(face_index));
842 pFace = m_pFontMgr->NewFixedFace(
843 pFontDesc, pFontDesc->FontData().first(ttc_size), face_index);
847 pFontDesc->SetFace(face_index, pFace.Get());
852 ByteString subst_name,
857 m_pFontMgr->GetCachedFontDesc(subst_name, weight, is_italic);
859 auto font_data = FixedSizeDataVector<uint8_t>::Uninit(data_size);
860 size_t size = m_pFontInfo->GetFontData(font_handle, 0, font_data.span());
861 if (size != data_size)
864 pFontDesc = m_pFontMgr->AddCachedFontDesc(subst_name, weight, is_italic,
865 std::move(font_data));
867 RetainPtr<CFX_Face> pFace(pFontDesc->GetFace(0));
871 pFace = m_pFontMgr->NewFixedFace(pFontDesc,
872 pFontDesc->FontData().first(data_size), 0);
876 pFontDesc->SetFace(0, pFace.Get());
881absl::optional<CFX_FontMapper::StandardFont>
883 const auto* end =
std::end(kAltFontNames);
886 [](
const AltFontName& element,
const char* name) {
889 if (found == end || FXSYS_stricmp(found->m_pName, name->c_str()))
890 return absl::nullopt;
892 *name = kBase14FontNames[
static_cast<size_t>(found->m_Index)];
893 return found->m_Index;
898 return pdfium::Contains(kBase14FontNames, name);
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)
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()
const_iterator begin() const
bool operator==(const char *ptr) const
const_iterator end() const
bool operator!=(const ByteString &other) const
ByteString & operator=(const char *str)
const char * c_str() const
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)
#define UNOWNED_PTR_EXCLUSION