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