xref: /haiku/src/servers/app/font/FontManager.cpp (revision 0c062f469a42f945fc4cb5efadce721728ac0996)
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 	fNextID(0)
48 {
49 }
50 
51 
52 FontManager::~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 */
63 FT_CharMap
64 FontManager::_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 */
101 int32
102 FontManager::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 */
112 int32
113 FontManager::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 */
127 int32
128 FontManager::CountStyles(uint16 familyID)
129 {
130 	FontFamily *family = GetFamily(familyID);
131 	if (family != NULL)
132 		return family->CountStyles();
133 
134 	return 0;
135 }
136 
137 
138 FontFamily*
139 FontManager::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 */
151 FontFamily*
152 FontManager::GetFamily(const char* name)
153 {
154 	if (name == NULL)
155 		return NULL;
156 
157 	return _FindFamily(name);
158 }
159 
160 
161 FontFamily*
162 FontManager::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 
173 FontStyle*
174 FontManager::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 
184 FontStyle*
185 FontManager::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 */
200 FontStyle*
201 FontManager::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 */
222 FontStyle*
223 FontManager::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 */
256 FontStyle*
257 FontManager::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 */
276 void
277 FontManager::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 
297 status_t
298 FontManager::_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 
346 FontStyle*
347 FontManager::_RemoveFont(uint16 familyID, uint16 styleID)
348 {
349 	ASSERT(IsLocked());
350 
351 	return fStyleHashTable.Remove(FontKey(familyID, styleID));
352 }
353 
354 
355 void
356 FontManager::_RemoveAllFonts()
357 {
358 	for (int32 i = fFamilies.CountItems(); i-- > 0;)
359 		delete fFamilies.RemoveItemAt(i);
360 
361 	fStyleHashTable.Clear();
362 }
363 
364 
365 FontFamily*
366 FontManager::_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 
377 uint16
378 FontManager::_NextID()
379 {
380 	return fNextID++;
381 }
382