xref: /haiku/src/servers/app/font/FontStyle.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
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 != NULL && 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 	fFamily = family;
231 	fID = id;
232 }
233 
234 
235 uint16
236 FontStyle::_TranslateStyleToFace(const char* name) const
237 {
238 	if (name == NULL)
239 		return 0;
240 
241 	BString string(name);
242 	uint16 face = 0;
243 
244 	if (string.IFindFirst("bold") >= 0)
245 		face |= B_BOLD_FACE;
246 
247 	if (string.IFindFirst("italic") >= 0
248 		|| string.IFindFirst("oblique") >= 0)
249 		face |= B_ITALIC_FACE;
250 
251 	if (string.IFindFirst("condensed") >= 0)
252 		face |= B_CONDENSED_FACE;
253 
254 	if (string.IFindFirst("light") >= 0
255 		|| string.IFindFirst("thin") >= 0)
256 		face |= B_LIGHT_FACE;
257 
258 	if (string.IFindFirst("heavy") >= 0
259 		|| string.IFindFirst("black") >= 0)
260 		face |= B_HEAVY_FACE;
261 
262 	if (face == 0)
263 		return B_REGULAR_FACE;
264 
265 	return face;
266 }
267 
268 
269 void
270 FontStyle::SetFontData(FT_Byte* location, uint32 size)
271 {
272 	// if memory was already allocated here, we should free it so it's not leaked
273 	if (fFontData != NULL)
274 		free(fFontData);
275 
276 	fFontDataSize = size;
277 	fFontData = location;
278 }
279