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 #include "ServerFont.h" 15 #include "GlobalFontManager.h" 16 17 #include <FontPrivate.h> 18 19 #include <Entry.h> 20 21 22 static BLocker sFontLock("font lock"); 23 24 25 /*! 26 \brief Constructor 27 \param filepath path to a font file 28 \param face FreeType handle for the font file after it is loaded - it will 29 be kept open until the FontStyle is destroyed 30 */ 31 FontStyle::FontStyle(node_ref& nodeRef, const char* path, FT_Face face) 32 : 33 fFreeTypeFace(face), 34 fName(face->style_name), 35 fPath(path), 36 fNodeRef(nodeRef), 37 fFamily(NULL), 38 fID(0), 39 fBounds(0, 0, 0, 0), 40 fFace(_TranslateStyleToFace(face->style_name)), 41 fFullAndHalfFixed(false), 42 fFontData(NULL) 43 { 44 fName.Truncate(B_FONT_STYLE_LENGTH); 45 // make sure this style can be found using the Be API 46 47 if (IsScalable()) { 48 fHeight.ascent = (double)face->ascender / face->units_per_EM; 49 fHeight.descent = (double)-face->descender / face->units_per_EM; 50 // FT2's descent numbers are negative. Be's is positive 51 52 // FT2 doesn't provide a linegap, but according to the docs, we can 53 // calculate it because height = ascending + descending + leading 54 fHeight.leading = (double)(face->height - face->ascender 55 + face->descender) / face->units_per_EM; 56 } else { 57 // We don't have global metrics, get them from a bitmap 58 FT_Pos size = face->available_sizes[0].size; 59 for (int i = 1; i < face->num_fixed_sizes; i++) 60 size = max_c(size, face->available_sizes[i].size); 61 FT_Set_Pixel_Sizes(face, 0, size / 64); 62 // Size is encoded as 26.6 fixed point, while FT_Set_Pixel_Sizes 63 // uses the integer unencoded value 64 65 FT_Size_Metrics metrics = face->size->metrics; 66 fHeight.ascent = (double)metrics.ascender / size; 67 fHeight.descent = (double)-metrics.descender / size; 68 fHeight.leading = (double)(metrics.height - metrics.ascender 69 + metrics.descender) / size; 70 } 71 72 if (IsFixedWidth()) 73 return; 74 75 // manually check if all applicable chars are the same width 76 77 FT_Int32 loadFlags = FT_LOAD_NO_SCALE | FT_LOAD_TARGET_NORMAL; 78 if (FT_Load_Char(face, (uint32)' ', loadFlags) != 0) 79 return; 80 81 int firstWidth = face->glyph->advance.x; 82 for (uint32 c = ' ' + 1; c <= 0x7e; c++) { 83 if (FT_Load_Char(face, c, loadFlags) != 0) 84 return; 85 86 if (face->glyph->advance.x != firstWidth) 87 return; 88 } 89 90 fFullAndHalfFixed = true; 91 } 92 93 94 FontStyle::~FontStyle() 95 { 96 // make sure the font server is ours 97 if (fFamily != NULL) { 98 if (fFontManager != NULL && fFontManager->Lock()) { 99 fFontManager->RemoveStyle(this); 100 fFontManager->Unlock(); 101 } else if (gFontManager->Lock()) { 102 gFontManager->RemoveStyle(this); 103 gFontManager->Unlock(); 104 } 105 } 106 107 FT_Done_Face(fFreeTypeFace); 108 109 if (fFontData != NULL) 110 free(fFontData); 111 } 112 113 114 bool 115 FontStyle::Lock() 116 { 117 return sFontLock.Lock(); 118 } 119 120 121 void 122 FontStyle::Unlock() 123 { 124 sFontLock.Unlock(); 125 } 126 127 128 void 129 FontStyle::GetHeight(float size, font_height& height) const 130 { 131 height.ascent = fHeight.ascent * size; 132 height.descent = fHeight.descent * size; 133 height.leading = fHeight.leading * size; 134 } 135 136 137 /*! 138 \brief Returns the path to the style's font file 139 \return The style's font file path 140 */ 141 const char* 142 FontStyle::Path() const 143 { 144 return fPath.Path(); 145 } 146 147 148 /*! 149 \brief Updates the path of the font style in case the style 150 has been moved around. 151 */ 152 void 153 FontStyle::UpdatePath(const node_ref& parentNodeRef) 154 { 155 entry_ref ref; 156 ref.device = parentNodeRef.device; 157 ref.directory = parentNodeRef.node; 158 ref.set_name(fPath.Leaf()); 159 160 fPath.SetTo(&ref); 161 } 162 163 164 /*! 165 \brief Unlike BFont::Flags() this returns the extra flags field as used 166 in the private part of BFont. 167 */ 168 uint32 169 FontStyle::Flags() const 170 { 171 uint32 flags = uint32(Direction()) << B_PRIVATE_FONT_DIRECTION_SHIFT; 172 173 if (IsFixedWidth()) 174 flags |= B_IS_FIXED; 175 if (IsFullAndHalfFixed()) 176 flags |= B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED; 177 if (TunedCount() > 0) 178 flags |= B_HAS_TUNED_FONT; 179 if (HasKerning()) 180 flags |= B_PRIVATE_FONT_HAS_KERNING; 181 182 return flags; 183 } 184 185 186 /*! 187 \brief Updates the given face to match the one from this style 188 189 The specified font face often doesn't match the exact face of 190 a style. This method will preserve the attributes of the face 191 that this style does not alter, and will only update the 192 attributes that matter to this style. 193 The font renderer could then emulate the other face attributes 194 taking this style as a base. 195 */ 196 uint16 197 FontStyle::PreservedFace(uint16 face) const 198 { 199 // TODO: make this better 200 face &= ~(B_REGULAR_FACE | B_BOLD_FACE | B_ITALIC_FACE | B_CONDENSED_FACE 201 | B_LIGHT_FACE | B_HEAVY_FACE); 202 face |= Face(); 203 204 return face; 205 } 206 207 208 status_t 209 FontStyle::UpdateFace(FT_Face face) 210 { 211 if (!sFontLock.IsLocked()) { 212 debugger("UpdateFace() called without having locked FontStyle!"); 213 return B_ERROR; 214 } 215 216 // we only accept the face if it hasn't change its style 217 218 BString name = face->style_name; 219 name.Truncate(B_FONT_STYLE_LENGTH); 220 221 if (name != fName) 222 return B_BAD_VALUE; 223 224 FT_Done_Face(fFreeTypeFace); 225 fFreeTypeFace = face; 226 return B_OK; 227 } 228 229 230 void 231 FontStyle::_SetFontFamily(FontFamily* family, uint16 id) 232 { 233 fFamily = family; 234 fID = id; 235 } 236 237 238 uint16 239 FontStyle::_TranslateStyleToFace(const char* name) const 240 { 241 if (name == NULL) 242 return 0; 243 244 BString string(name); 245 uint16 face = 0; 246 247 if (string.IFindFirst("bold") >= 0) 248 face |= B_BOLD_FACE; 249 250 if (string.IFindFirst("italic") >= 0 251 || string.IFindFirst("oblique") >= 0) 252 face |= B_ITALIC_FACE; 253 254 if (string.IFindFirst("condensed") >= 0) 255 face |= B_CONDENSED_FACE; 256 257 if (string.IFindFirst("light") >= 0 258 || string.IFindFirst("thin") >= 0) 259 face |= B_LIGHT_FACE; 260 261 if (string.IFindFirst("heavy") >= 0 262 || string.IFindFirst("black") >= 0) 263 face |= B_HEAVY_FACE; 264 265 if (face == 0) 266 return B_REGULAR_FACE; 267 268 return face; 269 } 270 271 272 void 273 FontStyle::SetFontData(FT_Byte* location, uint32 size) 274 { 275 // if memory was already allocated here, we should free it so it's not leaked 276 if (fFontData != NULL) 277 free(fFontData); 278 279 fFontDataSize = size; 280 fFontData = location; 281 }