1 /*
2 * Copyright 2001-2015, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
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>
11 */
12
13
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>
20
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>
29
30 #include <new>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <pthread.h>
34
35
36 using namespace std;
37
38 const float kUninitializedAscent = INFINITY;
39 const uint32 kUninitializedExtraFlags = 0xffffffff;
40
41 // The actual objects which the globals point to
42 static BFont sPlainFont;
43 static BFont sBoldFont;
44 static BFont sFixedFont;
45
46 const BFont* be_plain_font = &sPlainFont;
47 const BFont* be_bold_font = &sBoldFont;
48 const BFont* be_fixed_font = &sFixedFont;
49
50
51 struct style {
52 BString name;
53 uint16 face;
54 uint32 flags;
55 };
56
57 struct family {
58 BString name;
59 uint32 flags;
60 BObjectList<style> styles;
61 };
62
63 namespace {
64
65 class FontList : public BLocker {
66 public:
67 FontList();
68 virtual ~FontList();
69
70 static FontList* Default();
71
72 bool UpdatedOnServer();
73
74 status_t FamilyAt(int32 index, font_family* _family,
75 uint32* _flags);
76 status_t StyleAt(font_family family, int32 index,
77 font_style* _style, uint16* _face,
78 uint32* _flags);
79
80 int32 CountFamilies();
81 int32 CountStyles(font_family family);
82
83 private:
84 status_t _UpdateIfNecessary();
85 status_t _Update();
86 uint32 _RevisionOnServer();
87 family* _FindFamily(font_family name);
88 static void _InitSingleton();
89
90 private:
91 BObjectList<family> fFamilies;
92 family* fLastFamily;
93 bigtime_t fLastUpdate;
94 uint32 fRevision;
95
96 static pthread_once_t sDefaultInitOnce;
97 static FontList* sDefaultInstance;
98 };
99
100 pthread_once_t FontList::sDefaultInitOnce = PTHREAD_ONCE_INIT;
101 FontList* FontList::sDefaultInstance = NULL;
102
103 } // unnamed namespace
104
105
106 // #pragma mark -
107
108
109 static int
compare_families(const family * a,const family * b)110 compare_families(const family* a, const family* b)
111 {
112 // TODO: compare font names according to the user's locale settings
113 return strcmp(a->name.String(), b->name.String());
114 }
115
116
117 namespace {
118
FontList()119 FontList::FontList()
120 : BLocker("font list"),
121 fLastFamily(NULL),
122 fLastUpdate(0),
123 fRevision(0)
124 {
125 }
126
127
~FontList()128 FontList::~FontList()
129 {
130 }
131
132
133 /*static*/ FontList*
Default()134 FontList::Default()
135 {
136 if (sDefaultInstance == NULL)
137 pthread_once(&sDefaultInitOnce, &_InitSingleton);
138
139 return sDefaultInstance;
140 }
141
142
143 bool
UpdatedOnServer()144 FontList::UpdatedOnServer()
145 {
146 return _RevisionOnServer() != fRevision;
147 }
148
149
150 status_t
FamilyAt(int32 index,font_family * _family,uint32 * _flags)151 FontList::FamilyAt(int32 index, font_family* _family, uint32* _flags)
152 {
153 BAutolock locker(this);
154
155 status_t status = _UpdateIfNecessary();
156 if (status < B_OK)
157 return status;
158
159 ::family* family = fFamilies.ItemAt(index);
160 if (family == NULL)
161 return B_BAD_VALUE;
162
163 memcpy(*_family, family->name.String(), family->name.Length() + 1);
164 if (_flags)
165 *_flags = family->flags;
166 return B_OK;
167 }
168
169
170 status_t
StyleAt(font_family familyName,int32 index,font_style * _style,uint16 * _face,uint32 * _flags)171 FontList::StyleAt(font_family familyName, int32 index, font_style* _style,
172 uint16* _face, uint32* _flags)
173 {
174 BAutolock locker(this);
175
176 status_t status = _UpdateIfNecessary();
177 if (status < B_OK)
178 return status;
179
180 ::family* family = _FindFamily(familyName);
181 if (family == NULL)
182 return B_BAD_VALUE;
183
184 ::style* style = family->styles.ItemAt(index);
185 if (style == NULL)
186 return B_BAD_VALUE;
187
188 memcpy(*_style, style->name.String(), style->name.Length() + 1);
189 if (_face)
190 *_face = style->face;
191 if (_flags)
192 *_flags = style->flags;
193 return B_OK;
194 }
195
196
197 int32
CountFamilies()198 FontList::CountFamilies()
199 {
200 BAutolock locker(this);
201
202 _UpdateIfNecessary();
203 return fFamilies.CountItems();
204 }
205
206
207 int32
CountStyles(font_family familyName)208 FontList::CountStyles(font_family familyName)
209 {
210 BAutolock locker(this);
211
212 _UpdateIfNecessary();
213
214 ::family* family = _FindFamily(familyName);
215 if (family == NULL)
216 return 0;
217
218 return family->styles.CountItems();
219 }
220
221
222 status_t
_Update()223 FontList::_Update()
224 {
225 // check version
226
227 uint32 revision = _RevisionOnServer();
228 fLastUpdate = system_time();
229
230 // are we up-to-date already?
231 if (revision == fRevision)
232 return B_OK;
233
234 fFamilies.MakeEmpty();
235 fLastFamily = NULL;
236
237 BPrivate::AppServerLink link;
238
239 for (int32 index = 0;; index++) {
240 link.StartMessage(AS_GET_FAMILY_AND_STYLES);
241 link.Attach<int32>(index);
242
243 int32 status;
244 if (link.FlushWithReply(status) != B_OK
245 || status != B_OK)
246 break;
247
248 ::family* family = new (nothrow) ::family;
249 if (family == NULL)
250 return B_NO_MEMORY;
251
252 link.ReadString(family->name);
253 link.Read<uint32>(&family->flags);
254
255 int32 styleCount;
256 link.Read<int32>(&styleCount);
257
258 for (int32 i = 0; i < styleCount; i++) {
259 ::style* style = new (nothrow) ::style;
260 if (style == NULL) {
261 delete family;
262 return B_NO_MEMORY;
263 }
264
265 link.ReadString(style->name);
266 link.Read<uint16>(&style->face);
267 link.Read<uint32>(&style->flags);
268
269 family->styles.AddItem(style);
270 }
271
272 fFamilies.BinaryInsert(family, compare_families);
273 }
274
275 fRevision = revision;
276
277 // if the font list has been changed in the mean time, just update again
278 if (UpdatedOnServer())
279 _Update();
280
281 return B_OK;
282 }
283
284
285 status_t
_UpdateIfNecessary()286 FontList::_UpdateIfNecessary()
287 {
288 // an updated font list is at least valid for 1 second
289 if (fLastUpdate > system_time() - 1000000)
290 return B_OK;
291
292 return _Update();
293 }
294
295
296 uint32
_RevisionOnServer()297 FontList::_RevisionOnServer()
298 {
299 BPrivate::AppServerLink link;
300 link.StartMessage(AS_GET_FONT_LIST_REVISION);
301
302 int32 code;
303 if (link.FlushWithReply(code) != B_OK || code != B_OK) {
304 // Go on as if our list is up to date. If it is a one-time thing
305 // we'll try again soon. If it isn't, we have a bigger problem.
306 return fRevision;
307 }
308
309 uint32 revision;
310 link.Read<uint32>(&revision);
311
312 return revision;
313 }
314
315
316 family*
_FindFamily(font_family name)317 FontList::_FindFamily(font_family name)
318 {
319 if (fLastFamily != NULL && fLastFamily->name == name)
320 return fLastFamily;
321
322 ::family family;
323 family.name = name;
324 fLastFamily = const_cast< ::family*>(fFamilies.BinarySearch(family,
325 compare_families));
326 return fLastFamily;
327 }
328
329
330 /*static*/ void
_InitSingleton()331 FontList::_InitSingleton()
332 {
333 sDefaultInstance = new FontList;
334 }
335
336 } // unnamed namespace
337
338
339 // #pragma mark -
340
341
342 void
_init_global_fonts_()343 _init_global_fonts_()
344 {
345 BPrivate::AppServerLink link;
346 link.StartMessage(AS_GET_SYSTEM_FONTS);
347
348 int32 code;
349 if (link.FlushWithReply(code) != B_OK
350 || code != B_OK) {
351 printf("DEBUG: Couldn't initialize global fonts!\n");
352 return;
353 }
354
355 char type[B_OS_NAME_LENGTH];
356
357 while (link.ReadString(type, sizeof(type)) >= B_OK && type[0]) {
358 BFont dummy;
359 BFont* font = &dummy;
360
361 if (!strcmp(type, "plain"))
362 font = &sPlainFont;
363 else if (!strcmp(type, "bold"))
364 font = &sBoldFont;
365 else if (!strcmp(type, "fixed"))
366 font = &sFixedFont;
367
368 link.Read<uint16>(&font->fFamilyID);
369 link.Read<uint16>(&font->fStyleID);
370 link.Read<float>(&font->fSize);
371 link.Read<uint16>(&font->fFace);
372 link.Read<uint32>(&font->fFlags);
373
374 font->fHeight.ascent = kUninitializedAscent;
375 font->fExtraFlags = kUninitializedExtraFlags;
376 }
377 }
378
379
380 void
_font_control_(BFont * font,int32 cmd,void * data)381 _font_control_(BFont* font, int32 cmd, void* data)
382 {
383 }
384
385
386 status_t
get_font_cache_info(uint32 id,void * set)387 get_font_cache_info(uint32 id, void* set)
388 {
389 return B_ERROR;
390 }
391
392
393 status_t
set_font_cache_info(uint32 id,void * set)394 set_font_cache_info(uint32 id, void* set)
395 {
396 return B_ERROR;
397 }
398
399
400 // Private function used to replace the R5 hack which sets a system font
401 void
_set_system_font_(const char * which,font_family family,font_style style,float size)402 _set_system_font_(const char* which, font_family family, font_style style,
403 float size)
404 {
405 // R5 used a global area offset table to set the system fonts in the Font
406 // preferences panel. Bleah.
407 BPrivate::AppServerLink link;
408
409 link.StartMessage(AS_SET_SYSTEM_FONT);
410 link.AttachString(which, B_OS_NAME_LENGTH);
411 link.AttachString(family, sizeof(font_family));
412 link.AttachString(style, sizeof(font_style));
413 link.Attach<float>(size);
414 link.Flush();
415 }
416
417
418 status_t
_get_system_default_font_(const char * which,font_family family,font_style style,float * _size)419 _get_system_default_font_(const char* which, font_family family,
420 font_style style, float* _size)
421 {
422 BPrivate::AppServerLink link;
423
424 link.StartMessage(AS_GET_SYSTEM_DEFAULT_FONT);
425 link.AttachString(which, B_OS_NAME_LENGTH);
426
427 int32 status = B_ERROR;
428 if (link.FlushWithReply(status) != B_OK
429 || status < B_OK)
430 return status;
431
432 link.ReadString(family, sizeof(font_family));
433 link.ReadString(style, sizeof(font_style));
434 link.Read<float>(_size);
435 return B_OK;
436 }
437
438
439 // Returns the number of installed font families
440 int32
count_font_families()441 count_font_families()
442 {
443 return FontList::Default()->CountFamilies();
444 }
445
446
447 // Returns the number of styles available for a font family
448 int32
count_font_styles(font_family family)449 count_font_styles(font_family family)
450 {
451 return FontList::Default()->CountStyles(family);
452 }
453
454
455 // Retrieves the family name at the specified index
456 status_t
get_font_family(int32 index,font_family * _name,uint32 * _flags)457 get_font_family(int32 index, font_family* _name, uint32* _flags)
458 {
459 if (_name == NULL)
460 return B_BAD_VALUE;
461
462 return FontList::Default()->FamilyAt(index, _name, _flags);
463 }
464
465
466 // Retrieves the family name at the specified index
467 status_t
get_font_style(font_family family,int32 index,font_style * _name,uint32 * _flags)468 get_font_style(font_family family, int32 index, font_style* _name,
469 uint32* _flags)
470 {
471 return get_font_style(family, index, _name, NULL, _flags);
472 }
473
474
475 // Retrieves the family name at the specified index
476 status_t
get_font_style(font_family family,int32 index,font_style * _name,uint16 * _face,uint32 * _flags)477 get_font_style(font_family family, int32 index, font_style* _name,
478 uint16* _face, uint32* _flags)
479 {
480 // The face value returned by this function is not very reliable. At the
481 // same time, the value returned should be fairly reliable, returning the
482 // proper flag for 90%-99% of font names.
483
484 if (_name == NULL)
485 return B_BAD_VALUE;
486
487 return FontList::Default()->StyleAt(family, index, _name, _face, _flags);
488 }
489
490
491 // Updates the font family list
492 bool
update_font_families(bool)493 update_font_families(bool /*checkOnly*/)
494 {
495 return FontList::Default()->UpdatedOnServer();
496 }
497
498
499 // #pragma mark -
500
501
BFont()502 BFont::BFont()
503 :
504 // initialise for be_plain_font (avoid circular definition)
505 fFamilyID(0),
506 fStyleID(0),
507 fSize(10.0),
508 fShear(90.0),
509 fRotation(0.0),
510 fFalseBoldWidth(0.0),
511 fSpacing(B_BITMAP_SPACING),
512 fEncoding(B_UNICODE_UTF8),
513 fFace(0),
514 fFlags(0),
515 fExtraFlags(kUninitializedExtraFlags)
516 {
517 if (be_plain_font != NULL && this != &sPlainFont)
518 *this = *be_plain_font;
519 else {
520 fHeight.ascent = 7.0;
521 fHeight.descent = 2.0;
522 fHeight.leading = 13.0;
523 }
524 }
525
526
BFont(const BFont & font)527 BFont::BFont(const BFont& font)
528 {
529 *this = font;
530 }
531
532
BFont(const BFont * font)533 BFont::BFont(const BFont* font)
534 {
535 if (font != NULL)
536 *this = *font;
537 else
538 *this = *be_plain_font;
539 }
540
541
542 // Sets the font's family and style all at once
543 status_t
SetFamilyAndStyle(const font_family family,const font_style style)544 BFont::SetFamilyAndStyle(const font_family family, const font_style style)
545 {
546 if (family == NULL && style == NULL)
547 return B_BAD_VALUE;
548
549 BPrivate::AppServerLink link;
550
551 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS);
552 link.AttachString(family, sizeof(font_family));
553 link.AttachString(style, sizeof(font_style));
554 link.Attach<uint16>(fFamilyID);
555 link.Attach<uint16>(0xffff);
556 link.Attach<uint16>(fFace);
557
558 int32 status = B_ERROR;
559 if (link.FlushWithReply(status) != B_OK || status != B_OK)
560 return status;
561
562 link.Read<uint16>(&fFamilyID);
563 link.Read<uint16>(&fStyleID);
564 link.Read<uint16>(&fFace);
565
566 fHeight.ascent = kUninitializedAscent;
567 fExtraFlags = kUninitializedExtraFlags;
568
569 return B_OK;
570 }
571
572
573 // Sets the font's family and style all at once
574 void
SetFamilyAndStyle(uint32 code)575 BFont::SetFamilyAndStyle(uint32 code)
576 {
577 // R5 has a bug here: the face is not updated even though the IDs are set.
578 // This is a problem because the face flag includes Regular/Bold/Italic
579 // information in addition to stuff like underlining and strikethrough.
580 // As a result, this will need a trip to the server and, thus, be slower
581 // than R5's in order to be correct
582
583 uint16 family, style;
584 style = code & 0xFFFF;
585 family = (code & 0xFFFF0000) >> 16;
586
587 BPrivate::AppServerLink link;
588 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS);
589 link.AttachString(NULL); // no family and style name
590 link.AttachString(NULL);
591 link.Attach<uint16>(family);
592 link.Attach<uint16>(style);
593 link.Attach<uint16>(fFace);
594
595 int32 fontcode;
596 if (link.FlushWithReply(fontcode) != B_OK || fontcode != B_OK)
597 return;
598
599 link.Read<uint16>(&fFamilyID);
600 link.Read<uint16>(&fStyleID);
601 link.Read<uint16>(&fFace);
602 fHeight.ascent = kUninitializedAscent;
603 fExtraFlags = kUninitializedExtraFlags;
604 }
605
606
607 // Sets the font's family and face all at once
608 status_t
SetFamilyAndFace(const font_family family,uint16 face)609 BFont::SetFamilyAndFace(const font_family family, uint16 face)
610 {
611 // To comply with the BeBook, this function will only set valid values
612 // i.e. passing a nonexistent family will cause only the face to be set.
613 // Additionally, if a particular face does not exist in a family, the
614 // closest match will be chosen.
615
616 BPrivate::AppServerLink link;
617 link.StartMessage(AS_GET_FAMILY_AND_STYLE_IDS);
618 link.AttachString(family, sizeof(font_family));
619 link.AttachString(NULL); // no style given
620 link.Attach<uint16>(fFamilyID);
621 link.Attach<uint16>(0xffff);
622 link.Attach<uint16>(face);
623
624 int32 status = B_ERROR;
625 if (link.FlushWithReply(status) != B_OK || status != B_OK)
626 return status;
627
628 link.Read<uint16>(&fFamilyID);
629 link.Read<uint16>(&fStyleID);
630 link.Read<uint16>(&fFace);
631 fHeight.ascent = kUninitializedAscent;
632 fExtraFlags = kUninitializedExtraFlags;
633
634 return B_OK;
635 }
636
637
638 void
SetSize(float size)639 BFont::SetSize(float size)
640 {
641 fSize = size;
642 fHeight.ascent = kUninitializedAscent;
643 }
644
645
646 void
SetShear(float shear)647 BFont::SetShear(float shear)
648 {
649 fShear = shear;
650 fHeight.ascent = kUninitializedAscent;
651 }
652
653
654 void
SetRotation(float rotation)655 BFont::SetRotation(float rotation)
656 {
657 fRotation = rotation;
658 fHeight.ascent = kUninitializedAscent;
659 }
660
661
662 void
SetFalseBoldWidth(float width)663 BFont::SetFalseBoldWidth(float width)
664 {
665 fFalseBoldWidth = width;
666 }
667
668
669 void
SetSpacing(uint8 spacing)670 BFont::SetSpacing(uint8 spacing)
671 {
672 fSpacing = spacing;
673 }
674
675
676 void
SetEncoding(uint8 encoding)677 BFont::SetEncoding(uint8 encoding)
678 {
679 fEncoding = encoding;
680 }
681
682
683 void
SetFace(uint16 face)684 BFont::SetFace(uint16 face)
685 {
686 if (face == fFace)
687 return;
688
689 SetFamilyAndFace(NULL, face);
690 }
691
692
693 void
SetFlags(uint32 flags)694 BFont::SetFlags(uint32 flags)
695 {
696 fFlags = flags;
697 }
698
699
700 void
GetFamilyAndStyle(font_family * family,font_style * style) const701 BFont::GetFamilyAndStyle(font_family* family, font_style* style) const
702 {
703 if (family == NULL && style == NULL)
704 return;
705
706 // it's okay to call this function with either family or style set to NULL
707
708 font_family familyBuffer;
709 font_style styleBuffer;
710
711 if (family == NULL)
712 family = &familyBuffer;
713 if (style == NULL)
714 style = &styleBuffer;
715
716 BPrivate::AppServerLink link;
717 link.StartMessage(AS_GET_FAMILY_AND_STYLE);
718 link.Attach<uint16>(fFamilyID);
719 link.Attach<uint16>(fStyleID);
720
721 int32 code;
722 if (link.FlushWithReply(code) != B_OK || code != B_OK) {
723 // the least we can do is to clear the buffers
724 memset(*family, 0, sizeof(font_family));
725 memset(*style, 0, sizeof(font_style));
726 return;
727 }
728
729 link.ReadString(*family, sizeof(font_family));
730 link.ReadString(*style, sizeof(font_style));
731 }
732
733
734 uint32
FamilyAndStyle() const735 BFont::FamilyAndStyle() const
736 {
737 return (fFamilyID << 16UL) | fStyleID;
738 }
739
740
741 float
Size() const742 BFont::Size() const
743 {
744 return fSize;
745 }
746
747
748 float
Shear() const749 BFont::Shear() const
750 {
751 return fShear;
752 }
753
754
755 float
Rotation() const756 BFont::Rotation() const
757 {
758 return fRotation;
759 }
760
761
762 float
FalseBoldWidth() const763 BFont::FalseBoldWidth() const
764 {
765 return fFalseBoldWidth;
766 }
767
768
769 uint8
Spacing() const770 BFont::Spacing() const
771 {
772 return fSpacing;
773 }
774
775
776 uint8
Encoding() const777 BFont::Encoding() const
778 {
779 return fEncoding;
780 }
781
782
783 uint16
Face() const784 BFont::Face() const
785 {
786 return fFace;
787 }
788
789
790 uint32
Flags() const791 BFont::Flags() const
792 {
793 return fFlags;
794 }
795
796
797 font_direction
Direction() const798 BFont::Direction() const
799 {
800 _GetExtraFlags();
801 return (font_direction)(fExtraFlags >> B_PRIVATE_FONT_DIRECTION_SHIFT);
802 }
803
804
805 bool
IsFixed() const806 BFont::IsFixed() const
807 {
808 _GetExtraFlags();
809 return (fExtraFlags & B_IS_FIXED) != 0;
810 }
811
812
813 // Returns whether or not the font is fixed-width and contains both
814 // full and half-width characters.
815 bool
IsFullAndHalfFixed() const816 BFont::IsFullAndHalfFixed() const
817 {
818 // This was left unimplemented as of R5. It is a way to work with both
819 // Kanji and Roman characters in the same fixed-width font.
820
821 _GetExtraFlags();
822 return (fExtraFlags & B_PRIVATE_FONT_IS_FULL_AND_HALF_FIXED) != 0;
823 }
824
825
826 BRect
BoundingBox() const827 BFont::BoundingBox() const
828 {
829 BPrivate::AppServerLink link;
830 link.StartMessage(AS_GET_FONT_BOUNDING_BOX);
831 link.Attach<uint16>(fFamilyID);
832 link.Attach<uint16>(fStyleID);
833 link.Attach<float>(fSize);
834
835 int32 code;
836 if (link.FlushWithReply(code) != B_OK
837 || code != B_OK)
838 return BRect(0, 0, 0 ,0);
839
840 BRect box;
841 link.Read<BRect>(&box);
842 return box;
843 }
844
845
846 unicode_block
Blocks() const847 BFont::Blocks() const
848 {
849 BPrivate::AppServerLink link;
850 link.StartMessage(AS_GET_UNICODE_BLOCKS);
851 link.Attach<uint16>(fFamilyID);
852 link.Attach<uint16>(fStyleID);
853
854 int32 status;
855 if (link.FlushWithReply(status) != B_OK
856 || status != B_OK) {
857 return unicode_block(~0LL, ~0LL);
858 }
859
860 unicode_block blocksForFont;
861 link.Read<unicode_block>(&blocksForFont);
862
863 return blocksForFont;
864 }
865
866 bool
IncludesBlock(uint32 start,uint32 end) const867 BFont::IncludesBlock(uint32 start, uint32 end) const
868 {
869 BPrivate::AppServerLink link;
870 link.StartMessage(AS_GET_HAS_UNICODE_BLOCK);
871 link.Attach<uint16>(fFamilyID);
872 link.Attach<uint16>(fStyleID);
873 link.Attach<uint32>(start);
874 link.Attach<uint32>(end);
875
876 int32 status;
877 if (link.FlushWithReply(status) != B_OK
878 || status != B_OK) {
879 return false;
880 }
881
882 bool hasBlock;
883 link.Read<bool>(&hasBlock);
884
885 return hasBlock;
886 }
887
888
889 font_file_format
FileFormat() const890 BFont::FileFormat() const
891 {
892 BPrivate::AppServerLink link;
893 link.StartMessage(AS_GET_FONT_FILE_FORMAT);
894 link.Attach<uint16>(fFamilyID);
895 link.Attach<uint16>(fStyleID);
896
897 int32 status;
898 if (link.FlushWithReply(status) != B_OK
899 || status != B_OK) {
900 // just take a safe bet...
901 return B_TRUETYPE_WINDOWS;
902 }
903
904 uint16 format;
905 link.Read<uint16>(&format);
906
907 return (font_file_format)format;
908 }
909
910
911 int32
CountTuned() const912 BFont::CountTuned() const
913 {
914 BPrivate::AppServerLink link;
915 link.StartMessage(AS_GET_TUNED_COUNT);
916 link.Attach<uint16>(fFamilyID);
917 link.Attach<uint16>(fStyleID);
918
919 int32 code;
920 if (link.FlushWithReply(code) != B_OK
921 || code != B_OK)
922 return -1;
923
924 int32 count;
925 link.Read<int32>(&count);
926 return count;
927 }
928
929
930 void
GetTunedInfo(int32 index,tuned_font_info * info) const931 BFont::GetTunedInfo(int32 index, tuned_font_info* info) const
932 {
933 if (info == NULL)
934 return;
935
936 BPrivate::AppServerLink link;
937 link.StartMessage(AS_GET_TUNED_INFO);
938 link.Attach<uint16>(fFamilyID);
939 link.Attach<uint16>(fStyleID);
940 link.Attach<uint32>(index);
941
942 int32 code;
943 if (link.FlushWithReply(code) != B_OK || code != B_OK)
944 return;
945
946 link.Read<tuned_font_info>(info);
947 }
948
949
950 // Truncates a string to a given _pixel_ width based on the font and size
951 void
TruncateString(BString * inOut,uint32 mode,float width) const952 BFont::TruncateString(BString* inOut, uint32 mode, float width) const
953 {
954 if (mode == B_NO_TRUNCATION)
955 return;
956
957 // NOTE: Careful, we cannot directly use "inOut->String()" as result
958 // array, because the string length increases by 3 bytes in the worst
959 // case scenario.
960 const char* string = inOut->String();
961 GetTruncatedStrings(&string, 1, mode, width, inOut);
962 }
963
964
965 void
GetTruncatedStrings(const char * stringArray[],int32 numStrings,uint32 mode,float width,BString resultArray[]) const966 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings,
967 uint32 mode, float width, BString resultArray[]) const
968 {
969 if (stringArray != NULL && numStrings > 0) {
970 // the width of the "…" glyph
971 float ellipsisWidth = StringWidth(B_UTF8_ELLIPSIS);
972
973 for (int32 i = 0; i < numStrings; i++) {
974 resultArray[i] = stringArray[i];
975 int32 numChars = resultArray[i].CountChars();
976
977 // get the escapement of each glyph in font units
978 float* escapementArray = new float[numChars];
979 GetEscapements(stringArray[i], numChars, NULL, escapementArray);
980
981 truncate_string(resultArray[i], mode, width, escapementArray,
982 fSize, ellipsisWidth, numChars);
983
984 delete[] escapementArray;
985 }
986 }
987 }
988
989
990 void
GetTruncatedStrings(const char * stringArray[],int32 numStrings,uint32 mode,float width,char * resultArray[]) const991 BFont::GetTruncatedStrings(const char* stringArray[], int32 numStrings,
992 uint32 mode, float width, char* resultArray[]) const
993 {
994 if (stringArray != NULL && numStrings > 0) {
995 for (int32 i = 0; i < numStrings; i++) {
996 BString* strings = new BString[numStrings];
997 GetTruncatedStrings(stringArray, numStrings, mode, width, strings);
998
999 for (int32 i = 0; i < numStrings; i++)
1000 strcpy(resultArray[i], strings[i].String());
1001
1002 delete[] strings;
1003 }
1004 }
1005 }
1006
1007
1008 float
StringWidth(const char * string) const1009 BFont::StringWidth(const char* string) const
1010 {
1011 if (string == NULL)
1012 return 0.0;
1013
1014 int32 length = strlen(string);
1015 float width;
1016 GetStringWidths(&string, &length, 1, &width);
1017
1018 return width;
1019 }
1020
1021
1022 float
StringWidth(const char * string,int32 length) const1023 BFont::StringWidth(const char* string, int32 length) const
1024 {
1025 if (!string || length < 1)
1026 return 0.0f;
1027
1028 float width = 0.0f;
1029 GetStringWidths(&string, &length, 1, &width);
1030
1031 return width;
1032 }
1033
1034
1035 void
GetStringWidths(const char * stringArray[],const int32 lengthArray[],int32 numStrings,float widthArray[]) const1036 BFont::GetStringWidths(const char* stringArray[], const int32 lengthArray[],
1037 int32 numStrings, float widthArray[]) const
1038 {
1039 if (stringArray == NULL || lengthArray == NULL || numStrings < 1
1040 || widthArray == NULL) {
1041 return;
1042 }
1043
1044 BPrivate::AppServerLink link;
1045 link.StartMessage(AS_GET_STRING_WIDTHS);
1046 link.Attach<uint16>(fFamilyID);
1047 link.Attach<uint16>(fStyleID);
1048 link.Attach<float>(fSize);
1049 link.Attach<uint8>(fSpacing);
1050 link.Attach<int32>(numStrings);
1051
1052 // TODO: all strings into a single array???
1053 // we do have a maximum message length, and it could be easily touched
1054 // here...
1055 for (int32 i = 0; i < numStrings; i++)
1056 link.AttachString(stringArray[i], lengthArray[i]);
1057
1058 status_t status;
1059 if (link.FlushWithReply(status) != B_OK || status != B_OK)
1060 return;
1061
1062 link.Read(widthArray, sizeof(float) * numStrings);
1063 }
1064
1065
1066 void
GetEscapements(const char charArray[],int32 numChars,float escapementArray[]) const1067 BFont::GetEscapements(const char charArray[], int32 numChars,
1068 float escapementArray[]) const
1069 {
1070 GetEscapements(charArray, numChars, NULL, escapementArray);
1071 }
1072
1073
1074 void
GetEscapements(const char charArray[],int32 numChars,escapement_delta * delta,float escapementArray[]) const1075 BFont::GetEscapements(const char charArray[], int32 numChars,
1076 escapement_delta* delta, float escapementArray[]) const
1077 {
1078 if (charArray == NULL || numChars < 1 || escapementArray == NULL)
1079 return;
1080
1081 BPrivate::AppServerLink link;
1082 link.StartMessage(AS_GET_ESCAPEMENTS_AS_FLOATS);
1083 link.Attach<uint16>(fFamilyID);
1084 link.Attach<uint16>(fStyleID);
1085 link.Attach<float>(fSize);
1086 link.Attach<uint8>(fSpacing);
1087 link.Attach<float>(fRotation);
1088 link.Attach<uint32>(fFlags);
1089
1090 link.Attach<float>(delta ? delta->nonspace : 0.0f);
1091 link.Attach<float>(delta ? delta->space : 0.0f);
1092 link.Attach<int32>(numChars);
1093
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);
1098
1099 int32 code;
1100 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1101 return;
1102
1103 link.Read(escapementArray, numChars * sizeof(float));
1104 }
1105
1106
1107 void
GetEscapements(const char charArray[],int32 numChars,escapement_delta * delta,BPoint escapementArray[]) const1108 BFont::GetEscapements(const char charArray[], int32 numChars,
1109 escapement_delta* delta, BPoint escapementArray[]) const
1110 {
1111 GetEscapements(charArray, numChars, delta, escapementArray, NULL);
1112 }
1113
1114
1115 void
GetEscapements(const char charArray[],int32 numChars,escapement_delta * delta,BPoint escapementArray[],BPoint offsetArray[]) const1116 BFont::GetEscapements(const char charArray[], int32 numChars,
1117 escapement_delta* delta, BPoint escapementArray[],
1118 BPoint offsetArray[]) const
1119 {
1120 if (charArray == NULL || numChars < 1 || escapementArray == NULL)
1121 return;
1122
1123 BPrivate::AppServerLink link;
1124 link.StartMessage(AS_GET_ESCAPEMENTS);
1125 link.Attach<uint16>(fFamilyID);
1126 link.Attach<uint16>(fStyleID);
1127 link.Attach<float>(fSize);
1128 link.Attach<uint8>(fSpacing);
1129 link.Attach<float>(fRotation);
1130 link.Attach<uint32>(fFlags);
1131
1132 link.Attach<float>(delta ? delta->nonspace : 0.0);
1133 link.Attach<float>(delta ? delta->space : 0.0);
1134 link.Attach<bool>(offsetArray != NULL);
1135 link.Attach<int32>(numChars);
1136
1137 // TODO: Should we not worry about the port capacity here?!?
1138 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1139 link.Attach<int32>(bytesInBuffer);
1140 link.Attach(charArray, bytesInBuffer);
1141
1142 int32 code;
1143 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1144 return;
1145
1146 link.Read(escapementArray, sizeof(BPoint) * numChars);
1147 if (offsetArray)
1148 link.Read(offsetArray, sizeof(BPoint) * numChars);
1149 }
1150
1151
1152 void
GetEdges(const char charArray[],int32 numChars,edge_info edgeArray[]) const1153 BFont::GetEdges(const char charArray[], int32 numChars,
1154 edge_info edgeArray[]) const
1155 {
1156 if (!charArray || numChars < 1 || !edgeArray)
1157 return;
1158
1159 int32 code;
1160 BPrivate::AppServerLink link;
1161
1162 link.StartMessage(AS_GET_EDGES);
1163 link.Attach<uint16>(fFamilyID);
1164 link.Attach<uint16>(fStyleID);
1165 link.Attach<int32>(numChars);
1166
1167 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1168 link.Attach<int32>(bytesInBuffer);
1169 link.Attach(charArray, bytesInBuffer);
1170
1171 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1172 return;
1173
1174 link.Read(edgeArray, sizeof(edge_info) * numChars);
1175 }
1176
1177
1178 void
GetHeight(font_height * _height) const1179 BFont::GetHeight(font_height* _height) const
1180 {
1181 if (_height == NULL)
1182 return;
1183
1184 if (fHeight.ascent == kUninitializedAscent) {
1185 // we don't have the font height cached yet
1186 BPrivate::AppServerLink link;
1187
1188 link.StartMessage(AS_GET_FONT_HEIGHT);
1189 link.Attach<uint16>(fFamilyID);
1190 link.Attach<uint16>(fStyleID);
1191 link.Attach<float>(fSize);
1192
1193 int32 code;
1194 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1195 return;
1196
1197 // Who put that "const" to this method? :-)
1198 // We made fHeight mutable for this, but we should drop the "const"
1199 // when we can
1200 link.Read<font_height>(&fHeight);
1201 }
1202
1203 *_height = fHeight;
1204 }
1205
1206
1207 void
GetBoundingBoxesAsGlyphs(const char charArray[],int32 numChars,font_metric_mode mode,BRect boundingBoxArray[]) const1208 BFont::GetBoundingBoxesAsGlyphs(const char charArray[], int32 numChars,
1209 font_metric_mode mode, BRect boundingBoxArray[]) const
1210 {
1211 _GetBoundingBoxes(charArray, numChars, mode, false, NULL,
1212 boundingBoxArray, false);
1213 }
1214
1215
1216 void
GetBoundingBoxesAsString(const char charArray[],int32 numChars,font_metric_mode mode,escapement_delta * delta,BRect boundingBoxArray[]) const1217 BFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars,
1218 font_metric_mode mode, escapement_delta* delta,
1219 BRect boundingBoxArray[]) const
1220 {
1221 _GetBoundingBoxes(charArray, numChars, mode, true, delta,
1222 boundingBoxArray, true);
1223 }
1224
1225
1226 void
_GetBoundingBoxes(const char charArray[],int32 numChars,font_metric_mode mode,bool string_escapement,escapement_delta * delta,BRect boundingBoxArray[],bool asString) const1227 BFont::_GetBoundingBoxes(const char charArray[], int32 numChars,
1228 font_metric_mode mode, bool string_escapement, escapement_delta* delta,
1229 BRect boundingBoxArray[], bool asString) const
1230 {
1231 if (charArray == NULL || numChars < 1 || boundingBoxArray == NULL)
1232 return;
1233
1234 int32 code;
1235 BPrivate::AppServerLink link;
1236
1237 link.StartMessage(asString
1238 ? AS_GET_BOUNDINGBOXES_STRING : AS_GET_BOUNDINGBOXES_CHARS);
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
1247 link.Attach<uint32>(fFlags);
1248 link.Attach<font_metric_mode>(mode);
1249 link.Attach<bool>(string_escapement);
1250
1251 if (delta != NULL) {
1252 link.Attach<escapement_delta>(*delta);
1253 } else {
1254 escapement_delta emptyDelta = {0, 0};
1255 link.Attach<escapement_delta>(emptyDelta);
1256 }
1257
1258 link.Attach<int32>(numChars);
1259 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1260 link.Attach<int32>(bytesInBuffer);
1261 link.Attach(charArray, bytesInBuffer);
1262
1263 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1264 return;
1265
1266 link.Read(boundingBoxArray, sizeof(BRect) * numChars);
1267 }
1268
1269
1270 void
GetBoundingBoxesForStrings(const char * stringArray[],int32 numStrings,font_metric_mode mode,escapement_delta deltas[],BRect boundingBoxArray[]) const1271 BFont::GetBoundingBoxesForStrings(const char* stringArray[], int32 numStrings,
1272 font_metric_mode mode, escapement_delta deltas[],
1273 BRect boundingBoxArray[]) const
1274 {
1275 if (!stringArray || numStrings < 1 || !boundingBoxArray)
1276 return;
1277
1278 int32 code;
1279 BPrivate::AppServerLink link;
1280
1281 link.StartMessage(AS_GET_BOUNDINGBOXES_STRINGS);
1282 link.Attach<uint16>(fFamilyID);
1283 link.Attach<uint16>(fStyleID);
1284 link.Attach<float>(fSize);
1285 link.Attach<float>(fRotation);
1286 link.Attach<float>(fShear);
1287 link.Attach<float>(fFalseBoldWidth);
1288 link.Attach<uint8>(fSpacing);
1289 link.Attach<uint32>(fFlags);
1290 link.Attach<font_metric_mode>(mode);
1291 link.Attach<int32>(numStrings);
1292
1293 if (deltas) {
1294 for (int32 i = 0; i < numStrings; i++) {
1295 link.AttachString(stringArray[i]);
1296 link.Attach<escapement_delta>(deltas[i]);
1297 }
1298 } else {
1299 escapement_delta emptyDelta = {0, 0};
1300
1301 for (int32 i = 0; i < numStrings; i++) {
1302 link.AttachString(stringArray[i]);
1303 link.Attach<escapement_delta>(emptyDelta);
1304 }
1305 }
1306
1307 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1308 return;
1309
1310 link.Read(boundingBoxArray, sizeof(BRect) * numStrings);
1311 }
1312
1313
1314 void
GetGlyphShapes(const char charArray[],int32 numChars,BShape * glyphShapeArray[]) const1315 BFont::GetGlyphShapes(const char charArray[], int32 numChars,
1316 BShape* glyphShapeArray[]) const
1317 {
1318 // TODO: implement code specifically for passing BShapes to and
1319 // from the server
1320 if (!charArray || numChars < 1 || !glyphShapeArray)
1321 return;
1322
1323 int32 code;
1324 BPrivate::AppServerLink link;
1325
1326 link.StartMessage(AS_GET_GLYPH_SHAPES);
1327 link.Attach<uint16>(fFamilyID);
1328 link.Attach<uint16>(fStyleID);
1329 link.Attach<float>(fSize);
1330 link.Attach<float>(fShear);
1331 link.Attach<float>(fRotation);
1332 link.Attach<float>(fFalseBoldWidth);
1333 link.Attach<uint32>(fFlags);
1334 link.Attach<int32>(numChars);
1335
1336 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1337 link.Attach<int32>(bytesInBuffer);
1338 link.Attach(charArray, bytesInBuffer);
1339
1340 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1341 return;
1342
1343 for (int32 i = 0; i < numChars; i++)
1344 link.ReadShape(glyphShapeArray[i]);
1345 }
1346
1347
1348 void
GetHasGlyphs(const char charArray[],int32 numChars,bool hasArray[]) const1349 BFont::GetHasGlyphs(const char charArray[], int32 numChars,
1350 bool hasArray[]) const
1351 {
1352 GetHasGlyphs(charArray, numChars, hasArray, true);
1353 }
1354
1355
1356 void
GetHasGlyphs(const char charArray[],int32 numChars,bool hasArray[],bool useFallbacks) const1357 BFont::GetHasGlyphs(const char charArray[], int32 numChars, bool hasArray[],
1358 bool useFallbacks) const
1359 {
1360 if (!charArray || numChars < 1 || !hasArray)
1361 return;
1362
1363 int32 code;
1364 BPrivate::AppServerLink link;
1365
1366 link.StartMessage(AS_GET_HAS_GLYPHS);
1367 link.Attach<uint16>(fFamilyID);
1368 link.Attach<uint16>(fStyleID);
1369 link.Attach<int32>(numChars);
1370
1371 uint32 bytesInBuffer = UTF8CountBytes(charArray, numChars);
1372 link.Attach<int32>(bytesInBuffer);
1373 link.Attach(charArray, bytesInBuffer);
1374
1375 link.Attach<bool>(useFallbacks);
1376
1377 if (link.FlushWithReply(code) != B_OK || code != B_OK)
1378 return;
1379
1380 link.Read(hasArray, sizeof(bool) * numChars);
1381 }
1382
1383
1384 BFont&
operator =(const BFont & font)1385 BFont::operator=(const BFont& font)
1386 {
1387 fFamilyID = font.fFamilyID;
1388 fStyleID = font.fStyleID;
1389 fSize = font.fSize;
1390 fShear = font.fShear;
1391 fRotation = font.fRotation;
1392 fFalseBoldWidth = font.fFalseBoldWidth;
1393 fSpacing = font.fSpacing;
1394 fEncoding = font.fEncoding;
1395 fFace = font.fFace;
1396 fHeight = font.fHeight;
1397 fFlags = font.fFlags;
1398 fExtraFlags = font.fExtraFlags;
1399
1400 return *this;
1401 }
1402
1403
1404 bool
operator ==(const BFont & font) const1405 BFont::operator==(const BFont& font) const
1406 {
1407 return fFamilyID == font.fFamilyID
1408 && fStyleID == font.fStyleID
1409 && fSize == font.fSize
1410 && fShear == font.fShear
1411 && fRotation == font.fRotation
1412 && fFalseBoldWidth == font.fFalseBoldWidth
1413 && fSpacing == font.fSpacing
1414 && fEncoding == font.fEncoding
1415 && fFace == font.fFace;
1416 }
1417
1418
1419 bool
operator !=(const BFont & font) const1420 BFont::operator!=(const BFont& font) const
1421 {
1422 return fFamilyID != font.fFamilyID
1423 || fStyleID != font.fStyleID
1424 || fSize != font.fSize
1425 || fShear != font.fShear
1426 || fRotation != font.fRotation
1427 || fFalseBoldWidth != font.fFalseBoldWidth
1428 || fSpacing != font.fSpacing
1429 || fEncoding != font.fEncoding
1430 || fFace != font.fFace;
1431 }
1432
1433
1434 void
PrintToStream() const1435 BFont::PrintToStream() const
1436 {
1437 font_family family;
1438 font_style style;
1439 GetFamilyAndStyle(&family, &style);
1440
1441 printf("BFont { %s (%d), %s (%d) 0x%x %f/%f %fpt (%f %f %f), %d }\n",
1442 family, fFamilyID, style, fStyleID, fFace, fShear, fRotation, fSize,
1443 fHeight.ascent, fHeight.descent, fHeight.leading, fEncoding);
1444 }
1445
1446
1447 void
_GetExtraFlags() const1448 BFont::_GetExtraFlags() const
1449 {
1450 // TODO: this has to be const in order to allow other font getters to
1451 // stay const as well
1452 if (fExtraFlags != kUninitializedExtraFlags)
1453 return;
1454
1455 BPrivate::AppServerLink link;
1456 link.StartMessage(AS_GET_EXTRA_FONT_FLAGS);
1457 link.Attach<uint16>(fFamilyID);
1458 link.Attach<uint16>(fStyleID);
1459
1460 status_t status = B_ERROR;
1461 if (link.FlushWithReply(status) != B_OK || status != B_OK) {
1462 // use defaut values for the flags
1463 fExtraFlags = (uint32)B_FONT_LEFT_TO_RIGHT
1464 << B_PRIVATE_FONT_DIRECTION_SHIFT;
1465 return;
1466 }
1467
1468 link.Read<uint32>(&fExtraFlags);
1469 }
1470
1471
1472 status_t
LoadFont(const char * path)1473 BFont::LoadFont(const char* path)
1474 {
1475 return LoadFont(path, 0, 0);
1476 }
1477
1478
1479 status_t
LoadFont(const char * path,uint16 index,uint16 instance)1480 BFont::LoadFont(const char* path, uint16 index, uint16 instance)
1481 {
1482 BPrivate::AppServerLink link;
1483 link.StartMessage(AS_ADD_FONT_FILE);
1484 link.AttachString(path);
1485 link.Attach<uint16>(index);
1486 link.Attach<uint16>(instance);
1487 status_t status = B_ERROR;
1488 if (link.FlushWithReply(status) != B_OK || status != B_OK) {
1489 return status;
1490 }
1491
1492 link.Read<uint16>(&fFamilyID);
1493 link.Read<uint16>(&fStyleID);
1494 link.Read<uint16>(&fFace);
1495 fHeight.ascent = kUninitializedAscent;
1496 fExtraFlags = kUninitializedExtraFlags;
1497
1498 return B_OK;
1499 }
1500
1501
1502 status_t
LoadFont(const area_id fontAreaID,size_t size,size_t offset)1503 BFont::LoadFont(const area_id fontAreaID, size_t size, size_t offset)
1504 {
1505 return LoadFont(fontAreaID, size, offset, 0, 0);
1506 }
1507
1508
1509 status_t
LoadFont(const area_id fontAreaID,size_t size,size_t offset,uint16 index,uint16 instance)1510 BFont::LoadFont(const area_id fontAreaID, size_t size, size_t offset, uint16 index, uint16 instance)
1511 {
1512 BPrivate::AppServerLink link;
1513
1514 link.StartMessage(AS_ADD_FONT_MEMORY);
1515
1516 link.Attach<int32>(fontAreaID);
1517 link.Attach<size_t>(size);
1518 link.Attach<size_t>(offset);
1519 link.Attach<uint16>(index);
1520 link.Attach<uint16>(instance);
1521
1522 status_t status = B_ERROR;
1523 if (link.FlushWithReply(status) != B_OK || status != B_OK) {
1524 return status;
1525 }
1526
1527 link.Read<uint16>(&fFamilyID);
1528 link.Read<uint16>(&fStyleID);
1529 link.Read<uint16>(&fFace);
1530 fHeight.ascent = kUninitializedAscent;
1531 fExtraFlags = kUninitializedExtraFlags;
1532
1533 return B_OK;
1534 }
1535
1536
1537 status_t
UnloadFont()1538 BFont::UnloadFont()
1539 {
1540 BPrivate::AppServerLink link;
1541
1542 link.StartMessage(AS_REMOVE_FONT);
1543
1544 link.Attach<uint16>(fFamilyID);
1545 link.Attach<uint16>(fStyleID);
1546
1547 status_t status = B_ERROR;
1548 if (link.FlushWithReply(status) != B_OK || status != B_OK) {
1549 return status;
1550 }
1551
1552 // reset to plain font
1553 fFamilyID = sPlainFont.fFamilyID;
1554 fStyleID = sPlainFont.fStyleID;
1555 fFace = sPlainFont.fFace;
1556 fExtraFlags = sPlainFont.fExtraFlags;
1557
1558 fHeight.ascent = kUninitializedAscent;
1559
1560 return B_OK;
1561 }
1562