Even more font stuff:

* the node monitor is now working - fonts can only be added yet, though
* deleting a FontFamily did not work before, as the last style to be
  removed tried to delete the family again.
* "luckily", FontFamilies and FontStyles were not deleted at all before.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14824 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2005-11-10 14:52:26 +00:00
parent 174b20a89a
commit 2522a90fd1
4 changed files with 260 additions and 47 deletions
+11 -6
View File
@@ -10,11 +10,12 @@
#define FONT_FAMILY_H_ #define FONT_FAMILY_H_
#include <String.h>
#include <Rect.h>
#include <Font.h> #include <Font.h>
#include <ObjectList.h>
#include <Locker.h> #include <Locker.h>
#include <Node.h>
#include <ObjectList.h>
#include <Rect.h>
#include <String.h>
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
@@ -22,6 +23,7 @@
#include "HashTable.h" #include "HashTable.h"
struct node_ref;
class FontFamily; class FontFamily;
class ServerFont; class ServerFont;
@@ -66,12 +68,14 @@ class FontKey : public Hashable {
*/ */
class FontStyle : public SharedObject, public Hashable, public BLocker { class FontStyle : public SharedObject, public Hashable, public BLocker {
public: public:
FontStyle(const char* path, FT_Face face); FontStyle(node_ref& nodeRef, const char* path, FT_Face face);
virtual ~FontStyle(); virtual ~FontStyle();
virtual uint32 Hash() const; virtual uint32 Hash() const;
virtual bool CompareTo(Hashable& other) const; virtual bool CompareTo(Hashable& other) const;
const node_ref& NodeRef() const { return fNodeRef; }
/*! /*!
\fn bool FontStyle::IsFixedWidth(void) \fn bool FontStyle::IsFixedWidth(void)
\brief Determines whether the font's character width is fixed \brief Determines whether the font's character width is fixed
@@ -159,6 +163,7 @@ class FontStyle : public SharedObject, public Hashable, public BLocker {
FT_Face fFreeTypeFace; FT_Face fFreeTypeFace;
BString fName; BString fName;
BString fPath; BString fPath;
node_ref fNodeRef;
FontFamily* fFamily; FontFamily* fFamily;
uint16 fID; uint16 fID;
@@ -184,8 +189,8 @@ class FontFamily {
const char* Name() const; const char* Name() const;
bool AddStyle(FontStyle* style); bool AddStyle(FontStyle* style);
bool RemoveStyle(const char* style); bool RemoveStyle(const char* style, bool deleteSelfIfEmpty = true);
bool RemoveStyle(FontStyle* style); bool RemoveStyle(FontStyle* style, bool deleteSelfIfEmpty = true);
FontStyle* GetStyle(const char* style) const; FontStyle* GetStyle(const char* style) const;
FontStyle* GetStyleMatchingFace(uint16 face) const; FontStyle* GetStyleMatchingFace(uint16 face) const;
+3 -1
View File
@@ -73,6 +73,8 @@ class FontManager : public BLooper {
uint16 fallbackFace); uint16 fallbackFace);
status_t _SetDefaultFonts(); status_t _SetDefaultFonts();
void _AddSystemPaths(); void _AddSystemPaths();
font_directory* _FindDirectory(node_ref& nodeRef);
void _RemoveDirectory(font_directory* directory);
status_t _AddPath(const char* path); status_t _AddPath(const char* path);
status_t _AddPath(BEntry& entry, font_directory** _newDirectory = NULL); status_t _AddPath(BEntry& entry, font_directory** _newDirectory = NULL);
@@ -82,7 +84,7 @@ class FontManager : public BLooper {
void _ScanFontsIfNecessary(); void _ScanFontsIfNecessary();
void _ScanFonts(); void _ScanFonts();
status_t _ScanFontDirectory(font_directory& directory); status_t _ScanFontDirectory(font_directory& directory);
status_t _AddFont(BPath& path); status_t _AddFont(font_directory& directory, BEntry& entry);
FT_CharMap _GetSupportedCharmap(const FT_Face &face); FT_CharMap _GetSupportedCharmap(const FT_Face &face);
+12 -8
View File
@@ -27,11 +27,12 @@ const uint32 kInvalidFamilyFlags = ~0UL;
\param filepath path to a font file \param filepath path to a font file
\param face FreeType handle for the font file after it is loaded - it will be kept open until the FontStyle is destroied \param face FreeType handle for the font file after it is loaded - it will be kept open until the FontStyle is destroied
*/ */
FontStyle::FontStyle(const char *path, FT_Face face) FontStyle::FontStyle(node_ref& nodeRef, const char* path, FT_Face face)
: BLocker(BString("FontStyle_").Append(face->style_name).String()), : BLocker(BString("FontStyle_").Append(face->style_name).String()),
fFreeTypeFace(face), fFreeTypeFace(face),
fName(face->style_name), fName(face->style_name),
fPath(path), fPath(path),
fNodeRef(nodeRef),
fFamily(NULL), fFamily(NULL),
fID(0), fID(0),
fBounds(0, 0, 0, 0), fBounds(0, 0, 0, 0),
@@ -55,7 +56,7 @@ FontStyle::~FontStyle()
{ {
// make sure the font server is ours // make sure the font server is ours
if (fFamily != NULL && gFontManager->Lock()) { if (fFamily != NULL && gFontManager->Lock()) {
fFamily->RemoveStyle(this); fFamily->RemoveStyle(this, false);
gFontManager->Unlock(); gFontManager->Unlock();
} }
@@ -231,6 +232,7 @@ FontFamily::FontFamily(const char *name, uint16 id)
// make sure this family can be found using the Be API // make sure this family can be found using the Be API
} }
/*! /*!
\brief Destructor \brief Destructor
@@ -240,8 +242,8 @@ FontFamily::FontFamily(const char *name, uint16 id)
*/ */
FontFamily::~FontFamily() FontFamily::~FontFamily()
{ {
int32 count = fStyles.CountItems(); // styles are removing itself when deleted
for (int32 i = 0; i < count; i++) for (int32 i = fStyles.CountItems(); i-- > 0;)
delete fStyles.ItemAt(i); delete fStyles.ItemAt(i);
} }
@@ -286,11 +288,11 @@ FontFamily::AddStyle(FontStyle *style)
bool bool
FontFamily::RemoveStyle(const char* styleName) FontFamily::RemoveStyle(const char* styleName, bool deleteSelfIfEmpty)
{ {
FontStyle *style = GetStyle(styleName); FontStyle *style = GetStyle(styleName);
if (style != NULL) if (style != NULL)
return RemoveStyle(style); return RemoveStyle(style, deleteSelfIfEmpty);
return false; return false;
} }
@@ -306,7 +308,7 @@ FontFamily::RemoveStyle(const char* styleName)
\param style The style to be removed from the family \param style The style to be removed from the family
*/ */
bool bool
FontFamily::RemoveStyle(FontStyle* style) FontFamily::RemoveStyle(FontStyle* style, bool deleteSelfIfEmpty)
{ {
if (!gFontManager->IsLocked()) { if (!gFontManager->IsLocked()) {
debugger("FontFamily::RemoveStyle() called without having the font manager locked!"); debugger("FontFamily::RemoveStyle() called without having the font manager locked!");
@@ -319,7 +321,9 @@ FontFamily::RemoveStyle(FontStyle* style)
// force a refresh if a request for font flags is needed // force a refresh if a request for font flags is needed
fFlags = kInvalidFamilyFlags; fFlags = kInvalidFamilyFlags;
if (CountStyles() == 0) style->_SetFontFamily(NULL, -1);
if (deleteSelfIfEmpty && CountStyles() == 0)
delete this; delete this;
return true; return true;
+231 -29
View File
@@ -27,8 +27,16 @@
#include <new> #include <new>
//#define PRINT_FONT_LIST
//#define TRACE_WATCHING
#ifdef TRACE_WATCHING
# define WTRACE(x) printf x
#else
# define WTRACE(x) ;
#endif
// TODO: needs some more work for multi-user support
static FTC_Manager ftmanager; static FTC_Manager ftmanager;
FT_Library gFreeTypeLibrary; FT_Library gFreeTypeLibrary;
@@ -42,21 +50,53 @@ struct FontManager::font_directory {
BObjectList<FontStyle> styles; BObjectList<FontStyle> styles;
bool AlreadyScanned() const { return revision != 0; } bool AlreadyScanned() const { return revision != 0; }
FontStyle* FindStyle(const node_ref& nodeRef) const;
}; };
struct FontManager::font_mapping { struct FontManager::font_mapping {
BString family; BString family;
BString style; BString style;
BPath path; entry_ref ref;
}; };
FontStyle*
FontManager::font_directory::FindStyle(const node_ref& nodeRef) const
{
for (int32 i = styles.CountItems(); i-- > 0;) {
FontStyle* style = styles.ItemAt(i);
if (nodeRef == style->NodeRef())
return style;
}
return NULL;
}
static status_t
set_entry(node_ref& nodeRef, const char* name, BEntry& entry)
{
entry_ref ref;
ref.device = nodeRef.device;
ref.directory = nodeRef.node;
status_t status = ref.set_name(name);
if (status != B_OK)
return status;
return entry.SetTo(&ref);
}
// #pragma mark - // #pragma mark -
//! Does basic set up so that directories can be scanned //! Does basic set up so that directories can be scanned
FontManager::FontManager() FontManager::FontManager()
: BLooper("Font Manager"), : BLooper("Font Manager"),
fDirectories(10, true),
fMappings(10, true),
fFamilies(20), fFamilies(20),
fScanned(false), fScanned(false),
fNextID(0) fNextID(0)
@@ -85,12 +125,14 @@ FontManager::FontManager()
//! Frees items allocated in the constructor and shuts down FreeType //! Frees items allocated in the constructor and shuts down FreeType
FontManager::~FontManager() FontManager::~FontManager()
{ {
// free families before we're done with FreeType
for (int32 i = fFamilies.CountItems(); i-- > 0;) {
delete fFamilies.ItemAt(i);
}
FTC_Manager_Done(ftmanager); FTC_Manager_Done(ftmanager);
FT_Done_FreeType(gFreeTypeLibrary); FT_Done_FreeType(gFreeTypeLibrary);
// we need to make sure the hash table doesn't delete the font styles;
// that's already done by the lists
fStyleHashTable.MakeEmpty(false);
} }
@@ -99,8 +141,118 @@ FontManager::MessageReceived(BMessage* message)
{ {
switch (message->what) { switch (message->what) {
case B_NODE_MONITOR: case B_NODE_MONITOR:
// TODO: monitor fonts and update font_directories {
// TODO: support removing fonts!
int32 opcode;
if (message->FindInt32("opcode", &opcode) != B_OK)
return;
switch (opcode) {
case B_ENTRY_CREATED:
{
const char* name;
node_ref nodeRef;
if (message->FindInt32("device", &nodeRef.device) != B_OK
|| message->FindInt64("directory", &nodeRef.node) != B_OK
|| message->FindString("name", &name) != B_OK)
break; break;
BEntry entry;
if (set_entry(nodeRef, name, entry) != B_OK)
break;
if (entry.IsDirectory()) {
// a new directory to watch for us
_AddPath(entry);
} else {
// a new font
font_directory* directory = _FindDirectory(nodeRef);
if (directory == NULL) {
// unknown directory? how come?
break;
}
_AddFont(*directory, entry);
}
break;
}
case B_ENTRY_MOVED:
{
// has the entry been moved into a monitored directory or has
// it been removed from one?
const char* name;
node_ref nodeRef;
uint64 fromNode;
uint64 node;
if (message->FindInt32("device", &nodeRef.device) != B_OK
|| message->FindInt64("to directory", &nodeRef.node) != B_OK
|| message->FindInt64("from directory", (int64 *)&fromNode) != B_OK
|| message->FindInt64("node", (int64 *)&node) != B_OK
|| message->FindString("name", &name) != B_OK)
break;
font_directory* directory = _FindDirectory(nodeRef);
BEntry entry;
if (set_entry(nodeRef, name, entry) != B_OK)
break;
if (directory != NULL) {
// something has been added to our watched font directories
if (entry.IsDirectory()) {
// there is a new directory to watch for us
_AddPath(entry);
} else {
// test, if the source directory is one of ours as well
nodeRef.node = fromNode;
font_directory* fromDirectory = _FindDirectory(nodeRef);
if (fromDirectory != NULL) {
// find style in source and move it to the target
nodeRef.node = node;
FontStyle* style = fromDirectory->FindStyle(nodeRef);
if (style != NULL) {
fromDirectory->styles.RemoveItem(style, false);
directory->styles.AddItem(style);
}
WTRACE(("font moved"));
} else {
WTRACE(("font added: %s\n", name));
_AddFont(*directory, entry);
}
}
} else {
// and entry has been removed from our font directories
if (entry.IsDirectory()) {
if (entry.GetNodeRef(&nodeRef) == B_OK
&& (directory = _FindDirectory(nodeRef)) != NULL)
_RemoveDirectory(directory);
} else
WTRACE(("font removed: %s\n", name));
}
break;
}
case B_ENTRY_REMOVED:
{
node_ref nodeRef;
if (message->FindInt32("device", &nodeRef.device) != B_OK
|| message->FindInt64("node", &nodeRef.node) != B_OK)
break;
font_directory* directory = _FindDirectory(nodeRef);
if (directory != NULL) {
// the directory has been removed, so we remove it as well
_RemoveDirectory(directory);
} else {
// a font was removed?
WTRACE(("removed a font?"));
}
break;
}
}
break;
}
} }
} }
@@ -203,12 +355,12 @@ void
FontManager::_AddSystemPaths() FontManager::_AddSystemPaths()
{ {
BPath path; BPath path;
if (find_directory(B_BEOS_FONTS_DIRECTORY, &path) == B_OK) if (find_directory(B_BEOS_FONTS_DIRECTORY, &path, true) == B_OK)
_AddPath(path.Path()); _AddPath(path.Path());
// We don't scan these in test mode to help shave off some startup time // We don't scan these in test mode to help shave off some startup time
#if !TEST_MODE #if !TEST_MODE
if (find_directory(B_COMMON_FONTS_DIRECTORY, &path) == B_OK) if (find_directory(B_COMMON_FONTS_DIRECTORY, &path, true) == B_OK)
_AddPath(path.Path()); _AddPath(path.Path());
#endif #endif
} }
@@ -246,8 +398,18 @@ FontManager::_ScanFonts()
\brief Adds the FontFamily/FontStyle that is represented by this path. \brief Adds the FontFamily/FontStyle that is represented by this path.
*/ */
status_t status_t
FontManager::_AddFont(BPath &path) FontManager::_AddFont(font_directory& directory, BEntry& entry)
{ {
node_ref nodeRef;
status_t status = entry.GetNodeRef(&nodeRef);
if (status < B_OK)
return status;
BPath path;
status = entry.GetPath(&path);
if (status < B_OK)
return status;
FT_Face face; FT_Face face;
FT_Error error = FT_New_Face(gFreeTypeLibrary, path.Path(), 0, &face); FT_Error error = FT_New_Face(gFreeTypeLibrary, path.Path(), 0, &face);
if (error != 0) if (error != 0)
@@ -271,20 +433,51 @@ FontManager::_AddFont(BPath &path)
} }
} }
#ifdef PRINT_FONT_LIST WTRACE(("\tadd style: %s, %s\n", face->family_name, face->style_name));
printf("\tFont Style: %s, %s\n", face->family_name, face->style_name);
#endif
// the FontStyle takes over ownership of the FT_Face object // the FontStyle takes over ownership of the FT_Face object
FontStyle *style = new FontStyle(path.Path(), face); FontStyle *style = new FontStyle(nodeRef, path.Path(), face);
if (!family->AddStyle(style)) if (!family->AddStyle(style))
delete style; delete style;
directory.styles.AddItem(style);
fStyleHashTable.AddItem(style); fStyleHashTable.AddItem(style);
if (directory.AlreadyScanned())
directory.revision++;
return B_OK; return B_OK;
} }
FontManager::font_directory*
FontManager::_FindDirectory(node_ref& nodeRef)
{
for (int32 i = fDirectories.CountItems(); i-- > 0;) {
font_directory* directory = fDirectories.ItemAt(i);
if (directory->directory == nodeRef)
return directory;
}
return NULL;
}
void
FontManager::_RemoveDirectory(font_directory* directory)
{
WTRACE(("FontManager: Remove directory (%Ld)!\n", directory->directory.node));
fDirectories.RemoveItem(directory, false);
// TODO: remove styles from this directory!
watch_node(&directory->directory, B_STOP_WATCHING, this);
delete directory;
}
status_t status_t
FontManager::_AddPath(const char* path) FontManager::_AddPath(const char* path)
{ {
@@ -307,19 +500,15 @@ FontManager::_AddPath(BEntry& entry, font_directory** _newDirectory)
// check if we are already know this directory // check if we are already know this directory
for (int32 i = fDirectories.CountItems(); i-- > 0;) { font_directory* directory = _FindDirectory(nodeRef);
font_directory* directory = fDirectories.ItemAt(i); if (directory != NULL) {
*_newDirectory = directory;
if (directory->directory == nodeRef) {
if (_newDirectory)
*_newDirectory = NULL;
return B_OK; return B_OK;
} }
}
// it's a new one, so let's add it // it's a new one, so let's add it
font_directory* directory = new (nothrow) font_directory; directory = new (nothrow) font_directory;
if (directory == NULL) if (directory == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -341,6 +530,9 @@ FontManager::_AddPath(BEntry& entry, font_directory** _newDirectory)
// it's not a critical error // it's not a critical error
printf("could not watch directory %ld:%Ld\n", nodeRef.device, nodeRef.node); printf("could not watch directory %ld:%Ld\n", nodeRef.device, nodeRef.node);
// TODO: should go into syslog() // TODO: should go into syslog()
} else {
BPath path(&entry);
WTRACE(("FontManager: now watching: %s\n", path.Path()));
} }
fDirectories.AddItem(directory); fDirectories.AddItem(directory);
@@ -379,11 +571,6 @@ FontManager::_ScanFontDirectory(font_directory& fontDirectory)
continue; continue;
} }
BPath path;
status = entry.GetPath(&path);
if (status < B_OK)
continue;
// TODO: Commenting this out makes my "Unicode glyph lookup" // TODO: Commenting this out makes my "Unicode glyph lookup"
// work with our default fonts. The real fix is to select the // work with our default fonts. The real fix is to select the
// Unicode char map (if supported), and/or adjust the // Unicode char map (if supported), and/or adjust the
@@ -400,7 +587,7 @@ FontManager::_ScanFontDirectory(font_directory& fontDirectory)
face->charmap = charmap; face->charmap = charmap;
#endif #endif
_AddFont(path); _AddFont(fontDirectory, entry);
// takes over ownership of the FT_Face object // takes over ownership of the FT_Face object
} }
@@ -552,7 +739,22 @@ FontManager::GetFamily(const char* name)
font_mapping* mapping = fMappings.ItemAt(i); font_mapping* mapping = fMappings.ItemAt(i);
if (mapping->family == name) { if (mapping->family == name) {
if (_AddFont(mapping->path) == B_OK) BEntry entry(&mapping->ref);
if (entry.InitCheck() != B_OK)
continue;
// find parent directory
node_ref nodeRef;
nodeRef.device = mapping->ref.device;
nodeRef.node = mapping->ref.directory;
font_directory* directory = _FindDirectory(nodeRef);
if (directory == NULL) {
// unknown directory, maybe this is a user font
continue;
}
if (_AddFont(*directory, entry) == B_OK)
return _FindFamily(name); return _FindFamily(name);
} }
} }