xref: /haiku/src/servers/app/ServerFont.cpp (revision 3c08adef21129761f27ae654a1c5d1705786691a)
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 #include <Shape.h>
26 #include <String.h>
27 #include <UTF8.h>
28 
29 #include <agg_bounding_rect.h>
30 
31 #include <stdio.h>
32 #include <string.h>
33 
34 
35 // functions needed to convert a freetype vector graphics to a BShape
36 inline BPoint
37 VectorToPoint(const FT_Vector *vector)
38 {
39 	BPoint result;
40 	result.x = float(vector->x) / 64;
41 	result.y = -float(vector->y) / 64;
42 	return result;
43 }
44 
45 
46 int
47 MoveToFunc(const FT_Vector *to, void *user)
48 {
49 	((BShape *)user)->MoveTo(VectorToPoint(to));
50 	return 0;
51 }
52 
53 
54 int
55 LineToFunc(const FT_Vector *to, void *user)
56 {
57 	((BShape *)user)->LineTo(VectorToPoint(to));
58 	return 0;
59 }
60 
61 
62 int
63 ConicToFunc(const FT_Vector *control, const FT_Vector *to, void *user)
64 {
65 	BPoint controls[3];
66 
67 	controls[0] = VectorToPoint(control);
68 	controls[1] = VectorToPoint(to);
69 	controls[2] = controls[1];
70 
71 	((BShape *)user)->BezierTo(controls);
72 	return 0;
73 }
74 
75 
76 int
77 CubicToFunc(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user)
78 {
79 	BPoint controls[3];
80 
81 	controls[0] = VectorToPoint(control1);
82 	controls[1] = VectorToPoint(control2);
83 	controls[2] = VectorToPoint(to);
84 
85 	((BShape *)user)->BezierTo(controls);
86 	return 0;
87 }
88 
89 
90 inline bool
91 is_white_space(uint32 charCode)
92 {
93 	switch (charCode) {
94 		case 0x0009:	/* tab */
95 		case 0x000b:	/* vertical tab */
96 		case 0x000c:	/* form feed */
97 		case 0x0020:	/* space */
98 		case 0x00a0:	/* non breaking space */
99 		case 0x000a:	/* line feed */
100 		case 0x000d:	/* carriage return */
101 		case 0x2028:	/* line separator */
102 		case 0x2029:	/* paragraph separator */
103 			return true;
104 	}
105 
106 	return false;
107 }
108 
109 
110 //	#pragma mark -
111 
112 
113 /*!
114 	\brief Constructor
115 	\param style Style object to which the ServerFont belongs
116 	\param size Character size in points
117 	\param rotation Rotation in degrees
118 	\param shear Shear (slant) in degrees. 45 <= shear <= 135
119 	\param flags Style flags as defined in <Font.h>
120 	\param spacing String spacing flag as defined in <Font.h>
121 */
122 ServerFont::ServerFont(FontStyle& style, float size, float rotation,
123 		float shear, float falseBoldWidth, uint16 flags, uint8 spacing)
124 	:
125 	fStyle(&style),
126 	fSize(size),
127 	fRotation(rotation),
128 	fShear(shear),
129 	fFalseBoldWidth(falseBoldWidth),
130 	fBounds(0, 0, 0, 0),
131 	fFlags(flags),
132 	fSpacing(spacing),
133 	fDirection(style.Direction()),
134 	fFace(style.Face()),
135 	fEncoding(B_UNICODE_UTF8)
136 {
137 	fStyle->Acquire();
138 }
139 
140 
141 ServerFont::ServerFont()
142 	:
143 	fStyle(NULL)
144 {
145 	*this = *gFontManager->DefaultPlainFont();
146 }
147 
148 
149 /*!
150 	\brief Copy Constructor
151 	\param font ServerFont to copy
152 */
153 ServerFont::ServerFont(const ServerFont &font)
154 	:
155 	fStyle(NULL)
156 {
157 	*this = font;
158 }
159 
160 
161 /*!
162 	\brief Removes itself as a dependency of its owning style.
163 */
164 ServerFont::~ServerFont()
165 {
166 	fStyle->Release();
167 }
168 
169 
170 /*!
171 	\brief Returns a copy of the specified font
172 	\param The font to copy from.
173 	\return A copy of the specified font
174 */
175 ServerFont&
176 ServerFont::operator=(const ServerFont& font)
177 {
178 	fSize = font.fSize;
179 	fRotation = font.fRotation;
180 	fShear = font.fShear;
181 	fFalseBoldWidth = font.fFalseBoldWidth;
182 	fFlags = font.fFlags;
183 	fSpacing = font.fSpacing;
184 	fEncoding = font.fEncoding;
185 	fBounds = font.fBounds;
186 
187 	SetStyle(font.fStyle);
188 
189 	return *this;
190 }
191 
192 
193 bool
194 ServerFont::operator==(const ServerFont& other) const
195 {
196 	if (GetFamilyAndStyle() != other.GetFamilyAndStyle())
197 		return false;
198 
199 	return fSize == other.fSize && fRotation == other.fRotation
200 		&& fShear == other.fShear && fFalseBoldWidth == other.fFalseBoldWidth
201 		&& fFlags == other.fFlags && fSpacing == other.fSpacing
202 		&& fEncoding == other.fEncoding && fBounds == other.fBounds
203 		&& fDirection == other.fDirection && fFace == other.fFace;
204 }
205 
206 
207 /*!
208 	\brief Returns the number of strikes in the font
209 	\return The number of strikes in the font
210 */
211 int32
212 ServerFont::CountTuned()
213 {
214 	return fStyle->TunedCount();
215 }
216 
217 
218 /*!
219 	\brief Returns the file format of the font.
220 	\return Mostly B_TRUETYPE_WINDOWS :)
221 */
222 font_file_format
223 ServerFont::FileFormat()
224 {
225 	return fStyle->FileFormat();
226 }
227 
228 
229 const char*
230 ServerFont::Style() const
231 {
232 	return fStyle->Name();
233 }
234 
235 
236 const char*
237 ServerFont::Family() const
238 {
239 	return fStyle->Family()->Name();
240 }
241 
242 
243 void
244 ServerFont::SetStyle(FontStyle* style)
245 {
246 	if (style && style != fStyle) {
247 		// detach from old style
248 		if (fStyle != NULL)
249 			fStyle->Release();
250 
251 		// attach to new style
252 		fStyle = style;
253 
254 		fStyle->Acquire();
255 
256 		fFace = fStyle->Face();
257 		fDirection = fStyle->Direction();
258 	}
259 }
260 
261 
262 /*!
263 	\brief Sets the ServerFont instance to whatever font is specified
264 	This method will lock the font manager.
265 
266 	\param familyID ID number of the family to set
267 	\param styleID ID number of the style to set
268 	\return B_OK if successful, B_ERROR if not
269 */
270 status_t
271 ServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID)
272 {
273 	FontStyle* style = NULL;
274 
275 	if (gFontManager->Lock()) {
276 		style = gFontManager->GetStyle(familyID, styleID);
277 		if (style != NULL)
278 			style->Acquire();
279 
280 		gFontManager->Unlock();
281 	}
282 
283 	if (style == NULL)
284 		return B_ERROR;
285 
286 	SetStyle(style);
287 	style->Release();
288 
289 	return B_OK;
290 }
291 
292 
293 /*!
294 	\brief Sets the ServerFont instance to whatever font is specified
295 	\param fontID the combination of family and style ID numbers
296 	\return B_OK if successful, B_ERROR if not
297 */
298 status_t
299 ServerFont::SetFamilyAndStyle(uint32 fontID)
300 {
301 	uint16 style = fontID & 0xFFFF;
302 	uint16 family = (fontID & 0xFFFF0000) >> 16;
303 
304 	return SetFamilyAndStyle(family, style);
305 }
306 
307 
308 status_t
309 ServerFont::SetFace(uint16 face)
310 {
311 	// TODO: This needs further investigation. The face variable is actually
312 	// flags, but some of them are not enforcable at the same time. Also don't
313 	// confuse the Be API "face" with the Freetype face, which is just an
314 	// index in case a single font file exports multiple font faces. The
315 	// FontStyle class takes care of mapping the font style name to the Be
316 	// API face flags in FontStyle::_TranslateStyleToFace().
317 
318 	FontStyle* style = NULL;
319 	uint16 familyID = FamilyID();
320 	if (gFontManager->Lock()) {
321 		int32 count = gFontManager->CountStyles(familyID);
322 		for (int32 i = 0; i < count; i++) {
323 			style = gFontManager->GetStyleByIndex(familyID, i);
324 			if (style == NULL)
325 				break;
326 			if (style->Face() == face) {
327 				style->Acquire();
328 				break;
329 			} else
330 				style = NULL;
331 		}
332 
333 		gFontManager->Unlock();
334 	}
335 
336 	if (!style)
337 		return B_ERROR;
338 
339 	SetStyle(style);
340 	style->Release();
341 
342 	return B_OK;
343 }
344 
345 
346 /*!
347 	\brief Gets the ID values for the ServerFont instance in one shot
348 	\return the combination of family and style ID numbers
349 */
350 uint32
351 ServerFont::GetFamilyAndStyle() const
352 {
353 	return (FamilyID() << 16) | StyleID();
354 }
355 
356 
357 FT_Face
358 ServerFont::GetTransformedFace(bool rotate, bool shear) const
359 {
360 	fStyle->Lock();
361 	FT_Face face = fStyle->FreeTypeFace();
362 	if (!face) {
363 		fStyle->Unlock();
364 		return NULL;
365 	}
366 
367 	FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
368 
369 	if ((rotate && fRotation != 0) || (shear && fShear != 90)) {
370 		FT_Matrix rmatrix, smatrix;
371 
372 		Angle rotationAngle(fRotation);
373 		rmatrix.xx = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
374 		rmatrix.xy = (FT_Fixed)(-rotationAngle.Sine() * 0x10000);
375 		rmatrix.yx = (FT_Fixed)( rotationAngle.Sine() * 0x10000);
376 		rmatrix.yy = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
377 
378 		Angle shearAngle(fShear);
379 		smatrix.xx = (FT_Fixed)(0x10000);
380 		smatrix.xy = (FT_Fixed)(-shearAngle.Cosine() * 0x10000);
381 		smatrix.yx = (FT_Fixed)(0);
382 		smatrix.yy = (FT_Fixed)(0x10000);
383 
384 		// Multiply togheter and apply transform
385 		FT_Matrix_Multiply(&rmatrix, &smatrix);
386 		FT_Set_Transform(face, &smatrix, NULL);
387 	}
388 
389 	// fStyle will be unlocked in PutTransformedFace()
390 	return face;
391 }
392 
393 
394 void
395 ServerFont::PutTransformedFace(FT_Face face) const
396 {
397 	// Reset transformation
398 	FT_Set_Transform(face, NULL, NULL);
399 	fStyle->Unlock();
400 }
401 
402 
403 status_t
404 ServerFont::GetGlyphShapes(const char charArray[], int32 numChars,
405 	BShape* shapeArray[]) const
406 {
407 	if (!charArray || numChars <= 0 || !shapeArray)
408 		return B_BAD_DATA;
409 
410 	FT_Face face = GetTransformedFace(true, true);
411 	if (!face)
412 		return B_ERROR;
413 
414 	FT_Outline_Funcs funcs;
415 	funcs.move_to = MoveToFunc;
416 	funcs.line_to = LineToFunc;
417 	funcs.conic_to = ConicToFunc;
418 	funcs.cubic_to = CubicToFunc;
419 	funcs.shift = 0;
420 	funcs.delta = 0;
421 
422 	const char* string = charArray;
423 	for (int i = 0; i < numChars; i++) {
424 		shapeArray[i] = new (std::nothrow) BShape();
425 		if (shapeArray[i] == NULL) {
426 			PutTransformedFace(face);
427 			return B_NO_MEMORY;
428 		}
429 		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
430 		FT_Outline outline = face->glyph->outline;
431 		FT_Outline_Decompose(&outline, &funcs, shapeArray[i]);
432 		shapeArray[i]->Close();
433 	}
434 
435 	PutTransformedFace(face);
436 	return B_OK;
437 }
438 
439 
440 class HasGlyphsConsumer {
441  public:
442 	HasGlyphsConsumer(bool* hasArray)
443 		: fHasArray(hasArray)
444 	{
445 	}
446 	bool NeedsVector() { return false; }
447 	void Start() {}
448 	void Finish(double x, double y) {}
449 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
450 	{
451 		fHasArray[index] = false;
452 	}
453 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
454 		FontCacheEntry* entry, double x, double y, double advanceX,
455 			double advanceY)
456 	{
457 		fHasArray[index] = glyph->glyph_index != 0;
458 		return true;
459 	}
460 
461  private:
462 	bool* fHasArray;
463 };
464 
465 
466 status_t
467 ServerFont::GetHasGlyphs(const char* string, int32 numBytes,
468 	bool* hasArray) const
469 {
470 	if (!string || numBytes <= 0 || !hasArray)
471 		return B_BAD_DATA;
472 
473 	HasGlyphsConsumer consumer(hasArray);
474 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
475 		NULL, fSpacing))
476 		return B_OK;
477 
478 	return B_ERROR;
479 }
480 
481 
482 class EdgesConsumer {
483  public:
484 	EdgesConsumer(edge_info* edges, float size)
485 		: fEdges(edges)
486 		, fSize(size)
487 	{
488 	}
489 	bool NeedsVector() { return false; }
490 	void Start() {}
491 	void Finish(double x, double y) {}
492 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
493 	{
494 		fEdges[index].left = 0.0;
495 		fEdges[index].right = 0.0;
496 	}
497 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
498 		FontCacheEntry* entry, double x, double y, double advanceX,
499 			double advanceY)
500 	{
501 		fEdges[index].left = glyph->inset_left / fSize;
502 		fEdges[index].right = glyph->inset_right / fSize;
503 		return true;
504 	}
505 
506  private:
507 	edge_info* fEdges;
508 	float fSize;
509 };
510 
511 
512 status_t
513 ServerFont::GetEdges(const char* string, int32 numBytes,
514 	edge_info* edges) const
515 {
516 	if (!string || numBytes <= 0 || !edges)
517 		return B_BAD_DATA;
518 
519 	EdgesConsumer consumer(edges, fSize);
520 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
521 		NULL, fSpacing)) {
522 		return B_OK;
523 	}
524 
525 	return B_ERROR;
526 
527 //	FT_Face face = GetTransformedFace(false, false);
528 //	if (!face)
529 //		return B_ERROR;
530 //
531 //	const char *string = charArray;
532 //	for (int i = 0; i < numChars; i++) {
533 //		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
534 //		edgeArray[i].left = float(face->glyph->metrics.horiBearingX)
535 //			/ 64 / fSize;
536 //		edgeArray[i].right = float(face->glyph->metrics.horiBearingX
537 //			+ face->glyph->metrics.width - face->glyph->metrics.horiAdvance)
538 //			/ 64 / fSize;
539 //	}
540 //
541 //	PutTransformedFace(face);
542 //	return B_OK;
543 }
544 
545 
546 class BPointEscapementConsumer {
547 public:
548 	BPointEscapementConsumer(BPoint* escapements, BPoint* offsets,
549 			int32 numChars, float size)
550 		:
551 		fEscapements(escapements),
552 		fOffsets(offsets),
553 		fNumChars(numChars),
554 		fSize(size)
555 	{
556 	}
557 
558 	bool NeedsVector() { return false; }
559 	void Start() {}
560 	void Finish(double x, double y) {}
561 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
562 	{
563 		_Set(index, 0, 0);
564 	}
565 
566 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
567 		FontCacheEntry* entry, double x, double y, double advanceX,
568 			double advanceY)
569 	{
570 		return _Set(index, advanceX, advanceY);
571 	}
572 
573 private:
574 	inline bool _Set(int32 index, double x, double y)
575 	{
576 		if (index >= fNumChars)
577 			return false;
578 
579 		fEscapements[index].x = x / fSize;
580 		fEscapements[index].y = y / fSize;
581 		if (fOffsets) {
582 			// ToDo: According to the BeBook: "The offsetArray is applied by
583 			// the dynamic spacing in order to improve the relative position
584 			// of the character's width with relation to another character,
585 			// without altering the width." So this will probably depend on
586 			// the spacing mode.
587 			fOffsets[index].x = 0;
588 			fOffsets[index].y = 0;
589 		}
590 		return true;
591 	}
592 
593 	BPoint* fEscapements;
594 	BPoint* fOffsets;
595 	int32 fNumChars;
596  	float fSize;
597 };
598 
599 
600 status_t
601 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
602 	escapement_delta delta, BPoint escapementArray[],
603 	BPoint offsetArray[]) const
604 {
605 	if (!string || numBytes <= 0 || !escapementArray)
606 		return B_BAD_DATA;
607 
608 	BPointEscapementConsumer consumer(escapementArray, offsetArray, numChars,
609 		fSize);
610 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
611 		&delta, fSpacing)) {
612 		return B_OK;
613 	}
614 
615 	return B_ERROR;
616 }
617 
618 
619 class WidthEscapementConsumer {
620 public:
621 	WidthEscapementConsumer(float* widths, int32 numChars, float size)
622 		:
623 		fWidths(widths),
624 		fNumChars(numChars),
625 		fSize(size)
626 	{
627 	}
628 
629 	bool NeedsVector() { return false; }
630 	void Start() {}
631 	void Finish(double x, double y) {}
632 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
633 	{
634 		fWidths[index] = 0.0;
635 	}
636 
637 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
638 		FontCacheEntry* entry, double x, double y, double advanceX,
639 			double advanceY)
640 	{
641 		if (index >= fNumChars)
642 			return false;
643 
644 		fWidths[index] = advanceX / fSize;
645 		return true;
646 	}
647 
648  private:
649 	float* fWidths;
650 	int32 fNumChars;
651 	float fSize;
652 };
653 
654 
655 
656 status_t
657 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
658 	escapement_delta delta, float widthArray[]) const
659 {
660 	if (!string || numBytes <= 0 || !widthArray)
661 		return B_BAD_DATA;
662 
663 	WidthEscapementConsumer consumer(widthArray, numChars, fSize);
664 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
665 		&delta, fSpacing)) {
666 		return B_OK;
667 	}
668 	return B_ERROR;
669 }
670 
671 
672 class BoundingBoxConsumer {
673  public:
674 	BoundingBoxConsumer(Transformable& transform, BRect* rectArray,
675 			bool asString)
676 		: rectArray(rectArray)
677 		, stringBoundingBox(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN)
678 		, fAsString(asString)
679 		, fCurves(fPathAdaptor)
680 		, fContour(fCurves)
681 		, fTransformedOutline(fCurves, transform)
682 		, fTransformedContourOutline(fContour, transform)
683 		, fTransform(transform)
684 	{
685 	}
686 
687 	bool NeedsVector() { return false; }
688 	void Start() {}
689 	void Finish(double x, double y) {}
690 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
691 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
692 		FontCacheEntry* entry, double x, double y, double advanceX,
693 			double advanceY)
694 	{
695 		if (glyph->data_type != glyph_data_outline) {
696 			const agg::rect_i& r = glyph->bounds;
697 			if (fAsString) {
698 				if (rectArray) {
699 					rectArray[index].left = r.x1 + x;
700 					rectArray[index].top = r.y1 + y;
701 					rectArray[index].right = r.x2 + x + 1;
702 					rectArray[index].bottom = r.y2 + y + 1;
703 				} else {
704 					stringBoundingBox = stringBoundingBox
705 						| BRect(r.x1 + x, r.y1 + y,
706 							r.x2 + x + 1, r.y2 + y + 1);
707 				}
708 			} else {
709 				rectArray[index].left = r.x1;
710 				rectArray[index].top = r.y1;
711 				rectArray[index].right = r.x2 + 1;
712 				rectArray[index].bottom = r.y2 + 1;
713 			}
714 		} else {
715 			if (fAsString) {
716 				entry->InitAdaptors(glyph, x, y,
717 						fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
718 			} else {
719 				entry->InitAdaptors(glyph, 0, 0,
720 						fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
721 			}
722 			double left = 0.0;
723 			double top = 0.0;
724 			double right = -1.0;
725 			double bottom = -1.0;
726 			uint32 pathID[1];
727 			pathID[0] = 0;
728 			// TODO: use fContour if falseboldwidth is > 0
729 			agg::bounding_rect(fTransformedOutline, pathID, 0, 1,
730 				&left, &top, &right, &bottom);
731 
732 			if (rectArray) {
733 				rectArray[index] = BRect(left, top, right, bottom);
734 			} else {
735 				stringBoundingBox = stringBoundingBox
736 					| BRect(left, top, right, bottom);
737 			}
738 		}
739 		return true;
740 	}
741 
742 	BRect*								rectArray;
743 	BRect								stringBoundingBox;
744 
745  private:
746 	bool								fAsString;
747 	FontCacheEntry::GlyphPathAdapter	fPathAdaptor;
748 	FontCacheEntry::GlyphGray8Adapter	fGray8Adaptor;
749 	FontCacheEntry::GlyphMonoAdapter	fMonoAdaptor;
750 
751 	FontCacheEntry::CurveConverter		fCurves;
752 	FontCacheEntry::ContourConverter	fContour;
753 
754 	FontCacheEntry::TransformedOutline	fTransformedOutline;
755 	FontCacheEntry::TransformedContourOutline fTransformedContourOutline;
756 
757 	Transformable&						fTransform;
758 };
759 
760 
761 status_t
762 ServerFont::GetBoundingBoxes(const char* string, int32 numBytes,
763 	BRect rectArray[], bool stringEscapement, font_metric_mode mode,
764 	escapement_delta delta, bool asString)
765 {
766 	// TODO: The font_metric_mode is not used
767 	if (!string || numBytes <= 0 || !rectArray)
768 		return B_BAD_DATA;
769 
770 	Transformable transform(EmbeddedTransformation());
771 
772 	BoundingBoxConsumer consumer(transform, rectArray, asString);
773 	if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
774 		stringEscapement ? &delta : NULL, fSpacing)) {
775 		return B_OK;
776 	}
777 	return B_ERROR;
778 }
779 
780 
781 status_t
782 ServerFont::GetBoundingBoxesForStrings(char *charArray[], int32 lengthArray[],
783 	int32 numStrings, BRect rectArray[], font_metric_mode mode,
784 	escapement_delta deltaArray[])
785 {
786 	// TODO: The font_metric_mode is never used
787 	if (!charArray || !lengthArray|| numStrings <= 0 || !rectArray || !deltaArray)
788 		return B_BAD_DATA;
789 
790 	Transformable transform(EmbeddedTransformation());
791 
792 	for (int32 i = 0; i < numStrings; i++) {
793 		int32 numBytes = lengthArray[i];
794 		const char* string = charArray[i];
795 		escapement_delta delta = deltaArray[i];
796 
797 		BoundingBoxConsumer consumer(transform, NULL, true);
798 		if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
799 			&delta, fSpacing)) {
800 			return B_ERROR;
801 		}
802 
803 		rectArray[i] = consumer.stringBoundingBox;
804 	}
805 
806 	return B_OK;
807 }
808 
809 
810 class StringWidthConsumer {
811  public:
812 	StringWidthConsumer() : width(0.0) {}
813 	bool NeedsVector() { return false; }
814 	void Start() {}
815 	void Finish(double x, double y) { width = x; }
816 	void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
817 	bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
818 		FontCacheEntry* entry, double x, double y, double advanceX,
819 			double advanceY)
820 	{ return true; }
821 
822 	float width;
823 };
824 
825 
826 float
827 ServerFont::StringWidth(const char *string, int32 numBytes,
828 	const escapement_delta* deltaArray) const
829 {
830 	if (!string || numBytes <= 0)
831 		return 0.0;
832 
833 	StringWidthConsumer consumer;
834 	if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
835 			deltaArray, fSpacing)) {
836 		return 0.0;
837 	}
838 
839 	return consumer.width;
840 }
841 
842 
843 /*!
844 	\brief Returns a BRect which encloses the entire font
845 	\return A BRect which encloses the entire font
846 */
847 BRect
848 ServerFont::BoundingBox()
849 {
850 	// TODO: fBounds is nowhere calculated!
851 	return fBounds;
852 }
853 
854 
855 /*!
856 	\brief Obtains the height values for characters in the font in its current state
857 	\param fh pointer to a font_height object to receive the values for the font
858 */
859 void
860 ServerFont::GetHeight(font_height& height) const
861 {
862 	fStyle->GetHeight(fSize, height);
863 }
864 
865 
866 void
867 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const
868 {
869 	if (!inOut)
870 		return;
871 
872 	// the width of the "…" glyph
873 	float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, strlen(B_UTF8_ELLIPSIS));
874 
875 	// count the individual glyphs
876 	int32 numChars = inOut->CountChars();
877 
878 	// get the escapement of each glyph in font units
879 	float* escapementArray = new (std::nothrow) float[numChars];
880 	if (escapementArray == NULL)
881 		return;
882 
883 	static escapement_delta delta = (escapement_delta){ 0.0, 0.0 };
884 	if (GetEscapements(inOut->String(), inOut->Length(), numChars, delta,
885 		escapementArray) == B_OK) {
886 		truncate_string(*inOut, mode, width, escapementArray, fSize,
887 			ellipsisWidth, numChars);
888 	}
889 
890 	delete[] escapementArray;
891 }
892 
893 
894 Transformable
895 ServerFont::EmbeddedTransformation() const
896 {
897 	// TODO: cache this?
898 	Transformable transform;
899 
900 	transform.ShearBy(B_ORIGIN, (90.0 - fShear) * M_PI / 180.0, 0.0);
901 	transform.RotateBy(B_ORIGIN, -fRotation * M_PI / 180.0);
902 
903 	return transform;
904 }
905 
906