summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/FontUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/utils/FontUtils.cpp')
-rw-r--r--xbmc/utils/FontUtils.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/xbmc/utils/FontUtils.cpp b/xbmc/utils/FontUtils.cpp
new file mode 100644
index 0000000..4abf510
--- /dev/null
+++ b/xbmc/utils/FontUtils.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2022 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "FontUtils.h"
+
+#include "FileItem.h"
+#include "StringUtils.h"
+#include "URIUtils.h"
+#include "filesystem/Directory.h"
+#include "filesystem/File.h"
+#include "filesystem/SpecialProtocol.h"
+#include "utils/CharsetConverter.h"
+#include "utils/log.h"
+
+#include <ft2build.h>
+
+#include FT_FREETYPE_H
+#include FT_SFNT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+
+using namespace XFILE;
+
+namespace
+{
+// \brief Get font family from SFNT table entries
+std::string GetFamilyNameFromSfnt(FT_Face face)
+{
+ std::string familyName;
+
+ for (FT_UInt index = 0; index < FT_Get_Sfnt_Name_Count(face); ++index)
+ {
+ FT_SfntName name;
+ if (FT_Get_Sfnt_Name(face, index, &name) != 0)
+ {
+ CLog::LogF(LOGWARNING, "Failed to get SFNT name at index {}", index);
+ continue;
+ }
+
+ // Get the unicode font family name (format-specific interface)
+ // In properties there may be one or more font family names encoded for each platform.
+ // NOTE: we give preference to MS/APPLE platform data, then fallback to MAC
+ // because has been found some fonts that provide names not convertible MAC text to UTF8
+ if (name.name_id == TT_NAME_ID_FONT_FAMILY)
+ {
+ const std::string nameEnc{reinterpret_cast<const char*>(name.string), name.string_len};
+
+ if (name.platform_id == TT_PLATFORM_MICROSOFT ||
+ name.platform_id == TT_PLATFORM_APPLE_UNICODE)
+ {
+ if (name.language_id != TT_MAC_LANGID_ENGLISH &&
+ name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES &&
+ name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM)
+ continue;
+
+ if (CCharsetConverter::utf16BEtoUTF8(nameEnc, familyName))
+ break; // Stop here to prefer the name given with this platform
+ else
+ CLog::LogF(LOGERROR, "Failed to convert the font name string encoded as \"UTF-16BE\"");
+ }
+ else if (name.platform_id == TT_PLATFORM_MACINTOSH && familyName.empty())
+ {
+ if (name.language_id != TT_MAC_LANGID_ENGLISH || name.encoding_id != TT_MAC_ID_ROMAN)
+ continue;
+
+ if (!CCharsetConverter::MacintoshToUTF8(nameEnc, familyName))
+ CLog::LogF(LOGERROR, "Failed to convert the font name string encoded as \"macintosh\"");
+ }
+ else
+ {
+ CLog::LogF(LOGERROR, "Unsupported font SFNT name platform \"{}\"", name.platform_id);
+ }
+ }
+ }
+ return familyName;
+}
+} // unnamed namespace
+
+std::string UTILS::FONT::GetFontFamily(std::vector<uint8_t>& buffer)
+{
+ FT_Library m_library{nullptr};
+ FT_Init_FreeType(&m_library);
+ if (!m_library)
+ {
+ CLog::LogF(LOGERROR, "Unable to initialize freetype library");
+ return "";
+ }
+
+ // Load the font face
+ FT_Face face;
+ std::string familyName;
+ if (FT_New_Memory_Face(m_library, reinterpret_cast<const FT_Byte*>(buffer.data()), buffer.size(),
+ 0, &face) == 0)
+ {
+ familyName = GetFamilyNameFromSfnt(face);
+ if (familyName.empty())
+ {
+ CLog::LogF(LOGWARNING, "Failed to get the unicode family name for \"{}\", fallback to ASCII",
+ face->family_name);
+ // ASCII font family name may differ from the unicode one, use this as fallback only
+ familyName = std::string{face->family_name};
+ if (familyName.empty())
+ CLog::LogF(LOGERROR, "Family name missing in the font");
+ }
+ }
+ else
+ {
+ CLog::LogF(LOGERROR, "Failed to process font memory buffer");
+ }
+
+ FT_Done_Face(face);
+ FT_Done_FreeType(m_library);
+ return familyName;
+}
+
+std::string UTILS::FONT::GetFontFamily(const std::string& filepath)
+{
+ std::vector<uint8_t> buffer;
+ if (filepath.empty())
+ return "";
+ if (XFILE::CFile().LoadFile(filepath, buffer) <= 0)
+ {
+ CLog::LogF(LOGERROR, "Failed to load file {}", filepath);
+ return "";
+ }
+ return GetFontFamily(buffer);
+}
+
+bool UTILS::FONT::IsSupportedFontExtension(const std::string& filepath)
+{
+ return URIUtils::HasExtension(filepath, UTILS::FONT::SUPPORTED_EXTENSIONS_MASK);
+}
+
+void UTILS::FONT::ClearTemporaryFonts()
+{
+ if (!CDirectory::Exists(UTILS::FONT::FONTPATH::TEMP))
+ return;
+
+ CFileItemList items;
+ CDirectory::GetDirectory(UTILS::FONT::FONTPATH::TEMP, items,
+ UTILS::FONT::SUPPORTED_EXTENSIONS_MASK,
+ DIR_FLAG_NO_FILE_DIRS | DIR_FLAG_BYPASS_CACHE | DIR_FLAG_GET_HIDDEN);
+ for (const auto& item : items)
+ {
+ if (item->m_bIsFolder)
+ continue;
+
+ CFile::Delete(item->GetPath());
+ }
+}
+
+std::string UTILS::FONT::FONTPATH::GetSystemFontPath(const std::string& filename)
+{
+ std::string fontPath = URIUtils::AddFileToFolder(
+ CSpecialProtocol::TranslatePath(UTILS::FONT::FONTPATH::SYSTEM), filename);
+ if (XFILE::CFile::Exists(fontPath))
+ {
+ return CSpecialProtocol::TranslatePath(fontPath);
+ }
+
+ CLog::LogF(LOGERROR, "Could not find application system font {}", filename);
+ return "";
+}