1 /* 2 * Copyright 2001-2016, 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 11 /*! Manages font families and styles */ 12 13 14 #include "FontManager.h" 15 16 #include <new> 17 18 #include <Debug.h> 19 20 #include "FontFamily.h" 21 22 23 //#define TRACE_FONT_MANAGER 24 #ifdef TRACE_FONT_MANAGER 25 # define FTRACE(x) printf x 26 #else 27 # define FTRACE(x) ; 28 #endif 29 30 31 FT_Library gFreeTypeLibrary; 32 33 34 static int 35 compare_font_families(const FontFamily* a, const FontFamily* b) 36 { 37 return strcmp(a->Name(), b->Name()); 38 } 39 40 41 // #pragma mark - 42 43 44 FontManager::FontManager() 45 : 46 fFamilies(20), 47 fNextID(0) 48 { 49 } 50 51 52 FontManager::~FontManager() 53 { 54 _RemoveAllFonts(); 55 } 56 57 58 /*! \brief Finds and returns the first valid charmap in a font 59 60 \param face Font handle obtained from FT_Load_Face() 61 \return An FT_CharMap or NULL if unsuccessful 62 */ 63 FT_CharMap 64 FontManager::_GetSupportedCharmap(const FT_Face& face) 65 { 66 for (int32 i = 0; i < face->num_charmaps; i++) { 67 FT_CharMap charmap = face->charmaps[i]; 68 69 switch (charmap->platform_id) { 70 case 3: 71 // if Windows Symbol or Windows Unicode 72 if (charmap->encoding_id == 0 || charmap->encoding_id == 1) 73 return charmap; 74 break; 75 76 case 1: 77 // if Apple Unicode 78 if (charmap->encoding_id == 0) 79 return charmap; 80 break; 81 82 case 0: 83 // if Apple Roman 84 if (charmap->encoding_id == 0) 85 return charmap; 86 break; 87 88 default: 89 break; 90 } 91 } 92 93 return NULL; 94 } 95 96 97 98 /*! \brief Counts the number of font families available 99 \return The number of unique font families currently available 100 */ 101 int32 102 FontManager::CountFamilies() 103 { 104 return fFamilies.CountItems(); 105 } 106 107 108 /*! \brief Counts the number of styles available in a font family 109 \param family Name of the font family to scan 110 \return The number of font styles currently available for the font family 111 */ 112 int32 113 FontManager::CountStyles(const char *familyName) 114 { 115 FontFamily *family = GetFamily(familyName); 116 if (family != NULL) 117 return family->CountStyles(); 118 119 return 0; 120 } 121 122 123 /*! \brief Counts the number of styles available in a font family 124 \param family Name of the font family to scan 125 \return The number of font styles currently available for the font family 126 */ 127 int32 128 FontManager::CountStyles(uint16 familyID) 129 { 130 FontFamily *family = GetFamily(familyID); 131 if (family != NULL) 132 return family->CountStyles(); 133 134 return 0; 135 } 136 137 138 FontFamily* 139 FontManager::FamilyAt(int32 index) const 140 { 141 ASSERT(IsLocked()); 142 143 return fFamilies.ItemAt(index); 144 } 145 146 147 /*! \brief Locates a FontFamily object by name 148 \param name The family to find 149 \return Pointer to the specified family or NULL if not found. 150 */ 151 FontFamily* 152 FontManager::GetFamily(const char* name) 153 { 154 if (name == NULL) 155 return NULL; 156 157 return _FindFamily(name); 158 } 159 160 161 FontFamily* 162 FontManager::GetFamily(uint16 familyID) const 163 { 164 FontKey key(familyID, 0); 165 FontStyle* style = fStyleHashTable.Get(key); 166 if (style != NULL) 167 return style->Family(); 168 169 return NULL; 170 } 171 172 173 FontStyle* 174 FontManager::GetStyleByIndex(const char* familyName, int32 index) 175 { 176 FontFamily* family = GetFamily(familyName); 177 if (family != NULL) 178 return family->StyleAt(index); 179 180 return NULL; 181 } 182 183 184 FontStyle* 185 FontManager::GetStyleByIndex(uint16 familyID, int32 index) 186 { 187 FontFamily* family = GetFamily(familyID); 188 if (family != NULL) 189 return family->StyleAt(index); 190 191 return NULL; 192 } 193 194 195 /*! \brief Retrieves the FontStyle object 196 \param family ID for the font's family 197 \param style ID of the font's style 198 \return The FontStyle having those attributes or NULL if not available 199 */ 200 FontStyle* 201 FontManager::GetStyle(uint16 familyID, uint16 styleID) const 202 { 203 ASSERT(IsLocked()); 204 205 FontKey key(familyID, styleID); 206 return fStyleHashTable.Get(key); 207 } 208 209 210 /*! \brief Retrieves the FontStyle object that comes closest to the one 211 specified. 212 213 \param family The font's family or NULL in which case \a familyID is used 214 \param style The font's style or NULL in which case \a styleID is used 215 \param familyID will only be used if \a family is NULL (or empty) 216 \param styleID will only be used if \a style is NULL (or empty) 217 \param face is used to specify the style if both \a style is NULL or empty 218 and styleID is 0xffff. 219 220 \return The FontStyle having those attributes or NULL if not available 221 */ 222 FontStyle* 223 FontManager::GetStyle(const char* familyName, const char* styleName, 224 uint16 familyID, uint16 styleID, uint16 face) 225 { 226 ASSERT(IsLocked()); 227 228 FontFamily* family; 229 230 // find family 231 232 if (familyName != NULL && familyName[0]) 233 family = GetFamily(familyName); 234 else 235 family = GetFamily(familyID); 236 237 if (family == NULL) 238 return NULL; 239 240 // find style 241 242 if (styleName != NULL && styleName[0]) 243 return family->GetStyle(styleName); 244 245 if (styleID != 0xffff) 246 return family->GetStyleByID(styleID); 247 248 // try to get from face 249 return family->GetStyleMatchingFace(face); 250 } 251 252 253 /*! \brief If you don't find your preferred font style, but are anxious 254 to have one fitting your needs, you may want to use this method. 255 */ 256 FontStyle* 257 FontManager::FindStyleMatchingFace(uint16 face) const 258 { 259 int32 count = fFamilies.CountItems(); 260 261 for (int32 i = 0; i < count; i++) { 262 FontFamily* family = fFamilies.ItemAt(i); 263 FontStyle* style = family->GetStyleMatchingFace(face); 264 if (style != NULL) 265 return style; 266 } 267 268 return NULL; 269 } 270 271 272 /*! \brief This call is used by the FontStyle class - and the FontStyle class 273 only - to remove itself from the font manager. 274 At this point, the style is already no longer available to the user. 275 */ 276 void 277 FontManager::RemoveStyle(FontStyle* style) 278 { 279 ASSERT(IsLocked()); 280 281 FontFamily* family = style->Family(); 282 if (family == NULL) 283 debugger("family is NULL!"); 284 285 FontStyle* check = GetStyle(family->ID(), style->ID()); 286 if (check != NULL) 287 debugger("style removed but still available!"); 288 289 if (family->RemoveStyle(style) 290 && family->CountStyles() == 0) { 291 fFamilies.RemoveItem(family); 292 delete family; 293 } 294 } 295 296 297 status_t 298 FontManager::_AddFont(FT_Face face, node_ref nodeRef, const char* path, 299 uint16& familyID, uint16& styleID) 300 { 301 ASSERT(IsLocked()); 302 303 FontFamily* family = _FindFamily(face->family_name); 304 bool isNewFontFamily = family == NULL; 305 306 if (family != NULL && family->HasStyle(face->style_name)) { 307 // prevent adding the same style twice 308 // (this indicates a problem with the installed fonts maybe?) 309 FT_Done_Face(face); 310 return B_NAME_IN_USE; 311 } 312 313 if (family == NULL) { 314 family = new (std::nothrow) FontFamily(face->family_name, _NextID()); 315 316 if (family == NULL 317 || !fFamilies.BinaryInsert(family, compare_font_families)) { 318 delete family; 319 FT_Done_Face(face); 320 return B_NO_MEMORY; 321 } 322 } 323 324 FTRACE(("\tadd style: %s, %s\n", face->family_name, face->style_name)); 325 326 // the FontStyle takes over ownership of the FT_Face object 327 FontStyle* style = new (std::nothrow) FontStyle(nodeRef, path, face, this); 328 329 if (style == NULL || !family->AddStyle(style)) { 330 delete style; 331 if (isNewFontFamily) 332 delete family; 333 return B_NO_MEMORY; 334 } 335 336 familyID = style->Family()->ID(); 337 styleID = style->ID(); 338 339 fStyleHashTable.Put(FontKey(familyID, styleID), style); 340 style->ReleaseReference(); 341 342 return B_OK; 343 } 344 345 346 FontStyle* 347 FontManager::_RemoveFont(uint16 familyID, uint16 styleID) 348 { 349 ASSERT(IsLocked()); 350 351 return fStyleHashTable.Remove(FontKey(familyID, styleID)); 352 } 353 354 355 void 356 FontManager::_RemoveAllFonts() 357 { 358 for (int32 i = fFamilies.CountItems(); i-- > 0;) 359 delete fFamilies.RemoveItemAt(i); 360 361 fStyleHashTable.Clear(); 362 } 363 364 365 FontFamily* 366 FontManager::_FindFamily(const char* name) const 367 { 368 if (name == NULL) 369 return NULL; 370 371 FontFamily family(name, 0); 372 return const_cast<FontFamily*>(fFamilies.BinarySearch(family, 373 compare_font_families)); 374 } 375 376 377 uint16 378 FontManager::_NextID() 379 { 380 return fNextID++; 381 } 382