2 * Copyright 2001-2016, Haiku.
3 * Distributed under the terms of the MIT License.
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"
16 #include "GlyphLayoutEngine.h"
17 #include "FontManager.h"
18 #include "truncate_string.h"
19 #include "utf8_functions.h"
21 #include FT_FREETYPE_H
25 #ifdef FONTCONFIG_ENABLED
27 #include <fontconfig.h>
28 #include <fcfreetype.h>
30 #endif // FONTCONFIG_ENABLED
34 #include <UnicodeBlockObjects.h>
37 #include <agg_bounding_rect.h>
43 // functions needed to convert a freetype vector graphics to a BShape
45 VectorToPoint(const FT_Vector
*vector
)
48 result
.x
= float(vector
->x
) / 64;
49 result
.y
= -float(vector
->y
) / 64;
55 MoveToFunc(const FT_Vector
*to
, void *user
)
57 ((BShape
*)user
)->MoveTo(VectorToPoint(to
));
63 LineToFunc(const FT_Vector
*to
, void *user
)
65 ((BShape
*)user
)->LineTo(VectorToPoint(to
));
71 ConicToFunc(const FT_Vector
*control
, const FT_Vector
*to
, void *user
)
75 controls
[0] = VectorToPoint(control
);
76 controls
[1] = VectorToPoint(to
);
77 controls
[2] = controls
[1];
79 ((BShape
*)user
)->BezierTo(controls
);
85 CubicToFunc(const FT_Vector
*control1
, const FT_Vector
*control2
, const FT_Vector
*to
, void *user
)
89 controls
[0] = VectorToPoint(control1
);
90 controls
[1] = VectorToPoint(control2
);
91 controls
[2] = VectorToPoint(to
);
93 ((BShape
*)user
)->BezierTo(controls
);
99 is_white_space(uint32 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 */
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
)
137 fFalseBoldWidth(falseBoldWidth
),
141 fDirection(style
.Direction()),
143 fEncoding(B_UNICODE_UTF8
)
149 ServerFont::ServerFont()
153 *this = *gFontManager
->DefaultPlainFont();
158 \brief Copy Constructor
159 \param font ServerFont to copy
161 ServerFont::ServerFont(const ServerFont
&font
)
170 \brief Removes itself as a dependency of its owning style.
172 ServerFont::~ServerFont()
179 \brief Returns a copy of the specified font
180 \param The font to copy from.
181 \return A copy of the specified font
184 ServerFont::operator=(const ServerFont
& font
)
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
);
202 ServerFont::operator==(const ServerFont
& other
) const
204 if (GetFamilyAndStyle() != other
.GetFamilyAndStyle())
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
220 ServerFont::CountTuned()
222 return fStyle
->TunedCount();
227 \brief Returns the file format of the font.
228 \return Mostly B_TRUETYPE_WINDOWS :)
231 ServerFont::FileFormat()
233 return fStyle
->FileFormat();
238 ServerFont::Style() const
240 return fStyle
->Name();
245 ServerFont::Family() const
247 return fStyle
->Family()->Name();
252 ServerFont::SetStyle(FontStyle
* style
)
254 if (style
&& style
!= fStyle
) {
255 // detach from old style
259 // attach to new style
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
279 ServerFont::SetFamilyAndStyle(uint16 familyID
, uint16 styleID
)
281 FontStyle
* style
= NULL
;
283 if (gFontManager
->Lock()) {
284 style
= gFontManager
->GetStyle(familyID
, styleID
);
288 gFontManager
->Unlock();
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
307 ServerFont::SetFamilyAndStyle(uint32 fontID
)
309 uint16 style
= fontID
& 0xFFFF;
310 uint16 family
= (fontID
& 0xFFFF0000) >> 16;
312 return SetFamilyAndStyle(family
, style
);
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
);
334 if (style
->Face() == face
) {
341 gFontManager
->Unlock();
355 \brief Gets the ID values for the ServerFont instance in one shot
356 \return the combination of family and style ID numbers
359 ServerFont::GetFamilyAndStyle() const
361 return (FamilyID() << 16) | StyleID();
366 ServerFont::GetTransformedFace(bool rotate
, bool shear
) const
369 FT_Face face
= fStyle
->FreeTypeFace();
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()
403 ServerFont::PutTransformedFace(FT_Face face
) const
405 // Reset transformation
406 FT_Set_Transform(face
, NULL
, NULL
);
412 ServerFont::GetGlyphShapes(const char charArray
[], int32 numChars
,
413 BShape
* shapeArray
[]) const
415 if (!charArray
|| numChars
<= 0 || !shapeArray
)
418 FT_Face face
= GetTransformedFace(true, true);
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
;
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
);
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
);
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)
458 FindBlockForCodepoint(uint32 codePoint
, uint32 startGuess
)
461 uint32 max
= kNumUnicodeBlockRanges
;
462 uint32 guess
= (max
+ min
) / 2;
467 if (codePoint
> kUnicodeBlockMap
[max
-1].end
)
470 while ((max
>= min
) && (guess
< kNumUnicodeBlockRanges
)) {
471 uint32 start
= kUnicodeBlockMap
[guess
].start
;
472 uint32 end
= kUnicodeBlockMap
[guess
].end
;
474 if (start
<= codePoint
&& end
>= codePoint
)
477 if (end
< codePoint
) {
483 guess
= (max
+ min
) / 2;
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
498 ParseFcMap(FcChar32 charMap
[], FcChar32 baseCodePoint
, unicode_block
& blocksForMap
)
501 const uint8 BITS_PER_BLOCK
= 32;
502 uint32 currentCodePoint
= 0;
504 if (baseCodePoint
> kUnicodeBlockMap
[kNumUnicodeBlockRanges
-1].end
)
507 for (int i
= 0; i
< FC_CHARSET_MAP_SIZE
; ++i
) {
508 FcChar32 curMapBlock
= charMap
[i
];
509 int32 rangeStart
= -1;
510 int32 startBlock
= -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
521 if ((curMapBlock
& 0x1) != 0 && rangeStart
< 0) {
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
,
535 // start the binary search at the block where we found the
536 // start codepoint to ideally find the end in the same
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
544 blocksForMap
= blocksForMap
545 | kUnicodeBlockMap
[startBlock
].block
;
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
,
565 // start the binary search at the block where we found the
566 // start codepoint to ideally find the end in the same
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
574 blocksForMap
= blocksForMap
575 | kUnicodeBlockMap
[startBlock
].block
;
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
593 ServerFont::GetUnicodeBlocks(unicode_block
& blocksForFont
)
595 blocksForFont
= unicode_block();
597 #ifdef FONTCONFIG_ENABLED
598 FT_Face face
= GetTransformedFace(true, true);
602 FcCharSet
*charSet
= FcFreeTypeCharSet(face
, NULL
);
603 if (charSet
== NULL
) {
604 PutTransformedFace(face
);
608 FcChar32 charMap
[FC_CHARSET_MAP_SIZE
];
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
625 \brief Checks if a unicode block specified by a start and end point is defined
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
633 ServerFont::IncludesUnicodeBlock(uint32 start
, uint32 end
, bool& hasBlock
)
637 #ifdef FONTCONFIG_ENABLED
638 FT_Face face
= GetTransformedFace(true, true);
642 FcCharSet
*charSet
= FcFreeTypeCharSet(face
, NULL
);
643 if (charSet
== NULL
) {
644 PutTransformedFace(face
);
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
) {
661 FcCharSetDestroy(charSet
);
662 PutTransformedFace(face
);
663 #endif // FONTCONFIG_ENABLED
669 class HasGlyphsConsumer
{
671 HasGlyphsConsumer(bool* hasArray
)
672 : fHasArray(hasArray
)
675 bool NeedsVector() { return false; }
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
,
686 fHasArray
[index
] = glyph
->glyph_index
!= 0;
696 ServerFont::GetHasGlyphs(const char* string
, int32 numBytes
,
697 bool* hasArray
) const
699 if (!string
|| numBytes
<= 0 || !hasArray
)
702 HasGlyphsConsumer
consumer(hasArray
);
703 if (GlyphLayoutEngine::LayoutGlyphs(consumer
, *this, string
, numBytes
,
711 class EdgesConsumer
{
713 EdgesConsumer(edge_info
* edges
, float size
)
718 bool NeedsVector() { return false; }
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
,
730 fEdges
[index
].left
= glyph
->inset_left
/ fSize
;
731 fEdges
[index
].right
= glyph
->inset_right
/ fSize
;
742 ServerFont::GetEdges(const char* string
, int32 numBytes
,
743 edge_info
* edges
) const
745 if (!string
|| numBytes
<= 0 || !edges
)
748 EdgesConsumer
consumer(edges
, fSize
);
749 if (GlyphLayoutEngine::LayoutGlyphs(consumer
, *this, string
, numBytes
,
756 // FT_Face face = GetTransformedFace(false, false);
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)
765 // edgeArray[i].right = float(face->glyph->metrics.horiBearingX
766 // + face->glyph->metrics.width - face->glyph->metrics.horiAdvance)
770 // PutTransformedFace(face);
775 class BPointEscapementConsumer
{
777 BPointEscapementConsumer(BPoint
* escapements
, BPoint
* offsets
,
778 int32 numChars
, float size
)
780 fEscapements(escapements
),
787 bool NeedsVector() { return false; }
789 void Finish(double x
, double y
) {}
790 void ConsumeEmptyGlyph(int32 index
, uint32 charCode
, double x
, double y
)
795 bool ConsumeGlyph(int32 index
, uint32 charCode
, const GlyphCache
* glyph
,
796 FontCacheEntry
* entry
, double x
, double y
, double advanceX
,
799 return _Set(index
, advanceX
, advanceY
);
803 inline bool _Set(int32 index
, double x
, double y
)
805 if (index
>= fNumChars
)
808 fEscapements
[index
].x
= x
/ fSize
;
809 fEscapements
[index
].y
= y
/ fSize
;
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
816 fOffsets
[index
].x
= 0;
817 fOffsets
[index
].y
= 0;
822 BPoint
* fEscapements
;
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
)
837 BPointEscapementConsumer
consumer(escapementArray
, offsetArray
, numChars
,
839 if (GlyphLayoutEngine::LayoutGlyphs(consumer
, *this, string
, numBytes
,
848 class WidthEscapementConsumer
{
850 WidthEscapementConsumer(float* widths
, int32 numChars
, float size
)
858 bool NeedsVector() { return false; }
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
,
870 if (index
>= fNumChars
)
873 fWidths
[index
] = advanceX
/ fSize
;
886 ServerFont::GetEscapements(const char* string
, int32 numBytes
, int32 numChars
,
887 escapement_delta delta
, float widthArray
[]) const
889 if (!string
|| numBytes
<= 0 || !widthArray
)
892 WidthEscapementConsumer
consumer(widthArray
, numChars
, fSize
);
893 if (GlyphLayoutEngine::LayoutGlyphs(consumer
, *this, string
, numBytes
,
901 class BoundingBoxConsumer
{
903 BoundingBoxConsumer(Transformable
& transform
, BRect
* rectArray
,
905 : rectArray(rectArray
)
906 , stringBoundingBox(INT32_MAX
, INT32_MAX
, INT32_MIN
, INT32_MIN
)
907 , fAsString(asString
)
908 , fCurves(fPathAdaptor
)
910 , fTransformedOutline(fCurves
, transform
)
911 , fTransformedContourOutline(fContour
, transform
)
912 , fTransform(transform
)
916 bool NeedsVector() { return false; }
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
,
924 if (glyph
->data_type
!= glyph_data_outline
) {
925 const agg::rect_i
& r
= glyph
->bounds
;
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;
933 stringBoundingBox
= stringBoundingBox
934 | BRect(r
.x1
+ x
, r
.y1
+ y
,
935 r
.x2
+ x
+ 1, r
.y2
+ y
+ 1);
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;
945 entry
->InitAdaptors(glyph
, x
, y
,
946 fMonoAdaptor
, fGray8Adaptor
, fPathAdaptor
);
948 entry
->InitAdaptors(glyph
, 0, 0,
949 fMonoAdaptor
, fGray8Adaptor
, fPathAdaptor
);
954 double bottom
= -1.0;
957 // TODO: use fContour if falseboldwidth is > 0
958 agg::bounding_rect(fTransformedOutline
, pathID
, 0, 1,
959 &left
, &top
, &right
, &bottom
);
962 rectArray
[index
] = BRect(left
, top
, right
, bottom
);
964 stringBoundingBox
= stringBoundingBox
965 | BRect(left
, top
, right
, bottom
);
972 BRect stringBoundingBox
;
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
;
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
)
999 Transformable
transform(EmbeddedTransformation());
1001 BoundingBoxConsumer
consumer(transform
, rectArray
, asString
);
1002 if (GlyphLayoutEngine::LayoutGlyphs(consumer
, *this, string
, numBytes
,
1003 stringEscapement
? &delta
: NULL
, fSpacing
)) {
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
)
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
)) {
1032 rectArray
[i
] = consumer
.stringBoundingBox
;
1039 class StringWidthConsumer
{
1041 StringWidthConsumer() : width(0.0) {}
1042 bool NeedsVector() { return false; }
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
,
1056 ServerFont::StringWidth(const char *string
, int32 numBytes
,
1057 const escapement_delta
* deltaArray
) const
1059 if (!string
|| numBytes
<= 0)
1062 StringWidthConsumer consumer
;
1063 if (!GlyphLayoutEngine::LayoutGlyphs(consumer
, *this, string
, numBytes
,
1064 deltaArray
, fSpacing
)) {
1068 return consumer
.width
;
1073 \brief Returns a BRect which encloses the entire font
1074 \return A BRect which encloses the entire font
1077 ServerFont::BoundingBox()
1079 // TODO: fBounds is nowhere calculated!
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
1089 ServerFont::GetHeight(font_height
& height
) const
1091 fStyle
->GetHeight(fSize
, height
);
1096 ServerFont::TruncateString(BString
* inOut
, uint32 mode
, float width
) const
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
)
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
;
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);