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