#include "FontManager.h"
#include <new>
#include <Debug.h>
#include "FontFamily.h"
#ifdef TRACE_FONT_MANAGER
# define FTRACE(x) printf x
#else
# define FTRACE(x) ;
#endif
FT_Library gFreeTypeLibrary;
static int
compare_font_families(const FontFamily* a, const FontFamily* b)
{
return strcmp(a->Name(), b->Name());
}
FontManager::FontManager()
:
fFamilies(20),
fRevision(0),
fNextID(0)
{
}
FontManager::~FontManager()
{
_RemoveAllFonts();
}
FT_CharMap
FontManager::_GetSupportedCharmap(const FT_Face& face)
{
for (int32 i = 0; i < face->num_charmaps; i++) {
FT_CharMap charmap = face->charmaps[i];
switch (charmap->platform_id) {
case 3:
if (charmap->encoding_id == 0 || charmap->encoding_id == 1)
return charmap;
break;
case 1:
if (charmap->encoding_id == 0)
return charmap;
break;
case 0:
if (charmap->encoding_id == 0)
return charmap;
break;
default:
break;
}
}
return NULL;
}
int32
FontManager::CountFamilies()
{
return fFamilies.CountItems();
}
int32
FontManager::CountStyles(const char *familyName)
{
FontFamily *family = GetFamily(familyName);
if (family != NULL)
return family->CountStyles();
return 0;
}
int32
FontManager::CountStyles(uint16 familyID)
{
FontFamily *family = GetFamily(familyID);
if (family != NULL)
return family->CountStyles();
return 0;
}
FontFamily*
FontManager::FamilyAt(int32 index) const
{
ASSERT(IsLocked());
return fFamilies.ItemAt(index);
}
FontFamily*
FontManager::GetFamily(const char* name)
{
if (name == NULL)
return NULL;
return _FindFamily(name);
}
FontFamily*
FontManager::GetFamily(uint16 familyID) const
{
FontKey key(familyID, 0);
FontStyle* style = fStyleHashTable.Get(key);
if (style != NULL)
return style->Family();
return _FindFamily(familyID);
}
FontStyle*
FontManager::GetStyleByIndex(const char* familyName, int32 index)
{
FontFamily* family = GetFamily(familyName);
if (family != NULL)
return family->StyleAt(index);
return NULL;
}
FontStyle*
FontManager::GetStyleByIndex(uint16 familyID, int32 index)
{
FontFamily* family = GetFamily(familyID);
if (family != NULL)
return family->StyleAt(index);
return NULL;
}
FontStyle*
FontManager::GetStyle(uint16 familyID, uint16 styleID) const
{
ASSERT(IsLocked());
FontKey key(familyID, styleID);
FontStyle* style = fStyleHashTable.Get(key);
if (style != NULL)
return style;
return fDelistedStyleHashTable.Get(key);
}
FontStyle*
FontManager::GetStyle(const char* familyName, const char* styleName,
uint16 familyID, uint16 styleID, uint16 face)
{
ASSERT(IsLocked());
FontFamily* family;
if (styleID != 0xffff && (familyName == NULL || !familyName[0])
&& (styleName == NULL || !styleName[0])) {
return GetStyle(familyID, styleID);
}
if (familyName != NULL && familyName[0])
family = GetFamily(familyName);
else
family = GetFamily(familyID);
if (family == NULL)
return NULL;
if (styleName != NULL && styleName[0])
return family->GetStyle(styleName);
return family->GetStyleMatchingFace(face);
}
FontStyle*
FontManager::FindStyleMatchingFace(uint16 face) const
{
int32 count = fFamilies.CountItems();
for (int32 i = 0; i < count; i++) {
FontFamily* family = fFamilies.ItemAt(i);
FontStyle* style = family->GetStyleMatchingFace(face);
if (style != NULL)
return style;
}
return NULL;
}
void
FontManager::RemoveStyle(FontStyle* style)
{
ASSERT(IsLocked());
FontFamily* family = style->Family();
if (family == NULL)
debugger("family is NULL!");
family->RemoveStyle(style);
fDelistedStyleHashTable.Remove(FontKey(family->ID(), style->ID()));
}
uint32
FontManager::Revision()
{
return fRevision;
}
status_t
FontManager::_AddFont(FT_Face face, node_ref nodeRef, const char* path,
uint16& familyID, uint16& styleID)
{
ASSERT(IsLocked());
BReference<FontFamily> family(_FindFamily(face->family_name));
bool isNewFontFamily = !family.IsSet();
if (family.IsSet() && family->HasStyle(face->style_name)) {
FT_Done_Face(face);
return B_NAME_IN_USE;
}
if (!family.IsSet()) {
family.SetTo(new (std::nothrow) FontFamily(face->family_name, _NextID()), true);
if (!family.IsSet() || !fFamilies.BinaryInsert(family, compare_font_families)) {
FT_Done_Face(face);
return B_NO_MEMORY;
}
}
FTRACE(("\tadd style: %s, %s\n", face->family_name, face->style_name));
FontStyle* style = new (std::nothrow) FontStyle(nodeRef, path, face, this);
if (style == NULL || !family->AddStyle(style)) {
delete style;
if (isNewFontFamily)
fFamilies.RemoveItem(family);
return B_NO_MEMORY;
}
familyID = style->Family()->ID();
styleID = style->ID();
fStyleHashTable.Put(FontKey(familyID, styleID), style);
style->ReleaseReference();
fRevision++;
return B_OK;
}
FontStyle*
FontManager::_RemoveFont(uint16 familyID, uint16 styleID)
{
ASSERT(IsLocked());
FontKey key(familyID, styleID);
FontStyle* style = fStyleHashTable.Get(key);
if (style != NULL) {
fDelistedStyleHashTable.Put(key, style);
FontFamily* family = style->Family();
if (family->RemoveStyle(style) && family->CountStyles() == 0)
fFamilies.RemoveItem(family);
fStyleHashTable.Remove(key);
}
fRevision++;
return style;
}
void
FontManager::_RemoveAllFonts()
{
fFamilies.MakeEmpty();
HashMap<FontKey, FontStyle*>::Iterator delisted = fDelistedStyleHashTable.GetIterator();
while (delisted.HasNext())
delisted.Next().value->_SetFontFamily(NULL, -1);
fDelistedStyleHashTable.Clear();
HashMap<FontKey, BReference<FontStyle> >::Iterator referenced = fStyleHashTable.GetIterator();
while (referenced.HasNext())
referenced.Next().value->_SetFontFamily(NULL, -1);
fStyleHashTable.Clear();
}
FontFamily*
FontManager::_FindFamily(const char* name) const
{
if (name == NULL)
return NULL;
FontFamily family(name, 0);
return const_cast<FontFamily*>(fFamilies.BinarySearch(family,
compare_font_families));
}
FontFamily*
FontManager::_FindFamily(uint16 familyID) const
{
int32 count = fFamilies.CountItems();
for (int32 i = 0; i < count; i++) {
FontFamily* family = fFamilies.ItemAt(i);
if (family->ID() == familyID)
return family;
}
return NULL;
}
uint16
FontManager::_NextID()
{
return fNextID++;
}