xref: /haiku/src/servers/app/font/FontFamily.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
1 /*
2  * Copyright 2001-2008, 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 /**	Classes to represent font styles and families */
11 
12 
13 #include "FontFamily.h"
14 
15 #include "GlobalFontManager.h"
16 
17 #include <FontPrivate.h>
18 
19 
20 const uint32 kInvalidFamilyFlags = ~(uint32)0;
21 
22 
23 static int
24 font_score(const FontStyle* style)
25 {
26 	int score = 0;
27 	if (style->Face() & B_REGULAR_FACE)
28 		score += 10;
29 	else {
30 		if (style->Face() & B_BOLD_FACE)
31 			score += 5;
32 		if (style->Face() & B_ITALIC_FACE)
33 			score--;
34 	}
35 
36 	return score;
37 }
38 
39 
40 static int
41 compare_font_styles(const FontStyle* a, const FontStyle* b)
42 {
43 	// Regular fonts come first, then bold, then italics
44 	return font_score(b) - font_score(a);
45 }
46 
47 
48 //	#pragma mark -
49 
50 
51 /*!
52 	\brief Constructor
53 	\param namestr Name of the family
54 */
55 FontFamily::FontFamily(const char *name, uint16 id)
56 	:
57 	fName(name),
58 	fID(id),
59 	fNextID(0),
60 	fFlags(kInvalidFamilyFlags)
61 {
62 	fName.Truncate(B_FONT_FAMILY_LENGTH);
63 		// make sure this family can be found using the Be API
64 }
65 
66 
67 /*!
68 	\brief Destructor
69 
70 	Deletes all attached styles. Note that a FontFamily must only be deleted
71 	by the font manager.
72 */
73 FontFamily::~FontFamily()
74 {
75 	for (int32 i = fStyles.CountItems(); i-- > 0;) {
76 		FontStyle* style = fStyles.RemoveItemAt(i);
77 
78 		// we remove us before deleting the style, so that the font manager
79 		// is not contacted to remove the style from us
80 		style->_SetFontFamily(NULL, -1);
81 
82 		style->ReleaseReference();
83 	}
84 }
85 
86 
87 /*!
88 	\brief Returns the name of the family
89 	\return The family's name
90 */
91 const char*
92 FontFamily::Name() const
93 {
94 	return fName.String();
95 }
96 
97 
98 /*!
99 	\brief Adds the style to the family
100 	\param style pointer to FontStyle object to be added
101 */
102 bool
103 FontFamily::AddStyle(FontStyle* style, AppFontManager* fontManager)
104 {
105 	if (!style)
106 		return false;
107 
108 	// Don't add if it already is in the family.
109 	int32 count = fStyles.CountItems();
110 	for (int32 i = 0; i < count; i++) {
111 		FontStyle *item = fStyles.ItemAt(i);
112 		if (!strcmp(item->Name(), style->Name()))
113 			return false;
114 	}
115 
116 	if (!fStyles.BinaryInsert(style, compare_font_styles))
117 		return false;
118 
119 	style->_SetFontFamily(this, fNextID++);
120 	style->_SetFontManager(fontManager);
121 
122 	// force a refresh if a request for font flags is needed
123 	fFlags = kInvalidFamilyFlags;
124 
125 	return true;
126 }
127 
128 
129 /*!
130 	\brief Removes a style from the family.
131 
132 	The font style will not be deleted.
133 */
134 bool
135 FontFamily::RemoveStyle(FontStyle* style, AppFontManager* fontManager)
136 {
137 	if (!gFontManager->IsLocked() && fontManager == NULL) {
138 		debugger("FontFamily::RemoveStyle() called without having the font manager locked!");
139 		return false;
140 	}
141 
142 	if (!fStyles.RemoveItem(style))
143 		return false;
144 
145 	style->_SetFontFamily(NULL, -1);
146 
147 	// force a refresh if a request for font flags is needed
148 	fFlags = kInvalidFamilyFlags;
149 	return true;
150 }
151 
152 
153 /*!
154 	\brief Returns the number of styles in the family
155 	\return The number of styles in the family
156 */
157 int32
158 FontFamily::CountStyles() const
159 {
160 	return fStyles.CountItems();
161 }
162 
163 
164 FontStyle*
165 FontFamily::_FindStyle(const char* name) const
166 {
167 	int32 count = fStyles.CountItems();
168 	if (!name || count < 1)
169 		return NULL;
170 
171 	for (int32 i = 0; i < count; i++) {
172 		FontStyle *style = fStyles.ItemAt(i);
173 		if (!strcmp(style->Name(), name))
174 			return style;
175 	}
176 
177 	return NULL;
178 }
179 
180 
181 /*!
182 	\brief Determines whether the style belongs to the family
183 	\param style Name of the style being checked
184 	\return True if it belongs, false if not
185 */
186 bool
187 FontFamily::HasStyle(const char *styleName) const
188 {
189 	return _FindStyle(styleName) != NULL;
190 }
191 
192 
193 /*!
194 	\brief Returns the name of a style in the family
195 	\param index list index of the style to be found
196 	\return name of the style or NULL if the index is not valid
197 */
198 FontStyle*
199 FontFamily::StyleAt(int32 index) const
200 {
201 	return fStyles.ItemAt(index);
202 }
203 
204 
205 /*!
206 	\brief Get the FontStyle object for the name given
207 	\param style Name of the style to be obtained
208 	\return The FontStyle object or NULL if none was found.
209 
210 	The object returned belongs to the family and must not be deleted.
211 */
212 FontStyle*
213 FontFamily::GetStyle(const char *name) const
214 {
215 	if (name == NULL || !name[0])
216 		return NULL;
217 
218 	FontStyle* style = _FindStyle(name);
219 	if (style != NULL)
220 		return style;
221 
222 	// try alternative names
223 
224 	if (!strcmp(name, "Roman") || !strcmp(name, "Regular")
225 		|| !strcmp(name, "Book")) {
226 		style = _FindStyle("Roman");
227 		if (style == NULL) {
228 			style = _FindStyle("Regular");
229 			if (style == NULL)
230 				style = _FindStyle("Book");
231 		}
232 		return style;
233 	}
234 
235 	BString alternative = name;
236 	if (alternative.FindFirst("Italic") >= 0) {
237 		alternative.ReplaceFirst("Italic", "Oblique");
238 		return _FindStyle(alternative.String());
239 	}
240 	if (alternative.FindFirst("Oblique") >= 0) {
241 		alternative.ReplaceFirst("Oblique", "Italic");
242 		return _FindStyle(alternative.String());
243 	}
244 
245 	return NULL;
246 }
247 
248 
249 FontStyle*
250 FontFamily::GetStyleByID(uint16 id) const
251 {
252 	int32 count = fStyles.CountItems();
253 	for (int32 i = 0; i < count; i++) {
254 		FontStyle* style = fStyles.ItemAt(i);
255 		if (style->ID() == id)
256 			return style;
257 	}
258 
259 	return NULL;
260 }
261 
262 
263 FontStyle*
264 FontFamily::GetStyleMatchingFace(uint16 face) const
265 {
266 	// Other face flags do not impact the font selection (they are applied
267 	// during drawing)
268 	face &= B_BOLD_FACE | B_ITALIC_FACE | B_REGULAR_FACE | B_CONDENSED_FACE
269 		| B_LIGHT_FACE | B_HEAVY_FACE;
270 	if (face == 0)
271 		face = B_REGULAR_FACE;
272 
273 	int32 count = fStyles.CountItems();
274 	for (int32 i = 0; i < count; i++) {
275 		FontStyle* style = fStyles.ItemAt(i);
276 
277 		if (style->Face() == face)
278 			return style;
279 	}
280 
281 	return NULL;
282 }
283 
284 
285 uint32
286 FontFamily::Flags()
287 {
288 	if (fFlags == kInvalidFamilyFlags) {
289 		fFlags = 0;
290 
291 		int32 count = fStyles.CountItems();
292 		for (int32 i = 0; i < count; i++) {
293 			FontStyle* style = fStyles.ItemAt(i);
294 
295 			if (style->IsFixedWidth())
296 				fFlags |= B_IS_FIXED;
297 			if (style->IsFullAndHalfFixed())
298 				fFlags |= B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED;
299 			if (style->TunedCount() > 0)
300 				fFlags |= B_HAS_TUNED_FONT;
301 		}
302 	}
303 
304 	return fFlags;
305 }
306