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