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