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