xref: /haiku/src/servers/app/ServerFont.cpp (revision c05253c64ed5afe485062830e21ff448a48bc741)
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 class HasGlyphsConsumer {
656  public:
657 	HasGlyphsConsumer(bool* hasArray)
658 		:
659 		fHasArray(hasArray)
660 	{
661 	}
662 
663 	bool NeedsVector() { return false; }
664 	void Start() {}
665 	void Finish(double x, double y) {}
666 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
667 	{
668 		fHasArray[index] = false;
669 	}
670 
671 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
672 		FontCacheEntry* entry, double x, double y, double advanceX,
673 			double advanceY)
674 	{
675 		fHasArray[index] = glyph->glyph_index != 0;
676 		return true;
677 	}
678 
679  private:
680 	bool* fHasArray;
681 };
682 
683 
684 status_t
685 ServerFont::GetHasGlyphs(const char* string, int32 numBytes, int32 numChars,
686 	bool* hasArray) const
687 {
688 	if (string == NULL || numBytes <= 0 || numChars <= 0 || hasArray == NULL)
689 		return B_BAD_DATA;
690 
691 	HasGlyphsConsumer consumer(hasArray);
692 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
693 			numChars, NULL, fSpacing)) {
694 		return B_OK;
695 	}
696 
697 	return B_ERROR;
698 }
699 
700 
701 class EdgesConsumer {
702  public:
703 	EdgesConsumer(edge_info* edges, float size)
704 		:
705 		fEdges(edges),
706 		fSize(size)
707 	{
708 	}
709 
710 	bool NeedsVector() { return false; }
711 	void Start() {}
712 	void Finish(double x, double y) {}
713 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
714 	{
715 		fEdges[index].left = 0.0;
716 		fEdges[index].right = 0.0;
717 	}
718 
719 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
720 		FontCacheEntry* entry, double x, double y, double advanceX,
721 			double advanceY)
722 	{
723 		fEdges[index].left = glyph->inset_left / fSize;
724 		fEdges[index].right = glyph->inset_right / fSize;
725 		return true;
726 	}
727 
728  private:
729 	edge_info* fEdges;
730 	float fSize;
731 };
732 
733 
734 status_t
735 ServerFont::GetEdges(const char* string, int32 numBytes, int32 numChars,
736 	edge_info* edges) const
737 {
738 	if (string == NULL || numBytes <= 0 || numChars <= 0 || edges == NULL)
739 		return B_BAD_DATA;
740 
741 	EdgesConsumer consumer(edges, fSize);
742 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
743 			numChars, NULL, fSpacing)) {
744 		return B_OK;
745 	}
746 
747 	return B_ERROR;
748 
749 //	FT_Face face = GetTransformedFace(false, false);
750 //	if (!face)
751 //		return B_ERROR;
752 //
753 //	const char *string = charArray;
754 //	for (int i = 0; i < numChars; i++) {
755 //		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
756 //		edgeArray[i].left = float(face->glyph->metrics.horiBearingX)
757 //			/ 64 / fSize;
758 //		edgeArray[i].right = float(face->glyph->metrics.horiBearingX
759 //			+ face->glyph->metrics.width - face->glyph->metrics.horiAdvance)
760 //			/ 64 / fSize;
761 //	}
762 //
763 //	PutTransformedFace(face);
764 //	return B_OK;
765 }
766 
767 
768 class BPointEscapementConsumer {
769 public:
770 	BPointEscapementConsumer(BPoint* escapements, BPoint* offsets, float size)
771 		:
772 		fEscapements(escapements),
773 		fOffsets(offsets),
774 		fSize(size)
775 	{
776 	}
777 
778 	bool NeedsVector() { return false; }
779 	void Start() {}
780 	void Finish(double x, double y) {}
781 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
782 	{
783 		_Set(index, 0, 0);
784 	}
785 
786 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
787 		FontCacheEntry* entry, double x, double y, double advanceX,
788 			double advanceY)
789 	{
790 		return _Set(index, advanceX, advanceY);
791 	}
792 
793 private:
794 	inline bool _Set(int32 index, double x, double y)
795 	{
796 		fEscapements[index].x = x / fSize;
797 		fEscapements[index].y = y / fSize;
798 		if (fOffsets) {
799 			// ToDo: According to the BeBook: "The offsetArray is applied by
800 			// the dynamic spacing in order to improve the relative position
801 			// of the character's width with relation to another character,
802 			// without altering the width." So this will probably depend on
803 			// the spacing mode.
804 			fOffsets[index].x = 0;
805 			fOffsets[index].y = 0;
806 		}
807 		return true;
808 	}
809 
810 	BPoint* fEscapements;
811 	BPoint* fOffsets;
812 	float fSize;
813 };
814 
815 
816 status_t
817 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
818 	escapement_delta delta, BPoint escapementArray[],
819 	BPoint offsetArray[]) const
820 {
821 	if (string == NULL || numBytes <= 0 || numChars <= 0
822 		|| escapementArray == NULL) {
823 		return B_BAD_DATA;
824 	}
825 
826 	BPointEscapementConsumer consumer(escapementArray, offsetArray, fSize);
827 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
828 			numChars, &delta, fSpacing)) {
829 		return B_OK;
830 	}
831 
832 	return B_ERROR;
833 }
834 
835 
836 class WidthEscapementConsumer {
837 public:
838 	WidthEscapementConsumer(float* widths, float size)
839 		:
840 		fWidths(widths),
841 		fSize(size)
842 	{
843 	}
844 
845 	bool NeedsVector() { return false; }
846 	void Start() {}
847 	void Finish(double x, double y) {}
848 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
849 	{
850 		fWidths[index] = 0.0;
851 	}
852 
853 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
854 		FontCacheEntry* entry, double x, double y, double advanceX,
855 			double advanceY)
856 	{
857 		fWidths[index] = advanceX / fSize;
858 		return true;
859 	}
860 
861  private:
862 	float* fWidths;
863 	float fSize;
864 };
865 
866 
867 
868 status_t
869 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
870 	escapement_delta delta, float widthArray[]) const
871 {
872 	if (string == NULL || numBytes <= 0 || numChars <= 0 || widthArray == NULL)
873 		return B_BAD_DATA;
874 
875 	WidthEscapementConsumer consumer(widthArray, fSize);
876 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
877 			numChars, &delta, fSpacing)) {
878 		return B_OK;
879 	}
880 
881 	return B_ERROR;
882 }
883 
884 
885 class BoundingBoxConsumer {
886  public:
887 	BoundingBoxConsumer(Transformable& transform, BRect* rectArray,
888 			bool asString)
889 		:
890 		rectArray(rectArray),
891 		stringBoundingBox(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN),
892 		fAsString(asString),
893 		fCurves(fPathAdaptor),
894 		fContour(fCurves),
895 		fTransformedOutline(fCurves, transform),
896 		fTransformedContourOutline(fContour, transform),
897 		fTransform(transform)
898 	{
899 	}
900 
901 	bool NeedsVector() { return false; }
902 	void Start() {}
903 	void Finish(double x, double y) {}
904 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
905 
906 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
907 		FontCacheEntry* entry, double x, double y, double advanceX,
908 			double advanceY)
909 	{
910 		if (glyph->data_type != glyph_data_outline) {
911 			const agg::rect_i& r = glyph->bounds;
912 			if (fAsString) {
913 				if (rectArray) {
914 					rectArray[index].left = r.x1 + x;
915 					rectArray[index].top = r.y1 + y;
916 					rectArray[index].right = r.x2 + x + 1;
917 					rectArray[index].bottom = r.y2 + y + 1;
918 				} else {
919 					stringBoundingBox = stringBoundingBox
920 						| BRect(r.x1 + x, r.y1 + y,
921 							r.x2 + x + 1, r.y2 + y + 1);
922 				}
923 			} else {
924 				rectArray[index].left = r.x1;
925 				rectArray[index].top = r.y1;
926 				rectArray[index].right = r.x2 + 1;
927 				rectArray[index].bottom = r.y2 + 1;
928 			}
929 		} else {
930 			if (fAsString) {
931 				entry->InitAdaptors(glyph, x, y,
932 						fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
933 			} else {
934 				entry->InitAdaptors(glyph, 0, 0,
935 						fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
936 			}
937 			double left = 0.0;
938 			double top = 0.0;
939 			double right = -1.0;
940 			double bottom = -1.0;
941 			uint32 pathID[1];
942 			pathID[0] = 0;
943 			// TODO: use fContour if falseboldwidth is > 0
944 			agg::bounding_rect(fTransformedOutline, pathID, 0, 1,
945 				&left, &top, &right, &bottom);
946 
947 			if (rectArray) {
948 				rectArray[index] = BRect(left, top, right, bottom);
949 			} else {
950 				stringBoundingBox = stringBoundingBox
951 					| BRect(left, top, right, bottom);
952 			}
953 		}
954 		return true;
955 	}
956 
957 	BRect*								rectArray;
958 	BRect								stringBoundingBox;
959 
960  private:
961 	bool								fAsString;
962 	FontCacheEntry::GlyphPathAdapter	fPathAdaptor;
963 	FontCacheEntry::GlyphGray8Adapter	fGray8Adaptor;
964 	FontCacheEntry::GlyphMonoAdapter	fMonoAdaptor;
965 
966 	FontCacheEntry::CurveConverter		fCurves;
967 	FontCacheEntry::ContourConverter	fContour;
968 
969 	FontCacheEntry::TransformedOutline	fTransformedOutline;
970 	FontCacheEntry::TransformedContourOutline fTransformedContourOutline;
971 
972 	Transformable&						fTransform;
973 };
974 
975 
976 status_t
977 ServerFont::GetBoundingBoxes(const char* string, int32 numBytes, int32 numChars,
978 	BRect rectArray[], bool stringEscapement, font_metric_mode mode,
979 	escapement_delta delta, bool asString)
980 {
981 	// TODO: The font_metric_mode is not used
982 	if (string == NULL || numBytes <= 0 || numChars <= 0 || rectArray == NULL)
983 		return B_BAD_DATA;
984 
985 	Transformable transform(EmbeddedTransformation());
986 
987 	BoundingBoxConsumer consumer(transform, rectArray, asString);
988 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
989 			numChars, stringEscapement ? &delta : NULL, fSpacing)) {
990 		return B_OK;
991 	}
992 	return B_ERROR;
993 }
994 
995 
996 status_t
997 ServerFont::GetBoundingBoxesForStrings(char *charArray[], size_t lengthArray[],
998 	int32 numStrings, BRect rectArray[], font_metric_mode mode,
999 	escapement_delta deltaArray[])
1000 {
1001 	// TODO: The font_metric_mode is never used
1002 	if (charArray == NULL || lengthArray == NULL || numStrings <= 0
1003 		|| rectArray == NULL || deltaArray == NULL) {
1004 		return B_BAD_DATA;
1005 	}
1006 
1007 	Transformable transform(EmbeddedTransformation());
1008 
1009 	for (int32 i = 0; i < numStrings; i++) {
1010 		size_t numBytes = lengthArray[i];
1011 		const char* string = charArray[i];
1012 		escapement_delta delta = deltaArray[i];
1013 
1014 		BoundingBoxConsumer consumer(transform, NULL, true);
1015 		if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
1016 				INT32_MAX, &delta, fSpacing)) {
1017 			return B_ERROR;
1018 		}
1019 
1020 		rectArray[i] = consumer.stringBoundingBox;
1021 	}
1022 
1023 	return B_OK;
1024 }
1025 
1026 
1027 class StringWidthConsumer {
1028  public:
1029 	StringWidthConsumer()
1030 		:
1031 		width(0.0)
1032 	{
1033 	}
1034 
1035 	bool NeedsVector() { return false; }
1036 	void Start() {}
1037 	void Finish(double x, double y) { width = x; }
1038 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
1039 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
1040 		FontCacheEntry* entry, double x, double y, double advanceX,
1041 			double advanceY)
1042 	{
1043 		return true;
1044 	}
1045 
1046 	float width;
1047 };
1048 
1049 
1050 float
1051 ServerFont::StringWidth(const char *string, int32 numBytes,
1052 	const escapement_delta* deltaArray) const
1053 {
1054 	if (!string || numBytes <= 0)
1055 		return 0.0;
1056 
1057 	StringWidthConsumer consumer;
1058 	if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
1059 			INT32_MAX, deltaArray, fSpacing)) {
1060 		return 0.0;
1061 	}
1062 
1063 	return consumer.width;
1064 }
1065 
1066 
1067 /*!
1068 	\brief Returns a BRect which encloses the entire font
1069 	\return A BRect which encloses the entire font
1070 */
1071 BRect
1072 ServerFont::BoundingBox()
1073 {
1074 	// TODO: fBounds is nowhere calculated!
1075 	return fBounds;
1076 }
1077 
1078 
1079 /*!
1080 	\brief Obtains the height values for characters in the font in its current state
1081 	\param fh pointer to a font_height object to receive the values for the font
1082 */
1083 void
1084 ServerFont::GetHeight(font_height& height) const
1085 {
1086 	fStyle->GetHeight(fSize, height);
1087 }
1088 
1089 
1090 void
1091 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const
1092 {
1093 	if (!inOut)
1094 		return;
1095 
1096 	// the width of the "…" glyph
1097 	float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, strlen(B_UTF8_ELLIPSIS));
1098 
1099 	// count the individual glyphs
1100 	int32 numChars = inOut->CountChars();
1101 
1102 	// get the escapement of each glyph in font units
1103 	float* escapementArray = new (std::nothrow) float[numChars];
1104 	if (escapementArray == NULL)
1105 		return;
1106 
1107 	static escapement_delta delta = (escapement_delta){ 0.0, 0.0 };
1108 	if (GetEscapements(inOut->String(), inOut->Length(), numChars, delta,
1109 		escapementArray) == B_OK) {
1110 		truncate_string(*inOut, mode, width, escapementArray, fSize,
1111 			ellipsisWidth, numChars);
1112 	}
1113 
1114 	delete[] escapementArray;
1115 }
1116 
1117 
1118 Transformable
1119 ServerFont::EmbeddedTransformation() const
1120 {
1121 	// TODO: cache this?
1122 	Transformable transform;
1123 
1124 	transform.ShearBy(B_ORIGIN, (90.0 - fShear) * M_PI / 180.0, 0.0);
1125 	transform.RotateBy(B_ORIGIN, -fRotation * M_PI / 180.0);
1126 
1127 	return transform;
1128 }
1129 
1130