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