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