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