xref: /haiku/src/kits/interface/Font.cpp (revision 78d164f7eeb847830d4a02042981832784056e97)
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