From d0f06357f51a07fc5aedcbc3ae5822608e865bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Wed, 14 Feb 2024 16:40:20 +0100 Subject: [PATCH] app_server FontManager: load all fonts and named-variants from a file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BFont::LoadFont can now use an index (0-based) and an optional named-instance (1-based) to select the font variant from a file. BFont::LoadFont can also use an index when loading from memory. Change-Id: I0ce3eb6cc77d32cf43847416561eafe3063ca693 Reviewed-on: https://review.haiku-os.org/c/haiku/+/7402 Reviewed-by: Jérôme Duval Reviewed-by: Máximo Castañeda Tested-by: Commit checker robot --- headers/os/interface/Font.h | 3 ++ src/kits/interface/Font.cpp | 17 ++++++++ src/servers/app/ServerApp.cpp | 12 +++++- src/servers/app/ServerFont.h | 2 + src/servers/app/font/AppFontManager.cpp | 9 ++--- src/servers/app/font/AppFontManager.h | 6 +-- src/servers/app/font/FontCacheEntry.cpp | 4 +- src/servers/app/font/GlobalFontManager.cpp | 45 ++++++++++++++++------ 8 files changed, 74 insertions(+), 24 deletions(-) diff --git a/headers/os/interface/Font.h b/headers/os/interface/Font.h index ed93e75d02..5aa2bbd8b8 100644 --- a/headers/os/interface/Font.h +++ b/headers/os/interface/Font.h @@ -283,8 +283,11 @@ public: void PrintToStream() const; status_t LoadFont(const char* path); + status_t LoadFont(const char* path, uint16 index, uint16 instance); status_t LoadFont(const area_id fontAreaID, size_t size = 0, size_t offset = 0); + status_t LoadFont(const area_id fontAreaID, + size_t size = 0, size_t offset = 0, uint16 index = 0); status_t UnloadFont(); private: diff --git a/src/kits/interface/Font.cpp b/src/kits/interface/Font.cpp index 4553a2ee2c..ac279ec127 100644 --- a/src/kits/interface/Font.cpp +++ b/src/kits/interface/Font.cpp @@ -1458,10 +1458,19 @@ BFont::_GetExtraFlags() const status_t BFont::LoadFont(const char* path) +{ + return LoadFont(path, 0, 0); +} + + +status_t +BFont::LoadFont(const char* path, uint16 index, uint16 instance) { BPrivate::AppServerLink link; link.StartMessage(AS_ADD_FONT_FILE); link.AttachString(path); + link.Attach(index); + link.Attach(instance); status_t status = B_ERROR; if (link.FlushWithReply(status) != B_OK || status != B_OK) { return status; @@ -1479,6 +1488,13 @@ BFont::LoadFont(const char* path) status_t BFont::LoadFont(const area_id fontAreaID, size_t size, size_t offset) +{ + return LoadFont(fontAreaID, size, offset, 0); +} + + +status_t +BFont::LoadFont(const area_id fontAreaID, size_t size, size_t offset, uint16 index) { BPrivate::AppServerLink link; @@ -1487,6 +1503,7 @@ BFont::LoadFont(const area_id fontAreaID, size_t size, size_t offset) link.Attach(fontAreaID); link.Attach(size); link.Attach(offset); + link.Attach(index); status_t status = B_ERROR; if (link.FlushWithReply(status) != B_OK || status != B_OK) { diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index dbbb74f2ee..b3a1ae0ecb 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -1581,6 +1581,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) // Attached Data: // 1) char* - path to font on disk + // 2) uint16 - index in font file + // 3) uint16 - instance // Returns: // 1) uint16 - family ID of added font @@ -1597,9 +1599,12 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) uint16 familyID, styleID; char* fontPath; + uint16 index, instance; link.ReadString(&fontPath); + link.Read(&index); + link.Read(&instance); - status_t status = fAppFontManager->AddUserFontFromFile(fontPath, + status_t status = fAppFontManager->AddUserFontFromFile(fontPath, index, instance, familyID, styleID); if (status != B_OK) { @@ -1632,6 +1637,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) // 1) area_id - id of memory area where font resides // 2) size_t - size of memory area for font // 3) size_t - offset to start of font memory + // 4) uint16 - index in font buffer // Returns: // 1) uint16 - family ID of added font @@ -1650,10 +1656,12 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) area_info fontAreaInfo; char* area_addr; size_t size, offset; + uint16 index; link.Read(&fontAreaID); link.Read(&size); link.Read(&offset); + link.Read(&index); fontAreaCloneID = clone_area("user font", (void **)&area_addr, B_ANY_ADDRESS, @@ -1702,7 +1710,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) uint16 familyID, styleID; - status = fAppFontManager->AddUserFontFromMemory(fontData, size, + status = fAppFontManager->AddUserFontFromMemory(fontData, size, index, familyID, styleID); if (status != B_OK) { diff --git a/src/servers/app/ServerFont.h b/src/servers/app/ServerFont.h index d6a007a4ae..0d36e79eb1 100644 --- a/src/servers/app/ServerFont.h +++ b/src/servers/app/ServerFont.h @@ -68,6 +68,8 @@ class ServerFont { const char* Family() const; const char* Path() const { return fStyle->Path(); } + long FaceIndex() const + { return fStyle->FreeTypeFace()->face_index; } void SetStyle(FontStyle* style); status_t SetFamilyAndStyle(uint16 familyID, diff --git a/src/servers/app/font/AppFontManager.cpp b/src/servers/app/font/AppFontManager.cpp index 9515884258..a61b1a91c5 100644 --- a/src/servers/app/font/AppFontManager.cpp +++ b/src/servers/app/font/AppFontManager.cpp @@ -50,7 +50,7 @@ AppFontManager::AppFontManager() /*! \brief Adds the FontFamily/FontStyle that is represented by this path. */ status_t -AppFontManager::AddUserFontFromFile(const char* path, +AppFontManager::AddUserFontFromFile(const char* path, uint16 index, uint16 instance, uint16& familyID, uint16& styleID) { ASSERT(IsLocked()); @@ -66,12 +66,11 @@ AppFontManager::AddUserFontFromFile(const char* path, return status; FT_Face face; - FT_Error error = FT_New_Face(gFreeTypeLibrary, path, 0, &face); + FT_Error error = FT_New_Face(gFreeTypeLibrary, path, index | (instance << 16), &face); if (error != 0) return B_ERROR; status = _AddFont(face, nodeRef, path, familyID, styleID); - return status; } @@ -79,7 +78,7 @@ AppFontManager::AddUserFontFromFile(const char* path, /*! \brief Adds the FontFamily/FontStyle that is represented by the area in memory. */ status_t -AppFontManager::AddUserFontFromMemory(const FT_Byte* fontAddress, size_t size, +AppFontManager::AddUserFontFromMemory(const FT_Byte* fontAddress, size_t size, uint16 index, uint16& familyID, uint16& styleID) { ASSERT(IsLocked()); @@ -88,7 +87,7 @@ AppFontManager::AddUserFontFromMemory(const FT_Byte* fontAddress, size_t size, status_t status; FT_Face face; - FT_Error error = FT_New_Memory_Face(gFreeTypeLibrary, fontAddress, size, 0, + FT_Error error = FT_New_Memory_Face(gFreeTypeLibrary, fontAddress, size, index, &face); if (error != 0) return B_ERROR; diff --git a/src/servers/app/font/AppFontManager.h b/src/servers/app/font/AppFontManager.h index eb2b0fa140..af7a464158 100644 --- a/src/servers/app/font/AppFontManager.h +++ b/src/servers/app/font/AppFontManager.h @@ -37,10 +37,10 @@ public: void Unlock() { BLocker::Unlock(); } bool IsLocked() const { return BLocker::IsLocked(); } - status_t AddUserFontFromFile(const char* path, + status_t AddUserFontFromFile(const char* path, uint16 index, uint16 instance, uint16& familyID, uint16& styleID); - status_t AddUserFontFromMemory(const FT_Byte* fontAddress, - size_t size, uint16& familyID, uint16& styleID); + status_t AddUserFontFromMemory(const FT_Byte* fontAddress, size_t size, + uint16 index, uint16& familyID, uint16& styleID); status_t RemoveUserFont(uint16 familyID, uint16 styleID); private: diff --git a/src/servers/app/font/FontCacheEntry.cpp b/src/servers/app/font/FontCacheEntry.cpp index 2748b9736d..c13d062212 100644 --- a/src/servers/app/font/FontCacheEntry.cpp +++ b/src/servers/app/font/FontCacheEntry.cpp @@ -160,10 +160,10 @@ FontCacheEntry::Init(const ServerFont& font, bool forceVector) bool success; if (font.FontData() != NULL) - success = fEngine.Init(NULL, 0, font.Size(), charMap, + success = fEngine.Init(NULL, font.FaceIndex(), font.Size(), charMap, renderingType, hinting, (const void*)font.FontData(), font.FontDataSize()); else - success = fEngine.Init(font.Path(), 0, font.Size(), charMap, + success = fEngine.Init(font.Path(), font.FaceIndex(), font.Size(), charMap, renderingType, hinting); if (!success) { diff --git a/src/servers/app/font/GlobalFontManager.cpp b/src/servers/app/font/GlobalFontManager.cpp index 922eb48abd..8f0d504ea6 100644 --- a/src/servers/app/font/GlobalFontManager.cpp +++ b/src/servers/app/font/GlobalFontManager.cpp @@ -239,8 +239,8 @@ GlobalFontManager::MessageReceived(BMessage* message) if (fromDirectory != NULL) { // find style in source and move it to the target nodeRef.node = node; - FontStyle* style = fromDirectory->FindStyle(nodeRef); - if (style != NULL) { + FontStyle* style; + while ((style = fromDirectory->FindStyle(nodeRef)) != NULL) { fromDirectory->styles.RemoveItem(style, false); directory->styles.AddItem(style); style->UpdatePath(directory->directory); @@ -505,8 +505,8 @@ GlobalFontManager::_RemoveStyle(dev_t device, uint64 directoryNode, uint64 node) if (directory != NULL) { // find style in directory and remove it nodeRef.node = node; - FontStyle* style = directory->FindStyle(nodeRef); - if (style != NULL) + FontStyle* style; + while ((style = directory->FindStyle(nodeRef)) != NULL) _RemoveStyle(*directory, style); } } @@ -711,18 +711,39 @@ GlobalFontManager::_AddFont(font_directory& directory, BEntry& entry) return status; FT_Face face; - FT_Error error = FT_New_Face(gFreeTypeLibrary, path.Path(), 0, &face); + FT_Error error = FT_New_Face(gFreeTypeLibrary, path.Path(), -1, &face); if (error != 0) return B_ERROR; + FT_Long count = face->num_faces; + FT_Done_Face(face); - uint16 familyID, styleID; - status = FontManager::_AddFont(face, nodeRef, path.Path(), familyID, styleID); - if (status == B_NAME_IN_USE) - return B_OK; - if (status < B_OK) - return status; + for (FT_Long i = 0; i < count; i++) { + FT_Error error = FT_New_Face(gFreeTypeLibrary, path.Path(), -(i + 1), &face); + if (error != 0) + return B_ERROR; + uint32 variableCount = (face->style_flags & 0x7fff0000) >> 16; + FT_Done_Face(face); - directory.styles.AddItem(GetStyle(familyID, styleID)); + uint32 j = variableCount == 0 ? 0 : 1; + do { + FT_Long faceIndex = i | (j << 16); + error = FT_New_Face(gFreeTypeLibrary, path.Path(), faceIndex, &face); + if (error != 0) + return B_ERROR; + + uint16 familyID, styleID; + status = FontManager::_AddFont(face, nodeRef, path.Path(), familyID, styleID); + if (status == B_NAME_IN_USE) { + status = B_OK; + j++; + continue; + } + if (status < B_OK) + return status; + directory.styles.AddItem(GetStyle(familyID, styleID)); + j++; + } while (j <= variableCount); + } if (directory.AlreadyScanned()) directory.revision++;