1b5436616SAxel Dörfler/*
2eb69155bSAxel Dörfler * Copyright 2001-2016, Haiku.
3b5436616SAxel Dörfler * Distributed under the terms of the MIT License.
4b5436616SAxel Dörfler *
5b5436616SAxel Dörfler * Authors:
6b5436616SAxel Dörfler *		DarkWyrm <bpmagic@columbus.rr.com>
7ccdfe405SStephan Aßmus *		J��r��me Duval, jerome.duval@free.fr
8db5734a4SMichael Lotz *		Michael Lotz <mmlr@mlotz.ch>
92222864eSStephan Aßmus *		Stephan A��mus <superstippi@gmx.de>
10b5436616SAxel Dörfler */
11b5436616SAxel Dörfler
12b5436616SAxel Dörfler
1393820f1eSAxel Dörfler#include "ServerFont.h"
149bdb0522SStephan Aßmus
15ebf8af66SMichael Lotz#include "Angle.h"
162222864eSStephan Aßmus#include "GlyphLayoutEngine.h"
17bdd34c02SAxel Dörfler#include "FontManager.h"
1859345e26SStephan Aßmus#include "truncate_string.h"
1993820f1eSAxel Dörfler#include "utf8_functions.h"
209bdb0522SStephan Aßmus
21ebf8af66SMichael Lotz#include FT_FREETYPE_H
22c12196d4SAxel Dörfler#include FT_GLYPH_H
23ebf8af66SMichael Lotz#include FT_OUTLINE_H
248927dfb8SDarkWyrm
259b6b158bSdsizzle#ifdef FONTCONFIG_ENABLED
269b6b158bSdsizzle
279b6b158bSdsizzle#include <fontconfig.h>
289b6b158bSdsizzle#include <fcfreetype.h>
299b6b158bSdsizzle
309b6b158bSdsizzle#endif // FONTCONFIG_ENABLED
319b6b158bSdsizzle
3293820f1eSAxel Dörfler#include <Shape.h>
3393820f1eSAxel Dörfler#include <String.h>
349b6b158bSdsizzle#include <UnicodeBlockObjects.h>
3593820f1eSAxel Dörfler#include <UTF8.h>
369bdb0522SStephan Aßmus
372222864eSStephan Aßmus#include <agg_bounding_rect.h>
382222864eSStephan Aßmus
395f43b49bSRyan Leavengood#include <stdio.h>
405f43b49bSRyan Leavengood#include <string.h>
419bdb0522SStephan Aßmus
42eb69155bSAxel Dörfler
43b5436616SAxel Dörfler// functions needed to convert a freetype vector graphics to a BShape
44b5436616SAxel Dörflerinline BPoint
454894b870SJérôme DuvalVectorToPoint(const FT_Vector *vector)
46b5436616SAxel Dörfler{
47b5436616SAxel Dörfler	BPoint result;
48bb96bd0aSMichael Lotz	result.x = float(vector->x) / 64;
49bb96bd0aSMichael Lotz	result.y = -float(vector->y) / 64;
50b5436616SAxel Dörfler	return result;
51b5436616SAxel Dörfler}
52b5436616SAxel Dörfler
53bb96bd0aSMichael Lotz
54b5436616SAxel Dörflerint
554894b870SJérôme DuvalMoveToFunc(const FT_Vector *to, void *user)
56b5436616SAxel Dörfler{
57b5436616SAxel Dörfler	((BShape *)user)->MoveTo(VectorToPoint(to));
58b5436616SAxel Dörfler	return 0;
59b5436616SAxel Dörfler}
60b5436616SAxel Dörfler
61bb96bd0aSMichael Lotz
62b5436616SAxel Dörflerint
634894b870SJérôme DuvalLineToFunc(const FT_Vector *to, void *user)
64b5436616SAxel Dörfler{
65b5436616SAxel Dörfler	((BShape *)user)->LineTo(VectorToPoint(to));
66b5436616SAxel Dörfler	return 0;
67b5436616SAxel Dörfler}
68b5436616SAxel Dörfler
69bb96bd0aSMichael Lotz
70b5436616SAxel Dörflerint
714894b870SJérôme DuvalConicToFunc(const FT_Vector *control, const FT_Vector *to, void *user)
72b5436616SAxel Dörfler{
73b5436616SAxel Dörfler	BPoint controls[3];
74bb96bd0aSMichael Lotz
75b5436616SAxel Dörfler	controls[0] = VectorToPoint(control);
76b5436616SAxel Dörfler	controls[1] = VectorToPoint(to);
77b5436616SAxel Dörfler	controls[2] = controls[1];
78bb96bd0aSMichael Lotz
79b5436616SAxel Dörfler	((BShape *)user)->BezierTo(controls);
80b5436616SAxel Dörfler	return 0;
81b5436616SAxel Dörfler}
82b5436616SAxel Dörfler
83bb96bd0aSMichael Lotz
84b5436616SAxel Dörflerint
854894b870SJérôme DuvalCubicToFunc(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user)
86b5436616SAxel Dörfler{
87b5436616SAxel Dörfler	BPoint controls[3];
88bb96bd0aSMichael Lotz
89b5436616SAxel Dörfler	controls[0] = VectorToPoint(control1);
90b5436616SAxel Dörfler	controls[1] = VectorToPoint(control2);
91b5436616SAxel Dörfler	controls[2] = VectorToPoint(to);
92bb96bd0aSMichael Lotz
93b5436616SAxel Dörfler	((BShape *)user)->BezierTo(controls);
94b5436616SAxel Dörfler	return 0;
95b5436616SAxel Dörfler}
96b5436616SAxel Dörfler
97b5436616SAxel Dörfler
98b5436616SAxel Dörflerinline bool
9920a4e726SMichael Lotzis_white_space(uint32 charCode)
100b5436616SAxel Dörfler{
10120a4e726SMichael Lotz	switch (charCode) {
10220a4e726SMichael Lotz		case 0x0009:	/* tab */
10320a4e726SMichael Lotz		case 0x000b:	/* vertical tab */
10420a4e726SMichael Lotz		case 0x000c:	/* form feed */
10520a4e726SMichael Lotz		case 0x0020:	/* space */
10620a4e726SMichael Lotz		case 0x00a0:	/* non breaking space */
10720a4e726SMichael Lotz		case 0x000a:	/* line feed */
10820a4e726SMichael Lotz		case 0x000d:	/* carriage return */
10920a4e726SMichael Lotz		case 0x2028:	/* line separator */
11020a4e726SMichael Lotz		case 0x2029:	/* paragraph separator */
11120a4e726SMichael Lotz			return true;
11220a4e726SMichael Lotz	}
11320a4e726SMichael Lotz
114b5436616SAxel Dörfler	return false;
115b5436616SAxel Dörfler}
116b5436616SAxel Dörfler
117b5436616SAxel Dörfler
118b5436616SAxel Dörfler//	#pragma mark -
119b5436616SAxel Dörfler
120b5436616SAxel Dörfler
121f1efe9b3SAxel Dörfler/*!
1228927dfb8SDarkWyrm	\brief Constructor
123c37002b4SDarkWyrm	\param style Style object to which the ServerFont belongs
124c37002b4SDarkWyrm	\param size Character size in points
125c37002b4SDarkWyrm	\param rotation Rotation in degrees
126c37002b4SDarkWyrm	\param shear Shear (slant) in degrees. 45 <= shear <= 135
127c37002b4SDarkWyrm	\param flags Style flags as defined in <Font.h>
128c37002b4SDarkWyrm	\param spacing String spacing flag as defined in <Font.h>
1298927dfb8SDarkWyrm*/
13091233f88SStephan AßmusServerFont::ServerFont(FontStyle& style, float size, float rotation,
13191233f88SStephan Aßmus		float shear, float falseBoldWidth, uint16 flags, uint8 spacing)
13291233f88SStephan Aßmus	:
13391233f88SStephan Aßmus	fStyle(&style),
13491233f88SStephan Aßmus	fSize(size),
13591233f88SStephan Aßmus	fRotation(rotation),
13691233f88SStephan Aßmus	fShear(shear),
13791233f88SStephan Aßmus	fFalseBoldWidth(falseBoldWidth),
13891233f88SStephan Aßmus	fBounds(0, 0, 0, 0),
13991233f88SStephan Aßmus	fFlags(flags),
14091233f88SStephan Aßmus	fSpacing(spacing),
14191233f88SStephan Aßmus	fDirection(style.Direction()),
14291233f88SStephan Aßmus	fFace(style.Face()),
14391233f88SStephan Aßmus	fEncoding(B_UNICODE_UTF8)
1448927dfb8SDarkWyrm{
1458365d9ecSAxel Dörfler	fStyle->Acquire();
1468927dfb8SDarkWyrm}
1478927dfb8SDarkWyrm
148a52667eeSStephan Aßmus
14959345e26SStephan AßmusServerFont::ServerFont()
1508365d9ecSAxel Dörfler	:
1518365d9ecSAxel Dörfler	fStyle(NULL)
152b3d31bdbSDarkWyrm{
153974dd00cSAxel Dörfler	*this = *gFontManager->DefaultPlainFont();
154b3d31bdbSDarkWyrm}
155b3d31bdbSDarkWyrm
1568365d9ecSAxel Dörfler
157f1efe9b3SAxel Dörfler/*!
1588927dfb8SDarkWyrm	\brief Copy Constructor
159c37002b4SDarkWyrm	\param font ServerFont to copy
1608927dfb8SDarkWyrm*/
1618927dfb8SDarkWyrmServerFont::ServerFont(const ServerFont &font)
1628365d9ecSAxel Dörfler	:
1638365d9ecSAxel Dörfler	fStyle(NULL)
1648927dfb8SDarkWyrm{
1658365d9ecSAxel Dörfler	*this = font;
1668927dfb8SDarkWyrm}
1678927dfb8SDarkWyrm
1688365d9ecSAxel Dörfler
169f1efe9b3SAxel Dörfler/*!
17094cd5349SDarkWyrm	\brief Removes itself as a dependency of its owning style.
1718927dfb8SDarkWyrm*/
17259345e26SStephan AßmusServerFont::~ServerFont()
1738927dfb8SDarkWyrm{
1748365d9ecSAxel Dörfler	fStyle->Release();
1758927dfb8SDarkWyrm}
1768927dfb8SDarkWyrm
1778365d9ecSAxel Dörfler
178f1efe9b3SAxel Dörfler/*!
1794a60209dSAdi Oanca	\brief Returns a copy of the specified font
1804a60209dSAdi Oanca	\param The font to copy from.
1814a60209dSAdi Oanca	\return A copy of the specified font
1824a60209dSAdi Oanca*/
18359345e26SStephan AßmusServerFont&
18459345e26SStephan AßmusServerFont::operator=(const ServerFont& font)
18559345e26SStephan Aßmus{
186663738e9SStephan Aßmus	fSize = font.fSize;
187663738e9SStephan Aßmus	fRotation = font.fRotation;
188663738e9SStephan Aßmus	fShear = font.fShear;
189663738e9SStephan Aßmus	fFalseBoldWidth = font.fFalseBoldWidth;
190663738e9SStephan Aßmus	fFlags = font.fFlags;
191663738e9SStephan Aßmus	fSpacing = font.fSpacing;
192663738e9SStephan Aßmus	fEncoding = font.fEncoding;
193663738e9SStephan Aßmus	fBounds = font.fBounds;
194663738e9SStephan Aßmus
195663738e9SStephan Aßmus	SetStyle(font.fStyle);
1967afc7c50SStephan Aßmus
1974a60209dSAdi Oanca	return *this;
1984a60209dSAdi Oanca}
1994a60209dSAdi Oanca
2008365d9ecSAxel Dörfler
20168667bf4SMichael Lotzbool
20268667bf4SMichael LotzServerFont::operator==(const ServerFont& other) const
20368667bf4SMichael Lotz{
20468667bf4SMichael Lotz	if (GetFamilyAndStyle() != other.GetFamilyAndStyle())
20568667bf4SMichael Lotz		return false;
20668667bf4SMichael Lotz
20768667bf4SMichael Lotz	return fSize == other.fSize && fRotation == other.fRotation
20868667bf4SMichael Lotz		&& fShear == other.fShear && fFalseBoldWidth == other.fFalseBoldWidth
20968667bf4SMichael Lotz		&& fFlags == other.fFlags && fSpacing == other.fSpacing
21068667bf4SMichael Lotz		&& fEncoding == other.fEncoding && fBounds == other.fBounds
21168667bf4SMichael Lotz		&& fDirection == other.fDirection && fFace == other.fFace;
21268667bf4SMichael Lotz}
21368667bf4SMichael Lotz
21468667bf4SMichael Lotz
215f1efe9b3SAxel Dörfler/*!
2168927dfb8SDarkWyrm	\brief Returns the number of strikes in the font
2178927dfb8SDarkWyrm	\return The number of strikes in the font
2188927dfb8SDarkWyrm*/
21959345e26SStephan Aßmusint32
22059345e26SStephan AßmusServerFont::CountTuned()
2218927dfb8SDarkWyrm{
2228365d9ecSAxel Dörfler	return fStyle->TunedCount();
2238927dfb8SDarkWyrm}
2248927dfb8SDarkWyrm
2258365d9ecSAxel Dörfler
226f1efe9b3SAxel Dörfler/*!
2278365d9ecSAxel Dörfler	\brief Returns the file format of the font.
2288365d9ecSAxel Dörfler	\return Mostly B_TRUETYPE_WINDOWS :)
2298927dfb8SDarkWyrm*/
23059345e26SStephan Aßmusfont_file_format
23159345e26SStephan AßmusServerFont::FileFormat()
2328927dfb8SDarkWyrm{
2338365d9ecSAxel Dörfler	return fStyle->FileFormat();
2348927dfb8SDarkWyrm}
2358927dfb8SDarkWyrm
2368365d9ecSAxel Dörfler
23759345e26SStephan Aßmusconst char*
23890dfa707SAxel DörflerServerFont::Style() const
2398927dfb8SDarkWyrm{
2408365d9ecSAxel Dörfler	return fStyle->Name();
2418927dfb8SDarkWyrm}
2428927dfb8SDarkWyrm
2438365d9ecSAxel Dörfler
24459345e26SStephan Aßmusconst char*
24590dfa707SAxel DörflerServerFont::Family() const
2464bd87f48SDarkWyrm{
2478365d9ecSAxel Dörfler	return fStyle->Family()->Name();
2484bd87f48SDarkWyrm}
2494bd87f48SDarkWyrm
2508365d9ecSAxel Dörfler
25105bd1efeSAxel Dörflervoid
2527afc7c50SStephan AßmusServerFont::SetStyle(FontStyle* style)
25305bd1efeSAxel Dörfler{
2547afc7c50SStephan Aßmus	if (style && style != fStyle) {
25505bd1efeSAxel Dörfler		// detach from old style
2561d1031cfSStephan Aßmus		if (fStyle != NULL)
2571d1031cfSStephan Aßmus			fStyle->Release();
25805bd1efeSAxel Dörfler
25905bd1efeSAxel Dörfler		// attach to new style
2607afc7c50SStephan Aßmus		fStyle = style;
26190dfa707SAxel Dörfler
26205bd1efeSAxel Dörfler		fStyle->Acquire();
2637afc7c50SStephan Aßmus
2647afc7c50SStephan Aßmus		fFace = fStyle->Face();
2657afc7c50SStephan Aßmus		fDirection = fStyle->Direction();
26605bd1efeSAxel Dörfler	}
26705bd1efeSAxel Dörfler}
26805bd1efeSAxel Dörfler
26905bd1efeSAxel Dörfler
27059345e26SStephan Aßmus/*!
27159345e26SStephan Aßmus	\brief Sets the ServerFont instance to whatever font is specified
2726edab601SAxel Dörfler	This method will lock the font manager.
2736edab601SAxel Dörfler
27459345e26SStephan Aßmus	\param familyID ID number of the family to set
27559345e26SStephan Aßmus	\param styleID ID number of the style to set
27659345e26SStephan Aßmus	\return B_OK if successful, B_ERROR if not
27759345e26SStephan Aßmus*/
27859345e26SStephan Aßmusstatus_t
27959345e26SStephan AßmusServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID)
2804bd87f48SDarkWyrm{
28159345e26SStephan Aßmus	FontStyle* style = NULL;
28259345e26SStephan Aßmus
283bdd34c02SAxel Dörfler	if (gFontManager->Lock()) {
284bdd34c02SAxel Dörfler		style = gFontManager->GetStyle(familyID, styleID);
2858365d9ecSAxel Dörfler		if (style != NULL)
2868365d9ecSAxel Dörfler			style->Acquire();
2878365d9ecSAxel Dörfler
288bdd34c02SAxel Dörfler		gFontManager->Unlock();
28959345e26SStephan Aßmus	}
29059345e26SStephan Aßmus
291663738e9SStephan Aßmus	if (style == NULL)
29259345e26SStephan Aßmus		return B_ERROR;
29359345e26SStephan Aßmus
2947afc7c50SStephan Aßmus	SetStyle(style);
2958365d9ecSAxel Dörfler	style->Release();
29659345e26SStephan Aßmus
29759345e26SStephan Aßmus	return B_OK;
2984bd87f48SDarkWyrm}
2994bd87f48SDarkWyrm
3008365d9ecSAxel Dörfler
30159345e26SStephan Aßmus/*!
30259345e26SStephan Aßmus	\brief Sets the ServerFont instance to whatever font is specified
30359345e26SStephan Aßmus	\param fontID the combination of family and style ID numbers
30459345e26SStephan Aßmus	\return B_OK if successful, B_ERROR if not
3058927dfb8SDarkWyrm*/
30659345e26SStephan Aßmusstatus_t
30759345e26SStephan AßmusServerFont::SetFamilyAndStyle(uint32 fontID)
3088927dfb8SDarkWyrm{
30959345e26SStephan Aßmus	uint16 style = fontID & 0xFFFF;
31059345e26SStephan Aßmus	uint16 family = (fontID & 0xFFFF0000) >> 16;
311f1efe9b3SAxel Dörfler
31259345e26SStephan Aßmus	return SetFamilyAndStyle(family, style);
31359345e26SStephan Aßmus}
31459345e26SStephan Aßmus
3158365d9ecSAxel Dörfler
3165b30a26bSStephan Aßmusstatus_t
3175b30a26bSStephan AßmusServerFont::SetFace(uint16 face)
31890dfa707SAxel Dörfler{
3195b30a26bSStephan Aßmus	// TODO: This needs further investigation. The face variable is actually
3205b30a26bSStephan Aßmus	// flags, but some of them are not enforcable at the same time. Also don't
3215b30a26bSStephan Aßmus	// confuse the Be API "face" with the Freetype face, which is just an
3225b30a26bSStephan Aßmus	// index in case a single font file exports multiple font faces. The
3235b30a26bSStephan Aßmus	// FontStyle class takes care of mapping the font style name to the Be
3245b30a26bSStephan Aßmus	// API face flags in FontStyle::_TranslateStyleToFace().
3255b30a26bSStephan Aßmus
3265b30a26bSStephan Aßmus	FontStyle* style = NULL;
3275b30a26bSStephan Aßmus	uint16 familyID = FamilyID();
3285b30a26bSStephan Aßmus	if (gFontManager->Lock()) {
3295b30a26bSStephan Aßmus		int32 count = gFontManager->CountStyles(familyID);
3305b30a26bSStephan Aßmus		for (int32 i = 0; i < count; i++) {
3315b30a26bSStephan Aßmus			style = gFontManager->GetStyleByIndex(familyID, i);
3325b30a26bSStephan Aßmus			if (style == NULL)
3335b30a26bSStephan Aßmus				break;
3345b30a26bSStephan Aßmus			if (style->Face() == face) {
3355b30a26bSStephan Aßmus				style->Acquire();
3365b30a26bSStephan Aßmus				break;
3375593e6d9SStephan Aßmus			} else
3385593e6d9SStephan Aßmus				style = NULL;
3395b30a26bSStephan Aßmus		}
3405b30a26bSStephan Aßmus
3415b30a26bSStephan Aßmus		gFontManager->Unlock();
3425b30a26bSStephan Aßmus	}
3435b30a26bSStephan Aßmus
3445b30a26bSStephan Aßmus	if (!style)
3455b30a26bSStephan Aßmus		return B_ERROR;
3465b30a26bSStephan Aßmus
3475b30a26bSStephan Aßmus	SetStyle(style);
3485b30a26bSStephan Aßmus	style->Release();
3495b30a26bSStephan Aßmus
3505b30a26bSStephan Aßmus	return B_OK;
35190dfa707SAxel Dörfler}
35290dfa707SAxel Dörfler
35390dfa707SAxel Dörfler
35459345e26SStephan Aßmus/*!
35559345e26SStephan Aßmus	\brief Gets the ID values for the ServerFont instance in one shot
35659345e26SStephan Aßmus	\return the combination of family and style ID numbers
35759345e26SStephan Aßmus*/
35859345e26SStephan Aßmusuint32
359db5734a4SMichael LotzServerFont::GetFamilyAndStyle() const
36059345e26SStephan Aßmus{
36159345e26SStephan Aßmus	return (FamilyID() << 16) | StyleID();
36256bead32SDarkWyrm}
36356bead32SDarkWyrm
364ebf8af66SMichael Lotz
365db5734a4SMichael LotzFT_Face
366db5734a4SMichael LotzServerFont::GetTransformedFace(bool rotate, bool shear) const
367ebf8af66SMichael Lotz{
3689e7948f4SMichael Lotz	fStyle->Lock();
3699e7948f4SMichael Lotz	FT_Face face = fStyle->FreeTypeFace();
3709e7948f4SMichael Lotz	if (!face) {
3719e7948f4SMichael Lotz		fStyle->Unlock();
372ebf8af66SMichael Lotz		return NULL;
3739e7948f4SMichael Lotz	}
374bb96bd0aSMichael Lotz
375cf5ff0c0SStephan Aßmus	FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
376bb96bd0aSMichael Lotz
377db5734a4SMichael Lotz	if ((rotate && fRotation != 0) || (shear && fShear != 90)) {
378db5734a4SMichael Lotz		FT_Matrix rmatrix, smatrix;
379bb96bd0aSMichael Lotz
380db5734a4SMichael Lotz		Angle rotationAngle(fRotation);
381db5734a4SMichael Lotz		rmatrix.xx = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
382db5734a4SMichael Lotz		rmatrix.xy = (FT_Fixed)(-rotationAngle.Sine() * 0x10000);
383db5734a4SMichael Lotz		rmatrix.yx = (FT_Fixed)( rotationAngle.Sine() * 0x10000);
384db5734a4SMichael Lotz		rmatrix.yy = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
385bb96bd0aSMichael Lotz
386db5734a4SMichael Lotz		Angle shearAngle(fShear);
387f1efe9b3SAxel Dörfler		smatrix.xx = (FT_Fixed)(0x10000);
388db5734a4SMichael Lotz		smatrix.xy = (FT_Fixed)(-shearAngle.Cosine() * 0x10000);
389db5734a4SMichael Lotz		smatrix.yx = (FT_Fixed)(0);
390db5734a4SMichael Lotz		smatrix.yy = (FT_Fixed)(0x10000);
391bb96bd0aSMichael Lotz
392db5734a4SMichael Lotz		// Multiply togheter and apply transform
393db5734a4SMichael Lotz		FT_Matrix_Multiply(&rmatrix, &smatrix);
394db5734a4SMichael Lotz		FT_Set_Transform(face, &smatrix, NULL);
395db5734a4SMichael Lotz	}
396db5734a4SMichael Lotz
39738287e02SStephan Aßmus	// fStyle will be unlocked in PutTransformedFace()
398db5734a4SMichael Lotz	return face;
399db5734a4SMichael Lotz}
400bb96bd0aSMichael Lotz
401bb96bd0aSMichael Lotz
402db5734a4SMichael Lotzvoid
403db5734a4SMichael LotzServerFont::PutTransformedFace(FT_Face face) const
404db5734a4SMichael Lotz{
405db5734a4SMichael Lotz	// Reset transformation
4069e7948f4SMichael Lotz	FT_Set_Transform(face, NULL, NULL);
4079e7948f4SMichael Lotz	fStyle->Unlock();
408db5734a4SMichael Lotz}
409db5734a4SMichael Lotz
410db5734a4SMichael Lotz
411db5734a4SMichael Lotzstatus_t
412db5734a4SMichael LotzServerFont::GetGlyphShapes(const char charArray[], int32 numChars,
413eb69155bSAxel Dörfler	BShape* shapeArray[]) const
414db5734a4SMichael Lotz{
415db5734a4SMichael Lotz	if (!charArray || numChars <= 0 || !shapeArray)
416db5734a4SMichael Lotz		return B_BAD_DATA;
417db5734a4SMichael Lotz
418db5734a4SMichael Lotz	FT_Face face = GetTransformedFace(true, true);
419db5734a4SMichael Lotz	if (!face)
420db5734a4SMichael Lotz		return B_ERROR;
421db5734a4SMichael Lotz
422db5734a4SMichael Lotz	FT_Outline_Funcs funcs;
423db5734a4SMichael Lotz	funcs.move_to = MoveToFunc;
424db5734a4SMichael Lotz	funcs.line_to = LineToFunc;
425db5734a4SMichael Lotz	funcs.conic_to = ConicToFunc;
426db5734a4SMichael Lotz	funcs.cubic_to = CubicToFunc;
427db5734a4SMichael Lotz	funcs.shift = 0;
428db5734a4SMichael Lotz	funcs.delta = 0;
429db5734a4SMichael Lotz
430eb69155bSAxel Dörfler	const char* string = charArray;
431db5734a4SMichael Lotz	for (int i = 0; i < numChars; i++) {
432eb69155bSAxel Dörfler		shapeArray[i] = new (std::nothrow) BShape();
433eb69155bSAxel Dörfler		if (shapeArray[i] == NULL) {
434eb69155bSAxel Dörfler			PutTransformedFace(face);
435eb69155bSAxel Dörfler			return B_NO_MEMORY;
436eb69155bSAxel Dörfler		}
437db5734a4SMichael Lotz		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
438ebf8af66SMichael Lotz		FT_Outline outline = face->glyph->outline;
439db5734a4SMichael Lotz		FT_Outline_Decompose(&outline, &funcs, shapeArray[i]);
440db5734a4SMichael Lotz		shapeArray[i]->Close();
441ebf8af66SMichael Lotz	}
442bb96bd0aSMichael Lotz
443db5734a4SMichael Lotz	PutTransformedFace(face);
444db5734a4SMichael Lotz	return B_OK;
445ebf8af66SMichael Lotz}
446ebf8af66SMichael Lotz
447599be434SJérôme Duval
4489b6b158bSdsizzle#ifdef FONTCONFIG_ENABLED
4499b6b158bSdsizzle
4509b6b158bSdsizzle/*!
4519b6b158bSdsizzle	\brief For a given codepoint, do a binary search of the defined unicode
4529b6b158bSdsizzle	blocks to figure out which one contains the codepoint.
4539b6b158bSdsizzle	\param codePoint is the point to find
4549b6b158bSdsizzle	\param startGuess is the starting point for the binary search (default 0)
4559b6b158bSdsizzle*/
4569b6b158bSdsizzlestatic
4579b6b158bSdsizzleint32
4589b6b158bSdsizzleFindBlockForCodepoint(uint32 codePoint, uint32 startGuess)
4599b6b158bSdsizzle{
4609b6b158bSdsizzle	uint32 min = 0;
4619b6b158bSdsizzle	uint32 max = kNumUnicodeBlockRanges;
4629b6b158bSdsizzle	uint32 guess = (max + min) / 2;
4639b6b158bSdsizzle
4649b6b158bSdsizzle	if (startGuess > 0)
4659b6b158bSdsizzle		guess = startGuess;
4669b6b158bSdsizzle
4679b6b158bSdsizzle	if (codePoint > kUnicodeBlockMap[max-1].end)
4689b6b158bSdsizzle		return -1;
4699b6b158bSdsizzle
4709b6b158bSdsizzle	while ((max >= min) && (guess < kNumUnicodeBlockRanges)) {
4719b6b158bSdsizzle		uint32 start = kUnicodeBlockMap[guess].start;
4729b6b158bSdsizzle		uint32 end = kUnicodeBlockMap[guess].end;
4739b6b158bSdsizzle
4749b6b158bSdsizzle		if (start <= codePoint && end >= codePoint)
4759b6b158bSdsizzle			return guess;
4769b6b158bSdsizzle
4779b6b158bSdsizzle		if (end < codePoint) {
4789b6b158bSdsizzle			min = guess + 1;
4799b6b158bSdsizzle		} else {
4809b6b158bSdsizzle			max = guess - 1;
4819b6b158bSdsizzle		}
4829b6b158bSdsizzle
4839b6b158bSdsizzle		guess = (max + min) / 2;
4849b6b158bSdsizzle	}
4859b6b158bSdsizzle
4869b6b158bSdsizzle	return -1;
4879b6b158bSdsizzle}
4889b6b158bSdsizzle
4899b6b158bSdsizzle/*!
4909b6b158bSdsizzle	\brief parses charmap from fontconfig.  See fontconfig docs for FcCharSetFirstPage
4919b6b158bSdsizzle	and FcCharSetNextPage for details on format.
4929b6b158bSdsizzle	\param charMap is a fontconfig character map
4939b6b158bSdsizzle	\param baseCodePoint is the base codepoint returned by fontconfig
4949b6b158bSdsizzle	\param blocksForMap is a unicode_block to store the bitmap of contained blocks
4959b6b158bSdsizzle*/
4969b6b158bSdsizzlestatic
4979b6b158bSdsizzlevoid
4989b6b158bSdsizzleParseFcMap(FcChar32 charMap[], FcChar32 baseCodePoint, unicode_block& blocksForMap)
4999b6b158bSdsizzle{
50033c9787dSDale Cieslak	uint32 block = 0;
50133c9787dSDale Cieslak	const uint8 BITS_PER_BLOCK = 32;
50233c9787dSDale Cieslak	uint32 currentCodePoint = 0;
503061b9eecSDale Cieslak
504061b9eecSDale Cieslak	if (baseCodePoint > kUnicodeBlockMap[kNumUnicodeBlockRanges-1].end)
505061b9eecSDale Cieslak		return;
506061b9eecSDale Cieslak
5079b6b158bSdsizzle	for (int i = 0; i < FC_CHARSET_MAP_SIZE; ++i) {
5089b6b158bSdsizzle		FcChar32 curMapBlock = charMap[i];
50933c9787dSDale Cieslak		int32 rangeStart = -1;
51033c9787dSDale Cieslak		int32 startBlock = -1;
51133c9787dSDale Cieslak		int32 endBlock = -1;
51233c9787dSDale Cieslak		uint32 startPoint = 0;
513061b9eecSDale Cieslak
51433c9787dSDale Cieslak		currentCodePoint = baseCodePoint + block;
515061b9eecSDale Cieslak
516061b9eecSDale Cieslak		for (int bit = 0; bit < BITS_PER_BLOCK; ++bit) {
51733c9787dSDale Cieslak			if (curMapBlock == 0 && startBlock < 0)
51833c9787dSDale Cieslak				// if no more bits are set then short-circuit the loop
51933c9787dSDale Cieslak				break;
520061b9eecSDale Cieslak
52133c9787dSDale Cieslak			if ((curMapBlock & 0x1) != 0 && rangeStart < 0) {
52233c9787dSDale Cieslak				rangeStart = bit;
52333c9787dSDale Cieslak				startPoint = currentCodePoint + rangeStart;
52433c9787dSDale Cieslak				startBlock = FindBlockForCodepoint(startPoint, 0);
52533c9787dSDale Cieslak				if (startBlock >= 0) {
52633c9787dSDale Cieslak					blocksForMap = blocksForMap
52733c9787dSDale Cieslak						| kUnicodeBlockMap[startBlock].block;
528061b9eecSDale Cieslak				}
52933c9787dSDale Cieslak			} else if (rangeStart >= 0 && startBlock >= 0) {
5309b6b158bSdsizzle					// when we find an empty bit, that's the end of the range
53133c9787dSDale Cieslak				uint32 endPoint = currentCodePoint + (bit - 1);
5329b6b158bSdsizzle
53333c9787dSDale Cieslak				endBlock = FindBlockForCodepoint(endPoint,
53433c9787dSDale Cieslak					startBlock);
5359b6b158bSdsizzle					// start the binary search at the block where we found the
5369b6b158bSdsizzle					// start codepoint to ideally find the end in the same
5379b6b158bSdsizzle					// block.
53833c9787dSDale Cieslak				++startBlock;
5399b6b158bSdsizzle
54033c9787dSDale Cieslak				while (startBlock <= endBlock) {
5419b6b158bSdsizzle					// if the starting codepoint is found in a different block
5429b6b158bSdsizzle					// than the ending codepoint, we should add all the blocks
5439b6b158bSdsizzle					// inbetween.
5449b6b158bSdsizzle					blocksForMap = blocksForMap
54533c9787dSDale Cieslak						| kUnicodeBlockMap[startBlock].block;
54633c9787dSDale Cieslak					++startBlock;
5479b6b158bSdsizzle				}
5489b6b158bSdsizzle
54933c9787dSDale Cieslak				startBlock = -1;
55033c9787dSDale Cieslak				endBlock = -1;
55133c9787dSDale Cieslak				rangeStart = -1;
552061b9eecSDale Cieslak			}
5539b6b158bSdsizzle
5549b6b158bSdsizzle			curMapBlock >>= 1;
5559b6b158bSdsizzle		}
556061b9eecSDale Cieslak
55733c9787dSDale Cieslak		if (rangeStart >= 0 && startBlock >= 0) {
55833c9787dSDale Cieslak				// if we hit the end of the block and had
55933c9787dSDale Cieslak				// found a start of the range then we
56033c9787dSDale Cieslak				// should end the range at the end of the block
56133c9787dSDale Cieslak			uint32 endPoint = currentCodePoint + BITS_PER_BLOCK - 1;
56233c9787dSDale Cieslak
56333c9787dSDale Cieslak			endBlock = FindBlockForCodepoint(endPoint,
56433c9787dSDale Cieslak				startBlock);
56533c9787dSDale Cieslak				// start the binary search at the block where we found the
566