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
font_score(const FontStyle * style)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
compare_font_styles(const FontStyle * a,const FontStyle * b)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 */
FontFamily(const char * name,uint16 id)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*
Name() const70 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
AddStyle(FontStyle * style)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
RemoveStyle(FontStyle * style)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
CountStyles() const131 FontFamily::CountStyles() const
132 {
133 return fStyles.CountItems();
134 }
135
136
137 FontStyle*
_FindStyle(const char * name) const138 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
HasStyle(const char * styleName) const160 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*
StyleAt(int32 index) const172 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*
GetStyle(const char * name) const186 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*
GetStyleMatchingFace(uint16 face) const223 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
Flags()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