First steps into on-demand font scanning. When you've installed lots of fonts, this

will speed up launching the app_server considerably (once it's done).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14720 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-11-06 18:58:09 +00:00
parent ac4f06c5c6
commit 86ad4b9c5e
4 changed files with 220 additions and 83 deletions
+24 -21
View File
@@ -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<node_ref> fFontDirectories;
BObjectList<font_directory> fDirectories;
BObjectList<font_mapping> fMappings;
BObjectList<FontFamily> fFamilies;
ServerFont *fDefaultFont;
bool fNeedUpdate;
bool fScanned;
int32 fNextID;
};
+1 -1
View File
@@ -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
+193 -59
View File
@@ -21,31 +21,34 @@
#include <File.h>
#include <FindDirectory.h>
#include <Message.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <String.h>
#include <new>
//#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<FontStyle> 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)
+2 -2
View File
@@ -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<bool>(&checkonly);
gFontManager->Lock();
bool needsUpdate = gFontManager->FontsNeedUpdated();
bool needsUpdate = false; //gFontManager->FontsNeedUpdated();
gFontManager->Unlock();
if (checkonly) {