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
22static 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*/
31FontStyle::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
56FontStyle::~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
68uint32
69FontStyle::Hash() const
70{
71	return (ID() << 16) | fFamily->ID();
72}
73
74
75bool
76FontStyle::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
84bool
85FontStyle::Lock()
86{
87	return sFontLock.Lock();
88}
89
90
91void
92FontStyle::Unlock()
93{
94	sFontLock.Unlock();
95}
96
97
98void
99FontStyle::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*/
111const char*
112FontStyle::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*/
122void
123FontStyle::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*/
138uint32
139FontStyle::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*/
166uint16
167FontStyle::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
177status_t
178FontStyle::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
199void
200FontStyle::_SetFontFamily(FontFamily* family, uint16 id)
201{
202	fFamily = family;
203	fID = id;
204}
205
206
207uint16
208FontStyle::_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		face |= B_LIGHT_FACE;
228
229	if (string.IFindFirst("heavy") >= 0
230		|| string.IFindFirst("black") >= 0)
231		face |= B_HEAVY_FACE;
232
233	if (face == 0)
234		return B_REGULAR_FACE;
235
236	return face;
237}
238
239
240