xref: /haiku/src/servers/app/font/FontFamily.cpp (revision 68d37cfb3a755a7270d772b505ee15c8b18aa5e0)
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 "FontManager.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 }
83 
84 
85 /*!
86 	\brief Returns the name of the family
87 	\return The family's name
88 */
89 const char*
90 FontFamily::Name() const
91 {
92 	return fName.String();
93 }
94 
95 
96 /*!
97 	\brief Adds the style to the family
98 	\param style pointer to FontStyle object to be added
99 */
100 bool
101 FontFamily::AddStyle(FontStyle *style)
102 {
103 	if (!style)
104 		return false;
105 
106 	// Don't add if it already is in the family.
107 	int32 count = fStyles.CountItems();
108 	for (int32 i = 0; i < count; i++) {
109 		FontStyle *item = fStyles.ItemAt(i);
110 		if (!strcmp(item->Name(), style->Name()))
111 			return false;
112 	}
113 
114 	if (!fStyles.BinaryInsert(style, compare_font_styles))
115 		return false;
116 
117 	style->_SetFontFamily(this, fNextID++);
118 
119 	// force a refresh if a request for font flags is needed
120 	fFlags = kInvalidFamilyFlags;
121 
122 	return true;
123 }
124 
125 
126 /*!
127 	\brief Removes a style from the family.
128 
129 	The font style will not be deleted.
130 */
131 bool
132 FontFamily::RemoveStyle(FontStyle* style)
133 {
134 	if (!gFontManager->IsLocked()) {
135 		debugger("FontFamily::RemoveStyle() called without having the font manager locked!");
136 		return false;
137 	}
138 
139 	if (!fStyles.RemoveItem(style))
140 		return false;
141 
142 	style->_SetFontFamily(NULL, -1);
143 
144 	// force a refresh if a request for font flags is needed
145 	fFlags = kInvalidFamilyFlags;
146 	return true;
147 }
148 
149 
150 /*!
151 	\brief Returns the number of styles in the family
152 	\return The number of styles in the family
153 */
154 int32
155 FontFamily::CountStyles() const
156 {
157 	return fStyles.CountItems();
158 }
159 
160 
161 FontStyle*
162 FontFamily::_FindStyle(const char* name) const
163 {
164 	int32 count = fStyles.CountItems();
165 	if (!name || count < 1)
166 		return NULL;
167 
168 	for (int32 i = 0; i < count; i++) {
169 		FontStyle *style = fStyles.ItemAt(i);
170 		if (!strcmp(style->Name(), name))
171 			return style;
172 	}
173 
174 	return NULL;
175 }
176 
177 
178 /*!
179 	\brief Determines whether the style belongs to the family
180 	\param style Name of the style being checked
181 	\return True if it belongs, false if not
182 */
183 bool
184 FontFamily::HasStyle(const char *styleName) const
185 {
186 	return _FindStyle(styleName) != NULL;
187 }
188 
189 
190 /*!
191 	\brief Returns the name of a style in the family
192 	\param index list index of the style to be found
193 	\return name of the style or NULL if the index is not valid
194 */
195 FontStyle*
196 FontFamily::StyleAt(int32 index) const
197 {
198 	return fStyles.ItemAt(index);
199 }
200 
201 
202 /*!
203 	\brief Get the FontStyle object for the name given
204 	\param style Name of the style to be obtained
205 	\return The FontStyle object or NULL if none was found.
206 
207 	The object returned belongs to the family and must not be deleted.
208 */
209 FontStyle*
210 FontFamily::GetStyle(const char *name) const
211 {
212 	if (name == NULL || !name[0])
213 		return NULL;
214 
215 	FontStyle* style = _FindStyle(name);
216 	if (style != NULL)
217 		return style;
218 
219 	// try alternative names
220 
221 	if (!strcmp(name, "Roman") || !strcmp(name, "Regular")
222 		|| !strcmp(name, "Book")) {
223 		style = _FindStyle("Roman");
224 		if (style == NULL) {
225 			style = _FindStyle("Regular");
226 			if (style == NULL)
227 				style = _FindStyle("Book");
228 		}
229 		return style;
230 	}
231 
232 	BString alternative = name;
233 	if (alternative.FindFirst("Italic") >= 0) {
234 		alternative.ReplaceFirst("Italic", "Oblique");
235 		return _FindStyle(alternative.String());
236 	}
237 	if (alternative.FindFirst("Oblique") >= 0) {
238 		alternative.ReplaceFirst("Oblique", "Italic");
239 		return _FindStyle(alternative.String());
240 	}
241 
242 	return NULL;
243 }
244 
245 
246 FontStyle*
247 FontFamily::GetStyleByID(uint16 id) const
248 {
249 	int32 count = fStyles.CountItems();
250 	for (int32 i = 0; i < count; i++) {
251 		FontStyle* style = fStyles.ItemAt(i);
252 		if (style->ID() == id)
253 			return style;
254 	}
255 
256 	return NULL;
257 }
258 
259 
260 FontStyle*
261 FontFamily::GetStyleMatchingFace(uint16 face) const
262 {
263 	// TODO: support other faces (strike through, underlined, outlines...)
264 	face &= B_BOLD_FACE | B_ITALIC_FACE | B_REGULAR_FACE | B_CONDENSED_FACE
265 		| B_LIGHT_FACE | B_HEAVY_FACE;
266 
267 	int32 count = fStyles.CountItems();
268 	for (int32 i = 0; i < count; i++) {
269 		FontStyle* style = fStyles.ItemAt(i);
270 
271 		if (style->Face() == face)
272 			return style;
273 	}
274 
275 	return NULL;
276 }
277 
278 
279 uint32
280 FontFamily::Flags()
281 {
282 	if (fFlags == kInvalidFamilyFlags) {
283 		fFlags = 0;
284 
285 		int32 count = fStyles.CountItems();
286 		for (int32 i = 0; i < count; i++) {
287 			FontStyle* style = fStyles.ItemAt(i);
288 
289 			if (style->IsFixedWidth())
290 				fFlags |= B_IS_FIXED;
291 			if (style->IsFullAndHalfFixed())
292 				fFlags |= B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED;
293 			if (style->TunedCount() > 0)
294 				fFlags |= B_HAS_TUNED_FONT;
295 		}
296 	}
297 
298 	return fFlags;
299 }
300