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 fHeight.ascent = (double)face->ascender / face->units_per_EM; 47 fHeight.descent = (double)-face->descender / face->units_per_EM; 48 // FT2's descent numbers are negative. Be's is positive 49 50 // FT2 doesn't provide a linegap, but according to the docs, we can 51 // calculate it because height = ascending + descending + leading 52 fHeight.leading = (double)(face->height - face->ascender + face->descender) 53 / face->units_per_EM; 54 55 if (IsFixedWidth()) 56 return; 57 58 // manually check if all applicable chars are the same width 59 60 FT_Int32 loadFlags = FT_LOAD_NO_SCALE | FT_LOAD_TARGET_NORMAL; 61 if (FT_Load_Char(face, (uint32)' ', loadFlags) != 0) 62 return; 63 64 int firstWidth = face->glyph->advance.x; 65 for (uint32 c = ' ' + 1; c <= 0x7e; c++) { 66 if (FT_Load_Char(face, c, loadFlags) != 0) 67 return; 68 69 if (face->glyph->advance.x != firstWidth) 70 return; 71 } 72 73 fFullAndHalfFixed = true; 74 } 75 76 77 FontStyle::~FontStyle() 78 { 79 // make sure the font server is ours 80 if (fFamily != NULL && gFontManager->Lock()) { 81 gFontManager->RemoveStyle(this); 82 gFontManager->Unlock(); 83 } 84 85 FT_Done_Face(fFreeTypeFace); 86 } 87 88 89 uint32 90 FontStyle::Hash() const 91 { 92 return (ID() << 16) | fFamily->ID(); 93 } 94 95 96 bool 97 FontStyle::CompareTo(Hashable& other) const 98 { 99 // our hash values are unique (unless you have more than 65536 font 100 // families installed...) 101 return Hash() == other.Hash(); 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); 192 face |= Face(); 193 194 return face; 195 } 196 197 198 status_t 199 FontStyle::UpdateFace(FT_Face face) 200 { 201 if (!sFontLock.IsLocked()) { 202 debugger("UpdateFace() called without having locked FontStyle!"); 203 return B_ERROR; 204 } 205 206 // we only accept the face if it hasn't change its style 207 208 BString name = face->style_name; 209 name.Truncate(B_FONT_STYLE_LENGTH); 210 211 if (name != fName) 212 return B_BAD_VALUE; 213 214 FT_Done_Face(fFreeTypeFace); 215 fFreeTypeFace = face; 216 return B_OK; 217 } 218 219 220 void 221 FontStyle::_SetFontFamily(FontFamily* family, uint16 id) 222 { 223 fFamily = family; 224 fID = id; 225 } 226 227 228 uint16 229 FontStyle::_TranslateStyleToFace(const char* name) const 230 { 231 if (name == NULL) 232 return 0; 233 234 BString string(name); 235 uint16 face = 0; 236 237 if (string.IFindFirst("bold") >= 0) 238 face |= B_BOLD_FACE; 239 240 if (string.IFindFirst("italic") >= 0 241 || string.IFindFirst("oblique") >= 0) 242 face |= B_ITALIC_FACE; 243 244 if (string.IFindFirst("condensed") >= 0) 245 face |= B_CONDENSED_FACE; 246 247 if (string.IFindFirst("light") >= 0 248 || string.IFindFirst("thin") >= 0) 249 face |= B_LIGHT_FACE; 250 251 if (string.IFindFirst("heavy") >= 0 252 || string.IFindFirst("black") >= 0) 253 face |= B_HEAVY_FACE; 254 255 if (face == 0) 256 return B_REGULAR_FACE; 257 258 return face; 259 } 260 261 262