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 // Try the slow route in case style 0 was removed 170 return _FindFamily(familyID); 171 } 172 173 174 FontStyle* 175 FontManager::GetStyleByIndex(const char* familyName, int32 index) 176 { 177 FontFamily* family = GetFamily(familyName); 178 if (family != NULL) 179 return family->StyleAt(index); 180 181 return NULL; 182 } 183 184 185 FontStyle* 186 FontManager::GetStyleByIndex(uint16 familyID, int32 index) 187 { 188 FontFamily* family = GetFamily(familyID); 189 if (family != NULL) 190 return family->StyleAt(index); 191 192 return NULL; 193 } 194 195 196 /*! \brief Retrieves the FontStyle object 197 \param family ID for the font's family 198 \param style ID of the font's style 199 \return The FontStyle having those attributes or NULL if not available 200 */ 201 FontStyle* 202 FontManager::GetStyle(uint16 familyID, uint16 styleID) const 203 { 204 ASSERT(IsLocked()); 205 206 FontKey key(familyID, styleID); 207 FontStyle* style = fStyleHashTable.Get(key); 208 if (style != NULL) 209 return style; 210 211 return fDelistedStyleHashTable.Get(key); 212 } 213 214 215 /*! \brief Retrieves the FontStyle object that comes closest to the one 216 specified. 217 218 \param family The font's family or NULL in which case \a familyID is used 219 \param style The font's style or NULL in which case \a styleID is used 220 \param familyID will only be used if \a family is NULL (or empty) 221 \param styleID will only be used if \a family and \a style are NULL (or empty) 222 \param face is used to specify the style if both \a style is NULL or empty 223 and styleID is 0xffff. 224 225 \return The FontStyle having those attributes or NULL if not available 226 */ 227 FontStyle* 228 FontManager::GetStyle(const char* familyName, const char* styleName, 229 uint16 familyID, uint16 styleID, uint16 face) 230 { 231 ASSERT(IsLocked()); 232 233 FontFamily* family; 234 235 if (styleID != 0xffff && (familyName == NULL || !familyName[0]) 236 && (styleName == NULL || !styleName[0])) { 237 return GetStyle(familyID, styleID); 238 } 239 240 // find family 241 242 if (familyName != NULL && familyName[0]) 243 family = GetFamily(familyName); 244 else 245 family = GetFamily(familyID); 246 247 if (family == NULL) 248 return NULL; 249 250 // find style 251 252 if (styleName != NULL && styleName[0]) 253 return family->GetStyle(styleName); 254 255 // try to get from face 256 return family->GetStyleMatchingFace(face); 257 } 258 259 260 /*! \brief If you don't find your preferred font style, but are anxious 261 to have one fitting your needs, you may want to use this method. 262 */ 263 FontStyle* 264 FontManager::FindStyleMatchingFace(uint16 face) const 265 { 266 int32 count = fFamilies.CountItems(); 267 268 for (int32 i = 0; i < count; i++) { 269 FontFamily* family = fFamilies.ItemAt(i); 270 FontStyle* style = family->GetStyleMatchingFace(face); 271 if (style != NULL) 272 return style; 273 } 274 275 return NULL; 276 } 277 278 279 /*! \brief This call is used by the FontStyle class - and the FontStyle class 280 only - to remove itself from the font manager. 281 At this point, the style is already no longer available to the user. 282 */ 283 void 284 FontManager::RemoveStyle(FontStyle* style) 285 { 286 ASSERT(IsLocked()); 287 288 FontFamily* family = style->Family(); 289 if (family == NULL) 290 debugger("family is NULL!"); 291 292 family->RemoveStyle(style); 293 fDelistedStyleHashTable.Remove(FontKey(family->ID(), style->ID())); 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 BReference<FontFamily> family(_FindFamily(face->family_name)); 304 bool isNewFontFamily = !family.IsSet(); 305 306 if (family.IsSet() && 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.IsSet()) { 314 family.SetTo(new (std::nothrow) FontFamily(face->family_name, _NextID()), true); 315 316 if (!family.IsSet() || !fFamilies.BinaryInsert(family, compare_font_families)) { 317 FT_Done_Face(face); 318 return B_NO_MEMORY; 319 } 320 } 321 322 FTRACE(("\tadd style: %s, %s\n", face->family_name, face->style_name)); 323 324 // the FontStyle takes over ownership of the FT_Face object 325 FontStyle* style = new (std::nothrow) FontStyle(nodeRef, path, face, this); 326 327 if (style == NULL || !family->AddStyle(style)) { 328 delete style; 329 if (isNewFontFamily) 330 fFamilies.RemoveItem(family); 331 return B_NO_MEMORY; 332 } 333 334 familyID = style->Family()->ID(); 335 styleID = style->ID(); 336 337 fStyleHashTable.Put(FontKey(familyID, styleID), style); 338 style->ReleaseReference(); 339 340 return B_OK; 341 } 342 343 344 FontStyle* 345 FontManager::_RemoveFont(uint16 familyID, uint16 styleID) 346 { 347 ASSERT(IsLocked()); 348 349 FontKey key(familyID, styleID); 350 FontStyle* style = fStyleHashTable.Get(key); 351 if (style != NULL) { 352 fDelistedStyleHashTable.Put(key, style); 353 FontFamily* family = style->Family(); 354 if (family->RemoveStyle(style) && family->CountStyles() == 0) 355 fFamilies.RemoveItem(family); 356 fStyleHashTable.Remove(key); 357 } 358 return style; 359 } 360 361 362 void 363 FontManager::_RemoveAllFonts() 364 { 365 fFamilies.MakeEmpty(); 366 367 // Disconnect the styles from their families before removing them; once we 368 // get to this point, we are in the dtor and don't want them to call back. 369 370 HashMap<FontKey, FontStyle*>::Iterator delisted = fDelistedStyleHashTable.GetIterator(); 371 while (delisted.HasNext()) 372 delisted.Next().value->_SetFontFamily(NULL, -1); 373 fDelistedStyleHashTable.Clear(); 374 375 HashMap<FontKey, BReference<FontStyle> >::Iterator referenced = fStyleHashTable.GetIterator(); 376 while (referenced.HasNext()) 377 referenced.Next().value->_SetFontFamily(NULL, -1); 378 fStyleHashTable.Clear(); 379 } 380 381 382 FontFamily* 383 FontManager::_FindFamily(const char* name) const 384 { 385 if (name == NULL) 386 return NULL; 387 388 FontFamily family(name, 0); 389 return const_cast<FontFamily*>(fFamilies.BinarySearch(family, 390 compare_font_families)); 391 } 392 393 394 FontFamily* 395 FontManager::_FindFamily(uint16 familyID) const 396 { 397 int32 count = fFamilies.CountItems(); 398 399 for (int32 i = 0; i < count; i++) { 400 FontFamily* family = fFamilies.ItemAt(i); 401 if (family->ID() == familyID) 402 return family; 403 } 404 405 return NULL; 406 } 407 408 409 uint16 410 FontManager::_NextID() 411 { 412 return fNextID++; 413 } 414