xref: /haiku/src/servers/app/font/FontManager.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
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 <Autolock.h>
19 #include <Debug.h>
20 #include <Directory.h>
21 #include <Entry.h>
22 #include <File.h>
23 #include <FindDirectory.h>
24 #include <Message.h>
25 #include <NodeMonitor.h>
26 #include <Path.h>
27 #include <String.h>
28 
29 #include "FontFamily.h"
30 #include "ServerConfig.h"
31 #include "ServerFont.h"
32 
33 
34 //#define TRACE_FONT_MANAGER
35 #ifdef TRACE_FONT_MANAGER
36 #	define FTRACE(x) printf x
37 #else
38 #	define FTRACE(x) ;
39 #endif
40 
41 
42 FT_Library gFreeTypeLibrary;
43 
44 //	#pragma mark -
45 
46 
47 int
48 FontManagerBase::compare_font_families(const FontFamily* a, const FontFamily* b)
49 {
50 	return strcmp(a->Name(), b->Name());
51 }
52 
53 
54 //! Initializes FreeType if requested
55 FontManagerBase::FontManagerBase(bool init_freetype, const char* className)
56 	: BLooper(className),
57 	fFamilies(20),
58 	fNextID(0),
59 	fHasFreetypeLibrary(init_freetype)
60 {
61 	if (init_freetype == true)
62 		fInitStatus = FT_Init_FreeType(&gFreeTypeLibrary) == 0 ? B_OK : B_ERROR;
63 }
64 
65 
66 //! Frees font families shuts down FreeType if it was initialized
67 FontManagerBase::~FontManagerBase()
68 {
69 	// free families before we're done with FreeType
70 
71 	for (int32 i = fFamilies.CountItems(); i-- > 0;)
72 		delete fFamilies.ItemAt(i);
73 
74 	if (fHasFreetypeLibrary == true)
75 		FT_Done_FreeType(gFreeTypeLibrary);
76 }
77 
78 
79 void
80 FontManagerBase::MessageReceived(BMessage* message)
81 {
82 	switch (message->what) {
83 		default:
84 			BLooper::MessageReceived(message);
85 			break;
86 	}
87 }
88 
89 
90 /*!	\brief Finds and returns the first valid charmap in a font
91 
92 	\param face Font handle obtained from FT_Load_Face()
93 	\return An FT_CharMap or NULL if unsuccessful
94 */
95 FT_CharMap
96 FontManagerBase::_GetSupportedCharmap(const FT_Face& face)
97 {
98 	for (int32 i = 0; i < face->num_charmaps; i++) {
99 		FT_CharMap charmap = face->charmaps[i];
100 
101 		switch (charmap->platform_id) {
102 			case 3:
103 				// if Windows Symbol or Windows Unicode
104 				if (charmap->encoding_id == 0 || charmap->encoding_id == 1)
105 					return charmap;
106 				break;
107 
108 			case 1:
109 				// if Apple Unicode
110 				if (charmap->encoding_id == 0)
111 					return charmap;
112 				break;
113 
114 			case 0:
115 				// if Apple Roman
116 				if (charmap->encoding_id == 0)
117 					return charmap;
118 				break;
119 
120 			default:
121 				break;
122 		}
123 	}
124 
125 	return NULL;
126 }
127 
128 
129 
130 /*!	\brief Counts the number of font families available
131 	\return The number of unique font families currently available
132 */
133 int32
134 FontManagerBase::CountFamilies()
135 {
136 	return fFamilies.CountItems();
137 }
138 
139 
140 /*!	\brief Counts the number of styles available in a font family
141 	\param family Name of the font family to scan
142 	\return The number of font styles currently available for the font family
143 */
144 int32
145 FontManagerBase::CountStyles(const char *familyName)
146 {
147 	FontFamily *family = GetFamily(familyName);
148 	if (family)
149 		return family->CountStyles();
150 
151 	return 0;
152 }
153 
154 
155 /*!	\brief Counts the number of styles available in a font family
156 	\param family Name of the font family to scan
157 	\return The number of font styles currently available for the font family
158 */
159 int32
160 FontManagerBase::CountStyles(uint16 familyID)
161 {
162 	FontFamily *family = GetFamily(familyID);
163 	if (family)
164 		return family->CountStyles();
165 
166 	return 0;
167 }
168 
169 
170 FontFamily*
171 FontManagerBase::FamilyAt(int32 index) const
172 {
173 	ASSERT(IsLocked());
174 
175 	return fFamilies.ItemAt(index);
176 }
177 
178 
179 /*!	\brief Locates a FontFamily object by name
180 	\param name The family to find
181 	\return Pointer to the specified family or NULL if not found.
182 */
183 FontFamily*
184 FontManagerBase::GetFamily(const char* name)
185 {
186 	if (name == NULL)
187 		return NULL;
188 
189 	FontFamily* family = _FindFamily(name);
190 	if (family != NULL)
191 		return family;
192 
193 	return _FindFamily(name);
194 }
195 
196 
197 FontFamily*
198 FontManagerBase::GetFamily(uint16 familyID) const
199 {
200 	FontKey key(familyID, 0);
201 	FontStyle* style = fStyleHashTable.Get(key);
202 	if (style != NULL)
203 		return style->Family();
204 
205 	return NULL;
206 }
207 
208 
209 FontStyle*
210 FontManagerBase::GetStyleByIndex(const char* familyName, int32 index)
211 {
212 	FontFamily* family = GetFamily(familyName);
213 	if (family != NULL)
214 		return family->StyleAt(index);
215 
216 	return NULL;
217 }
218 
219 
220 FontStyle*
221 FontManagerBase::GetStyleByIndex(uint16 familyID, int32 index)
222 {
223 	FontFamily* family = GetFamily(familyID);
224 	if (family != NULL)
225 		return family->StyleAt(index);
226 
227 	return NULL;
228 }
229 
230 
231 /*!	\brief Retrieves the FontStyle object
232 	\param family ID for the font's family
233 	\param style ID of the font's style
234 	\return The FontStyle having those attributes or NULL if not available
235 */
236 FontStyle*
237 FontManagerBase::GetStyle(uint16 familyID, uint16 styleID) const
238 {
239 	ASSERT(IsLocked());
240 
241 	FontKey key(familyID, styleID);
242 	return fStyleHashTable.Get(key);
243 }
244 
245 
246 /*!	\brief Retrieves the FontStyle object that comes closest to the one
247 		specified.
248 
249 	\param family The font's family or NULL in which case \a familyID is used
250 	\param style The font's style or NULL in which case \a styleID is used
251 	\param familyID will only be used if \a family is NULL (or empty)
252 	\param styleID will only be used if \a style is NULL (or empty)
253 	\param face is used to specify the style if both \a style is NULL or empty
254 		and styleID is 0xffff.
255 
256 	\return The FontStyle having those attributes or NULL if not available
257 */
258 FontStyle*
259 FontManagerBase::GetStyle(const char* familyName, const char* styleName,
260 	uint16 familyID, uint16 styleID, uint16 face)
261 {
262 	ASSERT(IsLocked());
263 
264 	FontFamily* family;
265 
266 	// find family
267 
268 	if (familyName != NULL && familyName[0])
269 		family = GetFamily(familyName);
270 	else
271 		family = GetFamily(familyID);
272 
273 	if (family == NULL)
274 		return NULL;
275 
276 	// find style
277 
278 	if (styleName != NULL && styleName[0]) {
279 		FontStyle* fontStyle = family->GetStyle(styleName);
280 		if (fontStyle != NULL)
281 			return fontStyle;
282 
283 		return family->GetStyle(styleName);
284 	}
285 
286 	if (styleID != 0xffff)
287 		return family->GetStyleByID(styleID);
288 
289 	// try to get from face
290 	return family->GetStyleMatchingFace(face);
291 }
292 
293 
294 /*!	\brief If you don't find your preferred font style, but are anxious
295 		to have one fitting your needs, you may want to use this method.
296 */
297 FontStyle*
298 FontManagerBase::FindStyleMatchingFace(uint16 face) const
299 {
300 	int32 count = fFamilies.CountItems();
301 
302 	for (int32 i = 0; i < count; i++) {
303 		FontFamily* family = fFamilies.ItemAt(i);
304 		FontStyle* style = family->GetStyleMatchingFace(face);
305 		if (style != NULL)
306 			return style;
307 	}
308 
309 	return NULL;
310 }
311 
312 
313 /*!	\brief This call is used by the FontStyle class - and the FontStyle class
314 		only - to remove itself from the font manager.
315 	At this point, the style is already no longer available to the user.
316 */
317 void
318 FontManagerBase::RemoveStyle(FontStyle* style)
319 {
320 	ASSERT(IsLocked());
321 
322 	FontFamily* family = style->Family();
323 	if (family == NULL)
324 		debugger("family is NULL!");
325 
326 	FontStyle* check = GetStyle(family->ID(), style->ID());
327 	if (check != NULL)
328 		debugger("style removed but still available!");
329 
330 	if (family->RemoveStyle(style)
331 		&& family->CountStyles() == 0)
332 		fFamilies.RemoveItem(family);
333 }
334 
335 
336 FontFamily*
337 FontManagerBase::_FindFamily(const char* name) const
338 {
339 	if (name == NULL)
340 		return NULL;
341 
342 	FontFamily family(name, 0);
343 	return const_cast<FontFamily*>(fFamilies.BinarySearch(family,
344 		compare_font_families));
345 }