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