btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / servers / app / ServerFont.cpp
blob4cfc92dbf384e192bb7222cc87d17f261f879cc0
1 /*
2 * Copyright 2001-2016, Haiku.
3 * Distributed under the terms of the MIT License.
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>
13 #include "ServerFont.h"
15 #include "Angle.h"
16 #include "GlyphLayoutEngine.h"
17 #include "FontManager.h"
18 #include "truncate_string.h"
19 #include "utf8_functions.h"
21 #include FT_FREETYPE_H
22 #include FT_GLYPH_H
23 #include FT_OUTLINE_H
25 #ifdef FONTCONFIG_ENABLED
27 #include <fontconfig.h>
28 #include <fcfreetype.h>
30 #endif // FONTCONFIG_ENABLED
32 #include <Shape.h>
33 #include <String.h>
34 #include <UnicodeBlockObjects.h>
35 #include <UTF8.h>
37 #include <agg_bounding_rect.h>
39 #include <stdio.h>
40 #include <string.h>
43 // functions needed to convert a freetype vector graphics to a BShape
44 inline BPoint
45 VectorToPoint(const FT_Vector *vector)
47 BPoint result;
48 result.x = float(vector->x) / 64;
49 result.y = -float(vector->y) / 64;
50 return result;
54 int
55 MoveToFunc(const FT_Vector *to, void *user)
57 ((BShape *)user)->MoveTo(VectorToPoint(to));
58 return 0;
62 int
63 LineToFunc(const FT_Vector *to, void *user)
65 ((BShape *)user)->LineTo(VectorToPoint(to));
66 return 0;
70 int
71 ConicToFunc(const FT_Vector *control, const FT_Vector *to, void *user)
73 BPoint controls[3];
75 controls[0] = VectorToPoint(control);
76 controls[1] = VectorToPoint(to);
77 controls[2] = controls[1];
79 ((BShape *)user)->BezierTo(controls);
80 return 0;
84 int
85 CubicToFunc(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user)
87 BPoint controls[3];
89 controls[0] = VectorToPoint(control1);
90 controls[1] = VectorToPoint(control2);
91 controls[2] = VectorToPoint(to);
93 ((BShape *)user)->BezierTo(controls);
94 return 0;
98 inline bool
99 is_white_space(uint32 charCode)
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;
114 return false;
118 // #pragma mark -
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>
130 ServerFont::ServerFont(FontStyle& style, float size, float rotation,
131 float shear, float falseBoldWidth, uint16 flags, uint8 spacing)
133 fStyle(&style),
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)
145 fStyle->Acquire();
149 ServerFont::ServerFont()
151 fStyle(NULL)
153 *this = *gFontManager->DefaultPlainFont();
158 \brief Copy Constructor
159 \param font ServerFont to copy
161 ServerFont::ServerFont(const ServerFont &font)
163 fStyle(NULL)
165 *this = font;
170 \brief Removes itself as a dependency of its owning style.
172 ServerFont::~ServerFont()
174 fStyle->Release();
179 \brief Returns a copy of the specified font
180 \param The font to copy from.
181 \return A copy of the specified font
183 ServerFont&
184 ServerFont::operator=(const ServerFont& font)
186 fSize = font.fSize;
187 fRotation = font.fRotation;
188 fShear = font.fShear;
189 fFalseBoldWidth = font.fFalseBoldWidth;
190 fFlags = font.fFlags;
191 fSpacing = font.fSpacing;
192 fEncoding = font.fEncoding;
193 fBounds = font.fBounds;
195 SetStyle(font.fStyle);
197 return *this;
201 bool
202 ServerFont::operator==(const ServerFont& other) const
204 if (GetFamilyAndStyle() != other.GetFamilyAndStyle())
205 return false;
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;
216 \brief Returns the number of strikes in the font
217 \return The number of strikes in the font
219 int32
220 ServerFont::CountTuned()
222 return fStyle->TunedCount();
227 \brief Returns the file format of the font.
228 \return Mostly B_TRUETYPE_WINDOWS :)
230 font_file_format
231 ServerFont::FileFormat()
233 return fStyle->FileFormat();
237 const char*
238 ServerFont::Style() const
240 return fStyle->Name();
244 const char*
245 ServerFont::Family() const
247 return fStyle->Family()->Name();
251 void
252 ServerFont::SetStyle(FontStyle* style)
254 if (style && style != fStyle) {
255 // detach from old style
256 if (fStyle != NULL)
257 fStyle->Release();
259 // attach to new style
260 fStyle = style;
262 fStyle->Acquire();
264 fFace = fStyle->Face();
265 fDirection = fStyle->Direction();
271 \brief Sets the ServerFont instance to whatever font is specified
272 This method will lock the font manager.
274 \param familyID ID number of the family to set
275 \param styleID ID number of the style to set
276 \return B_OK if successful, B_ERROR if not
278 status_t
279 ServerFont::SetFamilyAndStyle(uint16 familyID, uint16 styleID)
281 FontStyle* style = NULL;
283 if (gFontManager->Lock()) {
284 style = gFontManager->GetStyle(familyID, styleID);
285 if (style != NULL)
286 style->Acquire();
288 gFontManager->Unlock();
291 if (style == NULL)
292 return B_ERROR;
294 SetStyle(style);
295 style->Release();
297 return B_OK;
302 \brief Sets the ServerFont instance to whatever font is specified
303 \param fontID the combination of family and style ID numbers
304 \return B_OK if successful, B_ERROR if not
306 status_t
307 ServerFont::SetFamilyAndStyle(uint32 fontID)
309 uint16 style = fontID & 0xFFFF;
310 uint16 family = (fontID & 0xFFFF0000) >> 16;
312 return SetFamilyAndStyle(family, style);
316 status_t
317 ServerFont::SetFace(uint16 face)
319 // TODO: This needs further investigation. The face variable is actually
320 // flags, but some of them are not enforcable at the same time. Also don't
321 // confuse the Be API "face" with the Freetype face, which is just an
322 // index in case a single font file exports multiple font faces. The
323 // FontStyle class takes care of mapping the font style name to the Be
324 // API face flags in FontStyle::_TranslateStyleToFace().
326 FontStyle* style = NULL;
327 uint16 familyID = FamilyID();
328 if (gFontManager->Lock()) {
329 int32 count = gFontManager->CountStyles(familyID);
330 for (int32 i = 0; i < count; i++) {
331 style = gFontManager->GetStyleByIndex(familyID, i);
332 if (style == NULL)
333 break;
334 if (style->Face() == face) {
335 style->Acquire();
336 break;
337 } else
338 style = NULL;
341 gFontManager->Unlock();
344 if (!style)
345 return B_ERROR;
347 SetStyle(style);
348 style->Release();
350 return B_OK;
355 \brief Gets the ID values for the ServerFont instance in one shot
356 \return the combination of family and style ID numbers
358 uint32
359 ServerFont::GetFamilyAndStyle() const
361 return (FamilyID() << 16) | StyleID();
365 FT_Face
366 ServerFont::GetTransformedFace(bool rotate, bool shear) const
368 fStyle->Lock();
369 FT_Face face = fStyle->FreeTypeFace();
370 if (!face) {
371 fStyle->Unlock();
372 return NULL;
375 FT_Set_Char_Size(face, 0, int32(fSize * 64), 72, 72);
377 if ((rotate && fRotation != 0) || (shear && fShear != 90)) {
378 FT_Matrix rmatrix, smatrix;
380 Angle rotationAngle(fRotation);
381 rmatrix.xx = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
382 rmatrix.xy = (FT_Fixed)(-rotationAngle.Sine() * 0x10000);
383 rmatrix.yx = (FT_Fixed)( rotationAngle.Sine() * 0x10000);
384 rmatrix.yy = (FT_Fixed)( rotationAngle.Cosine() * 0x10000);
386 Angle shearAngle(fShear);
387 smatrix.xx = (FT_Fixed)(0x10000);
388 smatrix.xy = (FT_Fixed)(-shearAngle.Cosine() * 0x10000);
389 smatrix.yx = (FT_Fixed)(0);
390 smatrix.yy = (FT_Fixed)(0x10000);
392 // Multiply togheter and apply transform
393 FT_Matrix_Multiply(&rmatrix, &smatrix);
394 FT_Set_Transform(face, &smatrix, NULL);
397 // fStyle will be unlocked in PutTransformedFace()
398 return face;
402 void
403 ServerFont::PutTransformedFace(FT_Face face) const
405 // Reset transformation
406 FT_Set_Transform(face, NULL, NULL);
407 fStyle->Unlock();
411 status_t
412 ServerFont::GetGlyphShapes(const char charArray[], int32 numChars,
413 BShape* shapeArray[]) const
415 if (!charArray || numChars <= 0 || !shapeArray)
416 return B_BAD_DATA;
418 FT_Face face = GetTransformedFace(true, true);
419 if (!face)
420 return B_ERROR;
422 FT_Outline_Funcs funcs;
423 funcs.move_to = MoveToFunc;
424 funcs.line_to = LineToFunc;
425 funcs.conic_to = ConicToFunc;
426 funcs.cubic_to = CubicToFunc;
427 funcs.shift = 0;
428 funcs.delta = 0;
430 const char* string = charArray;
431 for (int i = 0; i < numChars; i++) {
432 shapeArray[i] = new (std::nothrow) BShape();
433 if (shapeArray[i] == NULL) {
434 PutTransformedFace(face);
435 return B_NO_MEMORY;
437 FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
438 FT_Outline outline = face->glyph->outline;
439 FT_Outline_Decompose(&outline, &funcs, shapeArray[i]);
440 shapeArray[i]->Close();
443 PutTransformedFace(face);
444 return B_OK;
448 #ifdef FONTCONFIG_ENABLED
451 \brief For a given codepoint, do a binary search of the defined unicode
452 blocks to figure out which one contains the codepoint.
453 \param codePoint is the point to find
454 \param startGuess is the starting point for the binary search (default 0)
456 static
457 int32
458 FindBlockForCodepoint(uint32 codePoint, uint32 startGuess)
460 uint32 min = 0;
461 uint32 max = kNumUnicodeBlockRanges;
462 uint32 guess = (max + min) / 2;
464 if (startGuess > 0)
465 guess = startGuess;
467 if (codePoint > kUnicodeBlockMap[max-1].end)
468 return -1;
470 while ((max >= min) && (guess < kNumUnicodeBlockRanges)) {
471 uint32 start = kUnicodeBlockMap[guess].start;
472 uint32 end = kUnicodeBlockMap[guess].end;
474 if (start <= codePoint && end >= codePoint)
475 return guess;
477 if (end < codePoint) {
478 min = guess + 1;
479 } else {
480 max = guess - 1;
483 guess = (max + min) / 2;
486 return -1;
490 \brief parses charmap from fontconfig. See fontconfig docs for FcCharSetFirstPage
491 and FcCharSetNextPage for details on format.
492 \param charMap is a fontconfig character map
493 \param baseCodePoint is the base codepoint returned by fontconfig
494 \param blocksForMap is a unicode_block to store the bitmap of contained blocks
496 static
497 void
498 ParseFcMap(FcChar32 charMap[], FcChar32 baseCodePoint, unicode_block& blocksForMap)
500 uint32 block = 0;
501 const uint8 BITS_PER_BLOCK = 32;
502 uint32 currentCodePoint = 0;
504 if (baseCodePoint > kUnicodeBlockMap[kNumUnicodeBlockRanges-1].end)
505 return;
507 for (int i = 0; i < FC_CHARSET_MAP_SIZE; ++i) {
508 FcChar32 curMapBlock = charMap[i];
509 int32 rangeStart = -1;
510 int32 startBlock = -1;
511 int32 endBlock = -1;
512 uint32 startPoint = 0;
514 currentCodePoint = baseCodePoint + block;
516 for (int bit = 0; bit < BITS_PER_BLOCK; ++bit) {
517 if (curMapBlock == 0 && startBlock < 0)
518 // if no more bits are set then short-circuit the loop
519 break;
521 if ((curMapBlock & 0x1) != 0 && rangeStart < 0) {
522 rangeStart = bit;
523 startPoint = currentCodePoint + rangeStart;
524 startBlock = FindBlockForCodepoint(startPoint, 0);
525 if (startBlock >= 0) {
526 blocksForMap = blocksForMap
527 | kUnicodeBlockMap[startBlock].block;
529 } else if (rangeStart >= 0 && startBlock >= 0) {
530 // when we find an empty bit, that's the end of the range
531 uint32 endPoint = currentCodePoint + (bit - 1);
533 endBlock = FindBlockForCodepoint(endPoint,
534 startBlock);
535 // start the binary search at the block where we found the
536 // start codepoint to ideally find the end in the same
537 // block.
538 ++startBlock;
540 while (startBlock <= endBlock) {
541 // if the starting codepoint is found in a different block
542 // than the ending codepoint, we should add all the blocks
543 // inbetween.
544 blocksForMap = blocksForMap
545 | kUnicodeBlockMap[startBlock].block;
546 ++startBlock;
549 startBlock = -1;
550 endBlock = -1;
551 rangeStart = -1;
554 curMapBlock >>= 1;
557 if (rangeStart >= 0 && startBlock >= 0) {
558 // if we hit the end of the block and had
559 // found a start of the range then we
560 // should end the range at the end of the block
561 uint32 endPoint = currentCodePoint + BITS_PER_BLOCK - 1;
563 endBlock = FindBlockForCodepoint(endPoint,
564 startBlock);
565 // start the binary search at the block where we found the
566 // start codepoint to ideally find the end in the same
567 // block.
568 ++startBlock;
570 while (startBlock <= endBlock) {
571 // if the starting codepoint is found in a different block
572 // than the ending codepoint, we should add all the blocks
573 // inbetween.
574 blocksForMap = blocksForMap
575 | kUnicodeBlockMap[startBlock].block;
576 ++startBlock;
580 block += BITS_PER_BLOCK;
584 #endif // FONTCONFIG_ENABLED
588 \brief Gets a bitmap that indicates which Unicode blocks are in the font.
589 \param unicode_block to store bitmap in
590 \return B_OK; bitmap will be empty if something went wrong
592 status_t
593 ServerFont::GetUnicodeBlocks(unicode_block& blocksForFont)
595 blocksForFont = unicode_block();
597 #ifdef FONTCONFIG_ENABLED
598 FT_Face face = GetTransformedFace(true, true);
599 if (face == NULL)
600 return B_ERROR;
602 FcCharSet *charSet = FcFreeTypeCharSet(face, NULL);
603 if (charSet == NULL) {
604 PutTransformedFace(face);
605 return B_ERROR;
608 FcChar32 charMap[FC_CHARSET_MAP_SIZE];
609 FcChar32 next = 0;
610 FcChar32 baseCodePoint = FcCharSetFirstPage(charSet, charMap, &next);
612 while ((baseCodePoint != FC_CHARSET_DONE) && (next != FC_CHARSET_DONE)) {
613 ParseFcMap(charMap, baseCodePoint, blocksForFont);
614 baseCodePoint = FcCharSetNextPage(charSet, charMap, &next);
617 FcCharSetDestroy(charSet);
618 PutTransformedFace(face);
619 #endif // FONTCONFIG_ENABLED
621 return B_OK;
625 \brief Checks if a unicode block specified by a start and end point is defined
626 in the current font
627 \param start of unicode block
628 \param end of unicode block
629 \param hasBlock boolean to store whether the font contains the specified block
630 \return B_OK; hasBlock will be false if something goes wrong
632 status_t
633 ServerFont::IncludesUnicodeBlock(uint32 start, uint32 end, bool& hasBlock)
635 hasBlock = false;
637 #ifdef FONTCONFIG_ENABLED
638 FT_Face face = GetTransformedFace(true, true);
639 if (face == NULL)
640 return B_ERROR;
642 FcCharSet *charSet = FcFreeTypeCharSet(face, NULL);
643 if (charSet == NULL) {
644 PutTransformedFace(face);
645 return B_ERROR;
648 uint32 curCodePoint = start;
650 while (curCodePoint <= end && hasBlock == false) {
651 // loop through range; if any character in the range is in the charset
652 // then the block is represented.
653 if (FcCharSetHasChar(charSet, (FcChar32)curCodePoint) == FcTrue) {
654 hasBlock = true;
655 break;
658 ++curCodePoint;
661 FcCharSetDestroy(charSet);
662 PutTransformedFace(face);
663 #endif // FONTCONFIG_ENABLED
665 return B_OK;
669 class HasGlyphsConsumer {
670 public:
671 HasGlyphsConsumer(bool* hasArray)
672 : fHasArray(hasArray)
675 bool NeedsVector() { return false; }
676 void Start() {}
677 void Finish(double x, double y) {}
678 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
680 fHasArray[index] = false;
682 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
683 FontCacheEntry* entry, double x, double y, double advanceX,
684 double advanceY)
686 fHasArray[index] = glyph->glyph_index != 0;
687 return true;
690 private:
691 bool* fHasArray;
695 status_t
696 ServerFont::GetHasGlyphs(const char* string, int32 numBytes,
697 bool* hasArray) const
699 if (!string || numBytes <= 0 || !hasArray)
700 return B_BAD_DATA;
702 HasGlyphsConsumer consumer(hasArray);
703 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
704 NULL, fSpacing))
705 return B_OK;
707 return B_ERROR;
711 class EdgesConsumer {
712 public:
713 EdgesConsumer(edge_info* edges, float size)
714 : fEdges(edges)
715 , fSize(size)
718 bool NeedsVector() { return false; }
719 void Start() {}
720 void Finish(double x, double y) {}
721 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
723 fEdges[index].left = 0.0;
724 fEdges[index].right = 0.0;
726 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
727 FontCacheEntry* entry, double x, double y, double advanceX,
728 double advanceY)
730 fEdges[index].left = glyph->inset_left / fSize;
731 fEdges[index].right = glyph->inset_right / fSize;
732 return true;
735 private:
736 edge_info* fEdges;
737 float fSize;
741 status_t
742 ServerFont::GetEdges(const char* string, int32 numBytes,
743 edge_info* edges) const
745 if (!string || numBytes <= 0 || !edges)
746 return B_BAD_DATA;
748 EdgesConsumer consumer(edges, fSize);
749 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
750 NULL, fSpacing)) {
751 return B_OK;
754 return B_ERROR;
756 // FT_Face face = GetTransformedFace(false, false);
757 // if (!face)
758 // return B_ERROR;
760 // const char *string = charArray;
761 // for (int i = 0; i < numChars; i++) {
762 // FT_Load_Char(face, UTF8ToCharCode(&string), FT_LOAD_NO_BITMAP);
763 // edgeArray[i].left = float(face->glyph->metrics.horiBearingX)
764 // / 64 / fSize;
765 // edgeArray[i].right = float(face->glyph->metrics.horiBearingX
766 // + face->glyph->metrics.width - face->glyph->metrics.horiAdvance)
767 // / 64 / fSize;
768 // }
770 // PutTransformedFace(face);
771 // return B_OK;
775 class BPointEscapementConsumer {
776 public:
777 BPointEscapementConsumer(BPoint* escapements, BPoint* offsets,
778 int32 numChars, float size)
780 fEscapements(escapements),
781 fOffsets(offsets),
782 fNumChars(numChars),
783 fSize(size)
787 bool NeedsVector() { return false; }
788 void Start() {}
789 void Finish(double x, double y) {}
790 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
792 _Set(index, 0, 0);
795 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
796 FontCacheEntry* entry, double x, double y, double advanceX,
797 double advanceY)
799 return _Set(index, advanceX, advanceY);
802 private:
803 inline bool _Set(int32 index, double x, double y)
805 if (index >= fNumChars)
806 return false;
808 fEscapements[index].x = x / fSize;
809 fEscapements[index].y = y / fSize;
810 if (fOffsets) {
811 // ToDo: According to the BeBook: "The offsetArray is applied by
812 // the dynamic spacing in order to improve the relative position
813 // of the character's width with relation to another character,
814 // without altering the width." So this will probably depend on
815 // the spacing mode.
816 fOffsets[index].x = 0;
817 fOffsets[index].y = 0;
819 return true;
822 BPoint* fEscapements;
823 BPoint* fOffsets;
824 int32 fNumChars;
825 float fSize;
829 status_t
830 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
831 escapement_delta delta, BPoint escapementArray[],
832 BPoint offsetArray[]) const
834 if (!string || numBytes <= 0 || !escapementArray)
835 return B_BAD_DATA;
837 BPointEscapementConsumer consumer(escapementArray, offsetArray, numChars,
838 fSize);
839 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
840 &delta, fSpacing)) {
841 return B_OK;
844 return B_ERROR;
848 class WidthEscapementConsumer {
849 public:
850 WidthEscapementConsumer(float* widths, int32 numChars, float size)
852 fWidths(widths),
853 fNumChars(numChars),
854 fSize(size)
858 bool NeedsVector() { return false; }
859 void Start() {}
860 void Finish(double x, double y) {}
861 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y)
863 fWidths[index] = 0.0;
866 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
867 FontCacheEntry* entry, double x, double y, double advanceX,
868 double advanceY)
870 if (index >= fNumChars)
871 return false;
873 fWidths[index] = advanceX / fSize;
874 return true;
877 private:
878 float* fWidths;
879 int32 fNumChars;
880 float fSize;
885 status_t
886 ServerFont::GetEscapements(const char* string, int32 numBytes, int32 numChars,
887 escapement_delta delta, float widthArray[]) const
889 if (!string || numBytes <= 0 || !widthArray)
890 return B_BAD_DATA;
892 WidthEscapementConsumer consumer(widthArray, numChars, fSize);
893 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
894 &delta, fSpacing)) {
895 return B_OK;
897 return B_ERROR;
901 class BoundingBoxConsumer {
902 public:
903 BoundingBoxConsumer(Transformable& transform, BRect* rectArray,
904 bool asString)
905 : rectArray(rectArray)
906 , stringBoundingBox(INT32_MAX, INT32_MAX, INT32_MIN, INT32_MIN)
907 , fAsString(asString)
908 , fCurves(fPathAdaptor)
909 , fContour(fCurves)
910 , fTransformedOutline(fCurves, transform)
911 , fTransformedContourOutline(fContour, transform)
912 , fTransform(transform)
916 bool NeedsVector() { return false; }
917 void Start() {}
918 void Finish(double x, double y) {}
919 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
920 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
921 FontCacheEntry* entry, double x, double y, double advanceX,
922 double advanceY)
924 if (glyph->data_type != glyph_data_outline) {
925 const agg::rect_i& r = glyph->bounds;
926 if (fAsString) {
927 if (rectArray) {
928 rectArray[index].left = r.x1 + x;
929 rectArray[index].top = r.y1 + y;
930 rectArray[index].right = r.x2 + x + 1;
931 rectArray[index].bottom = r.y2 + y + 1;
932 } else {
933 stringBoundingBox = stringBoundingBox
934 | BRect(r.x1 + x, r.y1 + y,
935 r.x2 + x + 1, r.y2 + y + 1);
937 } else {
938 rectArray[index].left = r.x1;
939 rectArray[index].top = r.y1;
940 rectArray[index].right = r.x2 + 1;
941 rectArray[index].bottom = r.y2 + 1;
943 } else {
944 if (fAsString) {
945 entry->InitAdaptors(glyph, x, y,
946 fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
947 } else {
948 entry->InitAdaptors(glyph, 0, 0,
949 fMonoAdaptor, fGray8Adaptor, fPathAdaptor);
951 double left = 0.0;
952 double top = 0.0;
953 double right = -1.0;
954 double bottom = -1.0;
955 uint32 pathID[1];
956 pathID[0] = 0;
957 // TODO: use fContour if falseboldwidth is > 0
958 agg::bounding_rect(fTransformedOutline, pathID, 0, 1,
959 &left, &top, &right, &bottom);
961 if (rectArray) {
962 rectArray[index] = BRect(left, top, right, bottom);
963 } else {
964 stringBoundingBox = stringBoundingBox
965 | BRect(left, top, right, bottom);
968 return true;
971 BRect* rectArray;
972 BRect stringBoundingBox;
974 private:
975 bool fAsString;
976 FontCacheEntry::GlyphPathAdapter fPathAdaptor;
977 FontCacheEntry::GlyphGray8Adapter fGray8Adaptor;
978 FontCacheEntry::GlyphMonoAdapter fMonoAdaptor;
980 FontCacheEntry::CurveConverter fCurves;
981 FontCacheEntry::ContourConverter fContour;
983 FontCacheEntry::TransformedOutline fTransformedOutline;
984 FontCacheEntry::TransformedContourOutline fTransformedContourOutline;
986 Transformable& fTransform;
990 status_t
991 ServerFont::GetBoundingBoxes(const char* string, int32 numBytes,
992 BRect rectArray[], bool stringEscapement, font_metric_mode mode,
993 escapement_delta delta, bool asString)
995 // TODO: The font_metric_mode is not used
996 if (!string || numBytes <= 0 || !rectArray)
997 return B_BAD_DATA;
999 Transformable transform(EmbeddedTransformation());
1001 BoundingBoxConsumer consumer(transform, rectArray, asString);
1002 if (GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
1003 stringEscapement ? &delta : NULL, fSpacing)) {
1004 return B_OK;
1006 return B_ERROR;
1010 status_t
1011 ServerFont::GetBoundingBoxesForStrings(char *charArray[], int32 lengthArray[],
1012 int32 numStrings, BRect rectArray[], font_metric_mode mode,
1013 escapement_delta deltaArray[])
1015 // TODO: The font_metric_mode is never used
1016 if (!charArray || !lengthArray|| numStrings <= 0 || !rectArray || !deltaArray)
1017 return B_BAD_DATA;
1019 Transformable transform(EmbeddedTransformation());
1021 for (int32 i = 0; i < numStrings; i++) {
1022 int32 numBytes = lengthArray[i];
1023 const char* string = charArray[i];
1024 escapement_delta delta = deltaArray[i];
1026 BoundingBoxConsumer consumer(transform, NULL, true);
1027 if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
1028 &delta, fSpacing)) {
1029 return B_ERROR;
1032 rectArray[i] = consumer.stringBoundingBox;
1035 return B_OK;
1039 class StringWidthConsumer {
1040 public:
1041 StringWidthConsumer() : width(0.0) {}
1042 bool NeedsVector() { return false; }
1043 void Start() {}
1044 void Finish(double x, double y) { width = x; }
1045 void ConsumeEmptyGlyph(int32 index, uint32 charCode, double x, double y) {}
1046 bool ConsumeGlyph(int32 index, uint32 charCode, const GlyphCache* glyph,
1047 FontCacheEntry* entry, double x, double y, double advanceX,
1048 double advanceY)
1049 { return true; }
1051 float width;
1055 float
1056 ServerFont::StringWidth(const char *string, int32 numBytes,
1057 const escapement_delta* deltaArray) const
1059 if (!string || numBytes <= 0)
1060 return 0.0;
1062 StringWidthConsumer consumer;
1063 if (!GlyphLayoutEngine::LayoutGlyphs(consumer, *this, string, numBytes,
1064 deltaArray, fSpacing)) {
1065 return 0.0;
1068 return consumer.width;
1073 \brief Returns a BRect which encloses the entire font
1074 \return A BRect which encloses the entire font
1076 BRect
1077 ServerFont::BoundingBox()
1079 // TODO: fBounds is nowhere calculated!
1080 return fBounds;
1085 \brief Obtains the height values for characters in the font in its current state
1086 \param fh pointer to a font_height object to receive the values for the font
1088 void
1089 ServerFont::GetHeight(font_height& height) const
1091 fStyle->GetHeight(fSize, height);
1095 void
1096 ServerFont::TruncateString(BString* inOut, uint32 mode, float width) const
1098 if (!inOut)
1099 return;
1101 // the width of the "…" glyph
1102 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS, strlen(B_UTF8_ELLIPSIS));
1104 // count the individual glyphs
1105 int32 numChars = inOut->CountChars();
1107 // get the escapement of each glyph in font units
1108 float* escapementArray = new (std::nothrow) float[numChars];
1109 if (escapementArray == NULL)
1110 return;
1112 static escapement_delta delta = (escapement_delta){ 0.0, 0.0 };
1113 if (GetEscapements(inOut->String(), inOut->Length(), numChars, delta,
1114 escapementArray) == B_OK) {
1115 truncate_string(*inOut, mode, width, escapementArray, fSize,
1116 ellipsisWidth, numChars);
1119 delete[] escapementArray;
1123 Transformable
1124 ServerFont::EmbeddedTransformation() const
1126 // TODO: cache this?
1127 Transformable transform;
1129 transform.ShearBy(B_ORIGIN, (90.0 - fShear) * M_PI / 180.0, 0.0);
1130 transform.RotateBy(B_ORIGIN, -fRotation * M_PI / 180.0);
1132 return transform;