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