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.IsSet() && 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 if (fFamily.IsSet()) 231 fFamily->RemoveStyle(this); 232 233 fFamily.SetTo(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 } 282