xref: /haiku/src/servers/app/ServerFont.cpp (revision 93a78ecaa45114d68952d08c4778f073515102f2)
1 /*
2  * Copyright 2001-2006, 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  */
10 
11 
12 #include "ServerFont.h"
13 
14 #include "Angle.h"
15 #include "FontManager.h"
16 #include "truncate_string.h"
17 #include "utf8_functions.h"
18 
19 #include FT_FREETYPE_H
20 #include FT_GLYPH_H
21 #include FT_OUTLINE_H
22 
23 #include <Shape.h>
24 #include <String.h>
25 #include <UTF8.h>
26 
27 
28 // functions needed to convert a freetype vector graphics to a BShape
29 inline BPoint
30 VectorToPoint(const FT_Vector *vector)
31 {
32 	BPoint result;
33 	result.x = float(vector->x) / 64;
34 	result.y = -float(vector->y) / 64;
35 	return result;
36 }
37 
38 
39 int
40 MoveToFunc(const FT_Vector *to, void *user)
41 {
42 	((BShape *)user)->MoveTo(VectorToPoint(to));
43 	return 0;
44 }
45 
46 
47 int
48 LineToFunc(const FT_Vector *to, void *user)
49 {
50 	((BShape *)user)->LineTo(VectorToPoint(to));
51 	return 0;
52 }
53 
54 
55 int
56 ConicToFunc(const FT_Vector *control, const FT_Vector *to, void *user)
57 {
58 	BPoint controls[3];
59 
60 	controls[0] = VectorToPoint(control);
61 	controls[1] = VectorToPoint(to);
62 	controls[2] = controls[1];
63 
64 	((BShape *)user)->BezierTo(controls);
65 	return 0;
66 }
67 
68 
69 int
70 CubicToFunc(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user)
71 {
72 	BPoint controls[3];
73 
74 	controls[0] = VectorToPoint(control1);
75 	controls[1] = VectorToPoint(control2);
76 	controls[2] = VectorToPoint(to);
77 
78 	((BShape *)user)->BezierTo(controls);
79 	return 0;
80 }
81 
82 
83 inline bool
84 is_white_space(uint32 charCode)
85 {
86 	switch (charCode) {
87 		case 0x0009:	/* tab */
88 		case 0x000b:	/* vertical tab */
89 		case 0x000c:	/* form feed */
90 		case 0x0020:	/* space */
91 		case 0x00a0:	/* non breaking space */
92 		case 0x000a:	/* line feed */
93 		case 0x000d:	/* carriage return */
94 		case 0x2028:	/* line separator */
95 		case 0x2029:	/* paragraph separator */
96 			return true;
97 	}
98 
99 	return false;
100 }
101 
102 
103 //	#pragma mark -
104 
105 
106 /*!
107 	\brief Constructor
108 	\param style Style object to which the ServerFont belongs
109 	\param size Character size in points
110 	\param rotation Rotation in degrees
111 	\param shear Shear (slant) in degrees. 45 <= shear <= 135
112 	\param flags Style flags as defined in <Font.h>
113 	\param spacing String spacing flag as defined in <Font.h>
114 */
115 ServerFont::ServerFont(FontStyle& style, float size,
116 					   float rotation, float shear, float falseBoldWidth,
117 					   uint16 flags, uint8 spacing)
118 	: fStyle(&style),
119 	  fSize(size),
120 	  fRotation(rotation),
121 	  fShear(shear),
122 	  fFalseBoldWidth(falseBoldWidth),
123 	  fBounds(0, 0, 0, 0),
124 	  fFlags(flags),
125 	  fSpacing(spacing),
126 	  fDirection(style.Direction()),
127 	  fFace(style.Face()),
128 	  fEncoding(B_UNICODE_UTF8)
129 {
130 	fStyle->Acquire();
131 }
132 
133 
134 ServerFont::ServerFont()
135 	:
136 	fStyle(NULL)
137 {
138 	*this = *gFontManager->DefaultPlainFont();
139 }
140 
141 
142 /*!
143 	\brief Copy Constructor
144 	\param font ServerFont to copy
145 */
146 ServerFont::ServerFont(const ServerFont &font)
147 	:
148 	fStyle(NULL)
149 {
150 	*this = font;
151 }
152 
153 
154 /*!
155 	\brief Removes itself as a dependency of its owning style.
156 */
157 ServerFont::~ServerFont()
158 {
159 	fStyle->Release();
160 }
161 
162 
163 /*!
164 	\brief Returns a copy of the specified font
165 	\param The font to copy from.
166 	\return A copy of the specified font
167 */
168 ServerFont&
169 ServerFont::operator=(const ServerFont& font)
170 {
171 	if (font.fStyle) {
172 		fSize = font.fSize;
173 		fRotation = font.fRotation;
174 		fShear = font.fShear;
175 		fFalseBoldWidth = font.fFalseBoldWidth;
176 		fFlags = font.fFlags;
177 		fSpacing = font.fSpacing;
178 		fEncoding = font.fEncoding;
179 		fBounds = font.fBounds;
180 
181 		SetStyle(font.fStyle);
182 	}
183 
184 	return *this;
185 }
186 
187 
188 /*!
189 	\brief Returns the number of strikes in the font
190 	\return The number of strikes in the font
191 */
192 int32
193 ServerFont::CountTuned()
194 {
195 	return fStyle->TunedCount();
196 }
197 
198 
199 /*!
200 	\brief Returns the file format of the font.
201 	\return Mostly B_TRUETYPE_WINDOWS :)
202 */
203 font_file_format
204 ServerFont::FileFormat()
205 {
206 	return fStyle->FileFormat();
207 }
208 
209 
210 const char*
211 ServerFont::Style() const
212 {
213 	return fStyle->Name();
214 }
215 
216 
217 const char*
218 ServerFont::Family() const
219 {
220 	return fStyle->Family()->Name();
221 }
222 
223 
224 void
225 ServerFont::SetStyle(FontStyle* style)
226 {
227 	if (style && style != fStyle) {
228 		// detach from old style
229 		if (fStyle)
230 			fStyle->Release();
231 
232 		// attach to new style
233 		fStyle = style;
234 
235 		fStyle->Acquire();
236 
237 		fFace = fStyle->Face();
238 		fDirection = fStyle->Direction();
239 	}
240 }
241 
242 
243 /*!
244 	\brief Sets the ServerFont instance to whatever font is specified
245 	This method will lock the font manager.
246 
247 	\param familyID ID number of the family to set
248 	\param styleID ID number of the style to set
249 	\return B_OK if successful, B_ERROR if not
250 */
251 status_t
252 ServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID)
253 {
254 	FontStyle* style = NULL;
255 
256 	if (gFontManager->Lock()) {
257 		style = gFontManager->GetStyle(familyID, styleID);
258 		if (style != NULL)
259 			style->Acquire();
260 
261 		gFontManager->Unlock();
262 	}
263 
264 	if (!style)
265 		return B_ERROR;
266 
267 	SetStyle(style);
268 	style->Release();
269 
270 	return B_OK;
271 }
272 
273 
274 /*!
275 	\brief Sets the ServerFont instance to whatever font is specified
276 	\param fontID the combination of family and style ID numbers
277 	\return B_OK if successful, B_ERROR if not
278 */
279 status_t
280 ServerFont::SetFamilyAndStyle(uint32 fontID)
281 {
282 	uint16 style = fontID & 0xFFFF;
283 	uint16 family = (fontID & 0xFFFF0000) >> 16;
284 
285 	return SetFamilyAndStyle(family, style);
286 }
287 
288 
289 void
290 ServerFont::SetFace(uint32 face)
291 {
292 	// TODO: change font style as requested!
293 	fFace = face;
294 }
295 
296 
297 /*!
298 	\brief Gets the ID values for the ServerFont instance in one shot
299 	\return the combination of family and style ID numbers
300 */
301 uint32
302 ServerFont::GetFamilyAndStyle() const
303 {
304 	return (FamilyID() << 16) | StyleID();
305 }
306 
307 
308 FT_Face
309 ServerFont::GetTransformedFace(bool rotate, bool shear) const
310 {
311 	fStyle->Lock();
312 	FT_Face face = fStyle->FreeTypeFace();
313 	if (!face) {
314 		fStyle->Unlock();
315 		return NULL;
316 	}
317 
318 	FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
319 
320 	if ((rotate && fRotation != 0) || (shear && fShear != 90)) {
321 		FT_Matrix rmatrix, smatrix;
322 
323 		Angle rotationAngle(fRotation);
324 		rmatrix.xx = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
325 		rmatrix.xy = (FT_Fixed)(-rotationAngle.Sine() * 0x10000);
326 		rmatrix.yx = (FT_Fixed)( rotationAngle.Sine() * 0x10000);
327 		rmatrix.yy = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
328 
329 		Angle shearAngle(fShear);
330 		smatrix.xx = (FT_Fixed)(0x10000);
331 		smatrix.xy = (FT_Fixed)(-shearAngle.Cosine() * 0x10000);
332 		smatrix.yx = (FT_Fixed)(0);
333 		smatrix.yy = (FT_Fixed)(0x10000);
334 
335 		// Multiply togheter and apply transform
336 		FT_Matrix_Multiply(&rmatrix, &smatrix);
337 		FT_Set_Transform(face, &smatrix, NULL);
338 	}
339 
340 	return face;
341 }
342 
343 
344 void
345 ServerFont::PutTransformedFace(FT_Face face) const
346 {
347 	// Reset transformation
348 	FT_Set_Transform(face, NULL, NULL);
349 	fStyle->Unlock();
350 }
351 
352 
353 status_t
354 ServerFont::GetGlyphShapes(const char charArray[], int32 numChars,
355 	BShape *shapeArray[]) const
356 {
357 	if (!charArray || numChars <= 0 || !shapeArray)
358 		return B_BAD_DATA;
359 
360 	FT_Face face = GetTransformedFace(true, true);
361 	if (!face)
362 		return B_ERROR;
363 
364 	FT_Outline_Funcs funcs;
365 	funcs.move_to = MoveToFunc;
366 	funcs.line_to = LineToFunc;
367 	funcs.conic_to = ConicToFunc;
368 	funcs.cubic_to = CubicToFunc;
369 	funcs.shift = 0;
370 	funcs.delta = 0;
371 
372 	const char *string = charArray;
373 	for (int i = 0; i < numChars; i++) {
374 		shapeArray[i] = new BShape();
375 		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
376 		FT_Outline outline = face->glyph->outline;
377 		FT_Outline_Decompose(&outline, &funcs, shapeArray[i]);
378 		shapeArray[i]->Close();
379 	}
380 
381 	PutTransformedFace(face);
382 	return B_OK;
383 }
384 
385 
386 status_t
387 ServerFont::GetHasGlyphs(const char charArray[], int32 numChars,
388 	bool hasArray[]) const
389 {
390 	if (!charArray || numChars <= 0 || !hasArray)
391 		return B_BAD_DATA;
392 
393 	FT_Face face = GetTransformedFace(false, false);
394 	if (!face)
395 		return B_ERROR;
396 
397 	const char *string = charArray;
398 	for (int i = 0; i < numChars; i++)
399 		hasArray[i] = FT_Get_Char_Index(face, UTF8ToCharCode(&string)) > 0;
400 
401 	PutTransformedFace(face);
402 	return B_OK;
403 }
404 
405 
406 status_t
407 ServerFont::GetEdges(const char charArray[], int32 numChars,
408 	edge_info edgeArray[]) const
409 {
410 	if (!charArray || numChars <= 0 || !edgeArray)
411 		return B_BAD_DATA;
412 
413 	FT_Face face = GetTransformedFace(false, false);
414 	if (!face)
415 		return B_ERROR;
416 
417 	const char *string = charArray;
418 	for (int i = 0; i < numChars; i++) {
419 		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
420 		edgeArray[i].left = float(face->glyph->metrics.horiBearingX)
421 			/ 64 / fSize;
422 		edgeArray[i].right = float(face->glyph->metrics.horiBearingX
423 			+ face->glyph->metrics.width - face->glyph->metrics.horiAdvance)
424 			/ 64 / fSize;
425 	}
426 
427 	PutTransformedFace(face);
428 	return B_OK;
429 }
430 
431 
432 status_t
433 ServerFont::GetEscapements(const char charArray[], int32 numChars,
434 	escapement_delta delta, BPoint escapementArray[], BPoint offsetArray[]) const
435 {
436 	if (!charArray || numChars <= 0 || !escapementArray)
437 		return B_BAD_DATA;
438 
439 	FT_Face face = GetTransformedFace(true, false);
440 	if (!face)
441 		return B_ERROR;
442 
443 	const char *string = charArray;
444 	for (int i = 0; i < numChars; i++) {
445 		uint32 charCode = UTF8ToCharCode(&string);
446 		FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP);
447 		escapementArray[i].x = is_white_space(charCode) ? delta.space : delta.nonspace;
448 		escapementArray[i].x += float(face->glyph->advance.x) / 64;
449 		escapementArray[i].y = -float(face->glyph->advance.y) / 64;
450 		escapementArray[i].x /= fSize;
451 		escapementArray[i].y /= fSize;
452 
453 		if (offsetArray) {
454 			// ToDo: According to the BeBook: "The offsetArray is applied by
455 			// the dynamic spacing in order to improve the relative position
456 			// of the character's width with relation to another character,
457 			// without altering the width." So this will probably depend on
458 			// the spacing mode.
459 			offsetArray[i].x = 0;
460 			offsetArray[i].y = 0;
461 		}
462 	}
463 
464 	PutTransformedFace(face);
465 	return B_OK;
466 }
467 
468 
469 status_t
470 ServerFont::GetEscapements(const char charArray[], int32 numChars,
471 	escapement_delta delta, float widthArray[]) const
472 {
473 	if (!charArray || numChars <= 0 || !widthArray)
474 		return B_BAD_DATA;
475 
476 	FT_Face face = GetTransformedFace(false, false);
477 	if (!face)
478 		return B_ERROR;
479 
480 	const char *string = charArray;
481 	for (int i = 0; i < numChars; i++) {
482 		uint32 charCode = UTF8ToCharCode(&string);
483 		FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP);
484 		widthArray[i] = is_white_space(charCode) ? delta.space : delta.nonspace;
485 		widthArray[i] += float(face->glyph->metrics.horiAdvance) / 64.0;
486 		widthArray[i] /= fSize;
487 	}
488 
489 	PutTransformedFace(face);
490 	return B_OK;
491 }
492 
493 
494 status_t
495 ServerFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars,
496 	BRect rectArray[], bool stringEscapement, font_metric_mode mode,
497 	escapement_delta delta)
498 {
499 	if (!charArray || numChars <= 0 || !rectArray)
500 		return B_BAD_DATA;
501 
502 	FT_Face face = GetTransformedFace(true, true);
503 	if (!face)
504 		return B_ERROR;
505 
506 	const char *string = charArray;
507 	for (int i = 0; i < numChars; i++) {
508 		uint32 charCode = UTF8ToCharCode(&string);
509 		if (stringEscapement) {
510 			if (i > 0)
511 				rectArray[i].OffsetBy(is_white_space(charCode) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
512 
513 			rectArray[i].OffsetBy(is_white_space(charCode) ? delta.space / 2.0 : delta.nonspace / 2.0, 0.0);
514 		}
515 
516 		FT_Load_Char(face, charCode, FT_LOAD_NO_BITMAP);
517 		if (i < numChars - 1) {
518 			rectArray[i + 1].left = rectArray[i + 1].right = rectArray[i].left
519 				+ face->glyph->metrics.horiAdvance / 64.0;
520 		}
521 
522 		rectArray[i].left += float(face->glyph->metrics.horiBearingX) /64.0;
523 		rectArray[i].right += float(face->glyph->metrics.horiBearingX
524 			+ face->glyph->metrics.width) / 64.0;
525 		rectArray[i].top = -float(face->glyph->metrics.horiBearingY) / 64.0;
526 		rectArray[i].bottom = float(face->glyph->metrics.height
527 			- face->glyph->metrics.horiBearingY) /64.0;
528 	}
529 
530 	PutTransformedFace(face);
531 	return B_OK;
532 }
533 
534 
535 status_t
536 ServerFont::GetBoundingBoxesForStrings(char *charArray[], int32 lengthArray[],
537 	int32 numStrings, BRect rectArray[], font_metric_mode mode, escapement_delta deltaArray[])
538 {
539 	if (!charArray || !lengthArray|| numStrings <= 0 || !rectArray || !deltaArray)
540 		return B_BAD_DATA;
541 
542 	FT_Face face = GetTransformedFace(true, true);
543 	if (!face)
544 		return B_ERROR;
545 
546 	for (int32 i = 0; i < numStrings; i++) {
547 		// TODO: ...
548 	}
549 
550 	PutTransformedFace(face);
551 	return B_OK;
552 }
553 
554 
555 float
556 ServerFont::StringWidth(const char *_string, int32 numChars) const
557 {
558 	if (!_string || numChars <= 0)
559 		return 0.0;
560 
561 	FT_Face face = GetTransformedFace(false, false);
562 	if (!face)
563 		return 0.0;
564 
565 	float width = 0.0;
566 	const char *string = _string;
567 	for (int i = 0; i < numChars; i++) {
568 		FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
569 		width += face->glyph->advance.x / 64.0;
570 	}
571 
572 	PutTransformedFace(face);
573 	return width;
574 }
575 
576 
577 /*!
578 	\brief Returns a BRect which encloses the entire font
579 	\return A BRect which encloses the entire font
580 */
581 BRect
582 ServerFont::BoundingBox()
583 {
584 	// TODO: fBounds is nowhere calculated!
585 	return fBounds;
586 }
587 
588 
589 /*!
590 	\brief Obtains the height values for characters in the font in its current state
591 	\param fh pointer to a font_height object to receive the values for the font
592 */
593 void
594 ServerFont::GetHeight(font_height& height) const
595 {
596 	fStyle->GetHeight(fSize, height);
597 }
598 
599 
600 void
601 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const
602 {
603 	if (!inOut)
604 		return;
605 
606 	// the width of the "…" glyph
607 	float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, 1);
608 	const char *string = inOut->String();
609 	int32 length = inOut->Length();
610 
611 	// temporary array to hold result
612 	char *result = new char[length + 3];
613 
614 	// count the individual glyphs
615 	int32 numChars = UTF8CountChars(string, -1);
616 
617 	// get the escapement of each glyph in font units
618 	float *escapementArray = new float[numChars];
619 	static escapement_delta delta = (escapement_delta){ 0.0, 0.0 };
620 	if (GetEscapements(string, numChars, delta, escapementArray) == B_OK) {
621 		truncate_string(string, mode, width, result, escapementArray, fSize,
622 			ellipsisWidth, length, numChars);
623 
624 		inOut->SetTo(result);
625 	}
626 
627 	delete[] escapementArray;
628 	delete[] result;
629 }
630 
631