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