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