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