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 bool 90 FontStyle::Lock() 91 { 92 return sFontLock.Lock(); 93 } 94 95 96 void 97 FontStyle::Unlock() 98 { 99 sFontLock.Unlock(); 100 } 101 102 103 void 104 FontStyle::GetHeight(float size, font_height& height) const 105 { 106 height.ascent = fHeight.ascent * size; 107 height.descent = fHeight.descent * size; 108 height.leading = fHeight.leading * size; 109 } 110 111 112 /*! 113 \brief Returns the path to the style's font file 114 \return The style's font file path 115 */ 116 const char* 117 FontStyle::Path() const 118 { 119 return fPath.Path(); 120 } 121 122 123 /*! 124 \brief Updates the path of the font style in case the style 125 has been moved around. 126 */ 127 void 128 FontStyle::UpdatePath(const node_ref& parentNodeRef) 129 { 130 entry_ref ref; 131 ref.device = parentNodeRef.device; 132 ref.directory = parentNodeRef.node; 133 ref.set_name(fPath.Leaf()); 134 135 fPath.SetTo(&ref); 136 } 137 138 139 /*! 140 \brief Unlike BFont::Flags() this returns the extra flags field as used 141 in the private part of BFont. 142 */ 143 uint32 144 FontStyle::Flags() const 145 { 146 uint32 flags = uint32(Direction()) << B_PRIVATE_FONT_DIRECTION_SHIFT; 147 148 if (IsFixedWidth()) 149 flags |= B_IS_FIXED; 150 if (IsFullAndHalfFixed()) 151 flags |= B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED; 152 if (TunedCount() > 0) 153 flags |= B_HAS_TUNED_FONT; 154 if (HasKerning()) 155 flags |= B_PRIVATE_FONT_HAS_KERNING; 156 157 return flags; 158 } 159 160 161 /*! 162 \brief Updates the given face to match the one from this style 163 164 The specified font face often doesn't match the exact face of 165 a style. This method will preserve the attributes of the face 166 that this style does not alter, and will only update the 167 attributes that matter to this style. 168 The font renderer could then emulate the other face attributes 169 taking this style as a base. 170 */ 171 uint16 172 FontStyle::PreservedFace(uint16 face) const 173 { 174 // TODO: make this better 175 face &= ~(B_REGULAR_FACE | B_BOLD_FACE | B_ITALIC_FACE); 176 face |= Face(); 177 178 return face; 179 } 180 181 182 status_t 183 FontStyle::UpdateFace(FT_Face face) 184 { 185 if (!sFontLock.IsLocked()) { 186 debugger("UpdateFace() called without having locked FontStyle!"); 187 return B_ERROR; 188 } 189 190 // we only accept the face if it hasn't change its style 191 192 BString name = face->style_name; 193 name.Truncate(B_FONT_STYLE_LENGTH); 194 195 if (name != fName) 196 return B_BAD_VALUE; 197 198 FT_Done_Face(fFreeTypeFace); 199 fFreeTypeFace = face; 200 return B_OK; 201 } 202 203 204 void 205 FontStyle::_SetFontFamily(FontFamily* family, uint16 id) 206 { 207 fFamily = family; 208 fID = id; 209 } 210 211 212 uint16 213 FontStyle::_TranslateStyleToFace(const char* name) const 214 { 215 if (name == NULL) 216 return 0; 217 218 BString string(name); 219 uint16 face = 0; 220 221 if (string.IFindFirst("bold") >= 0) 222 face |= B_BOLD_FACE; 223 224 if (string.IFindFirst("italic") >= 0 225 || string.IFindFirst("oblique") >= 0) 226 face |= B_ITALIC_FACE; 227 228 if (string.IFindFirst("condensed") >= 0) 229 face |= B_CONDENSED_FACE; 230 231 if (string.IFindFirst("light") >= 0 232 || string.IFindFirst("thin") >= 0) 233 face |= B_LIGHT_FACE; 234 235 if (string.IFindFirst("heavy") >= 0 236 || string.IFindFirst("black") >= 0) 237 face |= B_HEAVY_FACE; 238 239 if (face == 0) 240 return B_REGULAR_FACE; 241 242 return face; 243 } 244 245 246