xref: /haiku/src/servers/app/font/FontManager.cpp (revision 909af08f4328301fbdef1ffb41f566c3b5bec0c7)
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 
31 FT_Library gFreeTypeLibrary;
32 
33 
34 static int
35 compare_font_families(const FontFamily* a, const FontFamily* b)
36 {
37 	return strcmp(a->Name(), b->Name());
38 }
39 
40 
41 //	#pragma mark -
42 
43 
44 FontManager::FontManager()
45 	:
46 	fFamilies(20),
47 	fRevision(0),
48 	fNextID(0)
49 {
50 }
51 
52 
53 FontManager::~FontManager()
54 {
55 	_RemoveAllFonts();
56 }
57 
58 
59 /*!	\brief Finds and returns the first valid charmap in a font
60 
61 	\param face Font handle obtained from FT_Load_Face()
62 	\return An FT_CharMap or NULL if unsuccessful
63 */
64 FT_CharMap
65 FontManager::_GetSupportedCharmap(const FT_Face& face)
66 {
67 	for (int32 i = 0; i < face->num_charmaps; i++) {
68 		FT_CharMap charmap = face->charmaps[i];
69 
70 		switch (charmap->platform_id) {
71 			case 3:
72 				// if Windows Symbol or Windows Unicode
73 				if (charmap->encoding_id == 0 || charmap->encoding_id == 1)
74 					return charmap;
75 				break;
76 
77 			case 1:
78 				// if Apple Unicode
79 				if (charmap->encoding_id == 0)
80 					return charmap;
81 				break;
82 
83 			case 0:
84 				// if Apple Roman
85 				if (charmap->encoding_id == 0)
86 					return charmap;
87 				break;
88 
89 			default:
90 				break;
91 		}
92 	}
93 
94 	return NULL;
95 }
96 
97 
98 
99 /*!	\brief Counts the number of font families available
100 	\return The number of unique font families currently available
101 */
102 int32
103 FontManager::CountFamilies()
104 {
105 	return fFamilies.CountItems();
106 }
107 
108 
109 /*!	\brief Counts the number of styles available in a font family
110 	\param family Name of the font family to scan
111 	\return The number of font styles currently available for the font family
112 */
113 int32
114 FontManager::CountStyles(const char *familyName)
115 {
116 	FontFamily *family = GetFamily(familyName);
117 	if (family != NULL)
118 		return family->CountStyles();
119 
120 	return 0;
121 }
122 
123 
124 /*!	\brief Counts the number of styles available in a font family
125 	\param family Name of the font family to scan
126 	\return The number of font styles currently available for the font family
127 */
128 int32
129 FontManager::CountStyles(uint16 familyID)
130 {
131 	FontFamily *family = GetFamily(familyID);
132 	if (family != NULL)
133 		return family->CountStyles();
134 
135 	return 0;
136 }
137 
138 
139 FontFamily*
140 FontManager::FamilyAt(int32 index) const
141 {
142 	ASSERT(IsLocked());
143 
144 	return fFamilies.ItemAt(index);
145 }
146 
147 
148 /*!	\brief Locates a FontFamily object by name
149 	\param name The family to find
150 	\return Pointer to the specified family or NULL if not found.
151 */
152 FontFamily*
153 FontManager::GetFamily(const char* name)
154 {
155 	if (name == NULL)
156 		return NULL;
157 
158 	return _FindFamily(name);
159 }
160 
161 
162 FontFamily*
163 FontManager::GetFamily(uint16 familyID) const
164 {
165 	FontKey key(familyID, 0);
166 	FontStyle* style = fStyleHashTable.Get(key);
167 	if (style != NULL)
168 		return style->Family();
169 
170 	// Try the slow route in case style 0 was removed
171 	return _FindFamily(familyID);
172 }
173 
174 
175 FontStyle*
176 FontManager::GetStyleByIndex(const char* familyName, int32 index)
177 {
178 	FontFamily* family = GetFamily(familyName);
179 	if (family != NULL)
180 		return family->StyleAt(index);
181 
182 	return NULL;
183 }
184 
185 
186 FontStyle*
187 FontManager::GetStyleByIndex(uint16 familyID, int32 index)
188 {
189 	FontFamily* family = GetFamily(familyID);
190 	if (family != NULL)
191 		return family->StyleAt(index);
192 
193 	return NULL;
194 }
195 
196 
197 /*!	\brief Retrieves the FontStyle object
198 	\param family ID for the font's family
199 	\param style ID of the font's style
200 	\return The FontStyle having those attributes or NULL if not available
201 */
202 FontStyle*
203 FontManager::GetStyle(uint16 familyID, uint16 styleID) const
204 {
205 	ASSERT(IsLocked());
206 
207 	FontKey key(familyID, styleID);
208 	FontStyle* style = fStyleHashTable.Get(key);
209 	if (style != NULL)
210 		return style;
211 
212 	return fDelistedStyleHashTable.Get(key);
213 }
214 
215 
216 /*!	\brief Retrieves the FontStyle object that comes closest to the one
217 		specified.
218 
219 	\param family The font's family or NULL in which case \a familyID is used
220 	\param style The font's style or NULL in which case \a styleID is used
221 	\param familyID will only be used if \a family is NULL (or empty)
222 	\param styleID will only be used if \a family and \a style are NULL (or empty)
223 	\param face is used to specify the style if both \a style is NULL or empty
224 		and styleID is 0xffff.
225 
226 	\return The FontStyle having those attributes or NULL if not available
227 */
228 FontStyle*
229 FontManager::GetStyle(const char* familyName, const char* styleName,
230 	uint16 familyID, uint16 styleID, uint16 face)
231 {
232 	ASSERT(IsLocked());
233 
234 	FontFamily* family;
235 
236 	if (styleID != 0xffff && (familyName == NULL || !familyName[0])
237 		&& (styleName == NULL || !styleName[0])) {
238 		return GetStyle(familyID, styleID);
239 	}
240 
241 	// find family
242 
243 	if (familyName != NULL && familyName[0])
244 		family = GetFamily(familyName);
245 	else
246 		family = GetFamily(familyID);
247 
248 	if (family == NULL)
249 		return NULL;
250 
251 	// find style
252 
253 	if (styleName != NULL && styleName[0])
254 		return family->GetStyle(styleName);
255 
256 	// try to get from face
257 	return family->GetStyleMatchingFace(face);
258 }
259 
260 
261 /*!	\brief If you don't find your preferred font style, but are anxious
262 		to have one fitting your needs, you may want to use this method.
263 */
264 FontStyle*
265 FontManager::FindStyleMatchingFace(uint16 face) const
266 {
267 	int32 count = fFamilies.CountItems();
268 
269 	for (int32 i = 0; i < count; i++) {
270 		FontFamily* family = fFamilies.ItemAt(i);
271 		FontStyle* style = family->GetStyleMatchingFace(face);
272 		if (style != NULL)
273 			return style;
274 	}
275 
276 	return NULL;
277 }
278 
279 
280 /*!	\brief This call is used by the FontStyle class - and the FontStyle class
281 		only - to remove itself from the font manager.
282 	At this point, the style is already no longer available to the user.
283 */
284 void
285 FontManager::RemoveStyle(FontStyle* style)
286 {
287 	ASSERT(IsLocked());
288 
289 	FontFamily* family = style->Family();
290 	if (family == NULL)
291 		debugger("family is NULL!");
292 
293 	family->RemoveStyle(style);
294 	fDelistedStyleHashTable.Remove(FontKey(family->ID(), style->ID()));
295 }
296 
297 
298 uint32
299 FontManager::Revision()
300 {
301 	return fRevision;
302 }
303 
304 
305 status_t
306 FontManager::_AddFont(FT_Face face, node_ref nodeRef, const char* path,
307 	uint16& familyID, uint16& styleID)
308 {
309 	ASSERT(IsLocked());
310 
311 	BReference<FontFamily> family(_FindFamily(face->family_name));
312 	bool isNewFontFamily = !family.IsSet();
313 
314 	if (family.IsSet() && family->HasStyle(face->style_name)) {
315 		// prevent adding the same style twice
316 		// (this indicates a problem with the installed fonts maybe?)
317 		FT_Done_Face(face);
318 		return B_NAME_IN_USE;
319 	}
320 
321 	if (!family.IsSet()) {
322 		family.SetTo(new (std::nothrow) FontFamily(face->family_name, _NextID()), true);
323 
324 		if (!family.IsSet() || !fFamilies.BinaryInsert(family, compare_font_families)) {
325 			FT_Done_Face(face);
326 			return B_NO_MEMORY;
327 		}
328 	}
329 
330 	FTRACE(("\tadd style: %s, %s\n", face->family_name, face->style_name));
331 
332 	// the FontStyle takes over ownership of the FT_Face object
333 	FontStyle* style = new (std::nothrow) FontStyle(nodeRef, path, face, this);
334 
335 	if (style == NULL || !family->AddStyle(style)) {
336 		delete style;
337 		if (isNewFontFamily)
338 			fFamilies.RemoveItem(family);
339 		return B_NO_MEMORY;
340 	}
341 
342 	familyID = style->Family()->ID();
343 	styleID = style->ID();
344 
345 	fStyleHashTable.Put(FontKey(familyID, styleID), style);
346 	style->ReleaseReference();
347 
348 	fRevision++;
349 	return B_OK;
350 }
351 
352 
353 FontStyle*
354 FontManager::_RemoveFont(uint16 familyID, uint16 styleID)
355 {
356 	ASSERT(IsLocked());
357 
358 	FontKey key(familyID, styleID);
359 	FontStyle* style = fStyleHashTable.Get(key);
360 	if (style != NULL) {
361 		fDelistedStyleHashTable.Put(key, style);
362 		FontFamily* family = style->Family();
363 		if (family->RemoveStyle(style) && family->CountStyles() == 0)
364 			fFamilies.RemoveItem(family);
365 		fStyleHashTable.Remove(key);
366 	}
367 
368 	fRevision++;
369 	return style;
370 }
371 
372 
373 void
374 FontManager::_RemoveAllFonts()
375 {
376 	fFamilies.MakeEmpty();
377 
378 	// Disconnect the styles from their families before removing them; once we
379 	// get to this point, we are in the dtor and don't want them to call back.
380 
381 	HashMap<FontKey, FontStyle*>::Iterator delisted = fDelistedStyleHashTable.GetIterator();
382 	while (delisted.HasNext())
383 		delisted.Next().value->_SetFontFamily(NULL, -1);
384 	fDelistedStyleHashTable.Clear();
385 
386 	HashMap<FontKey, BReference<FontStyle> >::Iterator referenced = fStyleHashTable.GetIterator();
387 	while (referenced.HasNext())
388 		referenced.Next().value->_SetFontFamily(NULL, -1);
389 	fStyleHashTable.Clear();
390 }
391 
392 
393 FontFamily*
394 FontManager::_FindFamily(const char* name) const
395 {
396 	if (name == NULL)
397 		return NULL;
398 
399 	FontFamily family(name, 0);
400 	return const_cast<FontFamily*>(fFamilies.BinarySearch(family,
401 		compare_font_families));
402 }
403 
404 
405 FontFamily*
406 FontManager::_FindFamily(uint16 familyID) const
407 {
408 	int32 count = fFamilies.CountItems();
409 
410 	for (int32 i = 0; i < count; i++) {
411 		FontFamily* family = fFamilies.ItemAt(i);
412 		if (family->ID() == familyID)
413 			return family;
414 	}
415 
416 	return NULL;
417 }
418 
419 
420 uint16
421 FontManager::_NextID()
422 {
423 	return fNextID++;
424 }
425