tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / interface / Font.cpp
blob804307fe542ec8bd49c7cc1db5aa710450e053cc
1 /*
2 * Copyright 2001-2015, Haiku, Inc.
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 * 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>
21 #include <Autolock.h>
22 #include <Font.h>
23 #include <Locker.h>
24 #include <Message.h>
25 #include <PortLink.h>
26 #include <Rect.h>
27 #include <Shape.h>
28 #include <String.h>
30 #include <new>
31 #include <stdio.h>
32 #include <stdlib.h>
34 using namespace std;
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;
49 struct style {
50 BString name;
51 uint16 face;
52 uint32 flags;
55 struct family {
56 BString name;
57 uint32 flags;
58 BObjectList<style> styles;
61 namespace {
63 class FontList : public BLocker {
64 public:
65 FontList();
66 virtual ~FontList();
68 static FontList* Default();
70 bool UpdatedOnServer();
72 status_t FamilyAt(int32 index, font_family* _family,
73 uint32* _flags);
74 status_t StyleAt(font_family family, int32 index,
75 font_style* _style, uint16* _face,
76 uint32* _flags);
78 int32 CountFamilies();
79 int32 CountStyles(font_family family);
81 private:
82 status_t _UpdateIfNecessary();
83 status_t _Update();
84 int32 _RevisionOnServer();
85 family* _FindFamily(font_family name);
86 static void _InitSingleton();
88 private:
89 BObjectList<family> fFamilies;
90 family* fLastFamily;
91 bigtime_t fLastUpdate;
92 int32 fRevision;
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
104 // #pragma mark -
107 static int
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());
115 namespace {
117 FontList::FontList()
118 : BLocker("font list"),
119 fLastFamily(NULL),
120 fLastUpdate(0),
121 fRevision(0)
126 FontList::~FontList()
131 /*static*/ FontList*
132 FontList::Default()
134 if (sDefaultInstance == NULL)
135 pthread_once(&sDefaultInitOnce, &_InitSingleton);
137 return sDefaultInstance;
141 bool
142 FontList::UpdatedOnServer()
144 return _RevisionOnServer() != fRevision;
148 status_t
149 FontList::FamilyAt(int32 index, font_family* _family, uint32* _flags)
151 BAutolock locker(this);
153 status_t status = _UpdateIfNecessary();
154 if (status < B_OK)
155 return status;
157 ::family* family = fFamilies.ItemAt(index);
158 if (family == NULL)
159 return B_BAD_VALUE;
161 memcpy(*_family, family->name.String(), family->name.Length() + 1);
162 if (_flags)
163 *_flags = family->flags;
164 return B_OK;
168 status_t
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();
175 if (status < B_OK)
176 return status;
178 ::family* family = _FindFamily(familyName);
179 if (family == NULL)
180 return B_BAD_VALUE;
182 ::style* style = family->styles.ItemAt(index);
183 if (style == NULL)
184 return B_BAD_VALUE;
186 memcpy(*_style, style->name.String(), style->name.Length() + 1);
187 if (_face)
188 *_face = style->face;
189 if (_flags)
190 *_flags = style->flags;
191 return B_OK;
195 int32
196 FontList::CountFamilies()
198 BAutolock locker(this);
200 _UpdateIfNecessary();
201 return fFamilies.CountItems();
205 int32
206 FontList::CountStyles(font_family familyName)
208 BAutolock locker(this);
210 _UpdateIfNecessary();
212 ::family* family = _FindFamily(familyName);
213 if (family == NULL)
214 return 0;
216 return family->styles.CountItems();
220 status_t
221 FontList::_Update()
223 // check version
225 int32 revision = _RevisionOnServer();
226 fLastUpdate = system_time();
228 // are we up-to-date already?
229 if (revision == fRevision)
230 return B_OK;
232 fFamilies.MakeEmpty();
233 fLastFamily = NULL;
235 BPrivate::AppServerLink link;
237 for (int32 index = 0;; index++) {
238 link.StartMessage(AS_GET_FAMILY_AND_STYLES);
239 link.Attach<int32>(index);
241 int32 status;
242 if (link.FlushWithReply(status) != B_OK
243 || status != B_OK)
244 break;
246 ::family* family = new (nothrow) ::family;
247 if (family == NULL)
248 return B_NO_MEMORY;
250 link.ReadString(family->name);
251 link.Read<uint32>(&family->flags);
253 int32 styleCount;
254 link.Read<int32>(&styleCount);
256 for (int32 i = 0; i < styleCount; i++) {
257 ::style* style = new (nothrow) ::style;
258 if (style == NULL) {
259 delete family;
260 return B_NO_MEMORY;
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())
277 _Update();
279 return B_OK;
283 status_t
284 FontList::_UpdateIfNecessary()
286 // an updated font list is at least valid for 1 second
287 if (fLastUpdate > system_time() - 1000000)
288 return B_OK;
290 return _Update();
294 int32
295 FontList::_RevisionOnServer()
297 BPrivate::AppServerLink link;
298 link.StartMessage(AS_GET_FONT_LIST_REVISION);
300 int32 code;
301 if (link.FlushWithReply(code) != B_OK || code != B_OK)
302 return B_ERROR;
304 int32 revision;
305 link.Read<int32>(&revision);
307 return revision;
311 family*
312 FontList::_FindFamily(font_family name)
314 if (fLastFamily != NULL && fLastFamily->name == name)
315 return fLastFamily;
317 ::family family;
318 family.name = name;
319 fLastFamily = const_cast< ::family*>(fFamilies.BinarySearch(family,
320 compare_families));
321 return fLastFamily;
325 /*static*/ void
326 FontList::_InitSingleton()
328 sDefaultInstance = new FontList;
331 } // unnamed namespace
334 // #pragma mark -
337 void
338 _init_global_fonts_()
340 BPrivate::AppServerLink link;
341 link.StartMessage(AS_GET_SYSTEM_FONTS);
343 int32 code;
344 if (link.FlushWithReply(code) != B_OK
345 || code != B_OK) {
346 printf("DEBUG: Couldn't initialize global fonts!\n");
347 return;
350 char type[B_OS_NAME_LENGTH];
352 while (link.ReadString(type, sizeof(type)) >= B_OK && type[0]) {
353 BFont dummy;
354 BFont* font = &dummy;
356 if (!strcmp(type, "plain"))
357 font = &sPlainFont;
358 else if (!strcmp(type, "bold"))
359 font = &sBoldFont;
360 else if (!strcmp(type, "fixed"))
361 font = &sFixedFont;
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;
375 void
376 _font_control_(BFont* font, int32 cmd, void* data)
381 status_t
382 get_font_cache_info(uint32 id, void* set)
384 return B_ERROR;
388 status_t
389 set_font_cache_info(uint32 id, void* set)
391 return B_ERROR;
395 // Private function used to replace the R5 hack which sets a system font
396 void
397 _set_system_font_(const char* which, font_family family, font_style style,
398 float size)
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);
409 link.Flush();
413 status_t
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
424 || status < B_OK)
425 return status;
427 link.ReadString(family, sizeof(font_family));
428 link.ReadString(style, sizeof(font_style));
429 link.Read<float>(_size);
430 return B_OK;
434 // Returns the number of installed font families
435 int32
436 count_font_families()
438 return FontList::Default()->CountFamilies();
442 // Returns the number of styles available for a font family
443 int32
444 count_font_styles(font_family family)
446 return FontList::Default()->CountStyles(family);
450 // Retrieves the family name at the specified index
451 status_t
452 get_font_family(int32 index, font_family* _name, uint32* _flags)
454 if (_name == NULL)
455 return B_BAD_VALUE;
457 return FontList::Default()->FamilyAt(index, _name, _flags);
461 // Retrieves the family name at the specified index
462 status_t
463 get_font_style(font_family family, int32 index, font_style* _name,
464 uint32* _flags)
466 return get_font_style(family, index, _name, NULL, _flags);
470 // Retrieves the family name at the specified index
471 status_t
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.
479 if (_name == NULL)
480 return B_BAD_VALUE;
482 return FontList::Default()->StyleAt(family, index, _name, _face, _flags);
486 // Updates the font family list
487 bool
488 update_font_families(bool /*checkOnly*/)
490 return FontList::Default()->UpdatedOnServer();
494 // #pragma mark -
497 BFont::BFont()
499 // initialise for be_plain_font (avoid circular definition)
500 fFamilyID(0),
501 fStyleID(0),
502 fSize(10.0),
503 fShear(90.0),
504 fRotation(0.0),
505 fFalseBoldWidth(0.0),
506 fSpacing(B_BITMAP_SPACING),
507 fEncoding(B_UNICODE_UTF8),
508 fFace(0),
509 fFlags(0),
510 fExtraFlags(kUninitializedExtraFlags)
512 if (be_plain_font != NULL && this != &sPlainFont)
513 *this = *be_plain_font;
514 else {
515 fHeight.ascent = 7.0;
516 fHeight.descent = 2.0;
517 fHeight.leading = 13.0;
522 BFont::BFont(const BFont& font)
524 *this = font;
528 BFont::BFont(const BFont* font)
530 if (font != NULL)
531 *this = *font;
532 else
533 *this = *be_plain_font;
537 // Sets the font's family and style all at once
538 status_t
539 BFont::SetFamilyAndStyle(const font_family family, const font_style style)
541 if (family == NULL && style == NULL)
542 return B_BAD_VALUE;
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)
555 return status;
557 link.Read<uint16>(&fFamilyID);
558 link.Read<uint16>(&fStyleID);
559 link.Read<uint16>(&fFace);
560 fHeight.ascent = kUninitializedAscent;
561 fExtraFlags = kUninitializedExtraFlags;
563 return B_OK;
567 // Sets the font's family and style all at once
568 void
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);
589 int32 fontcode;
590 if (link.FlushWithReply(fontcode) != B_OK || fontcode != B_OK)
591 return;
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
602 status_t
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)
620 return status;
622 link.Read<uint16>(&fFamilyID);
623 link.Read<uint16>(&fStyleID);
624 link.Read<uint16>(&fFace);
625 fHeight.ascent = kUninitializedAscent;
626 fExtraFlags = kUninitializedExtraFlags;
628 return B_OK;
632 void
633 BFont::SetSize(float size)
635 fSize = size;
636 fHeight.ascent = kUninitializedAscent;
640 void
641 BFont::SetShear(float shear)
643 fShear = shear;
644 fHeight.ascent = kUninitializedAscent;
648 void
649 BFont::SetRotation(float rotation)
651 fRotation = rotation;
652 fHeight.ascent = kUninitializedAscent;
656 void
657 BFont::SetFalseBoldWidth(float width)
659 fFalseBoldWidth = width;
663 void
664 BFont::SetSpacing(uint8 spacing)
666 fSpacing = spacing;
670 void
671 BFont::SetEncoding(uint8 encoding)
673 fEncoding = encoding;
677 void
678 BFont::SetFace(uint16 face)
680 if (face == fFace)
681 return;
683 SetFamilyAndFace(NULL, face);
687 void
688 BFont::SetFlags(uint32 flags)
690 fFlags = flags;
694 void
695 BFont::GetFamilyAndStyle(font_family* family, font_style* style) const
697 if (family == NULL && style == NULL)
698 return;
700 // it's okay to call this function with either family or style set to NULL
702 font_family familyBuffer;
703 font_style styleBuffer;
705 if (family == NULL)
706 family = &familyBuffer;
707 if (style == NULL)
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);
715 int32 code;
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));
720 return;
723 link.ReadString(*family, sizeof(font_family));
724 link.ReadString(*style, sizeof(font_style));
728 uint32
729 BFont::FamilyAndStyle() const
731 return (fFamilyID << 16UL) | fStyleID;
735 float
736 BFont::Size() const
738 return fSize;
742 float
743 BFont::Shear() const
745 return fShear;
749 float
750 BFont::Rotation() const
752 return fRotation;
756 float
757 BFont::FalseBoldWidth() const
759 return fFalseBoldWidth;
763 uint8
764 BFont::Spacing() const
766 return fSpacing;
770 uint8
771 BFont::Encoding() const
773 return fEncoding;
777 uint16
778 BFont::Face() const
780 return fFace;
784 uint32
785 BFont::Flags() const
787 return fFlags;
791 font_direction
792 BFont::Direction() const
794 _GetExtraFlags();
795 return (font_direction)(fExtraFlags >> B_PRIVATE_FONT_DIRECTION_SHIFT);
799 bool
800 BFont::IsFixed() const
802 _GetExtraFlags();
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.
809 bool
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.
815 _GetExtraFlags();
816 return (fExtraFlags & B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED) != 0;
820 BRect
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);
828 int32 code;
829 if (link.FlushWithReply(code) != B_OK
830 || code != B_OK)
831 return BRect(0, 0, 0 ,0);
833 BRect box;
834 link.Read<BRect>(&box);
835 return box;
839 unicode_block
840 BFont::Blocks() const
842 // TODO: Add Block support
843 return unicode_block(~0LL, ~0LL);
847 font_file_format
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);
855 int32 status;
856 if (link.FlushWithReply(status) != B_OK
857 || status != B_OK) {
858 // just take a safe bet...
859 return B_TRUETYPE_WINDOWS;
862 uint16 format;
863 link.Read<uint16>(&format);
865 return (font_file_format)format;
869 int32
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);
877 int32 code;
878 if (link.FlushWithReply(code) != B_OK
879 || code != B_OK)
880 return -1;
882 int32 count;
883 link.Read<int32>(&count);
884 return count;
888 void
889 BFont::GetTunedInfo(int32 index, tuned_font_info* info) const
891 if (info == NULL)
892 return;
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);
900 int32 code;
901 if (link.FlushWithReply(code) != B_OK || code != B_OK)
902 return;
904 link.Read<tuned_font_info>(info);
908 void
909 BFont::TruncateString(BString* inOut, uint32 mode, float width) const
911 if (mode == B_NO_TRUNCATION)
912 return;
914 // NOTE: Careful, we cannot directly use "inOut->String()" as result
915 // array, because the string length increases by 3 bytes in the worst
916 // case scenario.
917 const char* string = inOut->String();
918 GetTruncatedStrings(&string, 1, mode, width, inOut);
922 void
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;
947 void
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());
959 delete[] strings;
965 float
966 BFont::StringWidth(const char* string) const
968 if (string == NULL)
969 return 0.0;
971 int32 length = strlen(string);
972 float width;
973 GetStringWidths(&string, &length, 1, &width);
975 return width;
979 float
980 BFont::StringWidth(const char* string, int32 length) const
982 if (!string || length < 1)
983 return 0.0f;
985 float width = 0.0f;
986 GetStringWidths(&string, &length, 1, &width);
988 return width;
992 void
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) {
998 return;
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
1011 // here...
1012 for (int32 i = 0; i < numStrings; i++)
1013 link.AttachString(stringArray[i], lengthArray[i]);
1015 status_t status;
1016 if (link.FlushWithReply(status) != B_OK || status != B_OK)
1017 return;
1019 link.Read(widthArray, sizeof(float) * numStrings);
1023 void
1024 BFont::GetEscapements(const char charArray[], int32 numChars,
1025 float escapementArray[]) const
1027 GetEscapements(charArray, numChars, NULL, escapementArray);
1031 void
1032 BFont::GetEscapements(const char charArray[], int32 numChars,
1033 escapement_delta* delta, float escapementArray[]) const
1035 if (charArray == NULL || numChars < 1 || escapementArray == NULL)
1036 return;
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);
1056 int32 code;
1057 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1058 return;
1060 link.Read(escapementArray, numChars * sizeof(float));
1064 void
1065 BFont::GetEscapements(const char charArray[], int32 numChars,
1066 escapement_delta* delta, BPoint escapementArray[]) const
1068 GetEscapements(charArray, numChars, delta, escapementArray, NULL);
1072 void
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)
1078 return;
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);
1099 int32 code;
1100 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1101 return;
1103 link.Read(escapementArray, sizeof(BPoint) * numChars);
1104 if (offsetArray)
1105 link.Read(offsetArray, sizeof(BPoint) * numChars);
1109 void
1110 BFont::GetEdges(const char charArray[], int32 numChars,
1111 edge_info edgeArray[]) const
1113 if (!charArray || numChars < 1 || !edgeArray)
1114 return;
1116 int32 code;
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)
1129 return;
1131 link.Read(edgeArray, sizeof(edge_info) * numChars);
1135 void
1136 BFont::GetHeight(font_height* _height) const
1138 if (_height == NULL)
1139 return;
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);
1150 int32 code;
1151 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1152 return;
1154 // Who put that "const" to this method? :-)
1155 // We made fHeight mutable for this, but we should drop the "const"
1156 // when we can
1157 link.Read<font_height>(&fHeight);
1160 *_height = fHeight;
1164 void
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);
1173 void
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);
1183 void
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)
1189 return;
1191 int32 code;
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);
1210 } else {
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)
1221 return;
1223 link.Read(boundingBoxArray, sizeof(BRect) * numChars);
1227 void
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)
1233 return;
1235 int32 code;
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);
1250 if (deltas) {
1251 for (int32 i = 0; i < numStrings; i++) {
1252 link.AttachString(stringArray[i]);
1253 link.Attach<escapement_delta>(deltas[i]);
1255 } else {
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)
1265 return;
1267 link.Read(boundingBoxArray, sizeof(BRect) * numStrings);
1271 void
1272 BFont::GetGlyphShapes(const char charArray[], int32 numChars,
1273 BShape* glyphShapeArray[]) const
1275 // TODO: implement code specifically for passing BShapes to and
1276 // from the server
1277 if (!charArray || numChars < 1 || !glyphShapeArray)
1278 return;
1280 int32 code;
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)
1298 return;
1300 for (int32 i = 0; i < numChars; i++)
1301 link.ReadShape(glyphShapeArray[i]);
1305 void
1306 BFont::GetHasGlyphs(const char charArray[], int32 numChars,
1307 bool hasArray[]) const
1309 if (!charArray || numChars < 1 || !hasArray)
1310 return;
1312 int32 code;
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)
1325 return;
1327 link.Read(hasArray, sizeof(bool) * numChars);
1331 BFont&
1332 BFont::operator=(const BFont& font)
1334 fFamilyID = font.fFamilyID;
1335 fStyleID = font.fStyleID;
1336 fSize = font.fSize;
1337 fShear = font.fShear;
1338 fRotation = font.fRotation;
1339 fFalseBoldWidth = font.fFalseBoldWidth;
1340 fSpacing = font.fSpacing;
1341 fEncoding = font.fEncoding;
1342 fFace = font.fFace;
1343 fHeight = font.fHeight;
1344 fFlags = font.fFlags;
1345 fExtraFlags = font.fExtraFlags;
1347 return *this;
1351 bool
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;
1366 bool
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;
1381 void
1382 BFont::PrintToStream() const
1384 font_family family;
1385 font_style style;
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);
1394 void
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)
1400 return;
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;
1412 return;
1415 link.Read<uint32>(&fExtraFlags);