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:
parent
174b20a89a
commit
2522a90fd1
@ -10,11 +10,12 @@
|
||||
#define FONT_FAMILY_H_
|
||||
|
||||
|
||||
#include <String.h>
|
||||
#include <Rect.h>
|
||||
#include <Font.h>
|
||||
#include <ObjectList.h>
|
||||
#include <Locker.h>
|
||||
#include <Node.h>
|
||||
#include <ObjectList.h>
|
||||
#include <Rect.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
@ -22,6 +23,7 @@
|
||||
#include "HashTable.h"
|
||||
|
||||
|
||||
struct node_ref;
|
||||
class FontFamily;
|
||||
class ServerFont;
|
||||
|
||||
@ -66,12 +68,14 @@ class FontKey : public Hashable {
|
||||
*/
|
||||
class FontStyle : public SharedObject, public Hashable, public BLocker {
|
||||
public:
|
||||
FontStyle(const char* path, FT_Face face);
|
||||
FontStyle(node_ref& nodeRef, const char* path, FT_Face face);
|
||||
virtual ~FontStyle();
|
||||
|
||||
virtual uint32 Hash() const;
|
||||
virtual bool CompareTo(Hashable& other) const;
|
||||
|
||||
const node_ref& NodeRef() const { return fNodeRef; }
|
||||
|
||||
/*!
|
||||
\fn bool FontStyle::IsFixedWidth(void)
|
||||
\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;
|
||||
BString fName;
|
||||
BString fPath;
|
||||
node_ref fNodeRef;
|
||||
|
||||
FontFamily* fFamily;
|
||||
uint16 fID;
|
||||
@ -184,8 +189,8 @@ class FontFamily {
|
||||
const char* Name() const;
|
||||
|
||||
bool AddStyle(FontStyle* style);
|
||||
bool RemoveStyle(const char* style);
|
||||
bool RemoveStyle(FontStyle* style);
|
||||
bool RemoveStyle(const char* style, bool deleteSelfIfEmpty = true);
|
||||
bool RemoveStyle(FontStyle* style, bool deleteSelfIfEmpty = true);
|
||||
|
||||
FontStyle* GetStyle(const char* style) const;
|
||||
FontStyle* GetStyleMatchingFace(uint16 face) const;
|
||||
|
@ -73,6 +73,8 @@ class FontManager : public BLooper {
|
||||
uint16 fallbackFace);
|
||||
status_t _SetDefaultFonts();
|
||||
void _AddSystemPaths();
|
||||
font_directory* _FindDirectory(node_ref& nodeRef);
|
||||
void _RemoveDirectory(font_directory* directory);
|
||||
status_t _AddPath(const char* path);
|
||||
status_t _AddPath(BEntry& entry, font_directory** _newDirectory = NULL);
|
||||
|
||||
@ -82,7 +84,7 @@ class FontManager : public BLooper {
|
||||
void _ScanFontsIfNecessary();
|
||||
void _ScanFonts();
|
||||
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);
|
||||
|
||||
|
@ -27,11 +27,12 @@ const uint32 kInvalidFamilyFlags = ~0UL;
|
||||
\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
|
||||
*/
|
||||
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()),
|
||||
fFreeTypeFace(face),
|
||||
fName(face->style_name),
|
||||
fPath(path),
|
||||
fNodeRef(nodeRef),
|
||||
fFamily(NULL),
|
||||
fID(0),
|
||||
fBounds(0, 0, 0, 0),
|
||||
@ -55,7 +56,7 @@ FontStyle::~FontStyle()
|
||||
{
|
||||
// make sure the font server is ours
|
||||
if (fFamily != NULL && gFontManager->Lock()) {
|
||||
fFamily->RemoveStyle(this);
|
||||
fFamily->RemoveStyle(this, false);
|
||||
gFontManager->Unlock();
|
||||
}
|
||||
|
||||
@ -231,6 +232,7 @@ FontFamily::FontFamily(const char *name, uint16 id)
|
||||
// make sure this family can be found using the Be API
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Destructor
|
||||
|
||||
@ -240,8 +242,8 @@ FontFamily::FontFamily(const char *name, uint16 id)
|
||||
*/
|
||||
FontFamily::~FontFamily()
|
||||
{
|
||||
int32 count = fStyles.CountItems();
|
||||
for (int32 i = 0; i < count; i++)
|
||||
// styles are removing itself when deleted
|
||||
for (int32 i = fStyles.CountItems(); i-- > 0;)
|
||||
delete fStyles.ItemAt(i);
|
||||
}
|
||||
|
||||
@ -286,11 +288,11 @@ FontFamily::AddStyle(FontStyle *style)
|
||||
|
||||
|
||||
bool
|
||||
FontFamily::RemoveStyle(const char* styleName)
|
||||
FontFamily::RemoveStyle(const char* styleName, bool deleteSelfIfEmpty)
|
||||
{
|
||||
FontStyle *style = GetStyle(styleName);
|
||||
if (style != NULL)
|
||||
return RemoveStyle(style);
|
||||
return RemoveStyle(style, deleteSelfIfEmpty);
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -306,7 +308,7 @@ FontFamily::RemoveStyle(const char* styleName)
|
||||
\param style The style to be removed from the family
|
||||
*/
|
||||
bool
|
||||
FontFamily::RemoveStyle(FontStyle* style)
|
||||
FontFamily::RemoveStyle(FontStyle* style, bool deleteSelfIfEmpty)
|
||||
{
|
||||
if (!gFontManager->IsLocked()) {
|
||||
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
|
||||
fFlags = kInvalidFamilyFlags;
|
||||
|
||||
if (CountStyles() == 0)
|
||||
style->_SetFontFamily(NULL, -1);
|
||||
|
||||
if (deleteSelfIfEmpty && CountStyles() == 0)
|
||||
delete this;
|
||||
|
||||
return true;
|
||||
|
@ -27,8 +27,16 @@
|
||||
|
||||
#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;
|
||||
FT_Library gFreeTypeLibrary;
|
||||
@ -42,21 +50,53 @@ struct FontManager::font_directory {
|
||||
BObjectList<FontStyle> styles;
|
||||
|
||||
bool AlreadyScanned() const { return revision != 0; }
|
||||
FontStyle* FindStyle(const node_ref& nodeRef) const;
|
||||
};
|
||||
|
||||
struct FontManager::font_mapping {
|
||||
BString family;
|
||||
BString style;
|
||||
BPath path;
|
||||
BString family;
|
||||
BString style;
|
||||
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 -
|
||||
|
||||
|
||||
//! Does basic set up so that directories can be scanned
|
||||
FontManager::FontManager()
|
||||
: BLooper("Font Manager"),
|
||||
fDirectories(10, true),
|
||||
fMappings(10, true),
|
||||
fFamilies(20),
|
||||
fScanned(false),
|
||||
fNextID(0)
|
||||
@ -85,12 +125,14 @@ FontManager::FontManager()
|
||||
//! Frees items allocated in the constructor and shuts down FreeType
|
||||
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);
|
||||
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) {
|
||||
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;
|
||||
|
||||
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()
|
||||
{
|
||||
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());
|
||||
|
||||
// We don't scan these in test mode to help shave off some startup time
|
||||
#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());
|
||||
#endif
|
||||
}
|
||||
@ -246,8 +398,18 @@ FontManager::_ScanFonts()
|
||||
\brief Adds the FontFamily/FontStyle that is represented by this path.
|
||||
*/
|
||||
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_Error error = FT_New_Face(gFreeTypeLibrary, path.Path(), 0, &face);
|
||||
if (error != 0)
|
||||
@ -271,20 +433,51 @@ FontManager::_AddFont(BPath &path)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRINT_FONT_LIST
|
||||
printf("\tFont Style: %s, %s\n", face->family_name, face->style_name);
|
||||
#endif
|
||||
WTRACE(("\tadd style: %s, %s\n", face->family_name, face->style_name));
|
||||
|
||||
// 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))
|
||||
delete style;
|
||||
|
||||
directory.styles.AddItem(style);
|
||||
fStyleHashTable.AddItem(style);
|
||||
|
||||
if (directory.AlreadyScanned())
|
||||
directory.revision++;
|
||||
|
||||
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
|
||||
FontManager::_AddPath(const char* path)
|
||||
{
|
||||
@ -307,19 +500,15 @@ FontManager::_AddPath(BEntry& entry, font_directory** _newDirectory)
|
||||
|
||||
// check if we are already know 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;
|
||||
}
|
||||
font_directory* directory = _FindDirectory(nodeRef);
|
||||
if (directory != NULL) {
|
||||
*_newDirectory = directory;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// 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)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
@ -341,6 +530,9 @@ FontManager::_AddPath(BEntry& entry, font_directory** _newDirectory)
|
||||
// it's not a critical error
|
||||
printf("could not watch directory %ld:%Ld\n", nodeRef.device, nodeRef.node);
|
||||
// TODO: should go into syslog()
|
||||
} else {
|
||||
BPath path(&entry);
|
||||
WTRACE(("FontManager: now watching: %s\n", path.Path()));
|
||||
}
|
||||
|
||||
fDirectories.AddItem(directory);
|
||||
@ -379,11 +571,6 @@ FontManager::_ScanFontDirectory(font_directory& fontDirectory)
|
||||
continue;
|
||||
}
|
||||
|
||||
BPath path;
|
||||
status = entry.GetPath(&path);
|
||||
if (status < B_OK)
|
||||
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
|
||||
@ -400,7 +587,7 @@ FontManager::_ScanFontDirectory(font_directory& fontDirectory)
|
||||
face->charmap = charmap;
|
||||
#endif
|
||||
|
||||
_AddFont(path);
|
||||
_AddFont(fontDirectory, entry);
|
||||
// takes over ownership of the FT_Face object
|
||||
}
|
||||
|
||||
@ -552,7 +739,22 @@ FontManager::GetFamily(const char* name)
|
||||
font_mapping* mapping = fMappings.ItemAt(i);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user