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