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