xref: /haiku/src/servers/app/font/FontStyle.cpp (revision 47c05920fde47c2618efccd24bd82f1e79cdf05a)
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