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