2 * Copyright 2001-2015, Haiku, Inc.
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 * Axel Dörfler, axeld@pinc-software.de
9 * Stephan Aßmus <superstippi@gmx.de>
10 * Andrej Spielmann, <andrej.spielmann@seh.ox.ac.uk>
14 #include <AppServerLink.h>
15 #include <FontPrivate.h>
16 #include <ObjectList.h>
17 #include <ServerProtocol.h>
18 #include <truncate_string.h>
19 #include <utf8_functions.h>
36 const float kUninitializedAscent
= INFINITY
;
37 const uint32 kUninitializedExtraFlags
= 0xffffffff;
39 // The actual objects which the globals point to
40 static BFont sPlainFont
;
41 static BFont sBoldFont
;
42 static BFont sFixedFont
;
44 const BFont
* be_plain_font
= &sPlainFont
;
45 const BFont
* be_bold_font
= &sBoldFont
;
46 const BFont
* be_fixed_font
= &sFixedFont
;
58 BObjectList
<style
> styles
;
63 class FontList
: public BLocker
{
68 static FontList
* Default();
70 bool UpdatedOnServer();
72 status_t
FamilyAt(int32 index
, font_family
* _family
,
74 status_t
StyleAt(font_family family
, int32 index
,
75 font_style
* _style
, uint16
* _face
,
78 int32
CountFamilies();
79 int32
CountStyles(font_family family
);
82 status_t
_UpdateIfNecessary();
84 int32
_RevisionOnServer();
85 family
* _FindFamily(font_family name
);
86 static void _InitSingleton();
89 BObjectList
<family
> fFamilies
;
91 bigtime_t fLastUpdate
;
94 static pthread_once_t sDefaultInitOnce
;
95 static FontList
* sDefaultInstance
;
98 pthread_once_t
FontList::sDefaultInitOnce
= PTHREAD_ONCE_INIT
;
99 FontList
* FontList::sDefaultInstance
= NULL
;
101 } // unnamed namespace
108 compare_families(const family
* a
, const family
* b
)
110 // TODO: compare font names according to the user's locale settings
111 return strcmp(a
->name
.String(), b
->name
.String());
118 : BLocker("font list"),
126 FontList::~FontList()
134 if (sDefaultInstance
== NULL
)
135 pthread_once(&sDefaultInitOnce
, &_InitSingleton
);
137 return sDefaultInstance
;
142 FontList::UpdatedOnServer()
144 return _RevisionOnServer() != fRevision
;
149 FontList::FamilyAt(int32 index
, font_family
* _family
, uint32
* _flags
)
151 BAutolock
locker(this);
153 status_t status
= _UpdateIfNecessary();
157 ::family
* family
= fFamilies
.ItemAt(index
);
161 memcpy(*_family
, family
->name
.String(), family
->name
.Length() + 1);
163 *_flags
= family
->flags
;
169 FontList::StyleAt(font_family familyName
, int32 index
, font_style
* _style
,
170 uint16
* _face
, uint32
* _flags
)
172 BAutolock
locker(this);
174 status_t status
= _UpdateIfNecessary();
178 ::family
* family
= _FindFamily(familyName
);
182 ::style
* style
= family
->styles
.ItemAt(index
);
186 memcpy(*_style
, style
->name
.String(), style
->name
.Length() + 1);
188 *_face
= style
->face
;
190 *_flags
= style
->flags
;
196 FontList::CountFamilies()
198 BAutolock
locker(this);
200 _UpdateIfNecessary();
201 return fFamilies
.CountItems();
206 FontList::CountStyles(font_family familyName
)
208 BAutolock
locker(this);
210 _UpdateIfNecessary();
212 ::family
* family
= _FindFamily(familyName
);
216 return family
->styles
.CountItems();
225 int32 revision
= _RevisionOnServer();
226 fLastUpdate
= system_time();
228 // are we up-to-date already?
229 if (revision
== fRevision
)
232 fFamilies
.MakeEmpty();
235 BPrivate::AppServerLink link
;
237 for (int32 index
= 0;; index
++) {
238 link
.StartMessage(AS_GET_FAMILY_AND_STYLES
);
239 link
.Attach
<int32
>(index
);
242 if (link
.FlushWithReply(status
) != B_OK
246 ::family
* family
= new (nothrow
) ::family
;
250 link
.ReadString(family
->name
);
251 link
.Read
<uint32
>(&family
->flags
);
254 link
.Read
<int32
>(&styleCount
);
256 for (int32 i
= 0; i
< styleCount
; i
++) {
257 ::style
* style
= new (nothrow
) ::style
;
263 link
.ReadString(style
->name
);
264 link
.Read
<uint16
>(&style
->face
);
265 link
.Read
<uint32
>(&style
->flags
);
267 family
->styles
.AddItem(style
);
270 fFamilies
.BinaryInsert(family
, compare_families
);
273 fRevision
= revision
;
275 // if the font list has been changed in the mean time, just update again
276 if (UpdatedOnServer())
284 FontList::_UpdateIfNecessary()
286 // an updated font list is at least valid for 1 second
287 if (fLastUpdate
> system_time() - 1000000)
295 FontList::_RevisionOnServer()
297 BPrivate::AppServerLink link
;
298 link
.StartMessage(AS_GET_FONT_LIST_REVISION
);
301 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
305 link
.Read
<int32
>(&revision
);
312 FontList::_FindFamily(font_family name
)
314 if (fLastFamily
!= NULL
&& fLastFamily
->name
== name
)
319 fLastFamily
= const_cast< ::family
*>(fFamilies
.BinarySearch(family
,
326 FontList::_InitSingleton()
328 sDefaultInstance
= new FontList
;
331 } // unnamed namespace
338 _init_global_fonts_()
340 BPrivate::AppServerLink link
;
341 link
.StartMessage(AS_GET_SYSTEM_FONTS
);
344 if (link
.FlushWithReply(code
) != B_OK
346 printf("DEBUG: Couldn't initialize global fonts!\n");
350 char type
[B_OS_NAME_LENGTH
];
352 while (link
.ReadString(type
, sizeof(type
)) >= B_OK
&& type
[0]) {
354 BFont
* font
= &dummy
;
356 if (!strcmp(type
, "plain"))
358 else if (!strcmp(type
, "bold"))
360 else if (!strcmp(type
, "fixed"))
363 link
.Read
<uint16
>(&font
->fFamilyID
);
364 link
.Read
<uint16
>(&font
->fStyleID
);
365 link
.Read
<float>(&font
->fSize
);
366 link
.Read
<uint16
>(&font
->fFace
);
367 link
.Read
<uint32
>(&font
->fFlags
);
369 font
->fHeight
.ascent
= kUninitializedAscent
;
370 font
->fExtraFlags
= kUninitializedExtraFlags
;
376 _font_control_(BFont
* font
, int32 cmd
, void* data
)
382 get_font_cache_info(uint32 id
, void* set
)
389 set_font_cache_info(uint32 id
, void* set
)
395 // Private function used to replace the R5 hack which sets a system font
397 _set_system_font_(const char* which
, font_family family
, font_style style
,
400 // R5 used a global area offset table to set the system fonts in the Font
401 // preferences panel. Bleah.
402 BPrivate::AppServerLink link
;
404 link
.StartMessage(AS_SET_SYSTEM_FONT
);
405 link
.AttachString(which
, B_OS_NAME_LENGTH
);
406 link
.AttachString(family
, sizeof(font_family
));
407 link
.AttachString(style
, sizeof(font_style
));
408 link
.Attach
<float>(size
);
414 _get_system_default_font_(const char* which
, font_family family
,
415 font_style style
, float* _size
)
417 BPrivate::AppServerLink link
;
419 link
.StartMessage(AS_GET_SYSTEM_DEFAULT_FONT
);
420 link
.AttachString(which
, B_OS_NAME_LENGTH
);
422 int32 status
= B_ERROR
;
423 if (link
.FlushWithReply(status
) != B_OK
427 link
.ReadString(family
, sizeof(font_family
));
428 link
.ReadString(style
, sizeof(font_style
));
429 link
.Read
<float>(_size
);
434 // Returns the number of installed font families
436 count_font_families()
438 return FontList::Default()->CountFamilies();
442 // Returns the number of styles available for a font family
444 count_font_styles(font_family family
)
446 return FontList::Default()->CountStyles(family
);
450 // Retrieves the family name at the specified index
452 get_font_family(int32 index
, font_family
* _name
, uint32
* _flags
)
457 return FontList::Default()->FamilyAt(index
, _name
, _flags
);
461 // Retrieves the family name at the specified index
463 get_font_style(font_family family
, int32 index
, font_style
* _name
,
466 return get_font_style(family
, index
, _name
, NULL
, _flags
);
470 // Retrieves the family name at the specified index
472 get_font_style(font_family family
, int32 index
, font_style
* _name
,
473 uint16
* _face
, uint32
* _flags
)
475 // The face value returned by this function is not very reliable. At the
476 // same time, the value returned should be fairly reliable, returning the
477 // proper flag for 90%-99% of font names.
482 return FontList::Default()->StyleAt(family
, index
, _name
, _face
, _flags
);
486 // Updates the font family list
488 update_font_families(bool /*checkOnly*/)
490 return FontList::Default()->UpdatedOnServer();
499 // initialise for be_plain_font (avoid circular definition)
505 fFalseBoldWidth(0.0),
506 fSpacing(B_BITMAP_SPACING
),
507 fEncoding(B_UNICODE_UTF8
),
510 fExtraFlags(kUninitializedExtraFlags
)
512 if (be_plain_font
!= NULL
&& this != &sPlainFont
)
513 *this = *be_plain_font
;
515 fHeight
.ascent
= 7.0;
516 fHeight
.descent
= 2.0;
517 fHeight
.leading
= 13.0;
522 BFont::BFont(const BFont
& font
)
528 BFont::BFont(const BFont
* font
)
533 *this = *be_plain_font
;
537 // Sets the font's family and style all at once
539 BFont::SetFamilyAndStyle(const font_family family
, const font_style style
)
541 if (family
== NULL
&& style
== NULL
)
544 BPrivate::AppServerLink link
;
546 link
.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS
);
547 link
.AttachString(family
, sizeof(font_family
));
548 link
.AttachString(style
, sizeof(font_style
));
549 link
.Attach
<uint16
>(fFamilyID
);
550 link
.Attach
<uint16
>(0xffff);
551 link
.Attach
<uint16
>(fFace
);
553 int32 status
= B_ERROR
;
554 if (link
.FlushWithReply(status
) != B_OK
|| status
!= B_OK
)
557 link
.Read
<uint16
>(&fFamilyID
);
558 link
.Read
<uint16
>(&fStyleID
);
559 link
.Read
<uint16
>(&fFace
);
560 fHeight
.ascent
= kUninitializedAscent
;
561 fExtraFlags
= kUninitializedExtraFlags
;
567 // Sets the font's family and style all at once
569 BFont::SetFamilyAndStyle(uint32 code
)
571 // R5 has a bug here: the face is not updated even though the IDs are set.
572 // This is a problem because the face flag includes Regular/Bold/Italic
573 // information in addition to stuff like underlining and strikethrough.
574 // As a result, this will need a trip to the server and, thus, be slower
575 // than R5's in order to be correct
577 uint16 family
, style
;
578 style
= code
& 0xFFFF;
579 family
= (code
& 0xFFFF0000) >> 16;
581 BPrivate::AppServerLink link
;
582 link
.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS
);
583 link
.AttachString(NULL
); // no family and style name
584 link
.AttachString(NULL
);
585 link
.Attach
<uint16
>(family
);
586 link
.Attach
<uint16
>(style
);
587 link
.Attach
<uint16
>(fFace
);
590 if (link
.FlushWithReply(fontcode
) != B_OK
|| fontcode
!= B_OK
)
593 link
.Read
<uint16
>(&fFamilyID
);
594 link
.Read
<uint16
>(&fStyleID
);
595 link
.Read
<uint16
>(&fFace
);
596 fHeight
.ascent
= kUninitializedAscent
;
597 fExtraFlags
= kUninitializedExtraFlags
;
601 // Sets the font's family and face all at once
603 BFont::SetFamilyAndFace(const font_family family
, uint16 face
)
605 // To comply with the BeBook, this function will only set valid values
606 // i.e. passing a nonexistent family will cause only the face to be set.
607 // Additionally, if a particular face does not exist in a family, the
608 // closest match will be chosen.
610 BPrivate::AppServerLink link
;
611 link
.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS
);
612 link
.AttachString(family
, sizeof(font_family
));
613 link
.AttachString(NULL
); // no style given
614 link
.Attach
<uint16
>(fFamilyID
);
615 link
.Attach
<uint16
>(0xffff);
616 link
.Attach
<uint16
>(face
);
618 int32 status
= B_ERROR
;
619 if (link
.FlushWithReply(status
) != B_OK
|| status
!= B_OK
)
622 link
.Read
<uint16
>(&fFamilyID
);
623 link
.Read
<uint16
>(&fStyleID
);
624 link
.Read
<uint16
>(&fFace
);
625 fHeight
.ascent
= kUninitializedAscent
;
626 fExtraFlags
= kUninitializedExtraFlags
;
633 BFont::SetSize(float size
)
636 fHeight
.ascent
= kUninitializedAscent
;
641 BFont::SetShear(float shear
)
644 fHeight
.ascent
= kUninitializedAscent
;
649 BFont::SetRotation(float rotation
)
651 fRotation
= rotation
;
652 fHeight
.ascent
= kUninitializedAscent
;
657 BFont::SetFalseBoldWidth(float width
)
659 fFalseBoldWidth
= width
;
664 BFont::SetSpacing(uint8 spacing
)
671 BFont::SetEncoding(uint8 encoding
)
673 fEncoding
= encoding
;
678 BFont::SetFace(uint16 face
)
683 SetFamilyAndFace(NULL
, face
);
688 BFont::SetFlags(uint32 flags
)
695 BFont::GetFamilyAndStyle(font_family
* family
, font_style
* style
) const
697 if (family
== NULL
&& style
== NULL
)
700 // it's okay to call this function with either family or style set to NULL
702 font_family familyBuffer
;
703 font_style styleBuffer
;
706 family
= &familyBuffer
;
708 style
= &styleBuffer
;
710 BPrivate::AppServerLink link
;
711 link
.StartMessage(AS_GET_FAMILY_AND_STYLE
);
712 link
.Attach
<uint16
>(fFamilyID
);
713 link
.Attach
<uint16
>(fStyleID
);
716 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
) {
717 // the least we can do is to clear the buffers
718 memset(*family
, 0, sizeof(font_family
));
719 memset(*style
, 0, sizeof(font_style
));
723 link
.ReadString(*family
, sizeof(font_family
));
724 link
.ReadString(*style
, sizeof(font_style
));
729 BFont::FamilyAndStyle() const
731 return (fFamilyID
<< 16UL) | fStyleID
;
750 BFont::Rotation() const
757 BFont::FalseBoldWidth() const
759 return fFalseBoldWidth
;
764 BFont::Spacing() const
771 BFont::Encoding() const
792 BFont::Direction() const
795 return (font_direction
)(fExtraFlags
>> B_PRIVATE_FONT_DIRECTION_SHIFT
);
800 BFont::IsFixed() const
803 return (fExtraFlags
& B_IS_FIXED
) != 0;
807 // Returns whether or not the font is fixed-width and contains both
808 // full and half-width characters.
810 BFont::IsFullAndHalfFixed() const
812 // This was left unimplemented as of R5. It is a way to work with both
813 // Kanji and Roman characters in the same fixed-width font.
816 return (fExtraFlags
& B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED
) != 0;
821 BFont::BoundingBox() const
823 BPrivate::AppServerLink link
;
824 link
.StartMessage(AS_GET_FONT_BOUNDING_BOX
);
825 link
.Attach
<uint16
>(fFamilyID
);
826 link
.Attach
<uint16
>(fStyleID
);
829 if (link
.FlushWithReply(code
) != B_OK
831 return BRect(0, 0, 0 ,0);
834 link
.Read
<BRect
>(&box
);
840 BFont::Blocks() const
842 // TODO: Add Block support
843 return unicode_block(~0LL, ~0LL);
848 BFont::FileFormat() const
850 BPrivate::AppServerLink link
;
851 link
.StartMessage(AS_GET_FONT_FILE_FORMAT
);
852 link
.Attach
<uint16
>(fFamilyID
);
853 link
.Attach
<uint16
>(fStyleID
);
856 if (link
.FlushWithReply(status
) != B_OK
858 // just take a safe bet...
859 return B_TRUETYPE_WINDOWS
;
863 link
.Read
<uint16
>(&format
);
865 return (font_file_format
)format
;
870 BFont::CountTuned() const
872 BPrivate::AppServerLink link
;
873 link
.StartMessage(AS_GET_TUNED_COUNT
);
874 link
.Attach
<uint16
>(fFamilyID
);
875 link
.Attach
<uint16
>(fStyleID
);
878 if (link
.FlushWithReply(code
) != B_OK
883 link
.Read
<int32
>(&count
);
889 BFont::GetTunedInfo(int32 index
, tuned_font_info
* info
) const
894 BPrivate::AppServerLink link
;
895 link
.StartMessage(AS_GET_TUNED_INFO
);
896 link
.Attach
<uint16
>(fFamilyID
);
897 link
.Attach
<uint16
>(fStyleID
);
898 link
.Attach
<uint32
>(index
);
901 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
904 link
.Read
<tuned_font_info
>(info
);
909 BFont::TruncateString(BString
* inOut
, uint32 mode
, float width
) const
911 if (mode
== B_NO_TRUNCATION
)
914 // NOTE: Careful, we cannot directly use "inOut->String()" as result
915 // array, because the string length increases by 3 bytes in the worst
917 const char* string
= inOut
->String();
918 GetTruncatedStrings(&string
, 1, mode
, width
, inOut
);
923 BFont::GetTruncatedStrings(const char* stringArray
[], int32 numStrings
,
924 uint32 mode
, float width
, BString resultArray
[]) const
926 if (stringArray
!= NULL
&& numStrings
> 0) {
927 // the width of the "…" glyph
928 float ellipsisWidth
= StringWidth(B_UTF8_ELLIPSIS
);
930 for (int32 i
= 0; i
< numStrings
; i
++) {
931 resultArray
[i
] = stringArray
[i
];
932 int32 numChars
= resultArray
[i
].CountChars();
934 // get the escapement of each glyph in font units
935 float* escapementArray
= new float[numChars
];
936 GetEscapements(stringArray
[i
], numChars
, NULL
, escapementArray
);
938 truncate_string(resultArray
[i
], mode
, width
, escapementArray
,
939 fSize
, ellipsisWidth
, numChars
);
941 delete[] escapementArray
;
948 BFont::GetTruncatedStrings(const char* stringArray
[], int32 numStrings
,
949 uint32 mode
, float width
, char* resultArray
[]) const
951 if (stringArray
!= NULL
&& numStrings
> 0) {
952 for (int32 i
= 0; i
< numStrings
; i
++) {
953 BString
* strings
= new BString
[numStrings
];
954 GetTruncatedStrings(stringArray
, numStrings
, mode
, width
, strings
);
956 for (int32 i
= 0; i
< numStrings
; i
++)
957 strcpy(resultArray
[i
], strings
[i
].String());
966 BFont::StringWidth(const char* string
) const
971 int32 length
= strlen(string
);
973 GetStringWidths(&string
, &length
, 1, &width
);
980 BFont::StringWidth(const char* string
, int32 length
) const
982 if (!string
|| length
< 1)
986 GetStringWidths(&string
, &length
, 1, &width
);
993 BFont::GetStringWidths(const char* stringArray
[], const int32 lengthArray
[],
994 int32 numStrings
, float widthArray
[]) const
996 if (stringArray
== NULL
|| lengthArray
== NULL
|| numStrings
< 1
997 || widthArray
== NULL
) {
1001 BPrivate::AppServerLink link
;
1002 link
.StartMessage(AS_GET_STRING_WIDTHS
);
1003 link
.Attach
<uint16
>(fFamilyID
);
1004 link
.Attach
<uint16
>(fStyleID
);
1005 link
.Attach
<float>(fSize
);
1006 link
.Attach
<uint8
>(fSpacing
);
1007 link
.Attach
<int32
>(numStrings
);
1009 // TODO: all strings into a single array???
1010 // we do have a maximum message length, and it could be easily touched
1012 for (int32 i
= 0; i
< numStrings
; i
++)
1013 link
.AttachString(stringArray
[i
], lengthArray
[i
]);
1016 if (link
.FlushWithReply(status
) != B_OK
|| status
!= B_OK
)
1019 link
.Read(widthArray
, sizeof(float) * numStrings
);
1024 BFont::GetEscapements(const char charArray
[], int32 numChars
,
1025 float escapementArray
[]) const
1027 GetEscapements(charArray
, numChars
, NULL
, escapementArray
);
1032 BFont::GetEscapements(const char charArray
[], int32 numChars
,
1033 escapement_delta
* delta
, float escapementArray
[]) const
1035 if (charArray
== NULL
|| numChars
< 1 || escapementArray
== NULL
)
1038 BPrivate::AppServerLink link
;
1039 link
.StartMessage(AS_GET_ESCAPEMENTS_AS_FLOATS
);
1040 link
.Attach
<uint16
>(fFamilyID
);
1041 link
.Attach
<uint16
>(fStyleID
);
1042 link
.Attach
<float>(fSize
);
1043 link
.Attach
<uint8
>(fSpacing
);
1044 link
.Attach
<float>(fRotation
);
1045 link
.Attach
<uint32
>(fFlags
);
1047 link
.Attach
<float>(delta
? delta
->nonspace
: 0.0f
);
1048 link
.Attach
<float>(delta
? delta
->space
: 0.0f
);
1049 link
.Attach
<int32
>(numChars
);
1051 // TODO: Should we not worry about the port capacity here?!?
1052 uint32 bytesInBuffer
= UTF8CountBytes(charArray
, numChars
);
1053 link
.Attach
<int32
>(bytesInBuffer
);
1054 link
.Attach(charArray
, bytesInBuffer
);
1057 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
1060 link
.Read(escapementArray
, numChars
* sizeof(float));
1065 BFont::GetEscapements(const char charArray
[], int32 numChars
,
1066 escapement_delta
* delta
, BPoint escapementArray
[]) const
1068 GetEscapements(charArray
, numChars
, delta
, escapementArray
, NULL
);
1073 BFont::GetEscapements(const char charArray
[], int32 numChars
,
1074 escapement_delta
* delta
, BPoint escapementArray
[],
1075 BPoint offsetArray
[]) const
1077 if (charArray
== NULL
|| numChars
< 1 || escapementArray
== NULL
)
1080 BPrivate::AppServerLink link
;
1081 link
.StartMessage(AS_GET_ESCAPEMENTS
);
1082 link
.Attach
<uint16
>(fFamilyID
);
1083 link
.Attach
<uint16
>(fStyleID
);
1084 link
.Attach
<float>(fSize
);
1085 link
.Attach
<uint8
>(fSpacing
);
1086 link
.Attach
<float>(fRotation
);
1087 link
.Attach
<uint32
>(fFlags
);
1089 link
.Attach
<float>(delta
? delta
->nonspace
: 0.0);
1090 link
.Attach
<float>(delta
? delta
->space
: 0.0);
1091 link
.Attach
<bool>(offsetArray
!= NULL
);
1092 link
.Attach
<int32
>(numChars
);
1094 // TODO: Should we not worry about the port capacity here?!?
1095 uint32 bytesInBuffer
= UTF8CountBytes(charArray
, numChars
);
1096 link
.Attach
<int32
>(bytesInBuffer
);
1097 link
.Attach(charArray
, bytesInBuffer
);
1100 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
1103 link
.Read(escapementArray
, sizeof(BPoint
) * numChars
);
1105 link
.Read(offsetArray
, sizeof(BPoint
) * numChars
);
1110 BFont::GetEdges(const char charArray
[], int32 numChars
,
1111 edge_info edgeArray
[]) const
1113 if (!charArray
|| numChars
< 1 || !edgeArray
)
1117 BPrivate::AppServerLink link
;
1119 link
.StartMessage(AS_GET_EDGES
);
1120 link
.Attach
<uint16
>(fFamilyID
);
1121 link
.Attach
<uint16
>(fStyleID
);
1122 link
.Attach
<int32
>(numChars
);
1124 uint32 bytesInBuffer
= UTF8CountBytes(charArray
, numChars
);
1125 link
.Attach
<int32
>(bytesInBuffer
);
1126 link
.Attach(charArray
, bytesInBuffer
);
1128 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
1131 link
.Read(edgeArray
, sizeof(edge_info
) * numChars
);
1136 BFont::GetHeight(font_height
* _height
) const
1138 if (_height
== NULL
)
1141 if (fHeight
.ascent
== kUninitializedAscent
) {
1142 // we don't have the font height cached yet
1143 BPrivate::AppServerLink link
;
1145 link
.StartMessage(AS_GET_FONT_HEIGHT
);
1146 link
.Attach
<uint16
>(fFamilyID
);
1147 link
.Attach
<uint16
>(fStyleID
);
1148 link
.Attach
<float>(fSize
);
1151 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
1154 // Who put that "const" to this method? :-)
1155 // We made fHeight mutable for this, but we should drop the "const"
1157 link
.Read
<font_height
>(&fHeight
);
1165 BFont::GetBoundingBoxesAsGlyphs(const char charArray
[], int32 numChars
,
1166 font_metric_mode mode
, BRect boundingBoxArray
[]) const
1168 _GetBoundingBoxes(charArray
, numChars
, mode
, false, NULL
,
1169 boundingBoxArray
, false);
1174 BFont::GetBoundingBoxesAsString(const char charArray
[], int32 numChars
,
1175 font_metric_mode mode
, escapement_delta
* delta
,
1176 BRect boundingBoxArray
[]) const
1178 _GetBoundingBoxes(charArray
, numChars
, mode
, true, delta
,
1179 boundingBoxArray
, true);
1184 BFont::_GetBoundingBoxes(const char charArray
[], int32 numChars
,
1185 font_metric_mode mode
, bool string_escapement
, escapement_delta
* delta
,
1186 BRect boundingBoxArray
[], bool asString
) const
1188 if (charArray
== NULL
|| numChars
< 1 || boundingBoxArray
== NULL
)
1192 BPrivate::AppServerLink link
;
1194 link
.StartMessage(asString
1195 ? AS_GET_BOUNDINGBOXES_STRING
: AS_GET_BOUNDINGBOXES_CHARS
);
1196 link
.Attach
<uint16
>(fFamilyID
);
1197 link
.Attach
<uint16
>(fStyleID
);
1198 link
.Attach
<float>(fSize
);
1199 link
.Attach
<float>(fRotation
);
1200 link
.Attach
<float>(fShear
);
1201 link
.Attach
<float>(fFalseBoldWidth
);
1202 link
.Attach
<uint8
>(fSpacing
);
1204 link
.Attach
<uint32
>(fFlags
);
1205 link
.Attach
<font_metric_mode
>(mode
);
1206 link
.Attach
<bool>(string_escapement
);
1208 if (delta
!= NULL
) {
1209 link
.Attach
<escapement_delta
>(*delta
);
1211 escapement_delta emptyDelta
= {0, 0};
1212 link
.Attach
<escapement_delta
>(emptyDelta
);
1215 link
.Attach
<int32
>(numChars
);
1216 uint32 bytesInBuffer
= UTF8CountBytes(charArray
, numChars
);
1217 link
.Attach
<int32
>(bytesInBuffer
);
1218 link
.Attach(charArray
, bytesInBuffer
);
1220 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
1223 link
.Read(boundingBoxArray
, sizeof(BRect
) * numChars
);
1228 BFont::GetBoundingBoxesForStrings(const char* stringArray
[], int32 numStrings
,
1229 font_metric_mode mode
, escapement_delta deltas
[],
1230 BRect boundingBoxArray
[]) const
1232 if (!stringArray
|| numStrings
< 1 || !boundingBoxArray
)
1236 BPrivate::AppServerLink link
;
1238 link
.StartMessage(AS_GET_BOUNDINGBOXES_STRINGS
);
1239 link
.Attach
<uint16
>(fFamilyID
);
1240 link
.Attach
<uint16
>(fStyleID
);
1241 link
.Attach
<float>(fSize
);
1242 link
.Attach
<float>(fRotation
);
1243 link
.Attach
<float>(fShear
);
1244 link
.Attach
<float>(fFalseBoldWidth
);
1245 link
.Attach
<uint8
>(fSpacing
);
1246 link
.Attach
<uint32
>(fFlags
);
1247 link
.Attach
<font_metric_mode
>(mode
);
1248 link
.Attach
<int32
>(numStrings
);
1251 for (int32 i
= 0; i
< numStrings
; i
++) {
1252 link
.AttachString(stringArray
[i
]);
1253 link
.Attach
<escapement_delta
>(deltas
[i
]);
1256 escapement_delta emptyDelta
= {0, 0};
1258 for (int32 i
= 0; i
< numStrings
; i
++) {
1259 link
.AttachString(stringArray
[i
]);
1260 link
.Attach
<escapement_delta
>(emptyDelta
);
1264 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
1267 link
.Read(boundingBoxArray
, sizeof(BRect
) * numStrings
);
1272 BFont::GetGlyphShapes(const char charArray
[], int32 numChars
,
1273 BShape
* glyphShapeArray
[]) const
1275 // TODO: implement code specifically for passing BShapes to and
1277 if (!charArray
|| numChars
< 1 || !glyphShapeArray
)
1281 BPrivate::AppServerLink link
;
1283 link
.StartMessage(AS_GET_GLYPH_SHAPES
);
1284 link
.Attach
<uint16
>(fFamilyID
);
1285 link
.Attach
<uint16
>(fStyleID
);
1286 link
.Attach
<float>(fSize
);
1287 link
.Attach
<float>(fShear
);
1288 link
.Attach
<float>(fRotation
);
1289 link
.Attach
<float>(fFalseBoldWidth
);
1290 link
.Attach
<uint32
>(fFlags
);
1291 link
.Attach
<int32
>(numChars
);
1293 uint32 bytesInBuffer
= UTF8CountBytes(charArray
, numChars
);
1294 link
.Attach
<int32
>(bytesInBuffer
);
1295 link
.Attach(charArray
, bytesInBuffer
);
1297 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
1300 for (int32 i
= 0; i
< numChars
; i
++)
1301 link
.ReadShape(glyphShapeArray
[i
]);
1306 BFont::GetHasGlyphs(const char charArray
[], int32 numChars
,
1307 bool hasArray
[]) const
1309 if (!charArray
|| numChars
< 1 || !hasArray
)
1313 BPrivate::AppServerLink link
;
1315 link
.StartMessage(AS_GET_HAS_GLYPHS
);
1316 link
.Attach
<uint16
>(fFamilyID
);
1317 link
.Attach
<uint16
>(fStyleID
);
1318 link
.Attach
<int32
>(numChars
);
1320 uint32 bytesInBuffer
= UTF8CountBytes(charArray
, numChars
);
1321 link
.Attach
<int32
>(bytesInBuffer
);
1322 link
.Attach(charArray
, bytesInBuffer
);
1324 if (link
.FlushWithReply(code
) != B_OK
|| code
!= B_OK
)
1327 link
.Read(hasArray
, sizeof(bool) * numChars
);
1332 BFont::operator=(const BFont
& font
)
1334 fFamilyID
= font
.fFamilyID
;
1335 fStyleID
= font
.fStyleID
;
1337 fShear
= font
.fShear
;
1338 fRotation
= font
.fRotation
;
1339 fFalseBoldWidth
= font
.fFalseBoldWidth
;
1340 fSpacing
= font
.fSpacing
;
1341 fEncoding
= font
.fEncoding
;
1343 fHeight
= font
.fHeight
;
1344 fFlags
= font
.fFlags
;
1345 fExtraFlags
= font
.fExtraFlags
;
1352 BFont::operator==(const BFont
& font
) const
1354 return fFamilyID
== font
.fFamilyID
1355 && fStyleID
== font
.fStyleID
1356 && fSize
== font
.fSize
1357 && fShear
== font
.fShear
1358 && fRotation
== font
.fRotation
1359 && fFalseBoldWidth
== font
.fFalseBoldWidth
1360 && fSpacing
== font
.fSpacing
1361 && fEncoding
== font
.fEncoding
1362 && fFace
== font
.fFace
;
1367 BFont::operator!=(const BFont
& font
) const
1369 return fFamilyID
!= font
.fFamilyID
1370 || fStyleID
!= font
.fStyleID
1371 || fSize
!= font
.fSize
1372 || fShear
!= font
.fShear
1373 || fRotation
!= font
.fRotation
1374 || fFalseBoldWidth
!= font
.fFalseBoldWidth
1375 || fSpacing
!= font
.fSpacing
1376 || fEncoding
!= font
.fEncoding
1377 || fFace
!= font
.fFace
;
1382 BFont::PrintToStream() const
1386 GetFamilyAndStyle(&family
, &style
);
1388 printf("BFont { %s (%d), %s (%d) 0x%x %f/%f %fpt (%f %f %f), %d }\n",
1389 family
, fFamilyID
, style
, fStyleID
, fFace
, fShear
, fRotation
, fSize
,
1390 fHeight
.ascent
, fHeight
.descent
, fHeight
.leading
, fEncoding
);
1395 BFont::_GetExtraFlags() const
1397 // TODO: this has to be const in order to allow other font getters to
1398 // stay const as well
1399 if (fExtraFlags
!= kUninitializedExtraFlags
)
1402 BPrivate::AppServerLink link
;
1403 link
.StartMessage(AS_GET_EXTRA_FONT_FLAGS
);
1404 link
.Attach
<uint16
>(fFamilyID
);
1405 link
.Attach
<uint16
>(fStyleID
);
1407 status_t status
= B_ERROR
;
1408 if (link
.FlushWithReply(status
) != B_OK
|| status
!= B_OK
) {
1409 // use defaut values for the flags
1410 fExtraFlags
= (uint32
)B_FONT_LEFT_TO_RIGHT
1411 << B_PRIVATE_FONT_DIRECTION_SHIFT
;
1415 link
.Read
<uint32
>(&fExtraFlags
);