1/*
2 * Copyright 2001-2016, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		DarkWyrm <bpmagic@columbus.rr.com>
7 *		J��r��me Duval, jerome.duval@free.fr
8 *		Michael Lotz <mmlr@mlotz.ch>
9 *		Stephan A��mus <superstippi@gmx.de>
10 */
11
12
13#include "ServerFont.h"
14
15#include "Angle.h"
16#include "AppFontManager.h"
17#include "GlyphLayoutEngine.h"
18#include "GlobalFontManager.h"
19#include "truncate_string.h"
20#include "utf8_functions.h"
21
22#include FT_FREETYPE_H
23#include FT_GLYPH_H
24#include FT_OUTLINE_H
25
26#ifdef FONTCONFIG_ENABLED
27
28#include <fontconfig.h>
29#include <fcfreetype.h>
30
31#endif // FONTCONFIG_ENABLED
32
33#include <Shape.h>
34#include <String.h>
35#include <UnicodeBlockObjects.h>
36#include <UTF8.h>
37
38#include <agg_bounding_rect.h>
39
40#include <stdio.h>
41#include <string.h>
42
43
44// functions needed to convert a freetype vector graphics to a BShape
45inline BPoint
46VectorToPoint(const FT_Vector *vector)
47{
48	BPoint result;
49	result.x = float(vector->x) / 64;
50	result.y = -float(vector->y) / 64;
51	return result;
52}
53
54
55int
56MoveToFunc(const FT_Vector *to, void *user)
57{
58	((BShape *)user)->MoveTo(VectorToPoint(to));
59	return 0;
60}
61
62
63int
64LineToFunc(const FT_Vector *to, void *user)
65{
66	((BShape *)user)->LineTo(VectorToPoint(to));
67	return 0;
68}
69
70
71int
72ConicToFunc(const FT_Vector *control, const FT_Vector *to, void *user)
73{
74	BPoint controls[3];
75
76	controls[0] = VectorToPoint(control);
77	controls[1] = controls[0];
78	controls[2] = VectorToPoint(to);
79
80	((BShape *)user)->BezierTo(controls);
81	return 0;
82}
83
84
85int
86CubicToFunc(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user)
87{
88	BPoint controls[3];
89
90	controls[0] = VectorToPoint(control1);
91	controls[1] = VectorToPoint(control2);
92	controls[2] = VectorToPoint(to);
93
94	((BShape *)user)->BezierTo(controls);
95	return 0;
96}
97
98
99inline bool
100is_white_space(uint32 charCode)
101{
102	switch (charCode) {
103		case 0x0009:	/* tab */
104		case 0x000b:	/* vertical tab */
105		case 0x000c:	/* form feed */
106		case 0x0020:	/* space */
107		case 0x00a0:	/* non breaking space */
108		case 0x000a:	/* line feed */
109		case 0x000d:	/* carriage return */
110		case 0x2028:	/* line separator */
111		case 0x2029:	/* paragraph separator */
112			return true;
113	}
114
115	return false;
116}
117
118
119//	#pragma mark -
120
121
122/*!
123	\brief Constructor
124	\param style Style object to which the ServerFont belongs
125	\param size Character size in points
126	\param rotation Rotation in degrees
127	\param shear Shear (slant) in degrees. 45 <= shear <= 135
128	\param flags Style flags as defined in <Font.h>
129	\param spacing String spacing flag as defined in <Font.h>
130*/
131ServerFont::ServerFont(FontStyle& style, float size, float rotation,
132		float shear, float falseBoldWidth, uint16 flags, uint8 spacing)
133	:
134	fStyle(&style, false),
135	fSize(size),
136	fRotation(rotation),
137	fShear(shear),
138	fFalseBoldWidth(falseBoldWidth),
139	fBounds(0, 0, 0, 0),
140	fFlags(flags),
141	fSpacing(spacing),
142	fDirection(style.Direction()),
143	fFace(style.Face()),
144	fEncoding(B_UNICODE_UTF8)
145{
146}
147
148
149ServerFont::ServerFont()
150	:
151	fStyle(NULL)
152{
153	*this = *gFontManager->DefaultPlainFont();
154}
155
156
157/*!
158	\brief Copy Constructor
159	\param font ServerFont to copy
160*/
161ServerFont::ServerFont(const ServerFont &font)
162	:
163	fStyle(NULL)
164{
165	*this = font;
166}
167
168
169/*!
170	\brief Removes itself as a dependency of its owning style.
171*/
172ServerFont::~ServerFont()
173{
174}
175
176
177/*!
178	\brief Returns a copy of the specified font
179	\param The font to copy from.
180	\return A copy of the specified font
181*/
182ServerFont&
183ServerFont::operator=(const ServerFont& font)
184{
185	fSize = font.fSize;
186	fRotation = font.fRotation;
187	fShear = font.fShear;
188	fFalseBoldWidth = font.fFalseBoldWidth;
189	fFlags = font.fFlags;
190	fSpacing = font.fSpacing;
191	fEncoding = font.fEncoding;
192	fBounds = font.fBounds;
193
194	SetStyle(font.fStyle);
195
196	fFace = font.fFace;
197
198	return *this;
199}
200
201
202bool
203ServerFont::operator==(const ServerFont& other) const
204{
205	if (GetFamilyAndStyle() != other.GetFamilyAndStyle())
206		return false;
207
208	return fSize == other.fSize && fRotation == other.fRotation
209		&& fShear == other.fShear && fFalseBoldWidth == other.fFalseBoldWidth
210		&& fFlags == other.fFlags && fSpacing == other.fSpacing
211		&& fEncoding == other.fEncoding && fBounds == other.fBounds
212		&& fDirection == other.fDirection && fFace == other.fFace;
213}
214
215
216/*!
217	\brief Returns the number of strikes in the font
218	\return The number of strikes in the font
219*/
220int32
221ServerFont::CountTuned()
222{
223	return fStyle->TunedCount();
224}
225
226
227/*!
228	\brief Returns the file format of the font.
229	\return Mostly B_TRUETYPE_WINDOWS :)
230*/
231font_file_format
232ServerFont::FileFormat()
233{
234	return fStyle->FileFormat();
235}
236
237
238const char*
239ServerFont::Style() const
240{
241	return fStyle->Name();
242}
243
244
245const char*
246ServerFont::Family() const
247{
248	return fStyle->Family()->Name();
249}
250
251
252void
253ServerFont::SetStyle(FontStyle* style)
254{
255	if (style && style != fStyle) {
256		fStyle.SetTo(style, false);
257
258		fFace = fStyle->PreservedFace(fFace);
259		fDirection = fStyle->Direction();
260
261		// invalidate fBounds
262		fBounds.Set(0, -1, 0, -1);
263	}
264}
265
266
267/*!
268	\brief Sets the ServerFont instance to whatever font is specified
269	This method will lock the font manager.
270
271	\param familyID ID number of the family to set
272	\param styleID ID number of the style to set
273	\return B_OK if successful, B_ERROR if not
274*/
275status_t
276ServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID,
277	AppFontManager* fontManager)
278{
279
280	BReference<FontStyle> style;
281
282	if (gFontManager->Lock()) {
283		style.SetTo(gFontManager->GetStyle(familyID, styleID), false);
284
285		gFontManager->Unlock();
286	}
287
288	if (style == NULL) {
289		if (fontManager != NULL && fontManager->Lock()) {
290			style.SetTo(fontManager->GetStyle(familyID, styleID), false);
291
292			fontManager->Unlock();
293		}
294
295		if (style == NULL)
296			return B_ERROR;
297	}
298
299	SetStyle(style);
300
301	// invalidate fBounds
302	fBounds.Set(0, -1, 0, -1);
303
304	return B_OK;
305}
306
307
308/*!
309	\brief Sets the ServerFont instance to whatever font is specified
310	\param fontID the combination of family and style ID numbers
311	\return B_OK if successful, B_ERROR if not
312*/
313status_t
314ServerFont::SetFamilyAndStyle(uint32 fontID, AppFontManager* fontManager)
315{
316	uint16 style = fontID & 0xFFFF;
317	uint16 family = (fontID & 0xFFFF0000) >> 16;
318
319	return SetFamilyAndStyle(family, style, fontManager);
320}
321
322
323void
324ServerFont::SetSize(float value)
325{
326	fSize = value;
327
328	// invalidate fBounds
329	fBounds.Set(0, -1, 0, -1);
330}
331
332
333status_t
334ServerFont::SetFace(uint16 face)
335{
336	// Don't confuse the Be API "face" with the Freetype face, which is just
337	// an index in case a single font file exports multiple font faces. The
338	// FontStyle class takes care of mapping the font style name to the Be
339	// API face flags in FontStyle::_TranslateStyleToFace().
340
341	if (fStyle->PreservedFace(face) == face) {
342		fFace = face;
343		return B_OK;
344	}
345
346	BReference <FontStyle> style;
347	uint16 familyID = FamilyID();
348	if (gFontManager->Lock()) {
349		int32 count = gFontManager->CountStyles(familyID);
350		for (int32 i = 0; i < count; i++) {
351			style.SetTo(gFontManager->GetStyleByIndex(familyID, i), false);
352			if (style == NULL)
353				break;
354			if (style->PreservedFace(face) == face)
355				break;
356			else
357				style = NULL;
358		}
359
360		gFontManager->Unlock();
361	}
362
363	if (!style)
364		return B_ERROR;
365
366	fFace = face;
367	SetStyle(style);
368
369	// invalidate fBounds
370	fBounds.Set(0, -1, 0, -1);
371
372	return B_OK;
373}
374
375
376/*!
377	\brief Gets the ID values for the ServerFont instance in one shot
378	\return the combination of family and style ID numbers
379*/
380uint32
381ServerFont::GetFamilyAndStyle() const
382{
383	if (fStyle == NULL || fStyle->Family() == NULL)
384		return 0;
385
386	return (FamilyID() << 16) | StyleID();
387}
388
389
390FT_Face
391ServerFont::GetTransformedFace(bool rotate, bool shear) const
392{
393	fStyle->Lock();
394	FT_Face face = fStyle->FreeTypeFace();
395	if (!face) {
396		fStyle->Unlock();
397		return NULL;
398	}
399
400	FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
401
402	if ((rotate && fRotation != 0) || (shear && fShear != 90)) {
403		FT_Matrix rmatrix, smatrix;
404
405		Angle rotationAngle(fRotation);
406		rmatrix.xx = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
407		rmatrix.xy = (FT_Fixed)(-rotationAngle.Sine() * 0x10000);
408		rmatrix.yx = (FT_Fixed)( rotationAngle.Sine() * 0x10000);
409		rmatrix.yy = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
410
411		Angle shearAngle(fShear);
412		smatrix.xx = (FT_Fixed)(0x10000);
413		smatrix.xy = (FT_Fixed)(-shearAngle.Cosine() * 0x10000);
414		smatrix.yx = (FT_Fixed)(0);
415		smatrix.yy = (FT_Fixed)(0x10000);
416
417		// Multiply togheter and apply transform
418		FT_Matrix_Multiply(&rmatrix, &smatrix);
419		FT_Set_Transform(face, &smatrix, NULL);
420	}
421
422	// fStyle will be unlocked in PutTransformedFace()
423	return face;
424}
425
426
427void
428ServerFont::PutTransformedFace(FT_Face face) const
429{
430	// Reset transformation
431	FT_Set_Transform(face, NULL, NULL);
432	fStyle->Unlock();
433}
434
435
436status_t
437ServerFont::GetGlyphShapes(const char charArray[], int32 numChars,
438	BShape* shapeArray[]) const
439{
440	if (!charArray || numChars <= 0 || !shapeArray)
441		return B_BAD_DATA;
442
443	FT_Face face = GetTransformedFace(true, true);
444	if (!face)
445		return B_ERROR;
446
447	FT_Outline_Funcs funcs;
448	funcs.move_to = MoveToFunc;
449	funcs.line_to = LineToFunc;
450	funcs.conic_to = ConicToFunc;
451	funcs.cubic_to = CubicToFunc;
452	funcs.shift = 0;
453	funcs.delta = 0;
454
455	const char* string = charArray;
456	for (int i = 0; i < numChars; i++) {
457		shapeArray[i] = new (std::nothrow) BShape();
458		if (shapeArray[i] == NULL) {
459			PutTransformedFace(face);
460			return B_NO_MEMORY;
461		}
462		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
463		FT_Outline outline = face->glyph->outline;
464		FT_Outline_Decompose(&outline, &funcs, shapeArray[i]);
465		shapeArray[i]->Close();
466	}
467
468	PutTransformedFace(face);
469	return B_OK;
470}
471
472
473#ifdef FONTCONFIG_ENABLED
474
475/*!
476	\brief For a given codepoint, do a binary search of the defined unicode
477	blocks to figure out which one contains the codepoint.
478	\param codePoint is the point to find
479	\param startGuess is the starting point for the binary search (default 0)
480*/
481static
482int32
483FindBlockForCodepoint(uint32 codePoint, uint32 startGuess)
484{
485	uint32 min = 0;
486	uint32 max = kNumUnicodeBlockRanges;
487	uint32 guess = (max + min) / 2;
488
489	if (startGuess > 0)
490		guess = startGuess;
491
492	if (codePoint > kUnicodeBlockMap[max-1].end)
493		return -1;
494
495	while ((max >= min) && (guess < kNumUnicodeBlockRanges)) {
496		uint32 start = kUnicodeBlockMap[guess].start;
497		uint32 end = kUnicodeBlockMap[guess].end;
498
499		if (start <= codePoint && end >= codePoint)
500			return guess;
501
502		if (end < codePoint) {
503			min = guess + 1;
504		} else {
505			max = guess - 1;
506		}
507
508		guess = (max + min) / 2;
509	}
510
511	return -1;
512}
513
514/*!
515	\brief parses charmap from fontconfig.  See fontconfig docs for FcCharSetFirstPage
516	and FcCharSetNextPage for details on format.
517	\param charMap is a fontconfig character map
518	\param baseCodePoint is the base codepoint returned by fontconfig
519	\param blocksForMap is a unicode_block to store the bitmap of contained blocks
520*/
521static
522void
523ParseFcMap(FcChar32 charMap[], FcChar32 baseCodePoint, unicode_block& blocksForMap)
524{
525	uint32 block = 0;
526	const uint8 BITS_PER_BLOCK = 32;
527	uint32 currentCodePoint = 0;
528
529	if (baseCodePoint > kUnicodeBlockMap[kNumUnicodeBlockRanges-1].end)
530		return;
531
532	for (int i = 0; i < FC_CHARSET_MAP_SIZE; ++i) {
533		FcChar32 curMapBlock = charMap[i];
534		int32 rangeStart = -1;
535		int32 startBlock = -1;
536		int32 endBlock = -1;
537		uint32 startPoint = 0;
538
539		currentCodePoint = baseCodePoint + block;
540
541		for (int bit = 0; bit < BITS_PER_BLOCK; ++bit) {
542			if (curMapBlock == 0 && startBlock < 0)
543				// if no more bits are set then short-circuit the loop
544				break;
545
546			if ((curMapBlock & 0x1) != 0 && rangeStart < 0) {
547				rangeStart = bit;
548				startPoint = currentCodePoint + rangeStart;
549				startBlock = FindBlockForCodepoint(startPoint, 0);
550				if (startBlock >= 0) {
551					blocksForMap = blocksForMap
552						| kUnicodeBlockMap[startBlock].block;
553				}
554			} else if (rangeStart >= 0 && startBlock >= 0) {
555					// when we find an empty bit, that's the end of the range
556				uint32 endPoint = currentCodePoint + (bit - 1);
557
558				endBlock = FindBlockForCodepoint(endPoint,
559					startBlock);
560					// start the binary search at the block where we found the
561					// start codepoint to ideally find the end in the same
562					// block.
563				++startBlock;
564
565				while (startBlock <= endBlock) {
566					// if the starting codepoint is found in a different block
567					// than the ending codepoint, we should add all the blocks
568					// inbetween.
569					blocksForMap = blocksForMap
570						| kUnicodeBlockMap[startBlock].block;
571					++startBlock;
572				}
573
574				startBlock = -1;
575				endBlock = -1;
576				rangeStart = -1;
577			}
578
579			curMapBlock >>= 1;
580		}
581
582		if (rangeStart >= 0 && startBlock >= 0) {
583				// if we hit the end of the block and had
584				// found a start of the range then we
585				// should end the range at the end of the block
586			uint32 endPoint = currentCodePoint + BITS_PER_BLOCK - 1;
587
588			endBlock = FindBlockForCodepoint(endPoint,
589				startBlock);
590				// start the binary search at the block where we found the
591				// start codepoint to ideally find the end in the same
592				// block.
593			++startBlock;
594
595			while (startBlock <= endBlock) {
596				// if the starting codepoint is found in a different block
597				// than the ending codepoint, we should add all the blocks
598				// inbetween.
599				blocksForMap = blocksForMap
600					| kUnicodeBlockMap[startBlock].block;
601				++startBlock;
602			}
603		}
604
605		block += BITS_PER_BLOCK;
606	}
607}
608
609#endif // FONTCONFIG_ENABLED
610
611
612/*!
613	\brief Gets a bitmap that indicates which Unicode blocks are in the font.
614	\param unicode_block to store bitmap in
615	\return B_OK; bitmap will be empty if something went wrong
616*/
617status_t
618ServerFont::GetUnicodeBlocks(unicode_block& blocksForFont)
619{
620	blocksForFont = unicode_block();
621
622#ifdef FONTCONFIG_ENABLED
623	FT_Face face = GetTransformedFace(true, true);
624	if (face == NULL)
625		return B_ERROR;
626
627	FcCharSet *charSet = FcFreeTypeCharSet(face, NULL);
628	if (charSet == NULL) {
629		PutTransformedFace(face);
630		return B_ERROR;
631	}
632
633	FcChar32 charMap[FC_CHARSET_MAP_SIZE];
634	FcChar32 next = 0;
635	FcChar32 baseCodePoint = FcCharSetFirstPage(charSet, charMap, &next);
636
637	while ((baseCodePoint != FC_CHARSET_DONE) && (next != FC_CHARSET_DONE)) {
638		ParseFcMap(charMap, baseCodePoint, blocksForFont);
639		baseCodePoint = FcCharSetNextPage(charSet, charMap, &next);
640	}
641
642	FcCharSetDestroy(charSet);
643	PutTransformedFace(face);
644#endif // FONTCONFIG_ENABLED
645
646	return B_OK;
647}
648
649/*!
650	\brief Checks if a unicode block specified by a start and end point is defined
651	in the current font
652	\param start of unicode block
653	\param end of unicode block
654	\param hasBlock boolean to store whether the font contains the specified block
655	\return B_OK; hasBlock will be false if something goes wrong
656*/
657status_t
658ServerFont::IncludesUnicodeBlock(uint32 start, uint32 end, bool& hasBlock)
659{
660	hasBlock = false;
661
662#ifdef FONTCONFIG_ENABLED
663	FT_Face face = GetTransformedFace(true, true);
664	if (face == NULL)
665		return B_ERROR;
666
667	FcCharSet *charSet = FcFreeTypeCharSet(face, NULL);
668	if (charSet == NULL) {
669		PutTransformedFace(face);
670		return B_ERROR;
671	}
672
673	uint32 curCodePoint = start;
674
675	while (curCodePoint <= end && hasBlock == false) {
676		// loop through range; if any character in the range is in the charset
677		// then the block is represented.
678		if (FcCharSetHasChar(charSet, (FcChar32)curCodePoint) == FcTrue) {
679			hasBlock = true;
680			break;
681		}
682
683		++curCodePoint;
684	}
685
686	FcCharSetDestroy(charSet);
687	PutTransformedFace(face);
688#endif // FONTCONFIG_ENABLED
689
690	return B_OK;
691}
692
693
694status_t
695ServerFont::GetHasGlyphs(const char* string, int32 numBytes, int32 numChars,
696	bool* hasArray) const
697{
698	if (string == NULL || numBytes <= 0 || numChars <= 0 || hasArray == NULL)
699		return B_BAD_DATA;
700
701	FontCacheEntry* entry = NULL;
702	FontCacheReference cacheReference;
703	BObjectList<FontCacheReference> fallbacks(21, true);
704
705	entry = GlyphLayoutEngine::FontCacheEntryFor(*this, false);
706	if (entry == NULL)
707		return B_ERROR;
708
709	cacheReference.SetTo(entry);
710
711	uint32 charCode;
712	int32 charIndex = 0;
713	const char* start = string;
714	while (charIndex < numChars && (charCode = UTF8ToCharCode(&string)) != 0) {
715		hasArray[charIndex] = entry->CanCreateGlyph(charCode);
716
717		if (hasArray[charIndex] == false) {
718			if (fallbacks.IsEmpty())
719				GlyphLayoutEngine::PopulateFallbacks(fallbacks, *this, false);
720
721			if (GlyphLayoutEngine::GetFallbackReference(fallbacks, charCode) != NULL)
722				hasArray[charIndex] = true;
723		}
724
725		charIndex++;
726		if (string - start + 1 > numBytes)
727			break;
728	}
729
730	return B_OK;
731}
732
733
734class EdgesConsumer {
735 public:
736	EdgesConsumer(edge_info* edges, float size)
737		:
738		fEdges(edges),
739		fSize(size)
740	{
741	}
742
743	bool NeedsVector() { return false; }
744	void Start() {}
745	void Finish(double x, double y) {}
746	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
747	{
748		fEdges[index].left = 0.0;
749		fEdges[index].right = 0.0;
750	}
751
752	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
753		FontCacheEntry* entry, double x, double y, double advanceX,
754			double advanceY)
755	{
756		fEdges[index].left = glyph->inset_left / fSize;
757		fEdges[index].right = glyph->inset_right / fSize;
758		return true;
759	}
760
761 private:
762	edge_info* fEdges;
763	float fSize;
764};
765
766
767status_t
768ServerFont::GetEdges(const char* string, int32 numBytes, int32 numChars,
769	edge_info* edges) const
770{
771	if (string == NULL || numBytes <= 0 || numChars <= 0 || edges == NULL)
772		return B_BAD_DATA;
773
774	EdgesConsumer consumer(edges, fSize);
775	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
776			numChars, NULL, fSpacing)) {
777		return B_OK;
778	}
779
780	return B_ERROR;
781
782//	FT_Face face = GetTransformedFace(false, false);
783//	if (!face)
784//		return B_ERROR;
785//
786//	const char *string = charArray;
787//	for (int i = 0; i < numChars; i++) {
788//		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
789//		edgeArray[i].left = float(face->glyph->metrics.horiBearingX)
790//			/ 64 / fSize;
791//		edgeArray[i].right = float(face->glyph->metrics.horiBearingX
792//			+ face->glyph->metrics.width - face->glyph->metrics.horiAdvance)
793//			/ 64 / fSize;
794//	}
795//
796//	PutTransformedFace(face);
797//	return B_OK;
798}
799
800
801class BPointEscapementConsumer {
802public:
803	BPointEscapementConsumer(BPoint* escapements, BPoint* offsets, float size)
804		:
805		fEscapements(escapements),
806		fOffsets(offsets),
807		fSize(size)
808	{
809	}
810
811	bool NeedsVector() { return false; }
812	void Start() {}
813	void Finish(double x, double y) {}
814	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
815	{
816		_Set(index, 0, 0);
817	}
818
819	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
820		FontCacheEntry* entry, double x, double y, double advanceX,
821			double advanceY)
822	{
823		return _Set(index, advanceX, advanceY);
824	}
825
826private:
827	inline bool _Set(int32 index, double x, double y)
828	{
829		fEscapements[index].x = x / fSize;
830		fEscapements[index].y = y / fSize;
831		if (fOffsets) {
832			// ToDo: According to the BeBook: "The offsetArray is applied by
833			// the dynamic spacing in order to improve the relative position
834			// of the character's width with relation to another character,
835			// without altering the width." So this will probably depend on
836			// the spacing mode.
837			fOffsets[index].x = 0;
838			fOffsets[index].y = 0;
839		}
840		return true;
841	}
842
843	BPoint* fEscapements;
844	BPoint* fOffsets;
845	float fSize;
846};
847
848
849status_t
850ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
851	escapement_delta delta, BPoint escapementArray[],
852	BPoint offsetArray[]) const
853{
854	if (string == NULL || numBytes <= 0 || numChars <= 0
855		|| escapementArray == NULL) {
856		return B_BAD_DATA;
857	}
858
859	BPointEscapementConsumer consumer(escapementArray, offsetArray, fSize);
860	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
861			numChars, &delta, fSpacing)) {
862		return B_OK;
863	}
864
865	return B_ERROR;
866}
867
868
869class WidthEscapementConsumer {
870public:
871	WidthEscapementConsumer(float* widths, float size)
872		:
873		fWidths(widths),
874		fSize(size)
875	{
876	}
877
878	bool NeedsVector() { return false; }
879	void Start() {}
880	void Finish(double x, double y) {}
881	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
882	{
883		fWidths[index] = 0.0;
884	}
885
886	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
887		FontCacheEntry* entry, double x, double y, double advanceX,
888			double advanceY)
889	{
890		fWidths[index] = advanceX / fSize;
891		return true;
892	}
893
894 private:
895	float* fWidths;
896	float fSize;
897};
898
899
900
901status_t
902ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
903	escapement_delta delta, float widthArray[]) const
904{
905	if (string == NULL || numBytes <= 0 || numChars <= 0 || widthArray == NULL)
906		return B_BAD_DATA;
907
908	WidthEscapementConsumer consumer(widthArray, fSize);
909	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
910			numChars, &delta, fSpacing)) {
911		return B_OK;
912	}
913
914	return B_ERROR;
915}
916
917
918class BoundingBoxConsumer {
919 public:
920	BoundingBoxConsumer(Transformable& transform, BRect* rectArray,
921			bool asString)
922		:
923		rectArray(rectArray),
924		stringBoundingBox(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN),
925		fAsString(asString),
926		fCurves(fPathAdaptor),
927		fContour(fCurves),
928		fTransformedOutline(fCurves, transform),
929		fTransformedContourOutline(fContour, transform),
930		fTransform(transform)
931	{
932	}
933
934	bool NeedsVector() { return false; }
935	void Start() {}
936	void Finish(double x, double y) {}
937	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
938
939	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
940		FontCacheEntry* entry, double x, double y, double advanceX,
941			double advanceY)
942	{
943		if (glyph->data_type != glyph_data_outline) {
944			const agg::rect_i& r = glyph->bounds;
945			if (fAsString) {
946				if (rectArray) {
947					rectArray[index].left = r.x1 + x;
948					rectArray[index].top = r.y1 + y;
949					rectArray[index].right = r.x2 + x + 1;
950					rectArray[index].bottom = r.y2 + y + 1;
951				} else {
952					stringBoundingBox = stringBoundingBox
953						| BRect(r.x1 + x, r.y1 + y,
954							r.x2 + x + 1, r.y2 + y + 1);
955				}
956			} else {
957				rectArray[index].left = r.x1;
958				rectArray[index].top = r.y1;
959				rectArray[index].right = r.x2 + 1;
960				rectArray[index].bottom = r.y2 + 1;
961			}
962		} else {
963			if (fAsString) {
964				entry->InitAdaptors(glyph, x, y,
965						fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
966			} else {
967				entry->InitAdaptors(glyph, 0, 0,
968						fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
969			}
970			double left = 0.0;
971			double top = 0.0;
972			double right = -1.0;
973			double bottom = -1.0;
974			uint32 pathID[1];
975			pathID[0] = 0;
976			// TODO: use fContour if falseboldwidth is > 0
977			agg::bounding_rect(fTransformedOutline, pathID, 0, 1,
978				&left, &top, &right, &bottom);
979
980			if (rectArray) {
981				rectArray[index] = BRect(left, top, right, bottom);
982			} else {
983				stringBoundingBox = stringBoundingBox
984					| BRect(left, top, right, bottom);
985			}
986		}
987		return true;
988	}
989
990	BRect*								rectArray;
991	BRect								stringBoundingBox;
992
993 private:
994	bool								fAsString;
995	FontCacheEntry::GlyphPathAdapter	fPathAdaptor;
996	FontCacheEntry::GlyphGray8Adapter	fGray8Adaptor;
997	FontCacheEntry::GlyphMonoAdapter	fMonoAdaptor;
998
999	FontCacheEntry::CurveConverter		fCurves;
1000	FontCacheEntry::ContourConverter	fContour;
1001
1002	FontCacheEntry::TransformedOutline	fTransformedOutline;
1003	FontCacheEntry::TransformedContourOutline fTransformedContourOutline;
1004
1005	Transformable&						fTransform;
1006};
1007
1008
1009status_t
1010ServerFont::GetBoundingBoxes(const char* string, int32 numBytes, int32 numChars,
1011	BRect rectArray[], bool stringEscapement, font_metric_mode mode,
1012	escapement_delta delta, bool asString)
1013{
1014	// TODO: The font_metric_mode is not used
1015	if (string == NULL || numBytes <= 0 || numChars <= 0 || rectArray == NULL)
1016		return B_BAD_DATA;
1017
1018	Transformable transform(EmbeddedTransformation());
1019
1020	BoundingBoxConsumer consumer(transform, rectArray, asString);
1021	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
1022			numChars, stringEscapement ? &delta : NULL, fSpacing)) {
1023		return B_OK;
1024	}
1025	return B_ERROR;
1026}
1027
1028
1029status_t
1030ServerFont::GetBoundingBoxesForStrings(char *charArray[], size_t lengthArray[],
1031	int32 numStrings, BRect rectArray[], font_metric_mode mode,
1032	escapement_delta deltaArray[])
1033{
1034	// TODO: The font_metric_mode is never used
1035	if (charArray == NULL || lengthArray == NULL || numStrings <= 0
1036		|| rectArray == NULL || deltaArray == NULL) {
1037		return B_BAD_DATA;
1038	}
1039
1040	Transformable transform(EmbeddedTransformation());
1041
1042	for (int32 i = 0; i < numStrings; i++) {
1043		size_t numBytes = lengthArray[i];
1044		const char* string = charArray[i];
1045		escapement_delta delta = deltaArray[i];
1046
1047		BoundingBoxConsumer consumer(transform, NULL, true);
1048		if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
1049				INT32_MAX, &delta, fSpacing)) {
1050			return B_ERROR;
1051		}
1052
1053		rectArray[i] = consumer.stringBoundingBox;
1054	}
1055
1056	return B_OK;
1057}
1058
1059
1060class StringWidthConsumer {
1061 public:
1062	StringWidthConsumer()
1063		:
1064		width(0.0)
1065	{
1066	}
1067
1068	bool NeedsVector() { return false; }
1069	void Start() {}
1070	void Finish(double x, double y) { width = x; }
1071	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
1072	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
1073		FontCacheEntry* entry, double x, double y, double advanceX,
1074			double advanceY)
1075	{
1076		return true;
1077	}
1078
1079	float width;
1080};
1081
1082
1083float
1084ServerFont::StringWidth(const char *string, int32 numBytes,
1085	const escapement_delta* deltaArray) const
1086{
1087	if (!string || numBytes <= 0)
1088		return 0.0;
1089
1090	StringWidthConsumer consumer;
1091	if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
1092			INT32_MAX, deltaArray, fSpacing)) {
1093		return 0.0;
1094	}
1095
1096	return consumer.width;
1097}
1098
1099
1100/*!
1101	\brief Returns a BRect which encloses the entire font
1102	\return A BRect which encloses the entire font
1103*/
1104BRect
1105ServerFont::BoundingBox()
1106{
1107	FT_Face face = fStyle->FreeTypeFace();
1108
1109	if (fBounds.IsValid() &&
1110		fBounds.IntegerWidth() > 0 &&
1111		fBounds.IntegerHeight() > 0)
1112		return fBounds;
1113
1114	// if font has vector outlines, get the bounding box
1115	// from freetype and scale it by the font size
1116	if (IsScalable()) {
1117		FT_BBox bounds = face->bbox;
1118		fBounds.left = (float)bounds.xMin / (float)face->units_per_EM;
1119		fBounds.right = (float)bounds.xMax / (float)face->units_per_EM;
1120		fBounds.top = (float)bounds.yMin / (float)face->units_per_EM;
1121		fBounds.bottom = (float)bounds.yMax / (float)face->units_per_EM;
1122
1123		float scaledWidth = fBounds.Width() * fSize;
1124		float scaledHeight = fBounds.Height() * fSize;
1125
1126		fBounds.InsetBy((fBounds.Width() - scaledWidth) / 2.f,
1127			(fBounds.Height() - scaledHeight) / 2.f);
1128	} else {
1129		// otherwise find the bitmap that is closest in size
1130		// to the requested size
1131		float pixelSize = fSize * 64.f;
1132		float minDelta = abs(face->available_sizes[0].size - pixelSize);
1133		float width = face->available_sizes[0].x_ppem;
1134		float height = face->available_sizes[0].y_ppem;
1135
1136		for (int i = 1; i < face->num_fixed_sizes; ++i) {
1137			float delta = abs(face->available_sizes[i].size - pixelSize);
1138			if (delta < minDelta) {
1139				width = face->available_sizes[i].x_ppem;
1140				height = face->available_sizes[i].y_ppem;
1141			}
1142		}
1143
1144		fBounds.top = 0;
1145		fBounds.left = 0;
1146		fBounds.right = width / 64.f;
1147		fBounds.bottom = height / 64.f;
1148	}
1149
1150	return fBounds;
1151}
1152
1153
1154/*!
1155	\brief Obtains the height values for characters in the font in its current state
1156	\param fh pointer to a font_height object to receive the values for the font
1157*/
1158void
1159ServerFont::GetHeight(font_height& height) const
1160{
1161	fStyle->GetHeight(fSize, height);
1162}
1163
1164
1165void
1166ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const
1167{
1168	if (!inOut)
1169		return;
1170
1171	// the width of the "���" glyph
1172	float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, strlen(B_UTF8_ELLIPSIS));
1173
1174	// count the individual glyphs
1175	int32 numChars = inOut->CountChars();
1176
1177	// get the escapement of each glyph in font units
1178	float* escapementArray = new (std::nothrow) float[numChars];
1179	if (escapementArray == NULL)
1180		return;
1181
1182	static escapement_delta delta = (escapement_delta){ 0.0, 0.0 };
1183	if (GetEscapements(inOut->String(), inOut->Length(), numChars, delta,
1184		escapementArray) == B_OK) {
1185		truncate_string(*inOut, mode, width, escapementArray, fSize,
1186			ellipsisWidth, numChars);
1187	}
1188
1189	delete[] escapementArray;
1190}
1191
1192
1193Transformable
1194ServerFont::EmbeddedTransformation() const
1195{
1196	// TODO: cache this?
1197	Transformable transform;
1198
1199	transform.ShearBy(B_ORIGIN, (90.0 - fShear) * M_PI / 180.0, 0.0);
1200	transform.RotateBy(B_ORIGIN, -fRotation * M_PI / 180.0);
1201
1202	return transform;
1203}
1204
1205
1206void
1207ServerFont::SetFontData(FT_Byte* location, uint32 size)
1208{
1209	if (fStyle != NULL)
1210		fStyle->SetFontData(location, size);
1211}
1212