#include "FontFamily.h" #include "FontManager.h" #include "FontRenderer.h" #include "IGpFont.h" #include "IGpFontHandler.h" #include "GpAppInterface.h" #include "GpDriverIndex.h" #include "GpFontHandlerProperties.h" #include "GpFileSystem_Win32.h" #include "GpSystemServices_Win32.h" #include "CFileStream.h" #include "PLDrivers.h" #include "RenderedFont.h" #include "RenderedFontCatalog.h" #include "WindowsUnicodeToolShim.h" extern "C" __declspec(dllimport) IGpFontHandler *GpDriver_CreateFontHandler_FreeType2(const GpFontHandlerProperties &properties); class MemBufferStream final : public GpIOStream { public: size_t Read(void *bytesOut, size_t size) override; size_t Write(const void *bytes, size_t size) override; bool IsSeekable() const override; bool IsReadOnly() const override; bool IsWriteOnly() const override; bool SeekStart(GpUFilePos_t loc) override; bool SeekCurrent(GpFilePos_t loc) override; bool SeekEnd(GpUFilePos_t loc) override; GpUFilePos_t Size() const override; GpUFilePos_t Tell() const override; void Close() override; void Flush() override; const uint8_t *GetBytes() const; private: size_t m_writeOffset; std::vector m_buffer; }; size_t MemBufferStream::Read(void *bytesOut, size_t size) { return 0; } size_t MemBufferStream::Write(const void *bytes, size_t size) { const uint8_t *bytesUInt8 = static_cast(bytes); for (size_t i = 0; i < size; i++) { if (m_writeOffset == m_buffer.size()) m_buffer.push_back(bytesUInt8[i]); else m_buffer[m_writeOffset] = bytesUInt8[i]; m_writeOffset++; } return size; } bool MemBufferStream::IsSeekable() const { return true; } bool MemBufferStream::IsReadOnly() const { return false; } bool MemBufferStream::IsWriteOnly() const { return true; } bool MemBufferStream::SeekStart(GpUFilePos_t loc) { m_writeOffset = static_cast(loc); return true; } bool MemBufferStream::SeekCurrent(GpFilePos_t loc) { m_writeOffset = static_cast(static_cast(m_writeOffset) + loc); return true; } bool MemBufferStream::SeekEnd(GpUFilePos_t loc) { m_writeOffset = this->Size() - loc; return true; } GpUFilePos_t MemBufferStream::Size() const { return m_buffer.size(); } GpUFilePos_t MemBufferStream::Tell() const { return m_writeOffset; } void MemBufferStream::Close() { } void MemBufferStream::Flush() { } const uint8_t *MemBufferStream::GetBytes() const { return &m_buffer[0]; } struct KnownFontSpec { public: KnownFontSpec(); KnownFontSpec(const char *path, int size, bool aa, PortabilityLayer::FontHacks hacks); bool operator==(const KnownFontSpec &other) const; bool operator!=(const KnownFontSpec &other) const; private: std::string m_path; int m_size; bool m_aa; PortabilityLayer::FontHacks m_hacks; }; KnownFontSpec::KnownFontSpec() : m_size(0) , m_aa(false) , m_hacks(PortabilityLayer::FontHacks_None) { } KnownFontSpec::KnownFontSpec(const char *path, int size, bool aa, PortabilityLayer::FontHacks hacks) : m_path(path) , m_size(size) , m_aa(aa) , m_hacks(hacks) { } bool KnownFontSpec::operator==(const KnownFontSpec &other) const { return !((*this) != other); } bool KnownFontSpec::operator!=(const KnownFontSpec &other) const { return m_path != other.m_path || m_size != other.m_size || m_aa != other.m_aa || m_hacks != other.m_hacks; } int toolMain(int argc, const char **argv) { GpFontHandlerProperties fhProperties; fhProperties.m_type = EGpFontHandlerType_FreeType2; IGpFontHandler *ft2Handler = GpDriver_CreateFontHandler_FreeType2(fhProperties); PortabilityLayer::FontManager *fontManager = PortabilityLayer::FontManager::GetInstance(); PortabilityLayer::FontRenderer *fontRenderer = PortabilityLayer::FontRenderer::GetInstance(); fontManager->Init(); std::vector paths; std::vector catalog; std::vector fontSpecs; FILE *manifestF = fopen_utf8("Packaged/FontCacheManifest.json", "wb"); fprintf(manifestF, "{\n"); fprintf(manifestF, "\t\"add\" :\n"); fprintf(manifestF, "\t{\n"); fprintf(manifestF, "\t\t\"RFCT/1000.bin\" : \"Packaged/FontCacheCatalog.bin\""); int numFontsEmitted = 0; for (int presetIndex = 0; presetIndex < PortabilityLayer::FontPresets::kCount; presetIndex++) { int size = 0; int flags = 0; bool aa = false; PortabilityLayer::FontFamilyID_t fontFamilyID; fontManager->GetFontPreset(static_cast(presetIndex), &fontFamilyID, &size, &flags, &aa); PortabilityLayer::FontFamily *fontFamily = fontManager->GetFont(fontFamilyID); int variation = fontFamily->GetVariationForFlags(flags); PortabilityLayer::FontHacks hacks; PortabilityLayer::VirtualDirectory_t vDir; const char *path = nullptr; int typeFaceIndex = 0; fontFamily->GetFontSpec(variation, hacks, vDir, path, typeFaceIndex); KnownFontSpec spec(path, size, aa, hacks); if (std::find(fontSpecs.begin(), fontSpecs.end(), spec) != fontSpecs.end()) continue; fontSpecs.push_back(spec); std::string resPath = std::string("Resources/") + path; FILE *fontFile = fopen_utf8(resPath.c_str(), "rb"); if (fontFile) { PortabilityLayer::CFileStream stream(fontFile); IGpFont *font = ft2Handler->LoadFont(&stream, typeFaceIndex); if (!ft2Handler->KeepStreamOpen()) stream.Close(); PortabilityLayer::RenderedFont *rfont = fontRenderer->RenderFont(font, size, aa, hacks); { char fontPath[1024]; sprintf(fontPath, "Packaged/CachedFont%i.bin", numFontsEmitted); FILE *cachedFontF = fopen_utf8(fontPath, "wb"); PortabilityLayer::CFileStream cacheStream(cachedFontF); fontRenderer->SaveCache(rfont, &cacheStream); cacheStream.Close(); fprintf(manifestF, ",\n\t\t\"RFNT/%i.bin\" : \"%s\"", 1000 + numFontsEmitted, fontPath); } rfont->Destroy(); font->Destroy(); PortabilityLayer::RenderedFontCatalogRFontEntry catEntry; catEntry.m_fontSize = static_cast(size); catEntry.m_hacks = static_cast(hacks); catEntry.m_isAA = aa ? 1 : 0; catEntry.m_pathIndex = 0; bool foundPath = false; for (size_t i = 0; i < paths.size(); i++) { if (paths[i] == path) { catEntry.m_pathIndex = static_cast(i); foundPath = true; break; } } if (!foundPath) { catEntry.m_pathIndex = static_cast(paths.size()); paths.push_back(std::string(path)); } catalog.push_back(catEntry); numFontsEmitted++; } } fprintf(manifestF, "\n\t},\n"); fprintf(manifestF, "\t\"delete\" :\n"); fprintf(manifestF, "\t[\n"); fprintf(manifestF, "\t]\n"); fprintf(manifestF, "}\n"); PortabilityLayer::RenderedFontCatalogHeader catHeader; FILE *catF = fopen_utf8("Packaged/FontCacheCatalog.bin", "wb"); catHeader.m_version = PortabilityLayer::RenderedFontCatalogHeader::kVersion; catHeader.m_pathsOffset = static_cast(sizeof(PortabilityLayer::RenderedFontCatalogHeader) + paths.size() * sizeof(PortabilityLayer::RenderedFontCatalogPathEntry) + numFontsEmitted * sizeof(PortabilityLayer::RenderedFontCatalogRFontEntry)); catHeader.m_numPaths = static_cast(paths.size()); catHeader.m_numRFonts = static_cast(numFontsEmitted); fwrite(&catHeader, sizeof(catHeader), 1, catF); PortabilityLayer::RenderedFontCatalogPathEntry pathEntry; pathEntry.m_pathOffset = 0; pathEntry.m_pathSize = 0; for (size_t i = 0; i < paths.size(); i++) { pathEntry.m_pathOffset = static_cast(pathEntry.m_pathOffset) + pathEntry.m_pathSize; pathEntry.m_pathSize = static_cast(paths[i].size()); fwrite(&pathEntry, sizeof(pathEntry), 1, catF); } fwrite(&catalog[0], sizeof(PortabilityLayer::RenderedFontCatalogRFontEntry), catalog.size(), catF); for (size_t i = 0; i < paths.size(); i++) { const std::string &str = paths[i]; fwrite(&str[0], str.size(), 1, catF); } fclose(catF); return 0; }