xref: /haiku/src/servers/app/ServerFont.cpp (revision 6889394848e2dc9f41ff53b12141d572822ca0c6)
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
44 inline BPoint
45 VectorToPoint(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 
54 int
55 MoveToFunc(const FT_Vector *to, void *user)
56 {
57 	((BShape *)user)->MoveTo(VectorToPoint(to));
58 	return 0;
59 }
60 
61 
62 int
63 LineToFunc(const FT_Vector *to, void *user)
64 {
65 	((BShape *)user)->LineTo(VectorToPoint(to));
66 	return 0;
67 }
68 
69 
70 int
71 ConicToFunc(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 
84 int
85 CubicToFunc(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 
98 inline bool
99 is_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 */
130 ServerFont::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 
149 ServerFont::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 */
161 ServerFont::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 */
172 ServerFont::~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 */
183 ServerFont&
184 ServerFont::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 
201 bool
202 ServerFont::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 */
219 int32
220 ServerFont::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 */
230 font_file_format
231 ServerFont::FileFormat()
232 {
233 	return fStyle->FileFormat();
234 }
235 
236 
237 const char*
238 ServerFont::Style() const
239 {
240 	return fStyle->Name();
241 }
242 
243 
244 const char*
245 ServerFont::Family() const
246 {
247 	return fStyle->Family()->Name();
248 }
249 
250 
251 void
252 ServerFont::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 */
278 status_t
279 ServerFont::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 */
306 status_t
307 ServerFont::SetFamilyAndStyle(uint32 fontID)
308 {
309 	uint16 style = fontID & 0xFFFF;
310 	uint16 family = (fontID & 0xFFFF0000) >> 16;
311 
312 	return SetFamilyAndStyle(family, style);
313 }
314 
315 
316 status_t
317 ServerFont::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 */
358 uint32
359 ServerFont::GetFamilyAndStyle() const
360 {
361 	return (FamilyID() << 16) | StyleID();
362 }
363 
364 
365 FT_Face
366 ServerFont::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 
402 void
403 ServerFont::PutTransformedFace(FT_Face face) const
404 {
405 	// Reset transformation
406 	FT_Set_Transform(face, NULL, NULL);
407 	fStyle->Unlock();
408 }
409 
410 
411 status_t
412 ServerFont::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 */
456 static
457 int32
458 FindBlockForCodepoint(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 */
496 static
497 void
498 ParseFcMap(FcChar32 charMap[], FcChar32 baseCodePoint, unicode_block& blocksForMap)
499 {
500 	for (int i = 0; i < FC_CHARSET_MAP_SIZE; ++i) {
501 		FcChar32 curMapBlock = charMap[i];
502 		uint32 rangeStart = 0;
503 		uint32 block = 0;
504 
505 		for (int bit = 0; bit < 32; ++bit) {
506 			uint32 startPoint = 0;
507 			int32 foundStartBlock = -1;
508 			int32 foundEndBlock = -1;
509 
510 			if ((curMapBlock & 0x8) != 0) {
511 				if (rangeStart == 0) {
512 					rangeStart = bit;
513 					startPoint = baseCodePoint + block + (rangeStart);
514 					foundStartBlock = FindBlockForCodepoint(startPoint, 0);
515 					if (foundStartBlock >= 0) {
516 						blocksForMap = blocksForMap
517 							| kUnicodeBlockMap[foundStartBlock].block;
518 					}
519 				}
520 			} else if (rangeStart > 0 && foundStartBlock > 0) {
521 					// when we find an empty bit, that's the end of the range
522 				uint32 endPoint = baseCodePoint + block + (bit - 1);
523 
524 				foundEndBlock = FindBlockForCodepoint(endPoint,
525 					foundStartBlock);
526 					// start the binary search at the block where we found the
527 					// start codepoint to ideally find the end in the same
528 					// block.
529 				++foundStartBlock;
530 
531 				while (foundStartBlock <= foundEndBlock) {
532 					// if the starting codepoint is found in a different block
533 					// than the ending codepoint, we should add all the blocks
534 					// inbetween.
535 					blocksForMap = blocksForMap
536 						| kUnicodeBlockMap[foundStartBlock].block;
537 					++foundStartBlock;
538 				}
539 
540 				foundStartBlock = -1;
541 				foundEndBlock = -1;
542 				rangeStart = 0;
543 			} else {
544 				foundStartBlock = -1;
545 				rangeStart = 0;
546 			}
547 
548 			curMapBlock >>= 1;
549 		}
550 
551 		block += 32;
552 	}
553 }
554 
555 #endif // FONTCONFIG_ENABLED
556 
557 
558 /*!
559 	\brief Gets a bitmap that indicates which Unicode blocks are in the font.
560 	\param unicode_block to store bitmap in
561 	\return B_OK; bitmap will be empty if something went wrong
562 */
563 status_t
564 ServerFont::GetUnicodeBlocks(unicode_block& blocksForFont)
565 {
566 	blocksForFont = unicode_block();
567 
568 #ifdef FONTCONFIG_ENABLED
569 	FT_Face face = GetTransformedFace(true, true);
570 	if (face == NULL)
571 		return B_ERROR;
572 
573 	FcCharSet *charSet = FcFreeTypeCharSet(face, NULL);
574 	if (charSet == NULL)
575 		return B_ERROR;
576 
577 	FcChar32 charMap[FC_CHARSET_MAP_SIZE];
578 	FcChar32 next = 0;
579 	FcChar32 baseCodePoint = FcCharSetFirstPage(charSet, charMap, &next);
580 
581 	while ((baseCodePoint != FC_CHARSET_DONE) && (next != FC_CHARSET_DONE)) {
582 		ParseFcMap(charMap, baseCodePoint, blocksForFont);
583 		baseCodePoint = FcCharSetNextPage(charSet, charMap, &next);
584 	}
585 
586 #endif // FONTCONFIG_ENABLED
587 
588 	return B_OK;
589 }
590 
591 /*!
592 	\brief Checks if a unicode block specified by a start and end point is defined
593 	in the current font
594 	\param start of unicode block
595 	\param end of unicode block
596 	\param hasBlock boolean to store whether the font contains the specified block
597 	\return B_OK; hasBlock will be false if something goes wrong
598 */
599 status_t
600 ServerFont::IncludesUnicodeBlock(uint32 start, uint32 end, bool& hasBlock)
601 {
602 	hasBlock = false;
603 
604 #ifdef FONTCONFIG_ENABLED
605 	FT_Face face = GetTransformedFace(true, true);
606 	if (face == NULL)
607 		return B_ERROR;
608 
609 	FcCharSet *charSet = FcFreeTypeCharSet(face, NULL);
610 	if (charSet == NULL)
611 		return B_ERROR;
612 
613 	uint32 curCodePoint = start;
614 
615 	while (curCodePoint <= end && hasBlock == false) {
616 		// loop through range; if any character in the range is in the charset
617 		// then the block is represented.
618 		if (FcCharSetHasChar(charSet, (FcChar32)curCodePoint) == FcTrue) {
619 			hasBlock = true;
620 			break;
621 		}
622 
623 		++curCodePoint;
624 	}
625 
626 #endif // FONTCONFIG_ENABLED
627 
628 	return B_OK;
629 }
630 
631 
632 class HasGlyphsConsumer {
633  public:
634 	HasGlyphsConsumer(bool* hasArray)
635 		: fHasArray(hasArray)
636 	{
637 	}
638 	bool NeedsVector() { return false; }
639 	void Start() {}
640 	void Finish(double x, double y) {}
641 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
642 	{
643 		fHasArray[index] = false;
644 	}
645 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
646 		FontCacheEntry* entry, double x, double y, double advanceX,
647 			double advanceY)
648 	{
649 		fHasArray[index] = glyph->glyph_index != 0;
650 		return true;
651 	}
652 
653  private:
654 	bool* fHasArray;
655 };
656 
657 
658 status_t
659 ServerFont::GetHasGlyphs(const char* string, int32 numBytes,
660 	bool* hasArray) const
661 {
662 	if (!string || numBytes <= 0 || !hasArray)
663 		return B_BAD_DATA;
664 
665 	HasGlyphsConsumer consumer(hasArray);
666 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
667 		NULL, fSpacing))
668 		return B_OK;
669 
670 	return B_ERROR;
671 }
672 
673 
674 class EdgesConsumer {
675  public:
676 	EdgesConsumer(edge_info* edges, float size)
677 		: fEdges(edges)
678 		, fSize(size)
679 	{
680 	}
681 	bool NeedsVector() { return false; }
682 	void Start() {}
683 	void Finish(double x, double y) {}
684 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
685 	{
686 		fEdges[index].left = 0.0;
687 		fEdges[index].right = 0.0;
688 	}
689 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
690 		FontCacheEntry* entry, double x, double y, double advanceX,
691 			double advanceY)
692 	{
693 		fEdges[index].left = glyph->inset_left / fSize;
694 		fEdges[index].right = glyph->inset_right / fSize;
695 		return true;
696 	}
697 
698  private:
699 	edge_info* fEdges;
700 	float fSize;
701 };
702 
703 
704 status_t
705 ServerFont::GetEdges(const char* string, int32 numBytes,
706 	edge_info* edges) const
707 {
708 	if (!string || numBytes <= 0 || !edges)
709 		return B_BAD_DATA;
710 
711 	EdgesConsumer consumer(edges, fSize);
712 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
713 		NULL, fSpacing)) {
714 		return B_OK;
715 	}
716 
717 	return B_ERROR;
718 
719 //	FT_Face face = GetTransformedFace(false, false);
720 //	if (!face)
721 //		return B_ERROR;
722 //
723 //	const char *string = charArray;
724 //	for (int i = 0; i < numChars; i++) {
725 //		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
726 //		edgeArray[i].left = float(face->glyph->metrics.horiBearingX)
727 //			/ 64 / fSize;
728 //		edgeArray[i].right = float(face->glyph->metrics.horiBearingX
729 //			+ face->glyph->metrics.width - face->glyph->metrics.horiAdvance)
730 //			/ 64 / fSize;
731 //	}
732 //
733 //	PutTransformedFace(face);
734 //	return B_OK;
735 }
736 
737 
738 class BPointEscapementConsumer {
739 public:
740 	BPointEscapementConsumer(BPoint* escapements, BPoint* offsets,
741 			int32 numChars, float size)
742 		:
743 		fEscapements(escapements),
744 		fOffsets(offsets),
745 		fNumChars(numChars),
746 		fSize(size)
747 	{
748 	}
749 
750 	bool NeedsVector() { return false; }
751 	void Start() {}
752 	void Finish(double x, double y) {}
753 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
754 	{
755 		_Set(index, 0, 0);
756 	}
757 
758 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
759 		FontCacheEntry* entry, double x, double y, double advanceX,
760 			double advanceY)
761 	{
762 		return _Set(index, advanceX, advanceY);
763 	}
764 
765 private:
766 	inline bool _Set(int32 index, double x, double y)
767 	{
768 		if (index >= fNumChars)
769 			return false;
770 
771 		fEscapements[index].x = x / fSize;
772 		fEscapements[index].y = y / fSize;
773 		if (fOffsets) {
774 			// ToDo: According to the BeBook: "The offsetArray is applied by
775 			// the dynamic spacing in order to improve the relative position
776 			// of the character's width with relation to another character,
777 			// without altering the width." So this will probably depend on
778 			// the spacing mode.
779 			fOffsets[index].x = 0;
780 			fOffsets[index].y = 0;
781 		}
782 		return true;
783 	}
784 
785 	BPoint* fEscapements;
786 	BPoint* fOffsets;
787 	int32 fNumChars;
788  	float fSize;
789 };
790 
791 
792 status_t
793 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
794 	escapement_delta delta, BPoint escapementArray[],
795 	BPoint offsetArray[]) const
796 {
797 	if (!string || numBytes <= 0 || !escapementArray)
798 		return B_BAD_DATA;
799 
800 	BPointEscapementConsumer consumer(escapementArray, offsetArray, numChars,
801 		fSize);
802 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
803 		&delta, fSpacing)) {
804 		return B_OK;
805 	}
806 
807 	return B_ERROR;
808 }
809 
810 
811 class WidthEscapementConsumer {
812 public:
813 	WidthEscapementConsumer(float* widths, int32 numChars, float size)
814 		:
815 		fWidths(widths),
816 		fNumChars(numChars),
817 		fSize(size)
818 	{
819 	}
820 
821 	bool NeedsVector() { return false; }
822 	void Start() {}
823 	void Finish(double x, double y) {}
824 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
825 	{
826 		fWidths[index] = 0.0;
827 	}
828 
829 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
830 		FontCacheEntry* entry, double x, double y, double advanceX,
831 			double advanceY)
832 	{
833 		if (index >= fNumChars)
834 			return false;
835 
836 		fWidths[index] = advanceX / fSize;
837 		return true;
838 	}
839 
840  private:
841 	float* fWidths;
842 	int32 fNumChars;
843 	float fSize;
844 };
845 
846 
847 
848 status_t
849 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
850 	escapement_delta delta, float widthArray[]) const
851 {
852 	if (!string || numBytes <= 0 || !widthArray)
853 		return B_BAD_DATA;
854 
855 	WidthEscapementConsumer consumer(widthArray, numChars, fSize);
856 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
857 		&delta, fSpacing)) {
858 		return B_OK;
859 	}
860 	return B_ERROR;
861 }
862 
863 
864 class BoundingBoxConsumer {
865  public:
866 	BoundingBoxConsumer(Transformable& transform, BRect* rectArray,
867 			bool asString)
868 		: rectArray(rectArray)
869 		, stringBoundingBox(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN)
870 		, fAsString(asString)
871 		, fCurves(fPathAdaptor)
872 		, fContour(fCurves)
873 		, fTransformedOutline(fCurves, transform)
874 		, fTransformedContourOutline(fContour, transform)
875 		, fTransform(transform)
876 	{
877 	}
878 
879 	bool NeedsVector() { return false; }
880 	void Start() {}
881 	void Finish(double x, double y) {}
882 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
883 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
884 		FontCacheEntry* entry, double x, double y, double advanceX,
885 			double advanceY)
886 	{
887 		if (glyph->data_type != glyph_data_outline) {
888 			const agg::rect_i& r = glyph->bounds;
889 			if (fAsString) {
890 				if (rectArray) {
891 					rectArray[index].left = r.x1 + x;
892 					rectArray[index].top = r.y1 + y;
893 					rectArray[index].right = r.x2 + x + 1;
894 					rectArray[index].bottom = r.y2 + y + 1;
895 				} else {
896 					stringBoundingBox = stringBoundingBox
897 						| BRect(r.x1 + x, r.y1 + y,
898 							r.x2 + x + 1, r.y2 + y + 1);
899 				}
900 			} else {
901 				rectArray[index].left = r.x1;
902 				rectArray[index].top = r.y1;
903 				rectArray[index].right = r.x2 + 1;
904 				rectArray[index].bottom = r.y2 + 1;
905 			}
906 		} else {
907 			if (fAsString) {
908 				entry->InitAdaptors(glyph, x, y,
909 						fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
910 			} else {
911 				entry->InitAdaptors(glyph, 0, 0,
912 						fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
913 			}
914 			double left = 0.0;
915 			double top = 0.0;
916 			double right = -1.0;
917 			double bottom = -1.0;
918 			uint32 pathID[1];
919 			pathID[0] = 0;
920 			// TODO: use fContour if falseboldwidth is > 0
921 			agg::bounding_rect(fTransformedOutline, pathID, 0, 1,
922 				&left, &top, &right, &bottom);
923 
924 			if (rectArray) {
925 				rectArray[index] = BRect(left, top, right, bottom);
926 			} else {
927 				stringBoundingBox = stringBoundingBox
928 					| BRect(left, top, right, bottom);
929 			}
930 		}
931 		return true;
932 	}
933 
934 	BRect*								rectArray;
935 	BRect								stringBoundingBox;
936 
937  private:
938 	bool								fAsString;
939 	FontCacheEntry::GlyphPathAdapter	fPathAdaptor;
940 	FontCacheEntry::GlyphGray8Adapter	fGray8Adaptor;
941 	FontCacheEntry::GlyphMonoAdapter	fMonoAdaptor;
942 
943 	FontCacheEntry::CurveConverter		fCurves;
944 	FontCacheEntry::ContourConverter	fContour;
945 
946 	FontCacheEntry::TransformedOutline	fTransformedOutline;
947 	FontCacheEntry::TransformedContourOutline fTransformedContourOutline;
948 
949 	Transformable&						fTransform;
950 };
951 
952 
953 status_t
954 ServerFont::GetBoundingBoxes(const char* string, int32 numBytes,
955 	BRect rectArray[], bool stringEscapement, font_metric_mode mode,
956 	escapement_delta delta, bool asString)
957 {
958 	// TODO: The font_metric_mode is not used
959 	if (!string || numBytes <= 0 || !rectArray)
960 		return B_BAD_DATA;
961 
962 	Transformable transform(EmbeddedTransformation());
963 
964 	BoundingBoxConsumer consumer(transform, rectArray, asString);
965 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
966 		stringEscapement ? &delta : NULL, fSpacing)) {
967 		return B_OK;
968 	}
969 	return B_ERROR;
970 }
971 
972 
973 status_t
974 ServerFont::GetBoundingBoxesForStrings(char *charArray[], int32 lengthArray[],
975 	int32 numStrings, BRect rectArray[], font_metric_mode mode,
976 	escapement_delta deltaArray[])
977 {
978 	// TODO: The font_metric_mode is never used
979 	if (!charArray || !lengthArray|| numStrings <= 0 || !rectArray || !deltaArray)
980 		return B_BAD_DATA;
981 
982 	Transformable transform(EmbeddedTransformation());
983 
984 	for (int32 i = 0; i < numStrings; i++) {
985 		int32 numBytes = lengthArray[i];
986 		const char* string = charArray[i];
987 		escapement_delta delta = deltaArray[i];
988 
989 		BoundingBoxConsumer consumer(transform, NULL, true);
990 		if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
991 			&delta, fSpacing)) {
992 			return B_ERROR;
993 		}
994 
995 		rectArray[i] = consumer.stringBoundingBox;
996 	}
997 
998 	return B_OK;
999 }
1000 
1001 
1002 class StringWidthConsumer {
1003  public:
1004 	StringWidthConsumer() : width(0.0) {}
1005 	bool NeedsVector() { return false; }
1006 	void Start() {}
1007 	void Finish(double x, double y) { width = x; }
1008 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
1009 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
1010 		FontCacheEntry* entry, double x, double y, double advanceX,
1011 			double advanceY)
1012 	{ return true; }
1013 
1014 	float width;
1015 };
1016 
1017 
1018 float
1019 ServerFont::StringWidth(const char *string, int32 numBytes,
1020 	const escapement_delta* deltaArray) const
1021 {
1022 	if (!string || numBytes <= 0)
1023 		return 0.0;
1024 
1025 	StringWidthConsumer consumer;
1026 	if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
1027 			deltaArray, fSpacing)) {
1028 		return 0.0;
1029 	}
1030 
1031 	return consumer.width;
1032 }
1033 
1034 
1035 /*!
1036 	\brief Returns a BRect which encloses the entire font
1037 	\return A BRect which encloses the entire font
1038 */
1039 BRect
1040 ServerFont::BoundingBox()
1041 {
1042 	// TODO: fBounds is nowhere calculated!
1043 	return fBounds;
1044 }
1045 
1046 
1047 /*!
1048 	\brief Obtains the height values for characters in the font in its current state
1049 	\param fh pointer to a font_height object to receive the values for the font
1050 */
1051 void
1052 ServerFont::GetHeight(font_height& height) const
1053 {
1054 	fStyle->GetHeight(fSize, height);
1055 }
1056 
1057 
1058 void
1059 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const
1060 {
1061 	if (!inOut)
1062 		return;
1063 
1064 	// the width of the "…" glyph
1065 	float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, strlen(B_UTF8_ELLIPSIS));
1066 
1067 	// count the individual glyphs
1068 	int32 numChars = inOut->CountChars();
1069 
1070 	// get the escapement of each glyph in font units
1071 	float* escapementArray = new (std::nothrow) float[numChars];
1072 	if (escapementArray == NULL)
1073 		return;
1074 
1075 	static escapement_delta delta = (escapement_delta){ 0.0, 0.0 };
1076 	if (GetEscapements(inOut->String(), inOut->Length(), numChars, delta,
1077 		escapementArray) == B_OK) {
1078 		truncate_string(*inOut, mode, width, escapementArray, fSize,
1079 			ellipsisWidth, numChars);
1080 	}
1081 
1082 	delete[] escapementArray;
1083 }
1084 
1085 
1086 Transformable
1087 ServerFont::EmbeddedTransformation() const
1088 {
1089 	// TODO: cache this?
1090 	Transformable transform;
1091 
1092 	transform.ShearBy(B_ORIGIN, (90.0 - fShear) * M_PI / 180.0, 0.0);
1093 	transform.RotateBy(B_ORIGIN, -fRotation * M_PI / 180.0);
1094 
1095 	return transform;
1096 }
1097 
1098