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