infinipaint/src/FontData.cpp

140 lines
5.9 KiB
C++

/*
* InfiniPaint
* Copyright (C) 2025-2026 Yousef Khadadeh
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "FontData.hpp"
#include <include/ports/SkFontMgr_empty.h>
#include <include/core/SkFontMetrics.h>
#include <include/core/SkTextBlob.h>
#include <iostream>
#ifdef __EMSCRIPTEN__
#include <include/ports/SkFontMgr_directory.h>
#elif __ANDROID__
#include <include/ports/SkFontScanner_FreeType.h>
#include <include/ports/SkFontMgr_data.h>
#include <include/ports/SkFontMgr_android_ndk.h>
#include <SDL3/SDL_filesystem.h>
#include <Helpers/StringHelpers.hpp>
#elif __APPLE__
#include <include/ports/SkFontMgr_mac_ct.h>
#include <ApplicationServices/ApplicationServices.h>
#elif _WIN32
#include <include/ports/SkTypeface_win.h>
#include "WindowsFontData/CustomFontSetManager.h"
DWriteCustomFontSets::CustomFontSetManager fontSetManagerWindows;
#else
#include <include/ports/SkFontMgr_fontconfig.h>
#include <include/ports/SkFontScanner_FreeType.h>
#include <include/ports/SkFontMgr_directory.h>
#endif
#include <src/base/SkUTF.h>
#include <filesystem>
FontData::FontData()
{
#ifdef __EMSCRIPTEN__
defaultFontMgr = SkFontMgr_New_Custom_Directory("data/fonts");
#elif __ANDROID__
{
std::vector<sk_sp<SkData>> fontFiles;
int globCount;
std::filesystem::path fontFolderPath("data/fonts");
char** filesInPath = SDL_GlobDirectory(fontFolderPath.c_str(), nullptr, 0, &globCount);
if(filesInPath) {
for(int i = 0; i < globCount; i++) {
std::filesystem::path filePath = fontFolderPath / std::filesystem::path(filesInPath[i]);
SDL_PathInfo fileInfo;
if(SDL_GetPathInfo(filePath.c_str(), &fileInfo) && fileInfo.type == SDL_PATHTYPE_FILE) {
std::string strData = read_file_to_string(filePath);
fontFiles.emplace_back(SkData::MakeWithCopy(strData.data(), strData.size()));
}
}
SDL_free(filesInPath);
defaultFontMgr = SkFontMgr_New_Custom_Data(SkSpan(fontFiles.data(), fontFiles.size()));
}
}
localFontMgr = SkFontMgr_New_AndroidNDK(true, SkFontScanner_Make_FreeType());
#elif __APPLE__
for(const auto& dirEntry : std::filesystem::recursive_directory_iterator("data/fonts")) {
if(dirEntry.is_regular_file()) {
std::string urlStr = std::string(std::filesystem::canonical(dirEntry.path()).string());
CFURLRef fontURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(urlStr.c_str()), urlStr.size(), false);
CTFontManagerRegisterFontsForURL(fontURL, CTFontManagerScope::kCTFontManagerScopeProcess, nullptr);
CFRelease(fontURL);
}
}
defaultFontMgr = SkFontMgr_New_CoreText(nullptr);
#elif _WIN32
localFontMgr = SkFontMgr_New_DirectWrite();
std::vector<std::wstring> fontPaths;
for(const auto& dirEntry : std::filesystem::recursive_directory_iterator(std::filesystem::path(L"data\\fonts"))) {
if(dirEntry.is_regular_file())
fontPaths.emplace_back(dirEntry.path().wstring());
}
fontSetManagerWindows.CreateFontSetUsingLocalFontFiles(fontPaths);
fontSetManagerWindows.CreateFontCollectionFromFontSet();
IDWriteFactory* fac = fontSetManagerWindows.IDWriteFactory5_IsAvailable() ? fontSetManagerWindows.m_dwriteFactory5.Get() : fontSetManagerWindows.m_dwriteFactory3.Get();
defaultFontMgr = SkFontMgr_New_DirectWrite(fac, fontSetManagerWindows.m_customFontCollection.Get());
#else
localFontMgr = SkFontMgr_New_FontConfig(nullptr, SkFontScanner_Make_FreeType());
defaultFontMgr = SkFontMgr_New_Custom_Directory("data/fonts");
#endif
map["Roboto"] = defaultFontMgr->makeFromFile("data/fonts/Roboto-variable.ttf");
collection = sk_make_sp<skia::textlayout::FontCollection>();
collection->setDefaultFontManager(defaultFontMgr, std::vector<SkString>{SkString{"Roboto"}, SkString{"Noto Emoji"}, SkString{"Amiri"}});
if(localFontMgr)
collection->setDynamicFontManager(localFontMgr);
std::string s = "🙂";
const char* sPtr = s.data();
SkFontStyle defaultStyle;
SkString defaultLocale("en");
auto defaultEmojiFallback = collection->defaultEmojiFallback(SkUTF::NextUTF8(&sPtr, s.c_str() + s.length()), defaultStyle, defaultLocale);
fallbackOnEmoji = !defaultEmojiFallback;
}
const std::vector<SkString>& FontData::get_default_font_families() const {
static std::vector<SkString> defaultFontFamilies;
if(defaultFontFamilies.empty()) {
defaultFontFamilies.emplace_back("Roboto");
if(fallbackOnEmoji)
defaultFontFamilies.emplace_back("Noto Emoji");
defaultFontFamilies.emplace_back("Amiri");
}
return defaultFontFamilies;
}
void FontData::push_default_font_families(std::vector<SkString>& fontFamilies) const {
fontFamilies.emplace_back("Roboto");
if(fallbackOnEmoji)
fontFamilies.emplace_back("Noto Emoji");
fontFamilies.emplace_back("Amiri");
}
FontData::~FontData() {
}
Vector2f get_str_font_bounds(const SkFont& font, const std::string& str) {
SkFontMetrics metrics;
font.getMetrics(&metrics);
float nextText = font.measureText(str.data(), str.length(), SkTextEncoding::kUTF8, nullptr);
return Vector2f{nextText, - metrics.fAscent + metrics.fDescent};
}