xref: /haiku/src/servers/app/ServerFont.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 	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 */
592 status_t
593 ServerFont::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 */
632 status_t
633 ServerFont::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 
669 class 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 
698 status_t
699 ServerFont::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 
715 class 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 
748 status_t
749 ServerFont::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 
782 class BPointEscapementConsumer {
783 public:
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 
807 private:
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 
830 status_t
831 ServerFont::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 
850 class WidthEscapementConsumer {
851 public:
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 
882 status_t
883 ServerFont::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 
899 class 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 
990 status_t
991 ServerFont::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 
1010 status_t
1011 ServerFont::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 
1041 class 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 
1064 float
1065 ServerFont::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 */
1085 BRect
1086 ServerFont::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 */
1097 void
1098 ServerFont::GetHeight(font_height& height) const
1099 {
1100 	fStyle->GetHeight(fSize, height);
1101 }
1102 
1103 
1104 void
1105 ServerFont::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 
1132 Transformable
1133 ServerFont::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