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