diff --git a/headers/private/servers/app/FontManager.h b/headers/private/servers/app/FontManager.h index 4dba4d26c2..e068e25710 100644 --- a/headers/private/servers/app/FontManager.h +++ b/headers/private/servers/app/FontManager.h @@ -35,55 +35,58 @@ class FontManager : public BLooper { virtual ~FontManager(); status_t InitCheck() { return fInitStatus; } + void SaveRecentFontMappings(); virtual void MessageReceived(BMessage* message); - int32 CountFamilies() const; - int32 CountStyles(const char *family) const; + int32 CheckUpdate(uid_t user); + int32 CountFamilies(); + + int32 CountStyles(const char *family); FontFamily* FamilyAt(int32 index) const; FontFamily *GetFamily(uint16 familyID) const; - FontFamily *GetFamily(const char *name) const; + FontFamily *GetFamily(const char *name); - FontStyle *GetStyleByIndex(const char *family, int32 index) const; + FontStyle *GetStyleByIndex(const char *family, int32 index); FontStyle *GetStyle(const char *family, const char *style, uint16 familyID = 0xffff, uint16 styleID = 0xffff, uint16 face = 0); FontStyle *GetStyle(const char *family, uint16 styleID); - FontStyle *GetStyle(uint16 familyID, uint16 styleID); + FontStyle *GetStyle(uint16 familyID, uint16 styleID) const; FontStyle* FindStyleMatchingFace(uint16 face) const; - ServerFont* GetFont(const char *family, const char *style, float size); - ServerFont* GetFont(uint16 face, float size); const ServerFont* DefaultFont() const; - bool FontsNeedUpdated() { return fNeedUpdate; } - /*! - \brief Called when the fonts list has been updated - */ - void FontsUpdated() { fNeedUpdate = false; } - void AttachUser(uid_t userID); void DetachUser(uid_t userID); private: - void _SetDefaultFont(); - void _ScanSystemFonts(); + struct font_directory; + struct font_mapping; + + bool _LoadRecentFontMappings(); + status_t _SetDefaultFont(); + void _AddSystemPaths(); status_t _AddPath(const char* path); - status_t _AddPath(BEntry& entry); + status_t _AddPath(BEntry& entry, font_directory** _newDirectory = NULL); - void _RemoveFamily(const char *family); + FontFamily* _FindFamily(const char* family) const; + void _RemoveFamily(const char* family); - status_t _ScanDirectory(BEntry &entry); - void _AddFont(BPath& path); + void _ScanFontsIfNecessary(); + void _ScanFonts(); + status_t _ScanFontDirectory(font_directory& directory); + status_t _AddFont(BPath& path); FT_CharMap _GetSupportedCharmap(const FT_Face &face); private: status_t fInitStatus; - BObjectList fFontDirectories; + BObjectList fDirectories; + BObjectList fMappings; BObjectList fFamilies; ServerFont *fDefaultFont; - bool fNeedUpdate; + bool fScanned; int32 fNextID; }; diff --git a/src/servers/app/AppServer.cpp b/src/servers/app/AppServer.cpp index e851ed3f78..48f688c7aa 100644 --- a/src/servers/app/AppServer.cpp +++ b/src/servers/app/AppServer.cpp @@ -350,7 +350,7 @@ AppServer::_DispatchMessage(int32 code, BPrivate::LinkReceiver& msg) // 1) port_id reply port gFontManager->Lock(); - bool needsUpdate = gFontManager->FontsNeedUpdated(); + bool needsUpdate = false; //gFontManager->FontsNeedUpdated(); gFontManager->Unlock(); // Seeing how the client merely wants an answer, we'll skip the BPortLink diff --git a/src/servers/app/FontManager.cpp b/src/servers/app/FontManager.cpp index 5b12306ace..efe5546538 100644 --- a/src/servers/app/FontManager.cpp +++ b/src/servers/app/FontManager.cpp @@ -21,31 +21,34 @@ #include #include #include +#include #include #include #include +//#define PRINT_FONT_LIST + static FTC_Manager ftmanager; FT_Library gFreeTypeLibrary; FontManager *gFontManager = NULL; -//#define PRINT_FONT_LIST +struct FontManager::font_directory { + node_ref directory; + uid_t user; + gid_t group; + uint32 revision; + BObjectList styles; + bool AlreadyScanned() const { return revision != 0; } +}; -#if 0 -/*! - \brief Access function to request a face via the FreeType font cache -*/ -static FT_Error -face_requester(FTC_FaceID face_id, FT_Library library, - FT_Pointer request_data, FT_Face *aface) -{ - CachedFace face = (CachedFace) face_id; - return FT_New_Face(gFreeTypeLibrary, face->file_path.String(), face->face_index,aface); -} -#endif +struct FontManager::font_mapping { + BString family; + BString style; + BPath path; +}; // #pragma mark - @@ -56,17 +59,16 @@ FontManager::FontManager() : BLooper("Font Manager"), fFamilies(20), fDefaultFont(NULL), + fScanned(false), fNextID(0) { fInitStatus = FT_Init_FreeType(&gFreeTypeLibrary) == 0 ? B_OK : B_ERROR; if (fInitStatus == B_OK) { - _ScanSystemFonts(); - - if (CountFamilies() != 0) - _SetDefaultFont(); - else - fInitStatus = B_ENTRY_NOT_FOUND; + _AddSystemPaths(); + _LoadRecentFontMappings(); + + fInitStatus = _SetDefaultFont(); } /* @@ -92,7 +94,24 @@ FontManager::~FontManager() void FontManager::MessageReceived(BMessage* message) { - // nothing to do here yet + switch (message->what) { + case B_NODE_MONITOR: + // TODO: monitor fonts and update font_directories + break; + } +} + + +void +FontManager::SaveRecentFontMappings() +{ +} + + +bool +FontManager::_LoadRecentFontMappings() +{ + return false; } @@ -115,7 +134,7 @@ FontManager::_RemoveFamily(const char *familyName) \brief Sets the font that will be used when you create an empty ServerFont without specifying a style. */ -void +status_t FontManager::_SetDefaultFont() { FontStyle* style = GetStyle(DEFAULT_PLAIN_FONT_FAMILY, DEFAULT_PLAIN_FONT_STYLE); @@ -123,18 +142,24 @@ FontManager::_SetDefaultFont() style = GetStyle(FALLBACK_PLAIN_FONT_FAMILY, DEFAULT_PLAIN_FONT_STYLE); if (style == NULL) { style = FindStyleMatchingFace(B_REGULAR_FACE); - if (style == NULL) + if (style == NULL && fFamilies.CountItems() != 0) style = FamilyAt(0)->StyleAt(0); } } - fDefaultFont = new ServerFont(*style, DEFAULT_PLAIN_FONT_SIZE); + if (style == NULL) + return B_ERROR; + + fDefaultFont = new (nothrow) ServerFont(*style, DEFAULT_PLAIN_FONT_SIZE); + if (fDefaultFont == NULL) + return B_NO_MEMORY; + + return B_OK; } -//! Scans the four default system font folders void -FontManager::_ScanSystemFonts() +FontManager::_AddSystemPaths() { BPath path; if (find_directory(B_BEOS_FONTS_DIRECTORY, &path) == B_OK) @@ -148,23 +173,51 @@ FontManager::_ScanSystemFonts() } +void +FontManager::_ScanFontsIfNecessary() +{ + if (!fScanned) + _ScanFonts(); +} + + +//! Scans all currently known font directories +void +FontManager::_ScanFonts() +{ + if (fScanned) + return; + + for (int32 i = fDirectories.CountItems(); i-- > 0;) { + font_directory* directory = fDirectories.ItemAt(i); + + if (directory->AlreadyScanned()) + continue; + + _ScanFontDirectory(*directory); + } + + fScanned = true; +} + + /*! \brief Adds the FontFamily/FontStyle that is represented by this path. */ -void +status_t FontManager::_AddFont(BPath &path) { FT_Face face; FT_Error error = FT_New_Face(gFreeTypeLibrary, path.Path(), 0, &face); if (error != 0) - return; + return B_ERROR; - FontFamily *family = GetFamily(face->family_name); + FontFamily *family = _FindFamily(face->family_name); if (family != NULL && family->HasStyle(face->style_name)) { // prevent adding the same style twice // (this indicates a problem with the installed fonts maybe?) FT_Done_Face(face); - return; + return B_OK; } if (family == NULL) { @@ -173,7 +226,7 @@ FontManager::_AddFont(BPath &path) || !fFamilies.AddItem(family)) { delete family; FT_Done_Face(face); - return; + return B_NO_MEMORY; } } @@ -185,6 +238,8 @@ FontManager::_AddFont(BPath &path) FontStyle *style = new FontStyle(path.Path(), face); if (!family->AddStyle(style)) delete style; + + return B_OK; } @@ -201,18 +256,57 @@ FontManager::_AddPath(const char* path) status_t -FontManager::_AddPath(BEntry& entry) +FontManager::_AddPath(BEntry& entry, font_directory** _newDirectory) { - status_t status = _ScanDirectory(entry); + node_ref nodeRef; + status_t status = entry.GetNodeRef(&nodeRef); if (status != B_OK) return status; - node_ref nodeRef; - if (entry.GetNodeRef(&nodeRef) != B_OK) - return status; + // check if we are already know this directory - // TODO: don't add it twice! - // TODO: monitor this directory! + for (int32 i = fDirectories.CountItems(); i-- > 0;) { + font_directory* directory = fDirectories.ItemAt(i); + + if (directory->directory == nodeRef) { + if (_newDirectory) + *_newDirectory = NULL; + return B_OK; + } + } + + // it's a new one, so let's add it + + font_directory* directory = new (nothrow) font_directory; + if (directory == NULL) + return B_NO_MEMORY; + + struct stat stat; + status = entry.GetStat(&stat); + if (status != B_OK) { + delete directory; + return status; + } + + directory->directory = nodeRef; + directory->user = stat.st_uid; + directory->group = stat.st_gid; + directory->revision = 0; + + status = watch_node(&nodeRef, B_WATCH_DIRECTORY, this); + if (status != B_OK) { + // we cannot watch this directory - while this is unfortunate, + // it's not a critical error + printf("could not watch directory %ld:%Ld\n", nodeRef.device, nodeRef.node); + // TODO: should go into syslog() + } + + fDirectories.AddItem(directory); + + if (_newDirectory) + *_newDirectory = directory; + + fScanned = false; return B_OK; } @@ -222,29 +316,32 @@ FontManager::_AddPath(BEntry& entry) \param directoryPath Path of the folder to scan. */ status_t -FontManager::_ScanDirectory(BEntry& entry) +FontManager::_ScanFontDirectory(font_directory& fontDirectory) { // This bad boy does all the real work. It loads each entry in the // directory. If a valid font file, it adds both the family and the style. - // Both family and style are stored internally as BStrings. Once everything - BDirectory dir; - status_t status = dir.SetTo(&entry); + BDirectory directory; + status_t status = directory.SetTo(&fontDirectory.directory); if (status != B_OK) return status; - while (dir.GetNextEntry(&entry) == B_OK) { + BEntry entry; + while (directory.GetNextEntry(&entry) == B_OK) { + if (entry.IsDirectory()) { + // scan this directory recursively + font_directory* newDirectory; + if (_AddPath(entry, &newDirectory) == B_OK && newDirectory != NULL) + _ScanFontDirectory(*newDirectory); + + continue; + } + BPath path; status = entry.GetPath(&path); if (status < B_OK) continue; - if (entry.IsDirectory()) { - // scan this directory recursively - _AddPath(entry); - continue; - } - // TODO: Commenting this out makes my "Unicode glyph lookup" // work with our default fonts. The real fix is to select the // Unicode char map (if supported), and/or adjust the @@ -265,7 +362,7 @@ FontManager::_ScanDirectory(BEntry& entry) // takes over ownership of the FT_Face object } - fNeedUpdate = true; + fontDirectory.revision = 1; return B_OK; } @@ -315,8 +412,10 @@ FontManager::_GetSupportedCharmap(const FT_Face& face) \return The number of unique font families currently available */ int32 -FontManager::CountFamilies() const +FontManager::CountFamilies() { + _ScanFontsIfNecessary(); + return fFamilies.CountItems(); } @@ -327,8 +426,10 @@ FontManager::CountFamilies() const \return The number of font styles currently available for the font family */ int32 -FontManager::CountStyles(const char *familyName) const +FontManager::CountStyles(const char *familyName) { + _ScanFontsIfNecessary(); + FontFamily *family = GetFamily(familyName); if (family) return family->CountStyles(); @@ -344,13 +445,8 @@ FontManager::FamilyAt(int32 index) const } -/*! - \brief Locates a FontFamily object by name - \param name The family to find - \return Pointer to the specified family or NULL if not found. -*/ FontFamily* -FontManager::GetFamily(const char* name) const +FontManager::_FindFamily(const char* name) const { if (name == NULL) return NULL; @@ -367,6 +463,44 @@ FontManager::GetFamily(const char* name) const } +/*! + \brief Locates a FontFamily object by name + \param name The family to find + \return Pointer to the specified family or NULL if not found. +*/ +FontFamily* +FontManager::GetFamily(const char* name) +{ + if (name == NULL) + return NULL; + + FontFamily* family = _FindFamily(name); + if (family != NULL) + return family; + + if (fScanned) + return NULL; + + // try again + family = _FindFamily(name); + if (family != NULL) + return family; + + // try font mappings before failing + for (int32 i = 0; i < fMappings.CountItems(); i++) { + font_mapping* mapping = fMappings.ItemAt(i); + + if (mapping->family == name) { + if (_AddFont(mapping->path) == B_OK) + return _FindFamily(name); + } + } + + _ScanFonts(); + return _FindFamily(name); +} + + FontFamily* FontManager::GetFamily(uint16 familyID) const { @@ -381,7 +515,7 @@ FontManager::GetFamily(uint16 familyID) const FontStyle* -FontManager::GetStyleByIndex(const char* familyName, int32 index) const +FontManager::GetStyleByIndex(const char* familyName, int32 index) { FontFamily* family = GetFamily(familyName); if (family != NULL) @@ -439,7 +573,7 @@ FontManager::GetStyle(const char* familyName, const char* styleName, uint16 fami \return The FontStyle having those attributes or NULL if not available */ FontStyle* -FontManager::GetStyle(uint16 familyID, uint16 styleID) +FontManager::GetStyle(uint16 familyID, uint16 styleID) const { FontFamily *family = GetFamily(familyID); if (family) diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index 0a7055a515..fe52d9a101 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -1116,7 +1116,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) // received when the client-side global font list has been // refreshed gFontManager->Lock(); - gFontManager->FontsUpdated(); + //gFontManager->FontsUpdated(); gFontManager->Unlock(); break; } @@ -1130,7 +1130,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&checkonly); gFontManager->Lock(); - bool needsUpdate = gFontManager->FontsNeedUpdated(); + bool needsUpdate = false; //gFontManager->FontsNeedUpdated(); gFontManager->Unlock(); if (checkonly) {