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