xref: /haiku/src/kits/interface/Font.cpp (revision 95bac3fda53a4cb21880712d7b43f8c21db32a2e)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2004, Haiku
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		Font.cpp
23 //	Author:			DarkWyrm (bpmagic@columbus.rr.com)
24 //	Description:	Class to manage font-handling capabilities
25 //------------------------------------------------------------------------------
26 #include <Rect.h>
27 #include <stdio.h>
28 #include <Font.h>
29 #include <Message.h>
30 #include <String.h>
31 #include <Shape.h>
32 #include <PortLink.h>
33 #include <AppServerLink.h>
34 #include <stdlib.h>
35 #include <ServerProtocol.h>
36 
37 //----------------------------------------------------------------------------------------
38 //		Globals
39 //----------------------------------------------------------------------------------------
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 extern "C" void
52 _init_global_fonts()
53 {
54 	_font_control_(&sPlainFont,AS_SET_SYSFONT_PLAIN,NULL);
55 	_font_control_(&sBoldFont,AS_SET_SYSFONT_BOLD,NULL);
56 	_font_control_(&sFixedFont,AS_SET_SYSFONT_FIXED,NULL);
57 }
58 
59 
60 /*!
61 	\brief Private function originally used by Be. Now used for initialization
62 	\param font The font to initialize
63 	\param cmd message code to send to the app_server
64 	\param data unused
65 
66 	While it is not known what Be used it for, Haiku uses it to initialize the
67 	three system fonts when the interface kit is initialized when an app starts.
68 */
69 
70 void
71 _font_control_(BFont *font, int32 cmd, void *data)
72 {
73 	if(!font || (cmd!=AS_SET_SYSFONT_PLAIN && cmd!=AS_SET_SYSFONT_BOLD &&
74 				cmd!=AS_SET_SYSFONT_FIXED) )
75 	{
76 		// this shouldn't ever happen, but just in case....
77 		printf("DEBUG: Bad parameters in _font_control_()\n");
78 		return;
79 	}
80 
81 	int32 code;
82 	BPrivate::BAppServerLink link;
83 
84 	link.StartMessage(cmd);
85 	link.FlushWithReply(&code);
86 
87 	if(code!=SERVER_TRUE)
88 	{
89 		// Once again, this shouldn't ever happen, but I want to know about it
90 		// if it does
91 		printf("DEBUG: Couldn't initialize font in _font_control()\n");
92 		return;
93 	}
94 
95 	// there really isn't that much data that we need to set for such cases -- most
96 	// of them need to be set to the defaults. The stuff that can change are family,
97 	// style/face, size, and height.
98 	link.Read<uint16>(&font->fFamilyID);
99 	link.Read<uint16>(&font->fStyleID);
100 	link.Read<float>(&font->fSize);
101 	link.Read<uint16>(&font->fFace);
102 	link.Read<uint32>(&font->fFlags);
103 }
104 
105 
106 /*!
107 	\brief Returns the number of installed font families
108 	\return The number of installed font families
109 */
110 
111 int32
112 count_font_families(void)
113 {
114 	int32 code, count;
115 	BPrivate::BAppServerLink link;
116 
117 	link.StartMessage(AS_COUNT_FONT_FAMILIES);
118 	link.FlushWithReply(&code);
119 
120 	if(code!=SERVER_TRUE)
121 		return -1;
122 
123 	link.Read<int32>(&count);
124 	return count;
125 }
126 
127 
128 /*!
129 	\brief Returns the number of styles available for a font family
130 	\return The number of styles available for a font family
131 */
132 
133 int32
134 count_font_styles(font_family name)
135 {
136 	int32 code, count;
137 	BPrivate::BAppServerLink link;
138 
139 	link.StartMessage(AS_COUNT_FONT_STYLES);
140 	link.FlushWithReply(&code);
141 
142 	if(code!=SERVER_TRUE)
143 		return -1;
144 
145 	link.Read<int32>(&count);
146 	return count;
147 }
148 
149 
150 /*!
151 	\brief Retrieves the family name at the specified index
152 	\param index Unique font identifier code.
153 	\param name font_family string to receive the name of the family
154 	\param flags iF non-NULL, the values of the flags IS_FIXED and B_HAS_TUNED_FONT are returned
155 	\return B_ERROR if the index does not correspond to a font family
156 */
157 
158 status_t
159 get_font_family(int32 index, font_family *name, uint32 *flags)
160 {
161 	// Fix over R5, which does not check for NULL font family names - it just crashes
162 	if(!name)
163 		return B_ERROR;
164 
165 	int32 code;
166 	BPrivate::BAppServerLink link;
167 
168 	link.StartMessage(AS_GET_FAMILY_NAME);
169 	link.Attach<int32>(index);
170 	link.FlushWithReply(&code);
171 
172 	if(code!=SERVER_TRUE)
173 		return B_ERROR;
174 
175 	link.Read<font_family>(name);
176 
177 	if(flags)
178 		link.Read<uint32>(flags);
179 
180 	return B_OK;
181 }
182 
183 
184 /*!
185 	\brief Retrieves the family name at the specified index
186 	\param index Unique font identifier code.
187 	\param name font_family string to receive the name of the family
188 	\param flags iF non-NULL, the values of the flags IS_FIXED and B_HAS_TUNED_FONT are returned
189 	\return B_ERROR if the index does not correspond to a font style
190 */
191 
192 status_t
193 get_font_style(font_family family, int32 index, font_style *name,
194 	uint32 *flags)
195 {
196 	if(!name)
197 		return B_ERROR;
198 
199 	int32 code;
200 	BPrivate::BAppServerLink link;
201 
202 	link.StartMessage(AS_GET_STYLE_NAME);
203 	link.Attach(family,sizeof(font_family));
204 	link.Attach<int32>(index);
205 	link.FlushWithReply(&code);
206 
207 	if(code!=SERVER_TRUE)
208 		return B_ERROR;
209 
210 	link.Read<font_style>(name);
211 	if(flags)
212 	{
213 		uint16 face;
214 		link.Read<uint16>(&face);
215 		link.Read<uint32>(flags);
216 	}
217 	return B_OK;
218 }
219 
220 
221 /*!
222 	\brief Retrieves the family name at the specified index
223 	\param index Unique font identifier code.
224 	\param name font_family string to receive the name of the family
225 	\param face recipient of font face value, such as B_REGULAR_FACE
226 	\param flags iF non-NULL, the values of the flags IS_FIXED and B_HAS_TUNED_FONT are returned
227 	\return B_ERROR if the index does not correspond to a font style
228 
229 	The face value returned by this function is not very reliable. At the same time, the value
230 	returned should be fairly reliable, returning the proper flag for 90%-99% of font names.
231 */
232 
233 status_t
234 get_font_style(font_family family, int32 index, font_style *name,
235 	uint16 *face, uint32 *flags)
236 {
237 	if(!name || !face)
238 		return B_ERROR;
239 
240 	int32 code;
241 	BPrivate::BAppServerLink link;
242 
243 	link.StartMessage(AS_GET_STYLE_NAME);
244 	link.Attach(family,sizeof(font_family));
245 	link.Attach<int32>(index);
246 	link.FlushWithReply(&code);
247 
248 	if(code!=SERVER_TRUE)
249 		return B_ERROR;
250 
251 	link.Read<font_style>(name);
252 	link.Read<uint16>(face);
253 	if(flags)
254 		link.Read<uint32>(flags);
255 
256 	return B_OK;
257 }
258 
259 
260 /*!
261 	\brief Updates the font family list
262 	\param check_only If true, the function only checks to see if the font list has changed
263 	\return true if the font list has changed, false if not.
264 */
265 
266 bool
267 update_font_families(bool check_only)
268 {
269 	int32 code;
270 	bool value;
271 	BPrivate::BAppServerLink link;
272 
273 	link.StartMessage(AS_QUERY_FONTS_CHANGED);
274 	link.Attach<bool>(check_only);
275 	link.FlushWithReply(&code);
276 
277 	if(code!=SERVER_TRUE)
278 		return false;
279 
280 	link.Read<bool>(&value);
281 	return value;
282 }
283 
284 
285 status_t
286 get_font_cache_info(uint32 id, void *set)
287 {
288 	// TODO: Implement
289 
290 	// Note that the only reliable data from this function will probably be the cache size
291 	// Depending on how the font cache is implemented, this function and the corresponding
292 	// set function will either see major revision or completely disappear in R2.
293 	return B_ERROR;
294 }
295 
296 
297 status_t
298 set_font_cache_info(uint32 id, void *set)
299 {
300 	// TODO: Implement
301 
302 	// Note that this function will likely only set the cache size in our implementation
303 	// because of (a) the lack of knowledge on R5's font system and (b) the fact that it
304 	// is a completely different font engine.
305 	return B_ERROR;
306 }
307 
308 
309 //----------------------------------------------------------------------------------------
310 //		BFont Class Definition
311 //----------------------------------------------------------------------------------------
312 
313 
314 BFont::BFont(void)
315 	:
316 	// initialise for be_plain_font (avoid circular definition)
317 	fFamilyID(0),
318 	fStyleID(0),
319 	fSize(10.0),
320 	fShear(0.0),
321 	fRotation(0.0),
322 	fSpacing(0),
323 	fEncoding(0),
324 	fFace(0),
325 	fFlags(0)
326 {
327 	fHeight.ascent = 7.0;
328 	fHeight.descent = 2.0;
329 	fHeight.leading = 13.0;
330 
331 	fFamilyID = be_plain_font->fFamilyID;
332 	fStyleID = be_plain_font->fStyleID;
333 	fSize = be_plain_font->fSize;
334 }
335 
336 
337 BFont::BFont(const BFont &font)
338 {
339 	fFamilyID = font.fFamilyID;
340 	fStyleID = font.fStyleID;
341 	fSize = font.fSize;
342 	fShear = font.fShear;
343 	fRotation = font.fRotation;
344 	fSpacing = font.fSpacing;
345 	fEncoding = font.fEncoding;
346 	fFace = font.fFace;
347 	fHeight = font.fHeight;
348 }
349 
350 
351 BFont::BFont(const BFont *font)
352 {
353 	if (font) {
354 		fFamilyID = font->fFamilyID;
355 		fStyleID = font->fStyleID;
356 		fSize = font->fSize;
357 		fShear = font->fShear;
358 		fRotation = font->fRotation;
359 		fSpacing = font->fSpacing;
360 		fEncoding = font->fEncoding;
361 		fFace = font->fFace;
362 		fHeight = font->fHeight;
363 	} else {
364 		fFamilyID = be_plain_font->fFamilyID;
365 		fStyleID = be_plain_font->fStyleID;
366 		fSize = be_plain_font->fSize;
367 		fShear = be_plain_font->fShear;
368 		fRotation = be_plain_font->fRotation;
369 		fSpacing = be_plain_font->fSpacing;
370 		fEncoding = be_plain_font->fEncoding;
371 		fFace = be_plain_font->fFace;
372 		fHeight = be_plain_font->fHeight;
373 	}
374 }
375 
376 
377 /*!
378 	\brief Sets the font's family and style all at once
379 	\param family Font family to set
380 	\param style Font style to set
381 	\return B_ERROR if family or style do not exist or if style does not belong to family.
382 */
383 
384 status_t
385 BFont::SetFamilyAndStyle(const font_family family, const font_style style)
386 {
387 	// R5 version always returns B_OK. That's a problem...
388 	if(!family)
389 		return B_ERROR;
390 
391 	int32 code;
392 	BPrivate::BAppServerLink link;
393 
394 	if(!style)
395 	{
396 		// The BeBook states that a NULL style means set only the family
397 		link.StartMessage(AS_SET_FAMILY_NAME);
398 		link.Attach(family,sizeof(font_family));
399 		link.FlushWithReply(&code);
400 
401 		if(code!=SERVER_TRUE)
402 			return B_ERROR;
403 
404 		link.Read<uint16>(&fFamilyID);
405 	}
406 	else
407 	{
408 		link.StartMessage(AS_SET_FAMILY_AND_STYLE);
409 		link.Attach(family,sizeof(font_family));
410 		link.Attach(style,sizeof(font_style));
411 		link.FlushWithReply(&code);
412 
413 		if(code!=SERVER_TRUE)
414 			return B_ERROR;
415 
416 		link.Read<uint16>(&fFamilyID);
417 		link.Read<uint16>(&fStyleID);
418 	}
419 
420 	return B_OK;
421 }
422 
423 
424 /*!
425 	\brief Sets the font's family and style all at once
426 	\param code Unique font identifier obtained from the server.
427 */
428 
429 void
430 BFont::SetFamilyAndStyle(uint32 fontcode)
431 {
432 	// R5 has a bug here: the face is not updated even though the IDs are set. This
433 	// is a problem because the face flag includes Regular/Bold/Italic information in
434 	// addition to stuff like underlining and strikethrough. As a result, this will
435 	// need a trip to the server and, thus, be slower than R5's in order to be correct
436 
437 	uint16 family,style,face;
438 	int32 code;
439 	BPrivate::BAppServerLink link;
440 
441 	style = fontcode & 0xFFFF;
442 	family = (fontcode & 0xFFFF0000) >> 16;
443 
444 	link.StartMessage(AS_SET_FAMILY_AND_STYLE_FROM_ID);
445 	link.Attach<uint16>(family);
446 	link.Attach<uint16>(style);
447 	link.FlushWithReply(&code);
448 
449 	if(code!=SERVER_TRUE)
450 		return;
451 
452 	link.Read<uint16>(&face);
453 
454 	fStyleID = style;
455 	fFamilyID = family;
456 
457 	// Mask off any references in the face to Bold/Normal/Italic and set the face
458 	// value to reflect the new font style
459 	fFace&=B_UNDERSCORE_FACE | B_NEGATIVE_FACE | B_OUTLINED_FACE | B_STRIKEOUT_FACE;
460 	fFace|=face;
461 }
462 
463 
464 /*!
465 	\brief Sets the font's family and face all at once
466 	\param family Font family to set
467 	\param face Font face to set.
468 	\return B_ERROR if family does not exists or face is an invalid value.
469 
470 	To comply with the BeBook, this function will only set valid values - i.e. passing a
471 	nonexistent family will cause only the face to be set. Additionally, if a particular
472 	face does not exist in a family, the closest match will be chosen.
473 */
474 
475 status_t
476 BFont::SetFamilyAndFace(const font_family family, uint16 face)
477 {
478 	if (face & (B_ITALIC_FACE | B_UNDERSCORE_FACE | B_NEGATIVE_FACE | B_OUTLINED_FACE
479 			| B_STRIKEOUT_FACE | B_BOLD_FACE | B_REGULAR_FACE) != 0)
480 		fFace = face;
481 
482 	if(family)
483 	{
484 		int32 code;
485 		BPrivate::BAppServerLink link;
486 
487 		link.StartMessage(AS_SET_FAMILY_AND_FACE);
488 		link.Attach(family,sizeof(font_family));
489 		link.Attach<uint16>(face);
490 		link.FlushWithReply(&code);
491 
492 		if(code!=SERVER_TRUE)
493 			return B_ERROR;
494 
495 		link.Read<uint16>(&fFamilyID);
496 		link.Read<uint16>(&fStyleID);
497 	}
498 	else
499 		fFace=face;
500 
501 	return B_OK;
502 }
503 
504 
505 void
506 BFont::SetSize(float size)
507 {
508 	fSize = size;
509 }
510 
511 
512 void
513 BFont::SetShear(float shear)
514 {
515 	fShear = shear;
516 }
517 
518 
519 void
520 BFont::SetRotation(float rotation)
521 {
522 	fRotation = rotation;
523 }
524 
525 
526 void
527 BFont::SetSpacing(uint8 spacing)
528 {
529 	fSpacing = spacing;
530 }
531 
532 
533 void
534 BFont::SetEncoding(uint8 encoding)
535 {
536 	fEncoding = encoding;
537 }
538 
539 
540 void
541 BFont::SetFace(uint16 face)
542 {
543 	fFace = face;
544 }
545 
546 
547 void
548 BFont::SetFlags(uint32 flags)
549 {
550 	fFlags = flags;
551 }
552 
553 
554 void
555 BFont::GetFamilyAndStyle(font_family *family, font_style *style) const
556 {
557 	if(!family || !style)
558 		return;
559 
560 	int32 code;
561 	BPrivate::BAppServerLink link;
562 
563 	link.StartMessage(AS_GET_FAMILY_AND_STYLE);
564 	link.Attach<uint16>(fFamilyID);
565 	link.Attach<uint16>(fStyleID);
566 	link.FlushWithReply(&code);
567 
568 	if(code!=SERVER_TRUE)
569 		return;
570 
571 	link.Read<font_family>(family);
572 	link.Read<font_style>(style);
573 }
574 
575 
576 uint32
577 BFont::FamilyAndStyle(void) const
578 {
579 	uint32 token = (fFamilyID << 16) | fStyleID;
580 	return token;
581 }
582 
583 
584 float
585 BFont::Size(void) const
586 {
587 	return fSize;
588 }
589 
590 
591 float
592 BFont::Shear(void) const
593 {
594 	return fShear;
595 }
596 
597 
598 float
599 BFont::Rotation(void) const
600 {
601 	return fRotation;
602 }
603 
604 
605 uint8
606 BFont::Spacing(void) const
607 {
608 	return fSpacing;
609 }
610 
611 
612 uint8
613 BFont::Encoding(void) const
614 {
615 	return fEncoding;
616 }
617 
618 
619 uint16
620 BFont::Face(void) const
621 {
622 	return fFace;
623 }
624 
625 
626 uint32
627 BFont::Flags(void) const
628 {
629 	return fFlags;
630 }
631 
632 
633 font_direction
634 BFont::Direction(void) const
635 {
636 	int32 code;
637 	BPrivate::BAppServerLink link;
638 
639 	link.StartMessage(AS_GET_FONT_DIRECTION);
640 	link.Attach<uint16>(fFamilyID);
641 	link.Attach<uint16>(fStyleID);
642 	link.FlushWithReply(&code);
643 
644 	if(code!=SERVER_TRUE)
645 		return B_FONT_LEFT_TO_RIGHT;
646 
647 	font_direction fdir;
648 	link.Read<font_direction>(&fdir);
649 	return fdir;
650 }
651 
652 
653 bool
654 BFont::IsFixed(void) const
655 {
656 	int32 code;
657 	BPrivate::BAppServerLink link;
658 
659 	link.StartMessage(AS_QUERY_FONT_FIXED);
660 	link.Attach<uint16>(fFamilyID);
661 	link.Attach<uint16>(fStyleID);
662 	link.FlushWithReply(&code);
663 
664 	if(code!=SERVER_TRUE)
665 		return false;
666 
667 	bool fixed;
668 	link.Read<bool>(&fixed);
669 	return fixed;
670 }
671 
672 
673 /*!
674 	\brief Returns true if the font is fixed-width and contains both full and half-width characters
675 
676 	This was left unimplemented as of R5. It was a way to work with both Kanji and Roman
677 	characters in the same fixed-width font.
678 */
679 
680 bool
681 BFont::IsFullAndHalfFixed(void) const
682 {
683 	return false;
684 }
685 
686 
687 BRect
688 BFont::BoundingBox(void) const
689 {
690 	int32 code;
691 	BPrivate::BAppServerLink link;
692 
693 	link.StartMessage(AS_GET_FONT_BOUNDING_BOX);
694 	link.Attach<uint16>(fFamilyID);
695 	link.Attach<uint16>(fStyleID);
696 	link.FlushWithReply(&code);
697 
698 	if(code!=SERVER_TRUE)
699 		return BRect(0,0,0,0);
700 
701 	BRect box;
702 	link.Read<BRect>(&box);
703 	return box;
704 }
705 
706 
707 unicode_block
708 BFont::Blocks(void) const
709 {
710 	// TODO: Add Block support
711 	return unicode_block();
712 }
713 
714 
715 font_file_format
716 BFont::FileFormat(void) const
717 {
718 	// TODO: this will not work until I extend FreeType to handle this kind of call
719 	return B_TRUETYPE_WINDOWS;
720 }
721 
722 
723 int32
724 BFont::CountTuned(void) const
725 {
726 	int32 code;
727 	BPrivate::BAppServerLink link;
728 
729 	link.StartMessage(AS_GET_TUNED_COUNT);
730 	link.Attach<uint16>(fFamilyID);
731 	link.Attach<uint16>(fStyleID);
732 	link.FlushWithReply(&code);
733 
734 	if(code!=SERVER_TRUE)
735 		return -1;
736 
737 	int32 count;
738 	link.Read<int32>(&count);
739 	return count;
740 }
741 
742 
743 void
744 BFont::GetTunedInfo(int32 index, tuned_font_info *info) const
745 {
746 	if(!info)
747 		return;
748 
749 	int32 code;
750 	BPrivate::BAppServerLink link;
751 
752 	link.StartMessage(AS_GET_TUNED_INFO);
753 	link.Attach<uint16>(fFamilyID);
754 	link.Attach<uint16>(fStyleID);
755 	link.Attach<uint32>(index);
756 	link.FlushWithReply(&code);
757 
758 	if(code!=SERVER_TRUE)
759 		return;
760 
761 	link.Read<tuned_font_info>(info);
762 }
763 
764 
765 void
766 BFont::TruncateString(BString *inOut, uint32 mode, float width) const
767 {
768 	if(!inOut)
769 		return;
770 
771 	if(width<=0)
772 	{
773 		*inOut="";
774 		return;
775 	}
776 
777 	int32 code;
778 	BPrivate::BAppServerLink link;
779 
780 	link.StartMessage(AS_GET_TRUNCATED_STRINGS);
781 
782 	if(code!=SERVER_TRUE)
783 		return;
784 
785 	link.Attach<uint32>(mode);
786 	link.Attach<float>(width);
787 	link.Attach<int32>(1);
788 	link.AttachString(inOut->String());
789 	link.FlushWithReply(&code);
790 
791 	char *string;
792 	link.ReadString(&string);
793 	*inOut=string;
794 	free(string);
795 
796 }
797 
798 
799 void
800 BFont::GetTruncatedStrings(const char *stringArray[], int32 numStrings,
801 	uint32 mode, float width, BString resultArray[]) const
802 {
803 	if(!stringArray || numStrings<1 || !resultArray)
804 		return;
805 
806 	int32 code;
807 	BPrivate::BAppServerLink link;
808 
809 	link.StartMessage(AS_GET_TRUNCATED_STRINGS);
810 
811 	if(code!=SERVER_TRUE)
812 		return;
813 
814 	link.Attach<uint32>(mode);
815 	link.Attach<float>(width);
816 	link.Attach<int32>(numStrings);
817 
818 	for(int32 i=0; i<numStrings; i++)
819 		link.AttachString(stringArray[i]);
820 
821 	link.FlushWithReply(&code);
822 
823 	for(int32 i=0; i<numStrings; i++)
824 	{
825 		char *string;
826 		link.ReadString(&string);
827 		resultArray[i].SetTo(string);
828 		free(string);
829 	}
830 }
831 
832 
833 void
834 BFont::GetTruncatedStrings(const char *stringArray[], int32 numStrings,
835 	uint32 mode, float width, char *resultArray[]) const
836 {
837 	if(!stringArray || numStrings<1 || !resultArray)
838 		return;
839 
840 	int32 code;
841 	BPrivate::BAppServerLink link;
842 
843 	link.StartMessage(AS_GET_TRUNCATED_STRINGS);
844 
845 	if(code!=SERVER_TRUE)
846 		return;
847 
848 	link.Attach<uint32>(mode);
849 	link.Attach<float>(width);
850 	link.Attach<int32>(numStrings);
851 
852 	for(int32 i=0; i<numStrings; i++)
853 		link.AttachString(stringArray[i]);
854 
855 	link.FlushWithReply(&code);
856 
857 	// TODO: Look into a possible BPortLink::ReadIntoString() method to speed things
858 	// like this up, along with the other string truncation functions
859 	for(int32 i=0; i<numStrings; i++)
860 	{
861 		char *string;
862 		link.ReadString(&string);
863 		strcpy(resultArray[i],string);
864 		free(string);
865 	}
866 }
867 
868 
869 float
870 BFont::StringWidth(const char *string) const
871 {
872  	return StringWidth(string, strlen(string));
873 }
874 
875 
876 float
877 BFont::StringWidth(const char *string, int32 length) const
878 {
879 	if(!string || length<1)
880 		return 0.0;
881 
882 	int32 code;
883 	BPrivate::BAppServerLink link;
884 
885 	link.StartMessage(AS_GET_STRING_WIDTH);
886 	link.AttachString(string);
887 	link.Attach<int32>(length);
888 	link.FlushWithReply(&code);
889 
890 	if(code!=SERVER_TRUE)
891 		return 0.0;
892 
893 	float width;
894 	link.Read<float>(&width);
895 	return width;
896 }
897 
898 
899 void
900 BFont::GetStringWidths(const char *stringArray[], const int32 lengthArray[],
901 	int32 numStrings, float widthArray[]) const
902 {
903 	if(!stringArray || !lengthArray || numStrings<1 || !widthArray)
904 		return;
905 
906 	int32 code;
907 	BPrivate::BAppServerLink link;
908 
909 	link.StartMessage(AS_GET_STRING_WIDTHS);
910 
911 	if(code!=SERVER_TRUE)
912 		return;
913 
914 	link.Attach<int32>(numStrings);
915 
916 	for(int32 i=0; i<numStrings; i++)
917 	{
918 		link.AttachString(stringArray[i]);
919 		link.Attach<int32>(lengthArray[i]);
920 	}
921 
922 	link.FlushWithReply(&code);
923 
924 	for(int32 i=0; i<numStrings; i++)
925 		link.Read<float>(&widthArray[i]);
926 }
927 
928 
929 void
930 BFont::GetEscapements(const char charArray[], int32 numChars, float escapementArray[]) const
931 {
932 	GetEscapements(charArray, numChars,NULL,escapementArray);
933 }
934 
935 
936 void
937 BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *delta,
938 	float escapementArray[]) const
939 {
940 	// TODO: implement
941 }
942 
943 
944 void
945 BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *delta,
946 	BPoint escapementArray[]) const
947 {
948 	GetEscapements(charArray, numChars,delta,escapementArray,NULL);
949 }
950 
951 
952 void
953 BFont::GetEscapements(const char charArray[], int32 numChars, escapement_delta *delta,
954 	BPoint escapementArray[], BPoint offsetArray[]) const
955 {
956 	if(!charArray ||  numChars<1 || !escapementArray)
957 		return;
958 
959 	int32 code;
960 	BPrivate::BAppServerLink link;
961 
962 	link.StartMessage(AS_GET_ESCAPEMENTS);
963 	if(code!=SERVER_TRUE)
964 		return;
965 
966 	link.Attach<int32>(numChars);
967 
968 	if(offsetArray)
969 	{
970 		for(int32 i=0; i<numChars; i++)
971 		{
972 			link.Attach<char>(charArray[i]);
973 			link.Attach<BPoint>(offsetArray[i]);
974 		}
975 	}
976 	else
977 	{
978 		BPoint dummypt(0,0);
979 
980 		for(int32 i=0; i<numChars; i++)
981 		{
982 			link.Attach<char>(charArray[i]);
983 			link.Attach<BPoint>(dummypt);
984 		}
985 	}
986 	link.FlushWithReply(&code);
987 
988 	for(int32 i=0; i<numChars; i++)
989 		link.Read<BPoint>(&escapementArray[i]);
990 }
991 
992 
993 void
994 BFont::GetEdges(const char charArray[], int32 numBytes, edge_info edgeArray[]) const
995 {
996 	if(!charArray ||  numBytes<1 || !edgeArray)
997 		return;
998 
999 	int32 code;
1000 	BPrivate::BAppServerLink link;
1001 
1002 	link.StartMessage(AS_GET_EDGES);
1003 
1004 	if(code!=SERVER_TRUE)
1005 		return;
1006 
1007 	link.Attach<int32>(numBytes);
1008 
1009 	for(int32 i=0; i<numBytes; i++)
1010 		link.Attach<char>(charArray[i]);
1011 
1012 	link.FlushWithReply(&code);
1013 
1014 	for(int32 i=0; i<numBytes; i++)
1015 		link.Read<edge_info>(&edgeArray[i]);
1016 }
1017 
1018 
1019 void
1020 BFont::GetHeight(font_height *height) const
1021 {
1022 	if(height)
1023 	{
1024 		// R5's version actually contacts the server in this call. The more and more
1025 		// I work with this class, the more and more I can't wait for R2 to fix it. Yeesh.
1026 		int32 code;
1027 		BPrivate::BAppServerLink link;
1028 		link.StartMessage(AS_GET_FONT_HEIGHT);
1029 		link.Attach<uint16>(fFamilyID);
1030 		link.Attach<uint16>(fStyleID);
1031 		link.Attach<float>(fSize);
1032 		link.FlushWithReply(&code);
1033 
1034 		if(code==SERVER_FALSE)
1035 			return;
1036 
1037 		link.Read<font_height>(height);
1038 	}
1039 }
1040 
1041 
1042 void
1043 BFont::GetBoundingBoxesAsGlyphs(const char charArray[], int32 numChars, font_metric_mode mode,
1044 	BRect boundingBoxArray[]) const
1045 {
1046 	GetBoundingBoxesAsString(charArray,numChars,mode,NULL,boundingBoxArray);
1047 }
1048 
1049 
1050 void
1051 BFont::GetBoundingBoxesAsString(const char charArray[], int32 numChars, font_metric_mode mode,
1052 	escapement_delta *delta, BRect boundingBoxArray[]) const
1053 {
1054 	if(!charArray ||  numChars<1 || !boundingBoxArray)
1055 		return;
1056 
1057 	int32 code;
1058 	BPrivate::BAppServerLink link;
1059 
1060 	link.StartMessage(AS_GET_BOUNDINGBOXES_CHARS);
1061 
1062 	if(code!=SERVER_TRUE)
1063 		return;
1064 
1065 	link.Attach<font_metric_mode>(mode);
1066 
1067 	if(delta)
1068 	{
1069 		link.Attach<escapement_delta>(*delta);
1070 	}
1071 	else
1072 	{
1073 		escapement_delta esd={0,0};
1074 		link.Attach<escapement_delta>(esd);
1075 	}
1076 
1077 	link.Attach<int32>(numChars);
1078 
1079 	for(int32 i=0; i<numChars; i++)
1080 		link.Attach<char>(charArray[i]);
1081 
1082 	link.FlushWithReply(&code);
1083 
1084 	for(int32 i=0; i<numChars; i++)
1085 		link.Read<BRect>(&boundingBoxArray[i]);
1086 }
1087 
1088 
1089 void
1090 BFont::GetBoundingBoxesForStrings(const char *stringArray[], int32 numStrings,
1091 	font_metric_mode mode, escapement_delta deltas[], BRect boundingBoxArray[]) const
1092 {
1093 	if(!stringArray ||  numStrings<1 || !boundingBoxArray)
1094 		return;
1095 
1096 	int32 code;
1097 	BPrivate::BAppServerLink link;
1098 
1099 	link.StartMessage(AS_GET_BOUNDINGBOXES_STRINGS);
1100 
1101 	if(code!=SERVER_TRUE)
1102 		return;
1103 
1104 	link.Attach<font_metric_mode>(mode);
1105 	link.Attach<int32>(numStrings);
1106 
1107 	if(deltas)
1108 	{
1109 		for(int32 i=0; i<numStrings; i++)
1110 		{
1111 			link.AttachString(stringArray[i]);
1112 			link.Attach<escapement_delta>(deltas[i]);
1113 		}
1114 	}
1115 	else
1116 	{
1117 		escapement_delta esd={0,0};
1118 
1119 		for(int32 i=0; i<numStrings; i++)
1120 		{
1121 			link.AttachString(stringArray[i]);
1122 			link.Attach<escapement_delta>(esd);
1123 		}
1124 	}
1125 	link.FlushWithReply(&code);
1126 
1127 	for(int32 i=0; i<numStrings; i++)
1128 		link.Read<BRect>(&boundingBoxArray[i]);
1129 }
1130 
1131 
1132 void
1133 BFont::GetGlyphShapes(const char charArray[], int32 numChars, BShape *glyphShapeArray[]) const
1134 {
1135 	// TODO: implement code specifically for passing BShapes to and from the server
1136 
1137 	if(!charArray ||  numChars<1 || !glyphShapeArray)
1138 		return;
1139 
1140 	int32 code;
1141 	BPrivate::BAppServerLink link;
1142 
1143 	link.StartMessage(AS_GET_GLYPH_SHAPES);
1144 
1145 	if(code!=SERVER_TRUE)
1146 		return;
1147 
1148 	link.Attach<int32>(numChars);
1149 
1150 	for(int32 i=0; i<numChars; i++)
1151 		link.Attach<char>(charArray[i]);
1152 
1153 	link.FlushWithReply(&code);
1154 
1155 	// This is going to be dog slow, but it'll do for now
1156 	char *buffer=NULL;
1157 	size_t buffersize=0;
1158 
1159 	for(int32 i=0; i<numChars; i++)
1160 	{
1161 		size_t msgsize;
1162 
1163 		link.Read<size_t>(&msgsize);
1164 		if(msgsize>buffersize)
1165 		{
1166 			delete buffer;
1167 			buffer=new char[msgsize];
1168 		}
1169 
1170 		link.Read(buffer,msgsize);
1171 
1172 		BMessage shapemsg;
1173 		shapemsg.Unflatten(buffer);
1174 
1175 		BShape shape(&shapemsg);
1176 		glyphShapeArray[i]->Clear();
1177 		glyphShapeArray[i]->AddShape(&shape);
1178 	}
1179 
1180 	delete buffer;
1181 }
1182 
1183 
1184 void
1185 BFont::GetHasGlyphs(const char charArray[], int32 numChars, bool hasArray[]) const
1186 {
1187 	if(!charArray ||  numChars<1 || !hasArray)
1188 		return;
1189 
1190 	int32 code;
1191 	BPrivate::BAppServerLink link;
1192 
1193 	link.StartMessage(AS_GET_HAS_GLYPHS);
1194 
1195 	if(code!=SERVER_TRUE)
1196 		return;
1197 
1198 	link.Attach<int32>(numChars);
1199 
1200 	for(int32 i=0; i<numChars; i++)
1201 		link.Attach<char>(charArray[i]);
1202 
1203 	link.FlushWithReply(&code);
1204 
1205 	for(int32 i=0; i<numChars; i++)
1206 		link.Read<bool>(&hasArray[i]);
1207 }
1208 
1209 
1210 BFont
1211 &BFont::operator=(const BFont &font)
1212 {
1213 	fFamilyID = font.fFamilyID;
1214 	fStyleID = font.fStyleID;
1215 	fSize = font.fSize;
1216 	fShear = font.fShear;
1217 	fRotation = font.fRotation;
1218 	fSpacing = font.fSpacing;
1219 	fEncoding = font.fEncoding;
1220 	fFace = font.fFace;
1221 	fHeight = font.fHeight;
1222 	return *this;
1223 }
1224 
1225 
1226 bool
1227 BFont::operator==(const BFont &font) const
1228 {
1229 	return fFamilyID == font.fFamilyID
1230 		&& fStyleID == font.fStyleID
1231 		&& fSize == font.fSize
1232 		&& fShear == font.fShear
1233 		&& fRotation == font.fRotation
1234 		&& fSpacing == font.fSpacing
1235 		&& fEncoding == font.fEncoding
1236 		&& fFace == font.fFace;
1237 }
1238 
1239 
1240 bool
1241 BFont::operator!=(const BFont &font) const
1242 {
1243 	return fFamilyID != font.fFamilyID
1244 		|| fStyleID != font.fStyleID
1245 		|| fSize != font.fSize
1246 		|| fShear != font.fShear
1247 		|| fRotation != font.fRotation
1248 		|| fSpacing != font.fSpacing
1249 		|| fEncoding != font.fEncoding
1250 		|| fFace != font.fFace;
1251 }
1252 
1253 
1254 void
1255 BFont::PrintToStream(void) const
1256 {
1257 	printf("FAMILY STYLE %f %f %f %f %f %f\n", fSize, fShear, fRotation, fHeight.ascent,
1258 		fHeight.descent, fHeight.leading);
1259 }
1260 
1261