1 /*
2 * A Z-Machine
3 * Copyright (C) 2000 Andrew Hunter
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /*
21 * Fonts for Mac OS (Carbon)
22 *
23 * There are no less than three different font drivers here:
24 * - QuickDraw Text
25 * - ATSUI
26 * - Quartz
27 *
28 * ATSUI is slow, and to use it properly you'd really need to rewrite
29 * the whole rendering interface. That's probably not worth it...
30 * (Well, it would make copy/paste a bit easier to implement
31 *
32 * QuickDraw uses a crappy font rendering engine
33 *
34 * Quartz looks nice, but there is a shortage of ways of measuring text:
35 * the way we do it is a bit of a hack, but seems accurate enough.
36 * (You can't define USE_QUARTZ and USE_ATS...)
37 *
38 * All this is why this file is a bit of a mess in places...
39 */
40
41 #include "../config.h"
42
43 #if WINDOW_SYSTEM == 3
44
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include <Carbon/Carbon.h>
49
50 #include "zmachine.h"
51 #include "rc.h"
52 #include "font3.h"
53 #include "xfont.h"
54 #include "carbondisplay.h"
55
56 extern XFONT_MEASURE xfont_x;
57 extern XFONT_MEASURE xfont_y;
58
59 static PolyHandle f3[96];
60
61 struct xfont
62 {
63 enum
64 {
65 FONT_INTERNAL,
66 FONT_FONT3
67 } type;
68 union
69 {
70 struct
71 {
72 #ifdef USE_ATS
73 FMFontFamily family;
74 ATSUFontID font;
75 ATSUStyle style;
76 #else
77 FMFontFamily family;
78 int size;
79 int isbold;
80 int isitalic;
81 int isunderlined;
82
83 TextEncoding encoding;
84 UnicodeToTextInfo convert;
85
86 # ifdef USE_QUARTZ
87 ATSFontRef atsref;
88 ATSUStyle style;
89 char* psname;
90 CGFontRef cgfont;
91 # endif
92
93 #endif
94
95 XFONT_MEASURE ascent, descent, maxwidth;
96 } mac;
97 } data;
98 };
99
100 static RGBColor fg_col, bg_col;
101 static int transpar = 0;
102
103 #ifdef USE_QUARTZ
104 CGContextRef carbon_quartz_context = nil;
105
106 static xfont* winlastfont = NULL;
107 static int enable_quartz = 0;
108 #endif
109
110 /*** ----// 888 \\---- ***/
111
112 #ifdef USE_QUARTZ
carbon_set_context(void)113 void carbon_set_context(void)
114 {
115 CGrafPtr thePort = GetQDGlobalsThePort();
116
117 CGContextRelease(carbon_quartz_context);
118 CreateCGContextForPort(thePort, &carbon_quartz_context);
119 winlastfont = NULL;
120
121 if (rc_get_antialias())
122 {
123 CGContextSetShouldAntialias(carbon_quartz_context,
124 1);
125 }
126 else
127 {
128 CGContextSetShouldAntialias(carbon_quartz_context,
129 0);
130 }
131 }
132
carbon_set_quartz(int q)133 void carbon_set_quartz(int q)
134 {
135 enable_quartz = q;
136 }
137 #endif
138
139 static double scale_factor = 1.0;
140
carbon_set_scale_factor(double factor)141 void carbon_set_scale_factor(double factor)
142 {
143 scale_factor = factor;
144 }
145
xfont_initialise(void)146 void xfont_initialise(void)
147 {
148 int x;
149
150 #ifdef USE_QUARTZ
151 if (carbon_quartz_context == nil)
152 {
153 CGrafPtr p;
154 OSStatus res;
155
156 p = GetWindowPort(zoomWindow);
157
158 res = CreateCGContextForPort(p, &carbon_quartz_context);
159
160 winlastfont = NULL;
161 }
162 #endif
163
164 for (x=0; x<96; x++)
165 f3[x] = nil;
166 }
167
xfont_shutdown(void)168 void xfont_shutdown(void)
169 {
170 }
171
172 #ifndef USE_ATS
select_font(xfont * font)173 static void select_font(xfont* font)
174 {
175 TextFont(font->data.mac.family);
176 TextSize(font->data.mac.size);
177 TextFace((font->data.mac.isbold?bold:0) |
178 (font->data.mac.isitalic?italic:0) |
179 (font->data.mac.isunderlined?underline:0));
180 }
181 #endif
182
183 #define DEFAULT_FONT applFont
184
185
186 /*
187 * Internal format for Mac OS font names
188 *
189 * "face name" width properties
190 *
191 * Where properties can be one or more of:
192 * b - bold
193 * i - italic
194 * u - underline
195 */
xfont_default_font(void)196 static xfont* xfont_default_font(void)
197 {
198 xfont* xf;
199
200 #ifdef USE_ATS
201 return NULL;
202 #else
203 xf = malloc(sizeof(struct xfont));
204 xf->type = FONT_INTERNAL;
205 xf->data.mac.family = DEFAULT_FONT;
206 xf->data.mac.size = 12;
207 xf->data.mac.isbold = 0;
208 xf->data.mac.isitalic = 0;
209 xf->data.mac.isunderlined = 0;
210 return xf;
211 #endif
212 }
213
carbon_parse_font(char * font)214 carbon_font* carbon_parse_font(char* font)
215 {
216 int x;
217
218 static carbon_font fnt;
219 char* face_name;
220 static char fontcopy[256];
221 char* face_width;
222 char* face_props;
223
224 if (strcmp(font, "font3") == 0)
225 {
226 fnt.isfont3 = 1;
227 fnt.isbold = fnt.isitalic = fnt.isunderlined = 0;
228 fnt.size = 0;
229 return &fnt;
230 }
231 fnt.isfont3 = 0;
232
233 if (strlen(font) > 256)
234 {
235 zmachine_warning("Invalid font name (too long)");
236
237 return NULL;
238 }
239
240 /* Get the face name */
241 strcpy(fontcopy, font);
242 x = 0;
243 while (fontcopy[x++] != '\'')
244 {
245 if (fontcopy[x] == 0)
246 {
247 zmachine_warning("Invalid font name: %s (font name must be in single quotes)", font);
248
249 return NULL;
250 }
251 }
252
253 face_name = &fontcopy[x];
254
255 x--;
256 while (fontcopy[++x] != '\'')
257 {
258 if (fontcopy[x] == 0)
259 {
260 zmachine_warning("Invalid font name: %s (missing \')", font);
261
262 return NULL;
263 }
264 }
265 fontcopy[x] = 0;
266
267 /* Get the font width */
268 while (fontcopy[++x] == ' ')
269 {
270 if (fontcopy[x] == 0)
271 {
272 zmachine_warning("Invalid font name: %s (no font size specified)", font);
273
274 return NULL;
275 }
276 }
277
278 face_width = &fontcopy[x];
279
280 while (fontcopy[x] >= '0' &&
281 fontcopy[x] <= '9')
282 x++;
283
284 if (fontcopy[x] != ' ' &&
285 fontcopy[x] != 0)
286 {
287 zmachine_warning("Invalid font name: %s (invalid size)", font);
288
289 return NULL;
290 }
291
292 if (fontcopy[x] != 0)
293 {
294 fontcopy[x] = 0;
295 face_props = &fontcopy[x+1];
296 }
297 else
298 face_props = NULL;
299
300 fnt.face_name = face_name;
301 fnt.size = atoi(face_width);
302 fnt.isbold = fnt.isitalic = fnt.isunderlined = 0;
303
304 if (face_props != NULL)
305 {
306 for (x=0; face_props[x] != 0; x++)
307 {
308 switch (face_props[x])
309 {
310 case 'b':
311 case 'B':
312 fnt.isbold = 1;
313 break;
314
315 case 'i':
316 case 'I':
317 fnt.isitalic = 1;
318 break;
319
320 case 'u':
321 case 'U':
322 fnt.isunderlined = 1;
323 break;
324 }
325 }
326 }
327
328 return &fnt;
329 }
330
xfont_load_font(char * font)331 xfont* xfont_load_font(char* font)
332 {
333 char fontcopy[256];
334 char* face_name;
335 Str255 family;
336 char* face_width;
337 char* face_props;
338 xfont* xf;
339
340 int x;
341
342 GrafPtr oldport;
343 FontInfo fm;
344 int aspace[] = { 'T', 'e', 's', 't' };
345
346 #ifdef USE_ATS
347 OSStatus erm;
348
349 ATSUAttributeTag tags[3] =
350 {
351 kATSUSizeTag, kATSUQDUnderlineTag,
352 kATSUFontTag
353 };
354 ByteCount attsz [3];
355 ATSUAttributeValuePtr attptr[3];
356
357 Fixed size;
358 Boolean isbold, isitalic, isunderline;
359 #endif
360
361 if (strcmp(font, "font3") == 0)
362 {
363 xf = malloc(sizeof(struct xfont));
364
365 xf->type = FONT_FONT3;
366
367 return xf;
368 }
369
370 if (strlen(font) > 256)
371 {
372 zmachine_warning("Invalid font name (too long)");
373
374 return xfont_default_font();
375 }
376
377 /* Get the face name */
378 strcpy(fontcopy, font);
379 x = 0;
380 while (fontcopy[x++] != '\'')
381 {
382 if (fontcopy[x] == 0)
383 {
384 zmachine_warning("Invalid font name: %s (font name must be in single quotes)", font);
385
386 xf = xfont_default_font();
387 return xf;
388 }
389 }
390
391 face_name = &fontcopy[x];
392
393 x--;
394 while (fontcopy[++x] != '\'')
395 {
396 if (fontcopy[x] == 0)
397 {
398 zmachine_warning("Invalid font name: %s (missing \')", font);
399
400 xf = xfont_default_font();
401 return xf;
402 }
403 }
404 fontcopy[x] = 0;
405
406 /* Get the font width */
407 while (fontcopy[++x] == ' ')
408 {
409 if (fontcopy[x] == 0)
410 {
411 zmachine_warning("Invalid font name: %s (no font size specified)", font);
412
413 xf = xfont_default_font();
414 return xf;
415 }
416 }
417
418 face_width = &fontcopy[x];
419
420 while (fontcopy[x] >= '0' &&
421 fontcopy[x] <= '9')
422 x++;
423
424 if (fontcopy[x] != ' ' &&
425 fontcopy[x] != 0)
426 {
427 zmachine_warning("Invalid font name: %s (invalid size)", font);
428
429 xf = xfont_default_font();
430 return xf;
431 }
432
433 if (fontcopy[x] != 0)
434 {
435 fontcopy[x] = 0;
436 face_props = &fontcopy[x+1];
437 }
438 else
439 face_props = NULL;
440
441 xf = malloc(sizeof(xfont));
442
443 #ifdef USE_ATS
444 /* Locate the font */
445 xf->type = FONT_INTERNAL;
446 isbold = isitalic = isunderline = false;
447
448 if (face_props != NULL)
449 {
450 for (x=0; face_props[x] != 0; x++)
451 {
452 switch (face_props[x])
453 {
454 case 'b':
455 case 'B':
456 isbold = true;
457 break;
458
459 case 'i':
460 case 'I':
461 isitalic = true;
462 break;
463
464 case 'u':
465 case 'U':
466 isunderline = true;
467 break;
468 }
469 }
470 }
471
472 family[0] = strlen(face_name);
473 strcpy(family+1, face_name);
474 xf->data.mac.family = FMGetFontFamilyFromName(family);
475 erm = FMGetFontFromFontFamilyInstance(xf->data.mac.family,
476 (isbold?bold:0) |
477 (isitalic?italic:0) |
478 (isunderline?underline:0),
479 &xf->data.mac.font,
480 NULL);
481
482 if (erm != noErr)
483 {
484 zmachine_warning("Font family '%s' not found", face_name);
485 free(xf);
486 return xfont_default_font();
487 }
488
489 ATSUCreateStyle(&xf->data.mac.style);
490
491 size = atoi(face_width)<<16;
492 size = (int) ((double)size * scale_factor);
493
494 /* Set the attributes of this font */
495 attsz[0] = sizeof(Fixed);
496 attsz[1] = sizeof(Boolean);
497 attsz[2] = sizeof(ATSUFontID);
498 attptr[0] = &size;
499 attptr[1] = &isunderline;
500 attptr[2] = &xf->data.mac.font;
501
502 ATSUSetAttributes(xf->data.mac.style, 3, tags, attsz, attptr);
503
504 /* Measure the font */
505 {
506 ATSUTextLayout lo;
507 UniChar text[1] = { 'M' };
508
509 ATSUTextMeasurement before, after, ascent, descent;
510
511 /*
512 * (Sigh, there has to be a better way of doing things... We really just
513 * want the metrics)
514 */
515
516 ATSUCreateTextLayout(&lo);
517 ATSUSetTextPointerLocation(lo, text, 0, 1, 1);
518 ATSUSetRunStyle(lo, xf->data.mac.style, 0, 1);
519 ATSUMeasureText(lo, 0, 1, &before, &after, &ascent, &descent);
520
521 xf->data.mac.ascent = ascent/65536.0;
522 xf->data.mac.descent = descent/65536.0;
523 xf->data.mac.maxwidth = (after+before)/65536.0;
524
525 ATSUDisposeTextLayout(lo);
526 }
527 #else
528
529 xf->type = FONT_INTERNAL;
530 family[0] = strlen(face_name);
531 strcpy(family+1, face_name);
532 xf->data.mac.family = FMGetFontFamilyFromName(family);
533 if (xf->data.mac.family == kInvalidFontFamily)
534 {
535 zmachine_warning("Font '%s' not found, reverting to default", face_name);
536 xf->data.mac.family = DEFAULT_FONT;
537 }
538 xf->data.mac.size = (int)((double)atoi(face_width)*scale_factor);
539 xf->data.mac.isbold = 0;
540 xf->data.mac.isitalic = 0;
541 xf->data.mac.isunderlined = 0;
542
543 if (face_props != NULL)
544 {
545 for (x=0; face_props[x] != 0; x++)
546 {
547 switch (face_props[x])
548 {
549 case 'b':
550 case 'B':
551 xf->data.mac.isbold = 1;
552 break;
553
554 case 'i':
555 case 'I':
556 xf->data.mac.isitalic = 1;
557 break;
558
559 case 'u':
560 case 'U':
561 xf->data.mac.isunderlined = 1;
562 break;
563 }
564 }
565 }
566
567 if (FMGetFontFamilyTextEncoding(xf->data.mac.family, &xf->data.mac.encoding)
568 != noErr)
569 zmachine_fatal("Unable to get encoding for font '%s'", face_name);
570 if (CreateUnicodeToTextInfoByEncoding(xf->data.mac.encoding, &xf->data.mac.convert)
571 != noErr)
572 zmachine_fatal("Unable to create TextInfo structure for font '%s'", face_name);
573
574 GetPort(&oldport);
575 SetPort(GetWindowPort(zoomWindow));
576
577 select_font(xf);
578 GetFontInfo(&fm);
579
580 # ifdef USE_QUARTZ
581 {
582 FMFont font;
583 OSStatus erm;
584
585 erm = FMGetFontFromFontFamilyInstance(xf->data.mac.family,
586 (xf->data.mac.isbold?bold:0) |
587 (xf->data.mac.isitalic?italic:0) |
588 (xf->data.mac.isunderlined?underline:0),
589 &font,
590 NULL);
591
592 if (erm != noErr)
593 zmachine_fatal("Unable to get FMFont structure for font '%s'", face_name);
594
595 xf->data.mac.atsref = FMGetATSFontRefFromFont(font);
596 xf->data.mac.cgfont = CGFontCreateWithPlatformFont(&xf->data.mac.atsref);
597 {
598 CFStringRef str;
599 char buf[256];
600
601 ATSUAttributeTag tags[5] =
602 {
603 kATSUSizeTag, kATSUQDBoldfaceTag,
604 kATSUQDItalicTag, kATSUQDUnderlineTag,
605 kATSUFontTag
606 };
607 ByteCount attsz [5];
608 ATSUAttributeValuePtr attptr[5];
609
610 ATSUFontFeatureType fe_types[] = { kLigaturesType };
611 ATSUFontFeatureSelector fe_sel[] = { kCommonLigaturesOffSelector };
612
613 /* Get the name of this font */
614 ATSFontGetPostScriptName(xf->data.mac.atsref,
615 0,
616 &str);
617 CFStringGetCString(str, buf, 256, kCFStringEncodingMacRoman);
618
619 xf->data.mac.psname = malloc(strlen(buf)+1);
620 strcpy(xf->data.mac.psname, buf);
621 CFRelease(str);
622
623 /*
624 * Create an ATSU style (bleh, we need to do this so we can work out
625 * the glyph IDs to plot)
626 */
627 ATSUCreateStyle(&xf->data.mac.style);
628
629 attsz[1] = attsz[2] = attsz[3] = sizeof(Boolean);
630 attsz[4] = sizeof(ATSUFontID);
631 attptr[0] = &xf->data.mac.size;
632 attptr[1] = &xf->data.mac.isbold;
633 attptr[2] = &xf->data.mac.isitalic;
634 attptr[3] = &xf->data.mac.isunderlined;
635 attptr[4] = &xf->data.mac.atsref;
636
637 ATSUSetAttributes(xf->data.mac.style, 4, tags+1, attsz+1, attptr+1);
638
639 ATSUSetFontFeatures(xf->data.mac.style, 1, fe_types, fe_sel);
640 }
641 }
642 # endif
643
644 xf->data.mac.ascent = fm.ascent;
645 xf->data.mac.descent = fm.descent + fm.leading;
646 xf->data.mac.maxwidth = xfont_get_text_width(xf, aspace, 4)/4.0;
647
648 SetPort(oldport);
649 #endif
650
651 return xf;
652 }
653
xfont_release_font(xfont * xf)654 void xfont_release_font(xfont* xf)
655 {
656 if (xf->type != FONT_FONT3)
657 {
658 #ifdef USE_ATS
659 ATSUDisposeStyle(xf->data.mac.style);
660 #else
661 DisposeUnicodeToTextInfo(&xf->data.mac.convert);
662 # ifdef USE_QUARTZ
663 CGFontRelease(xf->data.mac.cgfont);
664 ATSUDisposeStyle(xf->data.mac.style);
665 free(xf->data.mac.psname);
666 # endif
667 #endif
668 }
669 free(xf);
670 }
671
xfont_set_colours(int fg,int bg)672 void xfont_set_colours(int fg, int bg)
673 {
674 fg_col = *carbon_get_colour(fg);
675
676 transpar = 0;
677 if (bg >= 0)
678 bg_col = *carbon_get_colour(bg);
679 else
680 transpar = 1;
681 }
682
xfont_get_height(xfont * xf)683 XFONT_MEASURE xfont_get_height(xfont* xf)
684 {
685 if (xf->type == FONT_FONT3)
686 return xfont_y;
687
688 return xf->data.mac.ascent + xf->data.mac.descent;
689 }
690
xfont_get_ascent(xfont * xf)691 XFONT_MEASURE xfont_get_ascent(xfont* xf)
692 {
693 if (xf->type == FONT_FONT3)
694 return xfont_y;
695
696 return xf->data.mac.ascent;
697 }
698
xfont_get_descent(xfont * xf)699 XFONT_MEASURE xfont_get_descent(xfont* xf)
700 {
701 if (xf->type == FONT_FONT3)
702 return 0;
703
704 return xf->data.mac.descent;
705 }
706
xfont_get_width(xfont * xf)707 XFONT_MEASURE xfont_get_width(xfont* xf)
708 {
709 if (xf->type == FONT_FONT3)
710 return xfont_x;
711
712 return xf->data.mac.maxwidth;
713 }
714
715 #ifndef USE_ATS
convert_text(xfont * font,const int * string,int length,ByteCount * olen)716 static char* convert_text(xfont* font,
717 const int* string,
718 int length,
719 ByteCount* olen)
720 {
721 static UniChar* iunicode = NULL;
722 static char* outbuf = NULL;
723 static int warned = 0;
724
725 int z;
726
727 ByteCount inread;
728 ByteCount outlen;
729
730 OSStatus res;
731
732 iunicode = realloc(iunicode, sizeof(UniChar)*length);
733 for (z=0; z < length; z++)
734 {
735 iunicode[z] = string[z];
736 }
737
738 outbuf = realloc(outbuf, length*2);
739
740 do
741 {
742 res = ConvertFromUnicodeToText(font->data.mac.convert,
743 sizeof(UniChar)*length, iunicode,
744 kUnicodeLooseMappingsMask, 0,
745 NULL, NULL, NULL,
746 length*2, &inread, &outlen,
747 outbuf);
748
749 if (res == kTECUnmappableElementErr)
750 {
751 if (iunicode[inread>>1] == '?')
752 break;
753 iunicode[inread>>1] = '?';
754 }
755 }
756 while (res == kTECUnmappableElementErr);
757
758 if (res != noErr)
759 {
760 if (warned == 0)
761 {
762 warned = 1;
763 zmachine_warning("Unable to convert game text to font text");
764 }
765
766 if (olen != NULL)
767 (*olen) = 3;
768 return "<?>";
769 }
770
771 if (olen != NULL)
772 (*olen) = outlen;
773
774 return outbuf;
775 }
776 #endif
777
778 #if 1
779 /*
780 * This requires some explaination...
781 *
782 * CGContextSelectFont() is slow. So we want to use CGContextSetFont,
783 * which is reasonably fast. However, that doesn't support *any* encoding
784 * conversions, so we need to use ATSU to get the glyph details of the
785 * text we're about to plot.
786 */
make_atsu_layout(xfont * font,const int * string,int length)787 static ATSUTextLayout make_atsu_layout(xfont* font,
788 const int* string,
789 int length)
790 {
791 ATSUTextLayout lay;
792
793 static UniChar* str = NULL;
794 UniCharCount runlength[1];
795 ATSUStyle style[1];
796
797 int x;
798
799 str = realloc(str, sizeof(UniChar)*length);
800 for (x=0; x<length; x++)
801 {
802 str[x] = string[x];
803 }
804
805 runlength[0] = length;
806 style[0] = font->data.mac.style;
807 ATSUCreateTextLayoutWithTextPtr(str, 0, length, length, 1, runlength, style,
808 &lay);
809
810 return lay;
811 }
812
convert_glyphs(xfont * font,const int * string,int length,SInt32 * olen)813 static CGGlyph* convert_glyphs(xfont* font,
814 const int* string,
815 int length,
816 SInt32* olen)
817 {
818 static ATSUGlyphInfoArray* res = NULL;
819 static CGGlyph* out = NULL;
820
821 ATSUTextLayout lay;
822
823 int x;
824
825 ByteCount bufsize;
826
827 if (length <= 0)
828 {
829 *olen = 0;
830 return NULL;
831 }
832
833 lay = make_atsu_layout(font, string, length);
834
835 if (ATSUGetGlyphInfo(lay, 0, length, &bufsize, NULL) != noErr)
836 {
837 *olen = 0;
838 return NULL;
839 }
840 res = realloc(res, bufsize);
841 ATSUGetGlyphInfo(lay, 0, length, &bufsize, res);
842
843 ATSUDisposeTextLayout(lay);
844
845 *olen = 0;
846
847 out = realloc(out, sizeof(CGGlyph)*res->numGlyphs);
848 for (x=0; x<res->numGlyphs; x++)
849 {
850 if (res->glyphs[x].glyphID != 0xffff)
851 out[(*olen)++] = res->glyphs[x].glyphID;
852 }
853
854 return out;
855 }
856 #endif
857
858 #ifdef USE_ATS
make_layout(xfont * xf,const int * string,int len,ATSUTextLayout lo)859 static void make_layout(xfont* xf,
860 const int* string,
861 int len,
862 ATSUTextLayout lo)
863 {
864 static UniChar* ustr = NULL;
865 int x;
866
867 ustr = realloc(ustr, sizeof(UniChar)*len);
868 for (x=0; x<len; x++)
869 ustr[x] = string[x];
870
871 ATSUSetTextPointerLocation(lo, ustr, 0, len, len);
872 ATSUSetRunStyle(lo, xf->data.mac.style, 0, len);
873 }
874 #endif
875
xfont_get_text_width(xfont * xf,const int * string,int length)876 XFONT_MEASURE xfont_get_text_width(xfont* xf,
877 const int* string,
878 int length)
879 {
880 #ifdef USE_ATS
881 ATSUTextLayout lo;
882 GrafPtr oldport;
883
884 static UniChar* str = NULL;
885 UniCharCount runlength[1];
886 ATSUStyle style[1];
887
888 int x;
889
890 if (length <= 0)
891 return;
892
893 ATSUTextMeasurement before, after, ascent, descent;
894
895 if (xf->type == FONT_FONT3)
896 return length*xfont_x;
897
898 GetPort(&oldport);
899 SetPort(GetWindowPort(zoomWindow));
900
901 str = realloc(str, sizeof(UniChar)*length);
902 for (x=0; x<length; x++)
903 str[x] = string[x];
904
905 runlength[0] = length;
906 style[0] = xf->data.mac.style;
907 ATSUCreateTextLayoutWithTextPtr(str, 0, length, length, 1, runlength, style,
908 &lo);
909
910 ATSUMeasureText(lo, 0, length, &before, &after, &ascent, &descent);
911 ATSUDisposeTextLayout(lo);
912
913 SetPort(oldport);
914
915 return (XFONT_MEASURE)(after+before)/65536.0;
916 #else
917 GrafPtr oldport;
918
919 char* outbuf;
920 ByteCount outlen;
921 XFONT_MEASURE res;
922
923 if (xf->type == FONT_FONT3)
924 return length*xfont_x;
925
926 #ifdef USE_QUARTZ
927 if (!enable_quartz)
928 {
929 #endif
930 GetPort(&oldport);
931 SetPort(GetWindowPort(zoomWindow));
932
933 select_font(xf);
934 outbuf = convert_text(xf, string, length, &outlen);
935 res = TextWidth(outbuf, 0, outlen);
936
937 SetPort(oldport);
938 #ifdef USE_QUARTZ
939 }
940 else
941 {
942 CGPoint end;
943 CGGlyph* glyph;
944
945 if (winlastfont != xf)
946 {
947 CGContextSetFont(carbon_quartz_context, xf->data.mac.cgfont);
948 CGContextSetFontSize(carbon_quartz_context, xf->data.mac.size);
949 winlastfont = xf;
950 }
951 glyph = convert_glyphs(xf, string, length, &outlen);
952 CGContextSetTextPosition(carbon_quartz_context, 0, 0);
953 CGContextSetTextDrawingMode(carbon_quartz_context, kCGTextInvisible);
954 CGContextShowGlyphs(carbon_quartz_context, glyph, outlen);
955
956 end = CGContextGetTextPosition(carbon_quartz_context);
957
958 res = end.x;
959 }
960 #endif
961
962 return res;
963 #endif
964 }
965
plot_font_3(int chr,XFONT_MEASURE xpos,XFONT_MEASURE ypos)966 static void plot_font_3(int chr, XFONT_MEASURE xpos, XFONT_MEASURE ypos)
967 {
968 int x;
969
970 if (chr > 127 || chr < 32)
971 return;
972 chr-=32;
973
974 if (font_3.chr[chr].num_coords < 0)
975 {
976 zmachine_warning("Attempt to plot unspecified character %i",
977 chr+32);
978 return;
979 }
980
981 #ifdef USE_QUARTZ
982 if (enable_quartz)
983 {
984 CGContextBeginPath(carbon_quartz_context);
985 CGContextMoveToPoint(carbon_quartz_context,
986 (font_3.chr[chr].coords[0]*xfont_x) / 8.0 + xpos,
987 ((8-font_3.chr[chr].coords[1])*xfont_y) / 8.0 + ypos);
988 for (x=0; x<font_3.chr[chr].num_coords; x++)
989 {
990 CGContextAddLineToPoint(carbon_quartz_context,
991 (font_3.chr[chr].coords[x<<1]*xfont_x) / 8.0 + xpos,
992 ((8-font_3.chr[chr].coords[(x<<1)+1])*xfont_y) / 8.0 + ypos);
993 }
994 CGContextEOFillPath(carbon_quartz_context);
995 }
996 else
997 #endif
998 {
999 if (f3[chr] == nil)
1000 {
1001 MoveTo((font_3.chr[chr].coords[0]*xfont_x) / 8.0 + 0.5,
1002 (font_3.chr[chr].coords[1]*xfont_y) / 8.0 + 0.5);
1003 f3[chr] = OpenPoly();
1004 for (x=0; x<font_3.chr[chr].num_coords; x++)
1005 {
1006 LineTo((font_3.chr[chr].coords[x<<1]*xfont_x) / 8.0 + 0.5,
1007 (font_3.chr[chr].coords[(x<<1)+1]*xfont_y) / 8.0 + 0.5);
1008 }
1009 ClosePoly();
1010 }
1011 OffsetPoly(f3[chr], xpos, ypos);
1012 PaintPoly(f3[chr]);
1013 OffsetPoly(f3[chr], -xpos, -ypos);
1014 }
1015 }
1016
xfont_plot_string(xfont * font,XFONT_MEASURE x,XFONT_MEASURE y,const int * string,int length)1017 void xfont_plot_string(xfont* font,
1018 XFONT_MEASURE x, XFONT_MEASURE y,
1019 const int* string,
1020 int length)
1021 {
1022 char* outbuf;
1023 ByteCount outlen;
1024
1025 Rect portRect;
1026
1027 CGrafPtr thePort = GetQDGlobalsThePort();
1028
1029 if (length <= 0)
1030 return;
1031
1032 GetPortBounds(thePort, &portRect);
1033
1034 if (font->type == FONT_FONT3)
1035 {
1036 int pos;
1037
1038 #ifdef USE_QUARTZ
1039 if (enable_quartz)
1040 {
1041 CGContextSetRGBFillColor(carbon_quartz_context,
1042 (float)fg_col.red/65536.0,
1043 (float)fg_col.green/65536.0,
1044 (float)fg_col.blue/65536.0,
1045 1.0);
1046
1047 for (pos = 0; pos<length; pos++)
1048 {
1049 plot_font_3(string[pos],
1050 portRect.left + x + xfont_x*pos,
1051 (portRect.bottom-portRect.top) + y);
1052 }
1053 }
1054 else
1055 #endif
1056 {
1057 RGBForeColor(&fg_col);
1058
1059 for (pos = 0; pos<length; pos++)
1060 {
1061 plot_font_3(string[pos],
1062 portRect.left+x + xfont_x*pos,
1063 portRect.top-y - xfont_y);
1064 }
1065 }
1066
1067 return;
1068 }
1069
1070 #ifdef USE_ATS
1071 {
1072 ATSUTextLayout lo;
1073 ATSUTextMeasurement before, after, ascent, descent;
1074
1075 ATSUCreateTextLayout(&lo);
1076 make_layout(font, string, length, lo);
1077
1078 RGBForeColor(&fg_col);
1079 ATSUDrawText(lo, 0, length, (portRect.left + x)*65536.0,
1080 (portRect.top - y)*65536.0);
1081 ATSUDisposeTextLayout(lo);
1082 }
1083 #else
1084 outbuf = convert_text(font, string, length, &outlen);
1085
1086 # ifdef USE_QUARTZ
1087 if (!enable_quartz)
1088 {
1089 # endif
1090 select_font(font);
1091
1092 RGBBackColor(&bg_col);
1093 RGBForeColor(&fg_col);
1094 MoveTo(portRect.left+x, portRect.top - y);
1095 DrawText(outbuf, 0, outlen);
1096 # ifdef USE_QUARTZ
1097 }
1098 else
1099 {
1100 CGGlyph* glyph;
1101
1102 glyph = convert_glyphs(font, string, length, &outlen);
1103
1104 if (outlen <= 0)
1105 return;
1106
1107 /*
1108 * There is always CGContextSetFont, but while I'm able to create
1109 * the structure, I can't make CGContextShowText display *anything*...
1110 */
1111 if (winlastfont != font)
1112 {
1113 CGContextSetFont(carbon_quartz_context, font->data.mac.cgfont);
1114 CGContextSetFontSize(carbon_quartz_context, font->data.mac.size);
1115 winlastfont = font;
1116 }
1117
1118 CGContextSetRGBFillColor(carbon_quartz_context,
1119 (float)fg_col.red/65536.0,
1120 (float)fg_col.green/65536.0,
1121 (float)fg_col.blue/65536.0,
1122 1.0);
1123
1124 CGContextSetTextDrawingMode(carbon_quartz_context, kCGTextFill);
1125 CGContextSetTextPosition(carbon_quartz_context,
1126 portRect.left + x,
1127 (portRect.bottom-portRect.top)+y);
1128 CGContextShowGlyphsAtPoint(carbon_quartz_context,
1129 portRect.left + x,
1130 (portRect.bottom-portRect.top)+y,
1131 glyph, outlen);
1132 }
1133 # endif
1134 #endif
1135 }
1136
1137 #endif
1138