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 Returns the name of the family 67 \return The family's name 68 */ 69 const char* 70 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 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 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 131 FontFamily::CountStyles() const 132 { 133 return fStyles.CountItems(); 134 } 135 136 137 FontStyle* 138 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 160 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* 172 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* 186 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* 223 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 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