1/*
2 * Copyright 2001-2016, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		DarkWyrm <bpmagic@columbus.rr.com>
7 *		Axel D��rfler, axeld@pinc-software.de
8 */
9
10
11/*!	Manages font families and styles */
12
13
14#include "FontManager.h"
15
16#include <new>
17
18#include <Debug.h>
19
20#include "FontFamily.h"
21
22
23//#define TRACE_FONT_MANAGER
24#ifdef TRACE_FONT_MANAGER
25#	define FTRACE(x) printf x
26#else
27#	define FTRACE(x) ;
28#endif
29
30
31FT_Library gFreeTypeLibrary;
32
33
34static int
35compare_font_families(const FontFamily* a, const FontFamily* b)
36{
37	return strcmp(a->Name(), b->Name());
38}
39
40
41//	#pragma mark -
42
43
44FontManager::FontManager()
45	:
46	fFamilies(20),
47	fNextID(0)
48{
49}
50
51
52FontManager::~FontManager()
53{
54	_RemoveAllFonts();
55}
56
57
58/*!	\brief Finds and returns the first valid charmap in a font
59
60	\param face Font handle obtained from FT_Load_Face()
61	\return An FT_CharMap or NULL if unsuccessful
62*/
63FT_CharMap
64FontManager::_GetSupportedCharmap(const FT_Face& face)
65{
66	for (int32 i = 0; i < face->num_charmaps; i++) {
67		FT_CharMap charmap = face->charmaps[i];
68
69		switch (charmap->platform_id) {
70			case 3:
71				// if Windows Symbol or Windows Unicode
72				if (charmap->encoding_id == 0 || charmap->encoding_id == 1)
73					return charmap;
74				break;
75
76			case 1:
77				// if Apple Unicode
78				if (charmap->encoding_id == 0)
79					return charmap;
80				break;
81
82			case 0:
83				// if Apple Roman
84				if (charmap->encoding_id == 0)
85					return charmap;
86				break;
87
88			default:
89				break;
90		}
91	}
92
93	return NULL;
94}
95
96
97
98/*!	\brief Counts the number of font families available
99	\return The number of unique font families currently available
100*/
101int32
102FontManager::CountFamilies()
103{
104	return fFamilies.CountItems();
105}
106
107
108/*!	\brief Counts the number of styles available in a font family
109	\param family Name of the font family to scan
110	\return The number of font styles currently available for the font family
111*/
112int32
113FontManager::CountStyles(const char *familyName)
114{
115	FontFamily *family = GetFamily(familyName);
116	if (family != NULL)
117		return family->CountStyles();
118
119	return 0;
120}
121
122
123/*!	\brief Counts the number of styles available in a font family
124	\param family Name of the font family to scan
125	\return The number of font styles currently available for the font family
126*/
127int32
128FontManager::CountStyles(uint16 familyID)
129{
130	FontFamily *family = GetFamily(familyID);
131	if (family != NULL)
132		return family->CountStyles();
133
134	return 0;
135}
136
137
138FontFamily*
139FontManager::FamilyAt(int32 index) const
140{
141	ASSERT(IsLocked());
142
143	return fFamilies.ItemAt(index);
144}
145
146
147/*!	\brief Locates a FontFamily object by name
148	\param name The family to find
149	\return Pointer to the specified family or NULL if not found.
150*/
151FontFamily*
152FontManager::GetFamily(const char* name)
153{
154	if (name == NULL)
155		return NULL;
156
157	return _FindFamily(name);
158}
159
160
161FontFamily*
162FontManager::GetFamily(uint16 familyID) const
163{
164	FontKey key(familyID, 0);
165	FontStyle* style = fStyleHashTable.Get(key);
166	if (style != NULL)
167		return style->Family();
168
169	return NULL;
170}
171
172
173FontStyle*
174FontManager::GetStyleByIndex(const char* familyName, int32 index)
175{
176	FontFamily* family = GetFamily(familyName);
177	if (family != NULL)
178		return family->StyleAt(index);
179
180	return NULL;
181}
182
183
184FontStyle*
185FontManager::GetStyleByIndex(uint16 familyID, int32 index)
186{
187	FontFamily* family = GetFamily(familyID);
188	if (family != NULL)
189		return family->StyleAt(index);
190
191	return NULL;
192}
193
194
195/*!	\brief Retrieves the FontStyle object
196	\param family ID for the font's family
197	\param style ID of the font's style
198	\return The FontStyle having those attributes or NULL if not available
199*/
200FontStyle*
201FontManager::GetStyle(uint16 familyID, uint16 styleID) const
202{
203	ASSERT(IsLocked());
204
205	FontKey key(familyID, styleID);
206	return fStyleHashTable.Get(key);
207}
208
209
210/*!	\brief Retrieves the FontStyle object that comes closest to the one
211		specified.
212
213	\param family The font's family or NULL in which case \a familyID is used
214	\param style The font's style or NULL in which case \a styleID is used
215	\param familyID will only be used if \a family is NULL (or empty)
216	\param styleID will only be used if \a style is NULL (or empty)
217	\param face is used to specify the style if both \a style is NULL or empty
218		and styleID is 0xffff.
219
220	\return The FontStyle having those attributes or NULL if not available
221*/
222FontStyle*
223FontManager::GetStyle(const char* familyName, const char* styleName,
224	uint16 familyID, uint16 styleID, uint16 face)
225{
226	ASSERT(IsLocked());
227
228	FontFamily* family;
229
230	// find family
231
232	if (familyName != NULL && familyName[0])
233		family = GetFamily(familyName);
234	else
235		family = GetFamily(familyID);
236
237	if (family == NULL)
238		return NULL;
239
240	// find style
241
242	if (styleName != NULL && styleName[0])
243		return family->GetStyle(styleName);
244
245	if (styleID != 0xffff)
246		return family->GetStyleByID(styleID);
247
248	// try to get from face
249	return family->GetStyleMatchingFace(face);
250}
251
252
253/*!	\brief If you don't find your preferred font style, but are anxious
254		to have one fitting your needs, you may want to use this method.
255*/
256FontStyle*
257FontManager::FindStyleMatchingFace(uint16 face) const
258{
259	int32 count = fFamilies.CountItems();
260
261	for (int32 i = 0; i < count; i++) {
262		FontFamily* family = fFamilies.ItemAt(i);
263		FontStyle* style = family->GetStyleMatchingFace(face);
264		if (style != NULL)
265			return style;
266	}
267
268	return NULL;
269}
270
271
272/*!	\brief This call is used by the FontStyle class - and the FontStyle class
273		only - to remove itself from the font manager.
274	At this point, the style is already no longer available to the user.
275*/
276void
277FontManager::RemoveStyle(FontStyle* style)
278{
279	ASSERT(IsLocked());
280
281	FontFamily* family = style->Family();
282	if (family == NULL)
283		debugger("family is NULL!");
284
285	FontStyle* check = GetStyle(family->ID(), style->ID());
286	if (check != NULL)
287		debugger("style removed but still available!");
288
289	if (family->RemoveStyle(style)
290		&& family->CountStyles() == 0) {
291		fFamilies.RemoveItem(family);
292		delete family;
293	}
294}
295
296
297status_t
298FontManager::_AddFont(FT_Face face, node_ref nodeRef, const char* path,
299	uint16& familyID, uint16& styleID)
300{
301	ASSERT(IsLocked());
302
303	FontFamily* family = _FindFamily(face->family_name);
304	bool isNewFontFamily = family == NULL;
305
306	if (family != NULL && family->HasStyle(face->style_name)) {
307		// prevent adding the same style twice
308		// (this indicates a problem with the installed fonts maybe?)
309		FT_Done_Face(face);
310		return B_NAME_IN_USE;
311	}
312
313	if (family == NULL) {
314		family = new (std::nothrow) FontFamily(face->family_name, _NextID());
315
316		if (family == NULL
317			|| !fFamilies.BinaryInsert(family, compare_font_families)) {
318			delete family;
319			FT_Done_Face(face);
320			return B_NO_MEMORY;
321		}
322	}
323
324	FTRACE(("\tadd style: %s, %s\n", face->family_name, face->style_name));
325
326	// the FontStyle takes over ownership of the FT_Face object
327	FontStyle* style = new (std::nothrow) FontStyle(nodeRef, path, face, this);
328
329	if (style == NULL || !family->AddStyle(style)) {
330		delete style;
331		if (isNewFontFamily)
332			delete family;
333		return B_NO_MEMORY;
334	}
335
336	familyID = style->Family()->ID();
337	styleID = style->ID();
338
339	fStyleHashTable.Put(FontKey(familyID, styleID), style);
340	style->ReleaseReference();
341
342	return B_OK;
343}
344
345
346FontStyle*
347FontManager::_RemoveFont(uint16 familyID, uint16 styleID)
348{
349	ASSERT(IsLocked());
350
351	return fStyleHashTable.Remove(FontKey(familyID, styleID));
352}
353
354
355void
356FontManager::_RemoveAllFonts()
357{
358	for (int32 i = fFamilies.CountItems(); i-- > 0;)
359		delete fFamilies.RemoveItemAt(i);
360
361	fStyleHashTable.Clear();
362}
363
364
365FontFamily*
366FontManager::_FindFamily(const char* name) const
367{
368	if (name == NULL)
369		return NULL;
370
371	FontFamily family(name, 0);
372	return const_cast<FontFamily*>(fFamilies.BinarySearch(family,
373		compare_font_families));
374}
375
376
377uint16
378FontManager::_NextID()
379{
380	return fNextID++;
381}
382