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