From ec9b3f7ca1be90d53588647da4f68cc9dbab9386 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 8 Nov 2005 16:49:33 +0000 Subject: [PATCH] The font manager now utilizes a hash table to look up fonts by ID. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14777 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/servers/app/FontFamily.h | 23 ++- headers/private/servers/app/FontManager.h | 4 +- headers/private/servers/app/HashTable.h | 47 +++++ src/servers/app/FontFamily.cpp | 15 ++ src/servers/app/FontManager.cpp | 24 +-- src/servers/app/HashTable.cpp | 199 ++++++++++++++++++++++ src/servers/app/Jamfile | 1 + 7 files changed, 301 insertions(+), 12 deletions(-) create mode 100644 headers/private/servers/app/HashTable.h create mode 100644 src/servers/app/HashTable.cpp diff --git a/headers/private/servers/app/FontFamily.h b/headers/private/servers/app/FontFamily.h index c9dabebaef..32f4ce4341 100644 --- a/headers/private/servers/app/FontFamily.h +++ b/headers/private/servers/app/FontFamily.h @@ -19,6 +19,7 @@ #include #include FT_FREETYPE_H #include "SharedObject.h" +#include "HashTable.h" class FontFamily; @@ -39,6 +40,23 @@ enum font_format { }; +class FontKey : public Hashable { + public: + FontKey(uint16 familyID, uint16 styleID) + : fHash(familyID | (styleID << 16UL)) + { + } + + virtual uint32 Hash() const + { return fHash; } + virtual bool CompareTo(Hashable& other) const + { return fHash == other.Hash(); } + + private: + uint32 fHash; +}; + + /*! \class FontStyle FontFamily.h \brief Object used to represent a font style @@ -46,11 +64,14 @@ enum font_format { FontStyle objects help abstract a lot of the font engine details while still offering plenty of information the style in question. */ -class FontStyle : public SharedObject, public BLocker { +class FontStyle : public SharedObject, public Hashable, public BLocker { public: FontStyle(const char* path, FT_Face face); virtual ~FontStyle(); + virtual uint32 Hash() const; + virtual bool CompareTo(Hashable& other) const; + /*! \fn bool FontStyle::IsFixedWidth(void) \brief Determines whether the font's character width is fixed diff --git a/headers/private/servers/app/FontManager.h b/headers/private/servers/app/FontManager.h index d65d0f0c23..aeb01532fc 100644 --- a/headers/private/servers/app/FontManager.h +++ b/headers/private/servers/app/FontManager.h @@ -10,9 +10,10 @@ #define FONT_MANAGER_H +#include "HashTable.h" + #include #include -#include #include #include FT_FREETYPE_H @@ -85,6 +86,7 @@ class FontManager : public BLooper { BObjectList fDirectories; BObjectList fMappings; BObjectList fFamilies; + HashTable fStyleHashTable; ServerFont *fDefaultFont; bool fScanned; int32 fNextID; diff --git a/headers/private/servers/app/HashTable.h b/headers/private/servers/app/HashTable.h new file mode 100644 index 0000000000..7207947766 --- /dev/null +++ b/headers/private/servers/app/HashTable.h @@ -0,0 +1,47 @@ +/* + * Copyright 2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef _HASH_TABLE_H_ +#define _HASH_TABLE_H_ + + +#include + + +class Hashable { + public: + virtual uint32 Hash() const = 0; + virtual bool CompareTo(Hashable& hashable) const = 0; +}; + +class HashTable { + public: + HashTable(int32 capacity = 100, float loadFactor = 0.75); + ~HashTable(); + + void MakeEmpty(); + bool IsEmpty() const { return fCount == 0; } + bool ContainsKey(Hashable& key) const { return _GetHashEntry(key) != NULL; } + int32 CountItems() const { return fCount; } + + Hashable *GetValue(Hashable& key) const; + + bool AddItem(Hashable* value); + Hashable *RemoveItem(Hashable& key); + + protected: + struct entry; + + bool _Rehash(); + entry *_GetHashEntry(Hashable& key) const; + + entry** fTable; + int32 fCapacity, fCount, fThreshold; + float fLoadFactor; +}; + +#endif /* HASHTABLE_H */ diff --git a/src/servers/app/FontFamily.cpp b/src/servers/app/FontFamily.cpp index d469ca038c..53ff365f48 100644 --- a/src/servers/app/FontFamily.cpp +++ b/src/servers/app/FontFamily.cpp @@ -63,6 +63,21 @@ FontStyle::~FontStyle() } +uint32 +FontStyle::Hash() const +{ + return (ID() << 16) | fFamily->ID(); +} + + +bool +FontStyle::CompareTo(Hashable& other) const +{ + // our hash values are unique (unless you have more than 65536 font families installed...) + return Hash() == other.Hash(); +} + + void FontStyle::GetHeight(float size, font_height& height) const { diff --git a/src/servers/app/FontManager.cpp b/src/servers/app/FontManager.cpp index bd06a6479b..ccb0a38986 100644 --- a/src/servers/app/FontManager.cpp +++ b/src/servers/app/FontManager.cpp @@ -124,6 +124,13 @@ FontManager::_RemoveFamily(const char *familyName) { FontFamily *family = GetFamily(familyName); if (family) { + // remove styles from hash + for (int32 i = 0; i < family->CountStyles(); i++) { + FontStyle* style = family->StyleAt(i); + + fStyleHashTable.RemoveItem(*style); + } + fFamilies.RemoveItem(family); delete family; } @@ -239,6 +246,7 @@ FontManager::_AddFont(BPath &path) if (!family->AddStyle(style)) delete style; + fStyleHashTable.AddItem(style); return B_OK; } @@ -523,11 +531,10 @@ FontManager::GetFamily(const char* name) FontFamily* FontManager::GetFamily(uint16 familyID) const { - for (int32 i = 0; i < fFamilies.CountItems(); i++) { - FontFamily *family = (FontFamily*)fFamilies.ItemAt(i); - if (family->ID() == familyID) - return family; - } + FontKey key(familyID, 0); + FontStyle* style = (FontStyle*)fStyleHashTable.GetValue(key); + if (style != NULL) + return style->Family(); return NULL; } @@ -594,11 +601,8 @@ FontManager::GetStyle(const char* familyName, const char* styleName, uint16 fami FontStyle* FontManager::GetStyle(uint16 familyID, uint16 styleID) const { - FontFamily *family = GetFamily(familyID); - if (family) - return family->GetStyleByID(styleID); - - return NULL; + FontKey key(familyID, styleID); + return (FontStyle*)fStyleHashTable.GetValue(key); } diff --git a/src/servers/app/HashTable.cpp b/src/servers/app/HashTable.cpp new file mode 100644 index 0000000000..5da0946156 --- /dev/null +++ b/src/servers/app/HashTable.cpp @@ -0,0 +1,199 @@ +/* + * Copyright 2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "HashTable.h" + +#include + +#include +//#include +#include + + +struct HashTable::entry { + entry* next; + Hashable* value; +}; + + +HashTable::HashTable(int32 capacity, float loadFactor) + : + fTable(NULL), + fCount(0), + fThreshold(0) +{ + if (capacity < 10) + capacity = 10; + if (loadFactor <= 0.3) + loadFactor = 0.3; + + fLoadFactor = loadFactor; + fCapacity = capacity; +} + + +HashTable::~HashTable() +{ + MakeEmpty(); +} + + +void +HashTable::MakeEmpty() +{ + for (int32 index = fCapacity; --index >= 0;) { + struct entry *entry, *next; + + for (entry = fTable[index]; entry != NULL; entry = next) { + next = entry->next; + + delete entry->value; + delete entry; + } + } + + free(fTable); + fTable = NULL; +} + + +Hashable * +HashTable::GetValue(Hashable& key) const +{ + struct entry* entry = _GetHashEntry(key); + + return entry != NULL ? entry->value : NULL; +} + + +bool +HashTable::AddItem(Hashable *value) +{ + struct entry *entry = _GetHashEntry(*value); + int32 hash = value->Hash(); + int32 index; + + // already in hash? + if (entry != NULL) + return true; + + if (fCount >= fThreshold) + _Rehash(); + + index = hash % fCapacity; + + entry = new (nothrow) HashTable::entry; + if (entry == NULL) + return false; + + entry->value = value; + entry->next = fTable[index]; + fTable[index] = entry; + fCount++; + return true; +} + + +Hashable * +HashTable::RemoveItem(Hashable& key) +{ + struct entry* previous = NULL; + struct entry* entry; + uint32 hash; + int32 index; + + if (fTable == NULL) + return NULL; + + hash = key.Hash(); + index = hash % fCapacity; + + for (entry = fTable[index]; entry != NULL; entry = entry->next) { + if (entry->value->Hash() == hash && entry->value->CompareTo(key)) { + // found value in array + Hashable* value; + + if (previous) + previous->next = entry->next; + else + fTable[index] = entry->next; + + fCount--; + value = entry->value; + delete entry; + return value; + } + + previous = entry; + } + return NULL; +} + + +bool +HashTable::_Rehash() +{ + struct entry** newTable; + int32 oldCapacity = fCapacity; + int32 newCapacity, i; + + if (fCount != 0) + newCapacity = oldCapacity * 2 + 1; + else + newCapacity = fCapacity; + + newTable = (struct entry **)malloc(newCapacity * sizeof(struct entry *)); + if (newTable == NULL) + return false; + + memset(newTable, 0, newCapacity * sizeof(struct entry *)); + + if (fTable != NULL) { + // repopulate the entries into the new array + for (i = fCapacity; i-- > 0;) { + struct entry* entry; + struct entry* next; + + for (entry = fTable[i]; entry != NULL; entry = next) { + next = entry->next; + + int32 index = entry->value->Hash() % newCapacity; + entry->next = newTable[index]; + newTable[index] = entry; + } + } + + free(fTable); + } + + fTable = newTable; + fCapacity = newCapacity; + fThreshold = int32(newCapacity * fLoadFactor); + + return true; +} + + +struct HashTable::entry * +HashTable::_GetHashEntry(Hashable& key) const +{ + struct entry* entry; + uint32 hash = key.Hash(); + + if (fTable == NULL) + return NULL; + + for (entry = fTable[hash % fCapacity]; entry != NULL; entry = entry->next) { + if (entry->value->Hash() == hash && entry->value->CompareTo(key)) + return entry; + } + + return NULL; +} + diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile index a881abcbca..638ff474f4 100644 --- a/src/servers/app/Jamfile +++ b/src/servers/app/Jamfile @@ -29,6 +29,7 @@ SharedLibrary libappserver.so : CursorSet.cpp DrawState.cpp FontFamily.cpp + HashTable.cpp IPoint.cpp RGBColor.cpp ServerBitmap.cpp