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