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