btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / interface / Font.cpp
blob5e65bbc695af5461c417dce7bcfa217ee25676ef
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 BPrivate::AppServerLink link;
843 link.StartMessage(AS_GET_UNICODE_BLOCKS);
844 link.Attach<uint16>(fFamilyID);
845 link.Attach<uint16>(fStyleID);
847 int32 status;
848 if (link.FlushWithReply(status) != B_OK
849 || status != B_OK) {
850 return unicode_block(~0LL, ~0LL);
853 unicode_block blocksForFont;
854 link.Read<unicode_block>(&blocksForFont);
856 return blocksForFont;
859 bool
860 BFont::IncludesBlock(uint32 start, uint32 end) const
862 BPrivate::AppServerLink link;
863 link.StartMessage(AS_GET_HAS_UNICODE_BLOCK);
864 link.Attach<uint16>(fFamilyID);
865 link.Attach<uint16>(fStyleID);
866 link.Attach<uint32>(start);
867 link.Attach<uint32>(end);
869 int32 status;
870 if (link.FlushWithReply(status) != B_OK
871 || status != B_OK) {
872 return false;
875 bool hasBlock;
876 link.Read<bool>(&hasBlock);
878 return hasBlock;
882 font_file_format
883 BFont::FileFormat() const
885 BPrivate::AppServerLink link;
886 link.StartMessage(AS_GET_FONT_FILE_FORMAT);
887 link.Attach<uint16>(fFamilyID);
888 link.Attach<uint16>(fStyleID);
890 int32 status;
891 if (link.FlushWithReply(status) != B_OK
892 || status != B_OK) {
893 // just take a safe bet...
894 return B_TRUETYPE_WINDOWS;
897 uint16 format;
898 link.Read<uint16>(&format);
900 return (font_file_format)format;
904 int32
905 BFont::CountTuned() const
907 BPrivate::AppServerLink link;
908 link.StartMessage(AS_GET_TUNED_COUNT);
909 link.Attach<uint16>(fFamilyID);
910 link.Attach<uint16>(fStyleID);
912 int32 code;
913 if (link.FlushWithReply(code) != B_OK
914 || code != B_OK)
915 return -1;
917 int32 count;
918 link.Read<int32>(&count);
919 return count;
923 void
924 BFont::GetTunedInfo(int32 index, tuned_font_info* info) const
926 if (info == NULL)
927 return;
929 BPrivate::AppServerLink link;
930 link.StartMessage(AS_GET_TUNED_INFO);
931 link.Attach<uint16>(fFamilyID);
932 link.Attach<uint16>(fStyleID);
933 link.Attach<uint32>(index);
935 int32 code;
936 if (link.FlushWithReply(code) != B_OK || code != B_OK)
937 return;
939 link.Read<tuned_font_info>(info);
943 void
944 BFont::TruncateString(BString* inOut, uint32 mode, float width) const
946 if (mode == B_NO_TRUNCATION)
947 return;
949 // NOTE: Careful, we cannot directly use "inOut->String()" as result
950 // array, because the string length increases by 3 bytes in the worst
951 // case scenario.
952 const char* string = inOut->String();
953 GetTruncatedStrings(&string, 1, mode, width, inOut);
957 void
958 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings,
959 uint32 mode, float width, BString resultArray[]) const
961 if (stringArray != NULL && numStrings > 0) {
962 // the width of the "…" glyph
963 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS);
965 for (int32 i = 0; i < numStrings; i++) {
966 resultArray[i] = stringArray[i];
967 int32 numChars = resultArray[i].CountChars();
969 // get the escapement of each glyph in font units
970 float* escapementArray = new float[numChars];
971 GetEscapements(stringArray[i], numChars, NULL, escapementArray);
973 truncate_string(resultArray[i], mode, width, escapementArray,
974 fSize, ellipsisWidth, numChars);
976 delete[] escapementArray;
982 void
983 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings,
984 uint32 mode, float width, char* resultArray[]) const
986 if (stringArray != NULL && numStrings > 0) {
987 for (int32 i = 0; i < numStrings; i++) {
988 BString* strings = new BString[numStrings];
989 GetTruncatedStrings(stringArray, numStrings, mode, width, strings);
991 for (int32 i = 0; i < numStrings; i++)
992 strcpy(resultArray[i], strings[i].String());
994 delete[] strings;
1000 float
1001 BFont::StringWidth(const char* string) const
1003 if (string == NULL)
1004 return 0.0;
1006 int32 length = strlen(string);
1007 float width;
1008 GetStringWidths(&string, &length, 1, &width);
1010 return width;
1014 float
1015 BFont::StringWidth(const char* string, int32 length) const
1017 if (!string || length < 1)
1018 return 0.0f;
1020 float width = 0.0f;
1021 GetStringWidths(&string, &length, 1, &width);
1023 return width;
1027 void
1028 BFont::GetStringWidths(const char* stringArray[], const int32 lengthArray[],
1029 int32 numStrings, float widthArray[]) const
1031 if (stringArray == NULL || lengthArray == NULL || numStrings < 1
1032 || widthArray == NULL) {
1033 return;
1036 BPrivate::AppServerLink link;
1037 link.StartMessage(AS_GET_STRING_WIDTHS);
1038 link.Attach<uint16>(fFamilyID);
1039 link.Attach<uint16>(fStyleID);
1040 link.Attach<float>(fSize);
1041 link.Attach<uint8>(fSpacing);
1042 link.Attach<int32>(numStrings);
1044 // TODO: all strings into a single array???
1045 // we do have a maximum message length, and it could be easily touched
1046 // here...
1047 for (int32 i = 0; i < numStrings; i++)
1048 link.AttachString(stringArray[i], lengthArray[i]);
1050 status_t status;
1051 if (link.FlushWithReply(status) != B_OK || status != B_OK)
1052 return;
1054 link.Read(widthArray, sizeof(float) * numStrings);
1058 void
1059 BFont::GetEscapements(const char charArray[], int32 numChars,
1060 float escapementArray[]) const
1062 GetEscapements(charArray, numChars, NULL, escapementArray);
1066 void
1067 BFont::GetEscapements(const char charArray[], int32 numChars,
1068 escapement_delta* delta, float escapementArray[]) const
1070 if (charArray == NULL || numChars < 1 || escapementArray == NULL)
1071 return;
1073 BPrivate::AppServerLink link;
1074 link.StartMessage(AS_GET_ESCAPEMENTS_AS_FLOATS);
1075 link.Attach<uint16>(fFamilyID);
1076 link.Attach<uint16>(fStyleID);
1077 link.Attach<float>(fSize);
1078 link.Attach<uint8>(fSpacing);
1079 link.Attach<float>(fRotation);
1080 link.Attach<uint32>(fFlags);
1082 link.Attach<float>(delta ? delta->nonspace : 0.0f);
1083 link.Attach<float>(delta ? delta->space : 0.0f);
1084 link.Attach<int32>(numChars);
1086 // TODO: Should we not worry about the port capacity here?!?
1087 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1088 link.Attach<int32>(bytesInBuffer);
1089 link.Attach(charArray, bytesInBuffer);
1091 int32 code;
1092 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1093 return;
1095 link.Read(escapementArray, numChars * sizeof(float));
1099 void
1100 BFont::GetEscapements(const char charArray[], int32 numChars,
1101 escapement_delta* delta, BPoint escapementArray[]) const
1103 GetEscapements(charArray, numChars, delta, escapementArray, NULL);
1107 void
1108 BFont::GetEscapements(const char charArray[], int32 numChars,
1109 escapement_delta* delta, BPoint escapementArray[],
1110 BPoint offsetArray[]) const
1112 if (charArray == NULL || numChars < 1 || escapementArray == NULL)
1113 return;
1115 BPrivate::AppServerLink link;
1116 link.StartMessage(AS_GET_ESCAPEMENTS);
1117 link.Attach<uint16>(fFamilyID);
1118 link.Attach<uint16>(fStyleID);
1119 link.Attach<float>(fSize);
1120 link.Attach<uint8>(fSpacing);
1121 link.Attach<float>(fRotation);
1122 link.Attach<uint32>(fFlags);
1124 link.Attach<float>(delta ? delta->nonspace : 0.0);
1125 link.Attach<float>(delta ? delta->space : 0.0);
1126 link.Attach<bool>(offsetArray != NULL);
1127 link.Attach<int32>(numChars);
1129 // TODO: Should we not worry about the port capacity here?!?
1130 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1131 link.Attach<int32>(bytesInBuffer);
1132 link.Attach(charArray, bytesInBuffer);
1134 int32 code;
1135 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1136 return;
1138 link.Read(escapementArray, sizeof(BPoint) * numChars);
1139 if (offsetArray)
1140 link.Read(offsetArray, sizeof(BPoint) * numChars);
1144 void
1145 BFont::GetEdges(const char charArray[], int32 numChars,
1146 edge_info edgeArray[]) const
1148 if (!charArray || numChars < 1 || !edgeArray)
1149 return;
1151 int32 code;
1152 BPrivate::AppServerLink link;
1154 link.StartMessage(AS_GET_EDGES);
1155 link.Attach<uint16>(fFamilyID);
1156 link.Attach<uint16>(fStyleID);
1157 link.Attach<int32>(numChars);
1159 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1160 link.Attach<int32>(bytesInBuffer);
1161 link.Attach(charArray, bytesInBuffer);
1163 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1164 return;
1166 link.Read(edgeArray, sizeof(edge_info) * numChars);
1170 void
1171 BFont::GetHeight(font_height* _height) const
1173 if (_height == NULL)
1174 return;
1176 if (fHeight.ascent == kUninitializedAscent) {
1177 // we don't have the font height cached yet
1178 BPrivate::AppServerLink link;
1180 link.StartMessage(AS_GET_FONT_HEIGHT);
1181 link.Attach<uint16>(fFamilyID);
1182 link.Attach<uint16>(fStyleID);
1183 link.Attach<float>(fSize);
1185 int32 code;
1186 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1187 return;
1189 // Who put that "const" to this method? :-)
1190 // We made fHeight mutable for this, but we should drop the "const"
1191 // when we can
1192 link.Read<font_height>(&fHeight);
1195 *_height = fHeight;
1199 void
1200 BFont::GetBoundingBoxesAsGlyphs(const char charArray[], int32 numChars,
1201 font_metric_mode mode, BRect boundingBoxArray[]) const
1203 _GetBoundingBoxes(charArray, numChars, mode, false, NULL,
1204 boundingBoxArray, false);
1208 void
1209 BFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars,
1210 font_metric_mode mode, escapement_delta* delta,
1211 BRect boundingBoxArray[]) const
1213 _GetBoundingBoxes(charArray, numChars, mode, true, delta,
1214 boundingBoxArray, true);
1218 void
1219 BFont::_GetBoundingBoxes(const char charArray[], int32 numChars,
1220 font_metric_mode mode, bool string_escapement, escapement_delta* delta,
1221 BRect boundingBoxArray[], bool asString) const
1223 if (charArray == NULL || numChars < 1 || boundingBoxArray == NULL)
1224 return;
1226 int32 code;
1227 BPrivate::AppServerLink link;
1229 link.StartMessage(asString
1230 ? AS_GET_BOUNDINGBOXES_STRING : AS_GET_BOUNDINGBOXES_CHARS);
1231 link.Attach<uint16>(fFamilyID);
1232 link.Attach<uint16>(fStyleID);
1233 link.Attach<float>(fSize);
1234 link.Attach<float>(fRotation);
1235 link.Attach<float>(fShear);
1236 link.Attach<float>(fFalseBoldWidth);
1237 link.Attach<uint8>(fSpacing);
1239 link.Attach<uint32>(fFlags);
1240 link.Attach<font_metric_mode>(mode);
1241 link.Attach<bool>(string_escapement);
1243 if (delta != NULL) {
1244 link.Attach<escapement_delta>(*delta);
1245 } else {
1246 escapement_delta emptyDelta = {0, 0};
1247 link.Attach<escapement_delta>(emptyDelta);
1250 link.Attach<int32>(numChars);
1251 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1252 link.Attach<int32>(bytesInBuffer);
1253 link.Attach(charArray, bytesInBuffer);
1255 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1256 return;
1258 link.Read(boundingBoxArray, sizeof(BRect) * numChars);
1262 void
1263 BFont::GetBoundingBoxesForStrings(const char* stringArray[], int32 numStrings,
1264 font_metric_mode mode, escapement_delta deltas[],
1265 BRect boundingBoxArray[]) const
1267 if (!stringArray || numStrings < 1 || !boundingBoxArray)
1268 return;
1270 int32 code;
1271 BPrivate::AppServerLink link;
1273 link.StartMessage(AS_GET_BOUNDINGBOXES_STRINGS);
1274 link.Attach<uint16>(fFamilyID);
1275 link.Attach<uint16>(fStyleID);
1276 link.Attach<float>(fSize);
1277 link.Attach<float>(fRotation);
1278 link.Attach<float>(fShear);
1279 link.Attach<float>(fFalseBoldWidth);
1280 link.Attach<uint8>(fSpacing);
1281 link.Attach<uint32>(fFlags);
1282 link.Attach<font_metric_mode>(mode);
1283 link.Attach<int32>(numStrings);
1285 if (deltas) {
1286 for (int32 i = 0; i < numStrings; i++) {
1287 link.AttachString(stringArray[i]);
1288 link.Attach<escapement_delta>(deltas[i]);
1290 } else {
1291 escapement_delta emptyDelta = {0, 0};
1293 for (int32 i = 0; i < numStrings; i++) {
1294 link.AttachString(stringArray[i]);
1295 link.Attach<escapement_delta>(emptyDelta);
1299 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1300 return;
1302 link.Read(boundingBoxArray, sizeof(BRect) * numStrings);
1306 void
1307 BFont::GetGlyphShapes(const char charArray[], int32 numChars,
1308 BShape* glyphShapeArray[]) const
1310 // TODO: implement code specifically for passing BShapes to and
1311 // from the server
1312 if (!charArray || numChars < 1 || !glyphShapeArray)
1313 return;
1315 int32 code;
1316 BPrivate::AppServerLink link;
1318 link.StartMessage(AS_GET_GLYPH_SHAPES);
1319 link.Attach<uint16>(fFamilyID);
1320 link.Attach<uint16>(fStyleID);
1321 link.Attach<float>(fSize);
1322 link.Attach<float>(fShear);
1323 link.Attach<float>(fRotation);
1324 link.Attach<float>(fFalseBoldWidth);
1325 link.Attach<uint32>(fFlags);
1326 link.Attach<int32>(numChars);
1328 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1329 link.Attach<int32>(bytesInBuffer);
1330 link.Attach(charArray, bytesInBuffer);
1332 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1333 return;
1335 for (int32 i = 0; i < numChars; i++)
1336 link.ReadShape(glyphShapeArray[i]);
1340 void
1341 BFont::GetHasGlyphs(const char charArray[], int32 numChars,
1342 bool hasArray[]) const
1344 if (!charArray || numChars < 1 || !hasArray)
1345 return;
1347 int32 code;
1348 BPrivate::AppServerLink link;
1350 link.StartMessage(AS_GET_HAS_GLYPHS);
1351 link.Attach<uint16>(fFamilyID);
1352 link.Attach<uint16>(fStyleID);
1353 link.Attach<int32>(numChars);
1355 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1356 link.Attach<int32>(bytesInBuffer);
1357 link.Attach(charArray, bytesInBuffer);
1359 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1360 return;
1362 link.Read(hasArray, sizeof(bool) * numChars);
1366 BFont&
1367 BFont::operator=(const BFont& font)
1369 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;
1378 fHeight = font.fHeight;
1379 fFlags = font.fFlags;
1380 fExtraFlags = font.fExtraFlags;
1382 return *this;
1386 bool
1387 BFont::operator==(const BFont& font) const
1389 return fFamilyID == font.fFamilyID
1390 && fStyleID == font.fStyleID
1391 && fSize == font.fSize
1392 && fShear == font.fShear
1393 && fRotation == font.fRotation
1394 && fFalseBoldWidth == font.fFalseBoldWidth
1395 && fSpacing == font.fSpacing
1396 && fEncoding == font.fEncoding
1397 && fFace == font.fFace;
1401 bool
1402 BFont::operator!=(const BFont& font) const
1404 return fFamilyID != font.fFamilyID
1405 || fStyleID != font.fStyleID
1406 || fSize != font.fSize
1407 || fShear != font.fShear
1408 || fRotation != font.fRotation
1409 || fFalseBoldWidth != font.fFalseBoldWidth
1410 || fSpacing != font.fSpacing
1411 || fEncoding != font.fEncoding
1412 || fFace != font.fFace;
1416 void
1417 BFont::PrintToStream() const
1419 font_family family;
1420 font_style style;
1421 GetFamilyAndStyle(&family, &style);
1423 printf("BFont { %s (%d), %s (%d) 0x%x %f/%f %fpt (%f %f %f), %d }\n",
1424 family, fFamilyID, style, fStyleID, fFace, fShear, fRotation, fSize,
1425 fHeight.ascent, fHeight.descent, fHeight.leading, fEncoding);
1429 void
1430 BFont::_GetExtraFlags() const
1432 // TODO: this has to be const in order to allow other font getters to
1433 // stay const as well
1434 if (fExtraFlags != kUninitializedExtraFlags)
1435 return;
1437 BPrivate::AppServerLink link;
1438 link.StartMessage(AS_GET_EXTRA_FONT_FLAGS);
1439 link.Attach<uint16>(fFamilyID);
1440 link.Attach<uint16>(fStyleID);
1442 status_t status = B_ERROR;
1443 if (link.FlushWithReply(status) != B_OK || status != B_OK) {
1444 // use defaut values for the flags
1445 fExtraFlags = (uint32)B_FONT_LEFT_TO_RIGHT
1446 << B_PRIVATE_FONT_DIRECTION_SHIFT;
1447 return;
1450 link.Read<uint32>(&fExtraFlags);