* NEWS: Remove items backported to NEWS.24
[emacs/old-mirror.git] / src / macfont.m
blob366d087f8c208f6f5bb3949918624973fa4a7f78
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2014 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
19 Original author: YAMAMOTO Mitsuharu
22 #include <config.h>
24 #include "lisp.h"
25 #include "dispextern.h"
26 #include "frame.h"
27 #include "blockinput.h"
28 #include "character.h"
29 #include "charset.h"
30 #include "composite.h"
31 #include "fontset.h"
32 #include "font.h"
33 #include "termchar.h"
34 #include "nsgui.h"
35 #include "nsterm.h"
36 #include "macfont.h"
37 #include "macuvs.h"
39 #include <libkern/OSByteOrder.h>
41 static struct font_driver macfont_driver;
43 /* Core Text, for Mac OS X.  */
44 static Lisp_Object Qmac_ct;
46 static double mac_ctfont_get_advance_width_for_glyph (CTFontRef, CGGlyph);
47 static CGRect mac_ctfont_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
48 static CFArrayRef mac_ctfont_create_available_families (void);
49 static Boolean mac_ctfont_equal_in_postscript_name (CTFontRef, CTFontRef);
50 static CTLineRef mac_ctfont_create_line_with_string_and_font (CFStringRef,
51                                                               CTFontRef);
52 static CFComparisonResult mac_font_family_compare (const void *,
53                                                    const void *, void *);
54 static Boolean mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef,
55                                                          CFArrayRef);
56 static CFStringRef mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef);
57 static CFIndex mac_ctfont_shape (CTFontRef, CFStringRef,
58                                  struct mac_glyph_layout *, CFIndex);
59 static CFArrayRef
60 mac_font_copy_default_descriptors_for_language (CFStringRef language);
62 static CFStringRef
63 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
64                                                       CFArrayRef languages);
66 #if USE_CT_GLYPH_INFO
67 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef,
68                                              CTCharacterCollection,
69                                              CGFontIndex);
70 #endif
72 /* The font property key specifying the font design destination.  The
73    value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
74    text.  (See the documentation of X Logical Font Description
75    Conventions.)  In the Mac font driver, 1 means the screen font is
76    used for calculating some glyph metrics.  You can see the
77    difference with Monaco 8pt or 9pt, for example.  */
78 static Lisp_Object QCdestination;
80 /* The boolean-valued font property key specifying the use of
81    leading.  */
82 static Lisp_Object QCminspace;
84 struct macfont_metrics;
86 /* The actual structure for Mac font that can be cast to struct font.  */
88 struct macfont_info
90   struct font font;
91   FontRef macfont;
92   CGFontRef cgfont;
93   ScreenFontRef screen_font;
94   struct macfont_cache *cache;
95   struct macfont_metrics **metrics;
96   short metrics_nrows;
97   bool_bf synthetic_italic_p : 1;
98   bool_bf synthetic_bold_p : 1;
99   unsigned spacing : 2;
100   unsigned antialias : 2;
101   bool_bf color_bitmap_p : 1;
104 /* Values for the `spacing' member in `struct macfont_info'.  */
106 enum
107   {
108     MACFONT_SPACING_PROPORTIONAL,
109     MACFONT_SPACING_MONO,
110     MACFONT_SPACING_SYNTHETIC_MONO,
111   };
113 /* Values for the `antialias' member in `struct macfont_info'.  */
115 enum
116   {
117     MACFONT_ANTIALIAS_DEFAULT,
118     MACFONT_ANTIALIAS_OFF,
119     MACFONT_ANTIALIAS_ON,
120   };
122 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
123 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
124 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
126 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
127 static const CGFloat synthetic_bold_factor = 0.024;
129 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
130                                                         FontSymbolicTraits *);
131 static void macfont_store_descriptor_attributes (FontDescriptorRef,
132                                                  Lisp_Object);
133 static Lisp_Object macfont_descriptor_entity (FontDescriptorRef,
134                                               Lisp_Object,
135                                               FontSymbolicTraits);
136 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
137 static int macfont_glyph_extents (struct font *, CGGlyph,
138                                   struct font_metrics *, CGFloat *, int);
139 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
140 static Boolean macfont_supports_charset_and_languages_p (FontDescriptorRef,
141                                                          CFCharacterSetRef,
142                                                          Lisp_Object,
143                                                          CFArrayRef);
144 static Boolean macfont_closest_traits_index_p (CFArrayRef, FontSymbolicTraits,
145                                                CFIndex);
146 static CFDataRef mac_font_copy_uvs_table (FontRef);
147 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
148                                               const UTF32Char [],
149                                               CGGlyph [], CFIndex);
151 /* From CFData to a lisp string.  Always returns a unibyte string.  */
153 static Lisp_Object
154 cfdata_to_lisp (CFDataRef data)
156   CFIndex len = CFDataGetLength (data);
157   Lisp_Object result = make_uninit_string (len);
159   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
161   return result;
166 /* From CFString to a lisp string.  Returns a unibyte string
167    containing a UTF-8 byte sequence.  */
169 static Lisp_Object
170 cfstring_to_lisp_nodecode (CFStringRef string)
172   Lisp_Object result = Qnil;
173   CFDataRef data;
174   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
176   if (s)
177     {
178       CFIndex i, length = CFStringGetLength (string);
180       for (i = 0; i < length; i++)
181         if (CFStringGetCharacterAtIndex (string, i) == 0)
182           break;
184       if (i == length)
185         return make_unibyte_string (s, strlen (s));
186     }
188   data = CFStringCreateExternalRepresentation (NULL, string,
189                                                kCFStringEncodingUTF8, '?');
190   if (data)
191     {
192       result = cfdata_to_lisp (data);
193       CFRelease (data);
194     }
196   return result;
199 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
200    cfstring_create_with_utf8_cstring, this function preserves NUL
201    characters.  */
203 static CFStringRef
204 cfstring_create_with_string_noencode (Lisp_Object s)
206   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
207                                                 kCFStringEncodingUTF8, false);
209   if (string == NULL)
210     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
211     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
212                                       kCFStringEncodingMacRoman, false);
214   return string;
217 static CGFloat
218 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
220   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
222   return advancement.width;
225 static CGGlyph
226 mac_font_get_glyph_for_cid (FontRef font, CharacterCollection collection,
227                             CGFontIndex cid)
229 #if USE_CT_GLYPH_INFO
230   return mac_ctfont_get_glyph_for_cid ((CTFontRef) font, collection, cid);
231 #else
232   {
233     CGGlyph result = kCGFontIndexInvalid;
234     NSFont *nsFont = (NSFont *) font;
235     unichar characters[] = {0xfffd};
236     NSString *string =
237       [NSString stringWithCharacters:characters
238                               length:ARRAYELTS (characters)];
239     NSGlyphInfo *glyphInfo =
240       [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
241                                          collection:collection
242                                          baseString:string];
243     NSDictionary *attributes =
244       [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
245                     glyphInfo,NSGlyphInfoAttributeName,nil];
246     NSTextStorage *textStorage =
247       [[NSTextStorage alloc] initWithString:string
248                                  attributes:attributes];
249     NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
250     NSTextContainer *textContainer = [[NSTextContainer alloc] init];
251     NSFont *fontInTextStorage;
253     [layoutManager addTextContainer:textContainer];
254     [textContainer release];
255     [textStorage addLayoutManager:layoutManager];
256     [layoutManager release];
258     /* Force layout.  */
259     (void) [layoutManager glyphRangeForTextContainer:textContainer];
261     fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
262                                 effectiveRange:NULL];
263     if (fontInTextStorage == nsFont
264         || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
265       {
266         NSGlyph glyph = [layoutManager glyphAtIndex:0];
268         if (glyph < [nsFont numberOfGlyphs])
269           result = glyph;
270       }
272     [textStorage release];
274     return result;
275   }
277 #endif
279 static ScreenFontRef
280 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
282   NSFont *result, *font;
284   font = [NSFont fontWithName:((NSString *) name) size:size];
285   result = [font screenFont];
287   return (ScreenFontRef)[result retain];
291 static Boolean
292 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
293                              CGFloat *descent, CGFloat *leading)
295   NSFont *nsFont = [(NSFont *)font printerFont];
296   NSTextStorage *textStorage;
297   NSLayoutManager *layoutManager;
298   NSTextContainer *textContainer;
299   NSRect usedRect;
300   NSPoint spaceLocation;
301   CGFloat descender;
303   textStorage = [[NSTextStorage alloc] initWithString:@" "];
304   layoutManager = [[NSLayoutManager alloc] init];
305   textContainer = [[NSTextContainer alloc] init];
307   [textStorage setFont:nsFont];
308   [textContainer setLineFragmentPadding:0];
309   [layoutManager setUsesScreenFonts:YES];
311   [layoutManager addTextContainer:textContainer];
312   [textContainer release];
313   [textStorage addLayoutManager:layoutManager];
314   [layoutManager release];
316   if (!(textStorage && layoutManager && textContainer))
317     {
318       [textStorage release];
320       return false;
321     }
323   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
324                                                  effectiveRange:NULL];
325   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
326   [textStorage release];
328   *ascent = spaceLocation.y;
329   *descent = NSHeight (usedRect) - spaceLocation.y;
330   *leading = 0;
331   descender = [nsFont descender];
332   if (- descender < *descent)
333     {
334       *leading = *descent + descender;
335       *descent = - descender;
336     }
338   return true;
341 static CFIndex
342 mac_font_shape_1 (NSFont *font, NSString *string,
343                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
344                   BOOL screen_font_p)
346   NSUInteger i;
347   CFIndex result = 0;
348   NSTextStorage *textStorage;
349   NSLayoutManager *layoutManager;
350   NSTextContainer *textContainer;
351   NSUInteger stringLength;
352   NSPoint spaceLocation;
353   NSUInteger used, numberOfGlyphs;
355   textStorage = [[NSTextStorage alloc] initWithString:string];
356   layoutManager = [[NSLayoutManager alloc] init];
357   textContainer = [[NSTextContainer alloc] init];
359   /* Append a trailing space to measure baseline position.  */
360   [textStorage appendAttributedString:([[[NSAttributedString alloc]
361                                           initWithString:@" "] autorelease])];
362   [textStorage setFont:font];
363   [textContainer setLineFragmentPadding:0];
364   [layoutManager setUsesScreenFonts:screen_font_p];
366   [layoutManager addTextContainer:textContainer];
367   [textContainer release];
368   [textStorage addLayoutManager:layoutManager];
369   [layoutManager release];
371   if (!(textStorage && layoutManager && textContainer))
372     {
373       [textStorage release];
375       return 0;
376     }
378   stringLength = [string length];
380   /* Force layout.  */
381   (void) [layoutManager glyphRangeForTextContainer:textContainer];
383   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
385   /* Remove the appended trailing space because otherwise it may
386      generate a wrong result for a right-to-left text.  */
387   [textStorage beginEditing];
388   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
389   [textStorage endEditing];
390   (void) [layoutManager glyphRangeForTextContainer:textContainer];
392   i = 0;
393   while (i < stringLength)
394     {
395       NSRange range;
396       NSFont *fontInTextStorage =
397         [textStorage attribute:NSFontAttributeName atIndex:i
398                      longestEffectiveRange:&range
399                        inRange:(NSMakeRange (0, stringLength))];
401       if (!(fontInTextStorage == font
402             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
403         break;
404       i = NSMaxRange (range);
405     }
406   if (i < stringLength)
407     /* Make the test `used <= glyph_len' below fail if textStorage
408        contained some fonts other than the specified one.  */
409     used = glyph_len + 1;
410   else
411     {
412       NSRange range = NSMakeRange (0, stringLength);
414       range = [layoutManager glyphRangeForCharacterRange:range
415                                     actualCharacterRange:NULL];
416       numberOfGlyphs = NSMaxRange (range);
417       used = numberOfGlyphs;
418       for (i = 0; i < numberOfGlyphs; i++)
419         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
420           used--;
421     }
423   if (0 < used && used <= glyph_len)
424     {
425       NSUInteger glyphIndex, prevGlyphIndex;
426       unsigned char bidiLevel;
427       NSUInteger *permutation;
428       NSRange compRange, range;
429       CGFloat totalAdvance;
431       glyphIndex = 0;
432       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
433         glyphIndex++;
435       /* For now we assume the direction is not changed within the
436          string.  */
437       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
438                                glyphs:NULL characterIndexes:NULL
439                     glyphInscriptions:NULL elasticBits:NULL
440                            bidiLevels:&bidiLevel];
441       if (bidiLevel & 1)
442         permutation = xmalloc (sizeof (NSUInteger) * used);
443       else
444         permutation = NULL;
446 #define RIGHT_TO_LEFT_P permutation
448       /* Fill the `comp_range' member of struct mac_glyph_layout, and
449          setup a permutation for right-to-left text.  */
450       compRange = NSMakeRange (0, 0);
451       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
452            range.length++)
453         {
454           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
455           NSUInteger characterIndex =
456             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
458           gl->string_index = characterIndex;
460           if (characterIndex >= NSMaxRange (compRange))
461             {
462               compRange.location = NSMaxRange (compRange);
463               do
464                 {
465                   NSRange characterRange =
466                     [string
467                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
469                   compRange.length =
470                     NSMaxRange (characterRange) - compRange.location;
471                   [layoutManager glyphRangeForCharacterRange:compRange
472                                         actualCharacterRange:&characterRange];
473                   characterIndex = NSMaxRange (characterRange) - 1;
474                 }
475               while (characterIndex >= NSMaxRange (compRange));
477               if (RIGHT_TO_LEFT_P)
478                 for (i = 0; i < range.length; i++)
479                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
481               range = NSMakeRange (NSMaxRange (range), 0);
482             }
484           gl->comp_range.location = compRange.location;
485           gl->comp_range.length = compRange.length;
487           while (++glyphIndex < numberOfGlyphs)
488             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
489               break;
490         }
491       if (RIGHT_TO_LEFT_P)
492         for (i = 0; i < range.length; i++)
493           permutation[range.location + i] = NSMaxRange (range) - i - 1;
495       /* Then fill the remaining members.  */
496       glyphIndex = prevGlyphIndex = 0;
497       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
498         glyphIndex++;
500       if (!RIGHT_TO_LEFT_P)
501         totalAdvance = 0;
502       else
503         {
504           NSUInteger nrects;
505           NSRect *glyphRects =
506             [layoutManager
507               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
508               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
509                      inTextContainer:textContainer rectCount:&nrects];
511           totalAdvance = NSMaxX (glyphRects[0]);
512         }
514       for (i = 0; i < used; i++)
515         {
516           struct mac_glyph_layout *gl;
517           NSPoint location;
518           NSUInteger nextGlyphIndex;
519           NSRange glyphRange;
520           NSRect *glyphRects;
521           NSUInteger nrects;
523           if (!RIGHT_TO_LEFT_P)
524             gl = glyph_layouts + i;
525           else
526             {
527               NSUInteger dest = permutation[i];
529               gl = glyph_layouts + dest;
530               if (i < dest)
531                 {
532                   CFIndex tmp = gl->string_index;
534                   gl->string_index = glyph_layouts[i].string_index;
535                   glyph_layouts[i].string_index = tmp;
536                 }
537             }
538           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
540           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
541           gl->baseline_delta = spaceLocation.y - location.y;
543           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
544                nextGlyphIndex++)
545             if (![layoutManager
546                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
547               break;
549           if (!RIGHT_TO_LEFT_P)
550             {
551               CGFloat maxX;
553               if (prevGlyphIndex == 0)
554                 glyphRange = NSMakeRange (0, nextGlyphIndex);
555               else
556                 glyphRange = NSMakeRange (glyphIndex,
557                                           nextGlyphIndex - glyphIndex);
558               glyphRects =
559                 [layoutManager
560                   rectArrayForGlyphRange:glyphRange
561                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
562                          inTextContainer:textContainer rectCount:&nrects];
563               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
564               gl->advance_delta = location.x - totalAdvance;
565               gl->advance = maxX - totalAdvance;
566               totalAdvance = maxX;
567             }
568           else
569             {
570               CGFloat minX;
572               if (nextGlyphIndex == numberOfGlyphs)
573                 glyphRange = NSMakeRange (prevGlyphIndex,
574                                           numberOfGlyphs - prevGlyphIndex);
575               else
576                 glyphRange = NSMakeRange (prevGlyphIndex,
577                                           glyphIndex + 1 - prevGlyphIndex);
578               glyphRects =
579                 [layoutManager
580                   rectArrayForGlyphRange:glyphRange
581                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
582                          inTextContainer:textContainer rectCount:&nrects];
583               minX = min (NSMinX (glyphRects[0]), totalAdvance);
584               gl->advance = totalAdvance - minX;
585               totalAdvance = minX;
586               gl->advance_delta = location.x - totalAdvance;
587             }
589           prevGlyphIndex = glyphIndex + 1;
590           glyphIndex = nextGlyphIndex;
591         }
593       if (RIGHT_TO_LEFT_P)
594         xfree (permutation);
596 #undef RIGHT_TO_LEFT_P
598       result = used;
599     }
600   [textStorage release];
602   return result;
605 static CFIndex
606 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
607                        struct mac_glyph_layout *glyph_layouts,
608                        CFIndex glyph_len)
610   return mac_font_shape_1 ([(NSFont *)font printerFont],
611                            (NSString *) string,
612                            glyph_layouts, glyph_len, YES);
615 static CGColorRef
616 get_cgcolor(unsigned long idx, struct frame *f)
618   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
619   [nsColor set];
620   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
621   NSInteger noc = [nsColor numberOfComponents];
622   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
623   CGColorRef cgColor;
625   [nsColor getComponents: components];
626   cgColor = CGColorCreate (colorSpace, components);
627   xfree (components);
628   return cgColor;
631 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
632   do {                                                                  \
633     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
634     CGContextSetFillColorWithColor (context, refcol_) ;                 \
635     CGColorRelease (refcol_);                                           \
636   } while (0)
637 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f)        \
638   do {                                                                  \
639     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f);    \
640     CGContextSetFillColorWithColor (context, refcol_);                  \
641     CGColorRelease (refcol_);                                           \
642   } while (0)
643 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f)      \
644   do {                                                                  \
645     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
646     CGContextSetStrokeColorWithColor (context, refcol_);                \
647     CGColorRelease (refcol_);                                           \
648   } while (0)
652 /* Mac font driver.  */
654 static struct
656   /* registry name */
657   const char *name;
658   /* characters to distinguish the charset from the others */
659   int uniquifier[6];
660   /* additional constraint by language */
661   CFStringRef lang;
662   /* set on demand */
663   CFCharacterSetRef cf_charset;
664   CFStringRef cf_charset_string;
665 } cf_charset_table[] =
666   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
667     { "iso8859-2", { 0x00A0, 0x010E }},
668     { "iso8859-3", { 0x00A0, 0x0108 }},
669     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
670     { "iso8859-5", { 0x00A0, 0x0401 }},
671     { "iso8859-6", { 0x00A0, 0x060C }},
672     { "iso8859-7", { 0x00A0, 0x0384 }},
673     { "iso8859-8", { 0x00A0, 0x05D0 }},
674     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
675     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
676     { "iso8859-11", { 0x00A0, 0x0E01 }},
677     { "iso8859-13", { 0x00A0, 0x201C }},
678     { "iso8859-14", { 0x00A0, 0x0174 }},
679     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
680     { "iso8859-16", { 0x00A0, 0x0218}},
681     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
682     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
683     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
684     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
685     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
686     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
687     { "cns11643.1992-3", { 0x201A9 }},
688     { "cns11643.1992-4", { 0x20057 }},
689     { "cns11643.1992-5", { 0x20000 }},
690     { "cns11643.1992-6", { 0x20003 }},
691     { "cns11643.1992-7", { 0x20055 }},
692     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
693     { "jisx0212.1990-0", { 0x4E44 }},
694     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
695     { "jisx0213.2000-2", { 0xFA49 }},
696     { "jisx0213.2004-1", { 0x20B9F }},
697     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
698     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
699     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
700     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
701     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
702     { "unicode-sip", { 0x20000 }},
703     { NULL }
704   };
706 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
707 static const struct
709   CFStringRef language;
710   CFStringRef font_names[3];
711 } macfont_language_default_font_names[] = {
712   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
713                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
714                     NULL }},
715   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
716                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
717                     NULL }},
718   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
719                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
720                          NULL }},
721   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
722                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
723                          NULL }},
724   { NULL }
726 #endif
728 static CGFloat macfont_antialias_threshold;
730 void
731 macfont_update_antialias_threshold (void)
733   int threshold;
734   Boolean valid_p;
736   threshold =
737     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
738                                      kCFPreferencesCurrentApplication,
739                                      &valid_p);
740   if (valid_p)
741     macfont_antialias_threshold = threshold;
744 static inline Lisp_Object
745 macfont_intern_prop_cfstring (CFStringRef cfstring)
747   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
749   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
752 static inline CFIndex
753 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
755   if (c < 0x10000)
756     {
757       unichars[0] = c;
759       return 1;
760     }
761   else
762     {
763       c -= 0x10000;
764       unichars[0] = (c >> 10) + 0xD800;
765       unichars[1] = (c & 0x3FF) + 0xDC00;
767       return 2;
768     }
771 static Boolean
772 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
773                                          FontSymbolicTraits *sym_traits)
775   SInt64 sint64_value;
777   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
778      OS X 10.6 when the value is greater than or equal to 1 << 31.  */
779   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
780     {
781       *sym_traits = (FontSymbolicTraits) sint64_value;
783       return true;
784     }
786   return false;
789 static void
790 macfont_store_descriptor_attributes (FontDescriptorRef desc,
791                                      Lisp_Object spec_or_entity)
793   CFStringRef str;
794   CFDictionaryRef dict;
795   CFNumberRef num;
796   CGFloat floatval;
798   str = mac_font_descriptor_copy_attribute (desc,
799                                             MAC_FONT_FAMILY_NAME_ATTRIBUTE);
800   if (str)
801     {
802       ASET (spec_or_entity, FONT_FAMILY_INDEX,
803             macfont_intern_prop_cfstring (str));
804       CFRelease (str);
805     }
806   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
807   if (dict)
808     {
809       struct {
810         enum font_property_index index;
811         CFStringRef trait;
812         CGPoint points[6];
813       } numeric_traits[] =
814           {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
815             {{-0.4, 50},        /* light */
816              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
817              {0, 100},          /* normal */
818              {0.24, 140},       /* (semi-bold + normal) / 2 */
819              {0.4, 200},        /* bold */
820              {CGFLOAT_MAX, CGFLOAT_MAX}}},
821            {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
822             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
823            {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
824             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
825       int i;
827       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
828         {
829           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
830           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
831             {
832               CGPoint *point = numeric_traits[i].points;
834               while (point->x < floatval)
835                 point++;
836               if (point == numeric_traits[i].points)
837                 point++;
838               else if (point->x == CGFLOAT_MAX)
839                 point--;
840               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
841                                            * ((point->y - (point - 1)->y)
842                                               / (point->x - (point - 1)->x)));
843               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
844                               make_number (lround (floatval)));
845             }
846         }
848       num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
849       if (num)
850         {
851           FontSymbolicTraits sym_traits;
852           int spacing;
854           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
855           spacing = (sym_traits & MAC_FONT_TRAIT_MONO_SPACE
856                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
857           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
858         }
860       CFRelease (dict);
861     }
862   num = mac_font_descriptor_copy_attribute (desc, MAC_FONT_SIZE_ATTRIBUTE);
863   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
864     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
865   else
866     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
867   if (num)
868     CFRelease (num);
871 static Lisp_Object
872 macfont_descriptor_entity (FontDescriptorRef desc, Lisp_Object extra,
873                            FontSymbolicTraits synth_sym_traits)
875   Lisp_Object entity;
876   CFDictionaryRef dict;
877   FontSymbolicTraits sym_traits = 0;
878   CFStringRef name;
880   entity = font_make_entity ();
882   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
883   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
885   macfont_store_descriptor_attributes (desc, entity);
887   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
888   if (dict)
889     {
890       CFNumberRef num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
892       if (num)
893         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
894       CFRelease (dict);
895     }
896   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
897     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
898   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
899   name = mac_font_descriptor_copy_attribute (desc, MAC_FONT_NAME_ATTRIBUTE);
900   font_put_extra (entity, QCfont_entity,
901                   make_save_ptr_int ((void *) name, sym_traits));
902   if (synth_sym_traits & MAC_FONT_TRAIT_ITALIC)
903     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
904                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
905   if (synth_sym_traits & MAC_FONT_TRAIT_BOLD)
906     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
907                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
908   if (synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
909     ASET (entity, FONT_SPACING_INDEX,
910           make_number (FONT_SPACING_SYNTHETIC_MONO));
912   return entity;
915 static CFStringRef
916 macfont_create_family_with_symbol (Lisp_Object symbol)
918   static CFArrayRef families = NULL;
919   CFStringRef result = NULL, family_name;
920   int using_cache_p = 1;
921   CFComparatorFunction family_name_comparator;
923   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
924   if (family_name == NULL)
925     return NULL;
927     {
928       family_name_comparator = CTFontManagerCompareFontFamilyNames;
929     }
931   if ((*family_name_comparator) (family_name, CFSTR ("LastResort"), NULL)
932       == kCFCompareEqualTo)
933     result = CFSTR ("LastResort");
934   else
935     while (1)
936       {
937         CFIndex i, count;
939         if (families == NULL)
940           {
941             families = mac_font_create_available_families ();
942             using_cache_p = 0;
943             if (families == NULL)
944               break;
945           }
947         count = CFArrayGetCount (families);
948         i = CFArrayBSearchValues (families, CFRangeMake (0, count),
949                                   (const void *) family_name,
950                                   family_name_comparator, NULL);
951         if (i < count)
952           {
953             CFStringRef name = CFArrayGetValueAtIndex (families, i);
955             if ((*family_name_comparator) (name, family_name, NULL)
956                 == kCFCompareEqualTo)
957               result = CFRetain (name);
958           }
960         if (result || !using_cache_p)
961           break;
962         else
963           {
964             CFRelease (families);
965             families = NULL;
966           }
967       }
969   CFRelease (family_name);
971   return result;
974 #define WIDTH_FRAC_BITS         (4)
975 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
977 struct macfont_metrics
979   unsigned char lbearing_low, rbearing_low;
980   signed lbearing_high : 4, rbearing_high : 4;
981   unsigned char ascent_low, descent_low;
982   signed ascent_high : 4, descent_high : 4;
984   /* These two members are used for fixed-point representation of
985      glyph width.  The `width_int' member is an integer that is
986      closest to the width.  The `width_frac' member is the fractional
987      adjustment representing a value in [-.5, .5], multiplied by
988      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
989      the advance delta for centering instead of the glyph width.  */
990   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
993 #define METRICS_VALUE(metrics, member)                          \
994   (((metrics)->member##_high << 8) | (metrics)->member##_low)
995 #define METRICS_SET_VALUE(metrics, member, value)                   \
996   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff;    \
997     (metrics)->member##_high = tmp >> 8;} while (0)
999 enum metrics_status
1001   METRICS_INVALID = -1,    /* metrics entry is invalid */
1002   METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1005 #define METRICS_STATUS(metrics)                                         \
1006   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1007 #define METRICS_SET_STATUS(metrics, status)                     \
1008   do {METRICS_SET_VALUE (metrics, ascent, 0);                   \
1009     METRICS_SET_VALUE (metrics, descent, status);} while (0)
1011 #define METRICS_NCOLS_PER_ROW   (128)
1012 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1013 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1015 static int
1016 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1017                        struct font_metrics *metrics, CGFloat *advance_delta,
1018                        int force_integral_p)
1020   struct macfont_info *macfont_info = (struct macfont_info *) font;
1021   FontRef macfont = macfont_info->macfont;
1022   int row, col;
1023   struct macfont_metrics *cache;
1024   int width;
1026   row = glyph / METRICS_NCOLS_PER_ROW;
1027   col = glyph % METRICS_NCOLS_PER_ROW;
1028   if (row >= macfont_info->metrics_nrows)
1029     {
1030       macfont_info->metrics =
1031         xrealloc (macfont_info->metrics,
1032                   sizeof (struct macfont_metrics *) * (row + 1));
1033       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1034               (sizeof (struct macfont_metrics *)
1035                * (row + 1 - macfont_info->metrics_nrows)));
1036       macfont_info->metrics_nrows = row + 1;
1037     }
1038   if (macfont_info->metrics[row] == NULL)
1039     {
1040       struct macfont_metrics *new;
1041       int i;
1043       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1044       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1045         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1046       macfont_info->metrics[row] = new;
1047     }
1048   cache = macfont_info->metrics[row] + col;
1050   if (METRICS_STATUS (cache) == METRICS_INVALID)
1051     {
1052       CGFloat fwidth;
1054       if (macfont_info->screen_font)
1055         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1056       else
1057         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1059       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1060          advance delta value.  */
1061       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1062         fwidth = (font->pixel_size - fwidth) / 2;
1063       cache->width_int = lround (fwidth);
1064       cache->width_frac = lround ((fwidth - cache->width_int)
1065                                   * WIDTH_FRAC_SCALE);
1066       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1067     }
1068   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1069     width = font->pixel_size;
1070   else
1071     width = cache->width_int;
1073   if (metrics)
1074     {
1075       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1076         {
1077           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1079           if (macfont_info->synthetic_italic_p)
1080             {
1081               /* We assume the members a, b, c, and d in
1082                  synthetic_italic_atfm are non-negative.  */
1083               bounds.origin =
1084                 CGPointApplyAffineTransform (bounds.origin,
1085                                              synthetic_italic_atfm);
1086               bounds.size =
1087                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1088             }
1089           if (macfont_info->synthetic_bold_p)
1090             {
1091               CGFloat d =
1092                 - synthetic_bold_factor * mac_font_get_size (macfont) / 2;
1094                 bounds = CGRectInset (bounds, d, d);
1095             }
1096           switch (macfont_info->spacing)
1097             {
1098             case MACFONT_SPACING_PROPORTIONAL:
1099               bounds.origin.x += - (cache->width_frac
1100                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1101               break;
1102             case MACFONT_SPACING_MONO:
1103               break;
1104             case MACFONT_SPACING_SYNTHETIC_MONO:
1105               bounds.origin.x += (cache->width_int
1106                                   + (cache->width_frac
1107                                      / (CGFloat) WIDTH_FRAC_SCALE));
1108               break;
1109             }
1110           if (bounds.size.width > 0)
1111             {
1112               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1113               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1114                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1115             }
1116           bounds = CGRectIntegral (bounds);
1117           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1118           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1119           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1120           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1121         }
1122       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1123       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1124       metrics->width = width;
1125       metrics->ascent = METRICS_VALUE (cache, ascent);
1126       metrics->descent = METRICS_VALUE (cache, descent);
1127     }
1129   if (advance_delta)
1130     {
1131       switch (macfont_info->spacing)
1132         {
1133         case MACFONT_SPACING_PROPORTIONAL:
1134           *advance_delta = (force_integral_p ? 0
1135                             : - (cache->width_frac
1136                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1137           break;
1138         case MACFONT_SPACING_MONO:
1139           *advance_delta = 0;
1140           break;
1141         case MACFONT_SPACING_SYNTHETIC_MONO:
1142           *advance_delta = (force_integral_p ? cache->width_int
1143                             : (cache->width_int
1144                                + (cache->width_frac
1145                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1146           break;
1147         }
1148     }
1150   return width;
1153 static CFMutableDictionaryRef macfont_cache_dictionary;
1155 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1156    equal to the number of rows that are invalid as BMP (i.e., from
1157    U+D800 to U+DFFF).  */
1158 #define ROW_PERM_OFFSET (8)
1160 /* The number of glyphs that can be stored in a value for a single
1161    entry of CFDictionary.  */
1162 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1164 struct macfont_cache
1166   int reference_count;
1167   CFCharacterSetRef cf_charset;
1168   struct {
1169     /* The cached glyph for a BMP character c is stored in
1170        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1171        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1172     unsigned char row_nkeys_or_perm[256];
1173     CGGlyph **matrix;
1175     /* Number of rows for which the BMP cache is allocated so far.
1176        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1177     int nrows;
1179     /* The cached glyph for a character c is stored as the (c %
1180        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1181        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1182        not stored here if row_nkeys_or_perm[c / 256] >=
1183        ROW_PERM_OFFSET.  */
1184     CFMutableDictionaryRef dictionary;
1185   } glyph;
1187   struct {
1188     /* UVS (Unicode Variation Sequence) subtable data, which is of
1189        type CFDataRef if available.  NULL means it is not initialized
1190        yet.  kCFNull means the subtable is not found and there is no
1191        suitable fallback table for this font.  */
1192     CFTypeRef table;
1194     /* Character collection specifying the destination of the mapping
1195        provided by `table' above.  If `table' is obtained from the UVS
1196        subtable in the font cmap table, then the value of this member
1197        should be MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING.  */
1198     CharacterCollection collection;
1199   } uvs;
1202 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1203 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1204 static void macfont_release_cache (struct macfont_cache *);
1205 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1206 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1207 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1208 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1209                                           CharacterCollection, CGFontIndex);
1210 static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1212 static struct macfont_cache *
1213 macfont_lookup_cache (CFStringRef key)
1215   struct macfont_cache *cache;
1217   if (macfont_cache_dictionary == NULL)
1218     {
1219       macfont_cache_dictionary =
1220         CFDictionaryCreateMutable (NULL, 0,
1221                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1222       cache = NULL;
1223     }
1224   else
1225     cache = ((struct macfont_cache *)
1226              CFDictionaryGetValue (macfont_cache_dictionary, key));
1228   if (cache == NULL)
1229     {
1230       FontRef macfont = mac_font_create_with_name (key, 0);
1232       if (macfont)
1233         {
1234           cache = xzalloc (sizeof (struct macfont_cache));
1235           /* Treat the LastResort font as if it contained glyphs for
1236              all characters.  This may look too rough, but neither
1237              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1238              for this font is correct for non-BMP characters on Mac OS
1239              X 10.5, anyway.  */
1240           if (CFEqual (key, CFSTR ("LastResort")))
1241             {
1242               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1244               cache->cf_charset =
1245                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1246             }
1247           if (cache->cf_charset == NULL)
1248             cache->cf_charset = mac_font_copy_character_set (macfont);
1249           CFDictionaryAddValue (macfont_cache_dictionary, key,
1250                                 (const void *) cache);
1251           CFRelease (macfont);
1252         }
1253     }
1255   return cache;
1258 static struct macfont_cache *
1259 macfont_retain_cache (struct macfont_cache *cache)
1261   cache->reference_count++;
1263   return cache;
1266 static void
1267 macfont_release_cache (struct macfont_cache *cache)
1269   if (--cache->reference_count == 0)
1270     {
1271       int i;
1273       for (i = 0; i < cache->glyph.nrows; i++)
1274         xfree (cache->glyph.matrix[i]);
1275       xfree (cache->glyph.matrix);
1276       if (cache->glyph.dictionary)
1277         CFRelease (cache->glyph.dictionary);
1278       memset (&cache->glyph, 0, sizeof (cache->glyph));
1279       if (cache->uvs.table)
1280         CFRelease (cache->uvs.table);
1281       memset (&cache->uvs, 0, sizeof (cache->uvs));
1282     }
1285 static CFCharacterSetRef
1286 macfont_get_cf_charset (struct font *font)
1288   struct macfont_info *macfont_info = (struct macfont_info *) font;
1290   return macfont_info->cache->cf_charset;
1293 static CFCharacterSetRef
1294 macfont_get_cf_charset_for_name (CFStringRef name)
1296   struct macfont_cache *cache = macfont_lookup_cache (name);
1298   return cache->cf_charset;
1301 static CGGlyph
1302 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1304   struct macfont_info *macfont_info = (struct macfont_info *) font;
1305   FontRef macfont = macfont_info->macfont;
1306   struct macfont_cache *cache = macfont_info->cache;
1308   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1309     {
1310       int row = c / 256;
1311       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1313       if (nkeys_or_perm < ROW_PERM_OFFSET)
1314         {
1315           UniChar unichars[256], ch;
1316           CGGlyph *glyphs;
1317           int i, len;
1318           int nrows;
1319           dispatch_queue_t queue;
1320           dispatch_group_t group = NULL;
1322           if (row != 0)
1323             {
1324               CFMutableDictionaryRef dictionary;
1325               uintptr_t key, value;
1326               int nshifts;
1327               CGGlyph glyph;
1329               if (cache->glyph.dictionary == NULL)
1330                 cache->glyph.dictionary =
1331                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1332               dictionary = cache->glyph.dictionary;
1333               key = c / NGLYPHS_IN_VALUE;
1334               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1335               value = ((uintptr_t)
1336                        CFDictionaryGetValue (dictionary, (const void *) key));
1337               glyph = (value >> nshifts);
1338               if (glyph)
1339                 return glyph;
1341               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1342                 {
1343                   ch = c;
1344                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1345                                                            &glyph, 1)
1346                       || glyph == 0)
1347                     glyph = kCGFontIndexInvalid;
1349                   if (value == 0)
1350                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1351                   value |= ((uintptr_t) glyph << nshifts);
1352                   CFDictionarySetValue (dictionary, (const void *) key,
1353                                         (const void *) value);
1355                   return glyph;
1356                 }
1358               queue =
1359                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1360               group = dispatch_group_create ();
1361               dispatch_group_async (group, queue, ^{
1362                   int nkeys;
1363                   uintptr_t key;
1364                   nkeys = nkeys_or_perm;
1365                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1366                     if (CFDictionaryContainsKey (dictionary,
1367                                                  (const void *) key))
1368                       {
1369                         CFDictionaryRemoveValue (dictionary,
1370                                                  (const void *) key);
1371                         if (--nkeys == 0)
1372                           break;
1373                       }
1374                 });
1375             }
1377           len = 0;
1378           for (i = 0; i < 256; i++)
1379             {
1380               ch = row * 256 + i;
1381               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1382                 unichars[len++] = ch;
1383             }
1385           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1386           if (len > 0)
1387             {
1388               mac_font_get_glyphs_for_characters (macfont, unichars,
1389                                                   glyphs, len);
1390               while (i > len)
1391                 {
1392                   int next = unichars[len - 1] % 256;
1394                   while (--i > next)
1395                     glyphs[i] = kCGFontIndexInvalid;
1397                   len--;
1398                   glyphs[i] = glyphs[len];
1399                   if (len == 0)
1400                     break;
1401                 }
1402             }
1403           if (i > len)
1404             while (i-- > 0)
1405               glyphs[i] = kCGFontIndexInvalid;
1407           nrows = cache->glyph.nrows;
1408           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1409           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1410           nrows++;
1411           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1412                                           sizeof (CGGlyph *) * nrows);
1413           cache->glyph.matrix[nrows - 1] = glyphs;
1414           cache->glyph.nrows = nrows;
1416           if (group)
1417             {
1418               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1419               dispatch_release (group);
1420             }
1421         }
1423       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1424     }
1425   else
1426     {
1427       uintptr_t key, value;
1428       int nshifts;
1429       CGGlyph glyph;
1431       if (cache->glyph.dictionary == NULL)
1432         cache->glyph.dictionary =
1433           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1434       key = c / NGLYPHS_IN_VALUE;
1435       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1436       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1437                                                 (const void *) key);
1438       glyph = (value >> nshifts);
1439       if (glyph == 0)
1440         {
1441           UniChar unichars[2];
1442           CGGlyph glyphs[2];
1443           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1445           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1446                                                   count))
1447             glyph = glyphs[0];
1448           if (glyph == 0)
1449             glyph = kCGFontIndexInvalid;
1451           value |= ((uintptr_t) glyph << nshifts);
1452           CFDictionarySetValue (cache->glyph.dictionary,
1453                                 (const void *) key, (const void *) value);
1454         }
1456       return glyph;
1457     }
1460 static CGGlyph
1461 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1462                            CGFontIndex cid)
1464   struct macfont_info *macfont_info = (struct macfont_info *) font;
1465   FontRef macfont = macfont_info->macfont;
1467   /* Cache it? */
1468   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1471 static CFDataRef
1472 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1474   struct macfont_info *macfont_info = (struct macfont_info *) font;
1475   FontRef macfont = macfont_info->macfont;
1476   struct macfont_cache *cache = macfont_info->cache;
1477   CFDataRef result = NULL;
1479   if (cache->uvs.table == NULL)
1480     {
1481       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1482       CharacterCollection uvs_collection =
1483         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1485       if (uvs_table == NULL
1486           && mac_font_get_glyph_for_cid (macfont,
1487                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1488                                          6480) != kCGFontIndexInvalid)
1489         {
1490           /* If the glyph for U+4E55 is accessible via its CID 6480,
1491              then we use the Adobe-Japan1 UVS table, which maps a
1492              variation sequence to a CID, as a fallback.  */
1493           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1495           if (mac_uvs_table_adobe_japan1 == NULL)
1496             mac_uvs_table_adobe_japan1 =
1497               CFDataCreateWithBytesNoCopy (NULL,
1498                                            mac_uvs_table_adobe_japan1_bytes,
1499                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1500                                            kCFAllocatorNull);
1501           if (mac_uvs_table_adobe_japan1)
1502             {
1503               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1504               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1505             }
1506         }
1507       if (uvs_table == NULL)
1508         cache->uvs.table = kCFNull;
1509       else
1510         cache->uvs.table = uvs_table;
1511       cache->uvs.collection = uvs_collection;
1512     }
1514   if (cache->uvs.table != kCFNull)
1515     {
1516       result = cache->uvs.table;
1517       *collection = cache->uvs.collection;
1518     }
1520   return result;
1523 static Lisp_Object macfont_get_cache (struct frame *);
1524 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1525 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1526 static Lisp_Object macfont_list_family (struct frame *);
1527 static void macfont_free_entity (Lisp_Object);
1528 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1529 static void macfont_close (struct font *);
1530 static int macfont_has_char (Lisp_Object, int);
1531 static unsigned macfont_encode_char (struct font *, int);
1532 static void macfont_text_extents (struct font *, unsigned int *, int,
1533                                   struct font_metrics *);
1534 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1535 static Lisp_Object macfont_shape (Lisp_Object);
1536 static int macfont_variation_glyphs (struct font *, int c,
1537                                      unsigned variations[256]);
1538 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1540 static struct font_driver macfont_driver =
1541   {
1542     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1543     0,                          /* case insensitive */
1544     macfont_get_cache,
1545     macfont_list,
1546     macfont_match,
1547     macfont_list_family,
1548     macfont_free_entity,
1549     macfont_open,
1550     macfont_close,
1551     NULL,                       /* prepare_face */
1552     NULL,                       /* done_face */
1553     macfont_has_char,
1554     macfont_encode_char,
1555     macfont_text_extents,
1556     macfont_draw,
1557     NULL,                       /* get_bitmap */
1558     NULL,                       /* free_bitmap */
1559     NULL,                       /* anchor_point */
1560     NULL,                       /* otf_capability */
1561     NULL,                       /* otf_drive */
1562     NULL,                       /* start_for_frame */
1563     NULL,                       /* end_for_frame */
1564     macfont_shape,
1565     NULL,                       /* check */
1566     macfont_variation_glyphs,
1567     macfont_filter_properties,
1568   };
1570 static Lisp_Object
1571 macfont_get_cache (struct frame * f)
1573   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1575   return (dpyinfo->name_list_element);
1578 static int
1579 macfont_get_charset (Lisp_Object registry)
1581   char *str = SSDATA (SYMBOL_NAME (registry));
1582   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1583   Lisp_Object regexp;
1584   int i, j;
1586   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1587     {
1588       if (str[i] == '.')
1589         re[j++] = '\\';
1590       else if (str[i] == '*')
1591         re[j++] = '.';
1592       re[j] = str[i];
1593       if (re[j] == '?')
1594         re[j] = '.';
1595     }
1596   re[j] = '\0';
1597   regexp = make_unibyte_string (re, j);
1598   for (i = 0; cf_charset_table[i].name; i++)
1599     if (fast_c_string_match_ignore_case
1600         (regexp, cf_charset_table[i].name,
1601          strlen (cf_charset_table[i].name)) >= 0)
1602       break;
1603   if (! cf_charset_table[i].name)
1604     return -1;
1605   if (! cf_charset_table[i].cf_charset)
1606     {
1607       int *uniquifier = cf_charset_table[i].uniquifier;
1608       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1609       CFIndex count = 0;
1610       CFStringRef string;
1611       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1613       if (! charset)
1614         return -1;
1615       for (j = 0; uniquifier[j]; j++)
1616         {
1617           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1618                                                         unichars + count);
1619           CFCharacterSetAddCharactersInRange (charset,
1620                                               CFRangeMake (uniquifier[j], 1));
1621         }
1623       string = CFStringCreateWithCharacters (NULL, unichars, count);
1624       if (! string)
1625         {
1626           CFRelease (charset);
1627           return -1;
1628         }
1629       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1630                                                                  charset);
1631       CFRelease (charset);
1632       /* CFCharacterSetCreateWithCharactersInString does not handle
1633          surrogate pairs properly as of Mac OS X 10.5.  */
1634       cf_charset_table[i].cf_charset_string = string;
1635     }
1636   return i;
1639 struct OpenTypeSpec
1641   Lisp_Object script;
1642   unsigned int script_tag, langsys_tag;
1643   int nfeatures[2];
1644   unsigned int *features[2];
1647 #define OTF_SYM_TAG(SYM, TAG)                               \
1648   do {                                                      \
1649     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1650     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1651   } while (0)
1653 #define OTF_TAG_STR(TAG, P)                     \
1654   do {                                          \
1655     (P)[0] = (char) (TAG >> 24);                \
1656     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1657     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1658     (P)[3] = (char) (TAG & 0xFF);               \
1659     (P)[4] = '\0';                              \
1660   } while (0)
1662 static struct OpenTypeSpec *
1663 macfont_get_open_type_spec (Lisp_Object otf_spec)
1665   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1666   Lisp_Object val;
1667   int i, j;
1668   bool negative;
1670   if (! spec)
1671     return NULL;
1672   spec->script = XCAR (otf_spec);
1673   if (! NILP (spec->script))
1674     {
1675       OTF_SYM_TAG (spec->script, spec->script_tag);
1676       val = assq_no_quit (spec->script, Votf_script_alist);
1677       if (CONSP (val) && SYMBOLP (XCDR (val)))
1678         spec->script = XCDR (val);
1679       else
1680         spec->script = Qnil;
1681     }
1682   else
1683     spec->script_tag = 0x44464C54;      /* "DFLT" */
1684   otf_spec = XCDR (otf_spec);
1685   spec->langsys_tag = 0;
1686   if (! NILP (otf_spec))
1687     {
1688       val = XCAR (otf_spec);
1689       if (! NILP (val))
1690         OTF_SYM_TAG (val, spec->langsys_tag);
1691       otf_spec = XCDR (otf_spec);
1692     }
1693   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1694   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1695     {
1696       Lisp_Object len;
1698       val = XCAR (otf_spec);
1699       if (NILP (val))
1700         continue;
1701       len = Flength (val);
1702       spec->features[i] =
1703         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1704          ? 0
1705          : malloc (XINT (len) * sizeof *spec->features[i]));
1706       if (! spec->features[i])
1707         {
1708           if (i > 0 && spec->features[0])
1709             free (spec->features[0]);
1710           free (spec);
1711           return NULL;
1712         }
1713       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1714         {
1715           if (NILP (XCAR (val)))
1716             negative = 1;
1717           else
1718             {
1719               unsigned int tag;
1721               OTF_SYM_TAG (XCAR (val), tag);
1722               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1723             }
1724         }
1725       spec->nfeatures[i] = j;
1726     }
1727   return spec;
1730 static CFMutableDictionaryRef
1731 macfont_create_attributes_with_spec (Lisp_Object spec)
1733   Lisp_Object tmp, extra;
1734   CFMutableArrayRef langarray = NULL;
1735   CFCharacterSetRef charset = NULL;
1736   CFStringRef charset_string = NULL;
1737   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1738   Lisp_Object script = Qnil;
1739   Lisp_Object registry;
1740   int cf_charset_idx, i;
1741   struct OpenTypeSpec *otspec = NULL;
1742   struct {
1743     enum font_property_index index;
1744     CFStringRef trait;
1745     CGPoint points[6];
1746   } numeric_traits[] =
1747       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1748         {{-0.4, 50},            /* light */
1749          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1750          {0, 100},              /* normal */
1751          {0.24, 140},           /* (semi-bold + normal) / 2 */
1752          {0.4, 200},            /* bold */
1753          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1754        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1755         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1756        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1757         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1759   registry = AREF (spec, FONT_REGISTRY_INDEX);
1760   if (NILP (registry)
1761       || EQ (registry, Qascii_0)
1762       || EQ (registry, Qiso10646_1)
1763       || EQ (registry, Qunicode_bmp))
1764     cf_charset_idx = -1;
1765   else
1766     {
1767       CFStringRef lang;
1769       cf_charset_idx = macfont_get_charset (registry);
1770       if (cf_charset_idx < 0)
1771         goto err;
1772       charset = cf_charset_table[cf_charset_idx].cf_charset;
1773       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1774       lang = cf_charset_table[cf_charset_idx].lang;
1775       if (lang)
1776         {
1777           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1778           if (! langarray)
1779             goto err;
1780           CFArrayAppendValue (langarray, lang);
1781         }
1782     }
1784   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1785        CONSP (extra); extra = XCDR (extra))
1786     {
1787       Lisp_Object key, val;
1789       tmp = XCAR (extra);
1790       key = XCAR (tmp), val = XCDR (tmp);
1791       if (EQ (key, QClang))
1792         {
1793           if (! langarray)
1794             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1795           if (! langarray)
1796             goto err;
1797           if (SYMBOLP (val))
1798             val = list1 (val);
1799           for (; CONSP (val); val = XCDR (val))
1800             if (SYMBOLP (XCAR (val)))
1801               {
1802                 CFStringRef lang =
1803                   cfstring_create_with_string_noencode (SYMBOL_NAME
1804                                                         (XCAR (val)));
1806                 if (lang == NULL)
1807                   goto err;
1808                 CFArrayAppendValue (langarray, lang);
1809                 CFRelease (lang);
1810               }
1811         }
1812       else if (EQ (key, QCotf))
1813         {
1814           otspec = macfont_get_open_type_spec (val);
1815           if (! otspec)
1816             goto err;
1817           script = otspec->script;
1818         }
1819       else if (EQ (key, QCscript))
1820         script = val;
1821     }
1823   if (! NILP (script) && ! charset)
1824     {
1825       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1827       if (CONSP (chars) && CONSP (CDR (chars)))
1828         {
1829           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1830           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1832           if (! string || !cs)
1833             {
1834               if (string)
1835                 CFRelease (string);
1836               else if (cs)
1837                 CFRelease (cs);
1838               goto err;
1839             }
1840           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1841             if (CHARACTERP (XCAR (chars)))
1842               {
1843                 UniChar unichars[2];
1844                 CFIndex count =
1845                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1846                                                        unichars);
1847                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1849                 CFStringAppendCharacters (string, unichars, count);
1850                 CFCharacterSetAddCharactersInRange (cs, range);
1851               }
1852           charset = cs;
1853           /* CFCharacterSetCreateWithCharactersInString does not
1854              handle surrogate pairs properly as of Mac OS X 10.5.  */
1855           charset_string = string;
1856         }
1857     }
1859   attributes = CFDictionaryCreateMutable (NULL, 0,
1860                                           &kCFTypeDictionaryKeyCallBacks,
1861                                           &kCFTypeDictionaryValueCallBacks);
1862   if (! attributes)
1863     goto err;
1865   tmp = AREF (spec, FONT_FAMILY_INDEX);
1866   if (SYMBOLP (tmp) && ! NILP (tmp))
1867     {
1868       CFStringRef family = macfont_create_family_with_symbol (tmp);
1870       if (! family)
1871         goto err;
1872       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1873                             family);
1874       CFRelease (family);
1875     }
1877   traits = CFDictionaryCreateMutable (NULL, 4,
1878                                       &kCFTypeDictionaryKeyCallBacks,
1879                                       &kCFTypeDictionaryValueCallBacks);
1880   if (! traits)
1881     goto err;
1883   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1884     {
1885       tmp = AREF (spec, numeric_traits[i].index);
1886       if (INTEGERP (tmp))
1887         {
1888           CGPoint *point = numeric_traits[i].points;
1889           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1890           CFNumberRef num;
1892           while (point->y < floatval)
1893             point++;
1894           if (point == numeric_traits[i].points)
1895             point++;
1896           else if (point->y == CGFLOAT_MAX)
1897             point--;
1898           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1899                                        * ((point->x - (point - 1)->x)
1900                                           / (point->y - (point - 1)->y)));
1901           if (floatval > 1.0)
1902             floatval = 1.0;
1903           else if (floatval < -1.0)
1904             floatval = -1.0;
1905           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1906           if (! num)
1907             goto err;
1908           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1909           CFRelease (num);
1910         }
1911     }
1912   if (CFDictionaryGetCount (traits))
1913     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1915   if (charset)
1916     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1917                           charset);
1918   if (charset_string)
1919     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1920                           charset_string);
1921   if (langarray)
1922     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1924   goto finish;
1926  err:
1927   if (attributes)
1928     {
1929       CFRelease (attributes);
1930       attributes = NULL;
1931     }
1933  finish:
1934   if (langarray) CFRelease (langarray);
1935   if (charset && cf_charset_idx < 0) CFRelease (charset);
1936   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1937   if (traits) CFRelease (traits);
1938   if (otspec)
1939     {
1940       if (otspec->nfeatures[0] > 0)
1941         free (otspec->features[0]);
1942       if (otspec->nfeatures[1] > 0)
1943         free (otspec->features[1]);
1944       free (otspec);
1945     }
1947   return attributes;
1950 static Boolean
1951 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1952                                           CFCharacterSetRef charset,
1953                                           Lisp_Object chars,
1954                                           CFArrayRef languages)
1956   Boolean result = true;
1958   if (charset || VECTORP (chars))
1959     {
1960       CFCharacterSetRef desc_charset =
1961         mac_font_descriptor_copy_attribute (desc,
1962                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1964       if (desc_charset == NULL)
1965         result = false;
1966       else
1967         {
1968           if (charset)
1969             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
1970           else                  /* VECTORP (chars) */
1971             {
1972               ptrdiff_t j;
1974               for (j = 0; j < ASIZE (chars); j++)
1975                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
1976                     && CFCharacterSetIsLongCharacterMember (desc_charset,
1977                                                             XFASTINT (AREF (chars, j))))
1978                   break;
1979               if (j == ASIZE (chars))
1980                 result = false;
1981             }
1982           CFRelease (desc_charset);
1983         }
1984     }
1985   if (result && languages)
1986     result = mac_font_descriptor_supports_languages (desc, languages);
1988   return result;
1991 static int
1992 macfont_traits_distance (FontSymbolicTraits sym_traits1,
1993                          FontSymbolicTraits sym_traits2)
1995   FontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
1996   int distance = 0;
1998   /* We prefer synthetic bold of italic to synthetic italic of bold
1999      when both bold and italic are available but bold-italic is not
2000      available.  */
2001   if (diff & MAC_FONT_TRAIT_BOLD)
2002     distance |= (1 << 0);
2003   if (diff & MAC_FONT_TRAIT_ITALIC)
2004     distance |= (1 << 1);
2005   if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2006     distance |= (1 << 2);
2008   return distance;
2011 static Boolean
2012 macfont_closest_traits_index_p (CFArrayRef traits_array,
2013                                 FontSymbolicTraits target,
2014                                 CFIndex index)
2016   CFIndex i, count = CFArrayGetCount (traits_array);
2017   FontSymbolicTraits traits;
2018   int my_distance;
2020   traits = ((FontSymbolicTraits) (uintptr_t)
2021             CFArrayGetValueAtIndex (traits_array, index));
2022   my_distance = macfont_traits_distance (target, traits);
2024   for (i = 0; i < count; i++)
2025     if (i != index)
2026       {
2027         traits = ((FontSymbolicTraits) (uintptr_t)
2028                   CFArrayGetValueAtIndex (traits_array, i));
2029         if (macfont_traits_distance (target, traits) < my_distance)
2030           return false;
2031       }
2033   return true;
2036 static Lisp_Object
2037 macfont_list (struct frame *f, Lisp_Object spec)
2039   Lisp_Object val = Qnil, family, extra;
2040   int i, n;
2041   CFStringRef family_name = NULL;
2042   CFMutableDictionaryRef attributes = NULL, traits;
2043   Lisp_Object chars = Qnil;
2044   int spacing = -1;
2045   FontSymbolicTraits synth_sym_traits = 0;
2046   CFArrayRef families;
2047   CFIndex families_count;
2048   CFCharacterSetRef charset = NULL;
2049   CFArrayRef languages = NULL;
2051   block_input ();
2053   family = AREF (spec, FONT_FAMILY_INDEX);
2054   if (! NILP (family))
2055     {
2056       family_name = macfont_create_family_with_symbol (family);
2057       if (family_name == NULL)
2058         goto finish;
2059     }
2061   attributes = macfont_create_attributes_with_spec (spec);
2062   if (! attributes)
2063     goto finish;
2065   languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2067   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2068     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2070   traits = ((CFMutableDictionaryRef)
2071             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2073   n = FONT_SLANT_NUMERIC (spec);
2074   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2075     {
2076       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2077       if (traits)
2078         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2079     }
2081   n = FONT_WEIGHT_NUMERIC (spec);
2082   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2083     {
2084       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2085       if (traits)
2086         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2087     }
2089   if (languages
2090       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2091     {
2092       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2094       if (CFStringHasPrefix (language, CFSTR ("ja"))
2095           || CFStringHasPrefix (language, CFSTR ("ko"))
2096           || CFStringHasPrefix (language, CFSTR ("zh")))
2097         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2098     }
2100   /* Create array of families.  */
2101   if (family_name)
2102     families = CFArrayCreate (NULL, (const void **) &family_name,
2103                               1, &kCFTypeArrayCallBacks);
2104   else
2105     {
2106       CFStringRef pref_family;
2107       CFIndex families_count, pref_family_index = -1;
2109       families = mac_font_create_available_families ();
2110       if (families == NULL)
2111         goto err;
2113       families_count = CFArrayGetCount (families);
2115       /* Move preferred family to the front if exists.  */
2116       pref_family =
2117         mac_font_create_preferred_family_for_attributes (attributes);
2118       if (pref_family)
2119         {
2120           pref_family_index =
2121             CFArrayGetFirstIndexOfValue (families,
2122                                          CFRangeMake (0, families_count),
2123                                          pref_family);
2124           CFRelease (pref_family);
2125         }
2126       if (pref_family_index > 0)
2127         {
2128           CFMutableArrayRef mutable_families =
2129             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2131           if (mutable_families)
2132             {
2133               CFArrayAppendValue (mutable_families,
2134                                   CFArrayGetValueAtIndex (families,
2135                                                           pref_family_index));
2136               CFArrayAppendArray (mutable_families, families,
2137                                   CFRangeMake (0, pref_family_index));
2138               if (pref_family_index + 1 < families_count)
2139                 CFArrayAppendArray (mutable_families, families,
2140                                     CFRangeMake (pref_family_index + 1,
2141                                                  families_count
2142                                                  - (pref_family_index + 1)));
2143               CFRelease (families);
2144               families = mutable_families;
2145             }
2146         }
2147     }
2149   charset = CFDictionaryGetValue (attributes,
2150                                   MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2151   if (charset)
2152     {
2153       CFRetain (charset);
2154       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2155     }
2156   else
2157     {
2158       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2159       if (! NILP (val))
2160         {
2161           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2162           if (CONSP (val) && VECTORP (XCDR (val)))
2163             chars = XCDR (val);
2164         }
2165       val = Qnil;
2166     }
2168   if (languages)
2169     {
2170       CFRetain (languages);
2171       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2172     }
2174   val = Qnil;
2175   extra = AREF (spec, FONT_EXTRA_INDEX);
2176   families_count = CFArrayGetCount (families);
2177   for (i = 0; i < families_count; i++)
2178     {
2179       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2180       FontDescriptorRef pat_desc;
2181       CFArrayRef descs;
2182       CFIndex descs_count;
2183       CFMutableArrayRef filtered_descs, traits_array;
2184       Lisp_Object entity;
2185       int j;
2187       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2188                             family_name);
2189       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2190       if (! pat_desc)
2191         goto err;
2193       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2194          10.7 returns NULL if pat_desc represents the LastResort font.
2195          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2196          trailing "s") for such a font.  */
2197       if (!CFEqual (family_name, CFSTR ("LastResort")))
2198         descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2199                                                                       NULL);
2200       else
2201         {
2202           FontDescriptorRef lr_desc =
2203             mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2204                                                                  NULL);
2205           if (lr_desc)
2206             {
2207               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2208                                      &kCFTypeArrayCallBacks);
2209               CFRelease (lr_desc);
2210             }
2211           else
2212             descs = NULL;
2213         }
2214       CFRelease (pat_desc);
2215       if (! descs)
2216         goto err;
2218       descs_count = CFArrayGetCount (descs);
2219       if (descs_count == 0
2220           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2221                                                         charset, chars,
2222                                                         languages))
2223         {
2224           CFRelease (descs);
2225           continue;
2226         }
2228       filtered_descs =
2229         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2230       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2231       for (j = 0; j < descs_count; j++)
2232         {
2233           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2234           CFDictionaryRef dict;
2235           CFNumberRef num;
2236           FontSymbolicTraits sym_traits;
2238           dict = mac_font_descriptor_copy_attribute (desc,
2239                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2240           if (dict == NULL)
2241             continue;
2243           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2244           CFRelease (dict);
2245           if (num == NULL
2246               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2247             continue;
2249           if (spacing >= 0
2250               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2251               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2252                   != (spacing >= FONT_SPACING_MONO)))
2253             continue;
2255           /* Don't use a color bitmap font unless its family is
2256              explicitly specified.  */
2257           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2258             continue;
2260           if (j > 0
2261               && !macfont_supports_charset_and_languages_p (desc, charset,
2262                                                             chars, languages))
2263             continue;
2265           CFArrayAppendValue (filtered_descs, desc);
2266           CFArrayAppendValue (traits_array,
2267                               (const void *) (uintptr_t) sym_traits);
2268         }
2270       CFRelease (descs);
2271       descs = filtered_descs;
2272       descs_count = CFArrayGetCount (descs);
2274       for (j = 0; j < descs_count; j++)
2275         {
2276           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2277           FontSymbolicTraits sym_traits =
2278             ((FontSymbolicTraits) (uintptr_t)
2279              CFArrayGetValueAtIndex (traits_array, j));
2280           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2282           mask_min = ((synth_sym_traits ^ sym_traits)
2283                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2284           if (FONT_SLANT_NUMERIC (spec) < 0)
2285             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2286           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2287             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2289           mask_max = (synth_sym_traits & ~sym_traits);
2290           /* Synthetic bold does not work for bitmap-only fonts on Mac
2291              OS X 10.6.  */
2292           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2293             {
2294               CFNumberRef format =
2295                 mac_font_descriptor_copy_attribute (desc,
2296                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2298               if (format)
2299                 {
2300                   uint32_t format_val;
2302                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2303                                         &format_val)
2304                       && format_val == MAC_FONT_FORMAT_BITMAP)
2305                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2306                 }
2307             }
2308           if (spacing >= 0)
2309             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2311           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2312                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2313                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2314             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2315                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2316                  bmask += MAC_FONT_TRAIT_BOLD)
2317               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2318                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2319                    imask += MAC_FONT_TRAIT_ITALIC)
2320                 {
2321                   FontSymbolicTraits synth = (imask | bmask | mmask);
2323                   if (synth == 0
2324                       || macfont_closest_traits_index_p (traits_array,
2325                                                          (sym_traits | synth),
2326                                                          j))
2327                     {
2328                       entity = macfont_descriptor_entity (desc, extra, synth);
2329                       if (! NILP (entity))
2330                         val = Fcons (entity, val);
2331                     }
2332                 }
2333         }
2335       CFRelease (traits_array);
2336       CFRelease (descs);
2337     }
2339   CFRelease (families);
2340   val = Fnreverse (val);
2341   goto finish;
2342  err:
2343   val = Qnil;
2345  finish:
2346   FONT_ADD_LOG ("macfont-list", spec, val);
2347   if (charset) CFRelease (charset);
2348   if (languages) CFRelease (languages);
2349   if (attributes) CFRelease (attributes);
2350   if (family_name) CFRelease (family_name);
2352   unblock_input ();
2354   return val;
2357 static Lisp_Object
2358 macfont_match (struct frame * frame, Lisp_Object spec)
2360   Lisp_Object entity = Qnil;
2361   CFMutableDictionaryRef attributes;
2362   FontDescriptorRef pat_desc = NULL, desc = NULL;
2364   block_input ();
2366   attributes = macfont_create_attributes_with_spec (spec);
2367   if (attributes)
2368     {
2369       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2370       CFRelease (attributes);
2371     }
2372   if (pat_desc)
2373     {
2374       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2375                                                                   NULL);
2376       CFRelease (pat_desc);
2377     }
2378   if (desc)
2379     {
2380       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2381                                           0);
2382       CFRelease (desc);
2383     }
2384   unblock_input ();
2386   FONT_ADD_LOG ("macfont-match", spec, entity);
2387   return entity;
2390 static Lisp_Object
2391 macfont_list_family (struct frame *frame)
2393   Lisp_Object list = Qnil;
2394   CFArrayRef families;
2396   block_input ();
2398   families = mac_font_create_available_families ();
2399   if (families)
2400     {
2401       CFIndex i, count = CFArrayGetCount (families);
2403       for (i = 0; i < count; i++)
2404         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2405       CFRelease (families);
2406     }
2408   unblock_input ();
2410   return list;
2413 static void
2414 macfont_free_entity (Lisp_Object entity)
2416   Lisp_Object val = assq_no_quit (QCfont_entity,
2417                                   AREF (entity, FONT_EXTRA_INDEX));
2418   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2420   block_input ();
2421   CFRelease (name);
2422   unblock_input ();
2425 static Lisp_Object
2426 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2428   Lisp_Object val, font_object;
2429   CFStringRef font_name;
2430   struct macfont_info *macfont_info = NULL;
2431   struct font *font;
2432   int size;
2433   FontRef macfont;
2434   FontSymbolicTraits sym_traits;
2435   char name[256];
2436   int len, i, total_width;
2437   CGGlyph glyph;
2438   CGFloat ascent, descent, leading;
2440   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2441   if (! CONSP (val)
2442       || XTYPE (XCDR (val)) != Lisp_Misc
2443       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2444     return Qnil;
2445   font_name = XSAVE_POINTER (XCDR (val), 0);
2446   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2448   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2449   if (size == 0)
2450     size = pixel_size;
2452   block_input ();
2453   macfont = mac_font_create_with_name (font_name, size);
2454   if (macfont)
2455     {
2456       int fontsize = (int) [((NSFont *) macfont) pointSize];
2457       if (fontsize != size) size = fontsize;
2458     }
2459   unblock_input ();
2460   if (! macfont)
2461     return Qnil;
2463   font_object = font_build_object (VECSIZE (struct macfont_info),
2464                                    Qmac_ct, entity, size);
2465   font = XFONT_OBJECT (font_object);
2466   font->pixel_size = size;
2467   font->driver = &macfont_driver;
2468   font->encoding_charset = font->repertory_charset = -1;
2470   block_input ();
2472   macfont_info = (struct macfont_info *) font;
2473   macfont_info->macfont = macfont;
2474   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2476   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2477   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2478     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2479                                                                   size);
2480   else
2481     macfont_info->screen_font = NULL;
2482   macfont_info->cache = macfont_lookup_cache (font_name);
2483   macfont_retain_cache (macfont_info->cache);
2484   macfont_info->metrics = NULL;
2485   macfont_info->metrics_nrows = 0;
2486   macfont_info->synthetic_italic_p = 0;
2487   macfont_info->synthetic_bold_p = 0;
2488   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2489   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2490   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2491       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2492     macfont_info->synthetic_italic_p = 1;
2493   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2494       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2495     macfont_info->synthetic_bold_p = 1;
2496   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2497     macfont_info->spacing = MACFONT_SPACING_MONO;
2498   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2499            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2500                == FONT_SPACING_SYNTHETIC_MONO))
2501     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2502   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2503     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2504   else
2505     {
2506       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2507       if (CONSP (val))
2508         macfont_info->antialias =
2509           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2510     }
2511   macfont_info->color_bitmap_p = 0;
2512   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2513     macfont_info->color_bitmap_p = 1;
2515   glyph = macfont_get_glyph_for_character (font, ' ');
2516   if (glyph != kCGFontIndexInvalid)
2517     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2518   else
2519     /* dirty workaround */
2520     font->space_width = pixel_size;
2522   total_width = font->space_width;
2523   for (i = 1; i < 95; i++)
2524     {
2525       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2526       if (glyph == kCGFontIndexInvalid)
2527         break;
2528       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2529     }
2530   if (i == 95)
2531     font->average_width = total_width / 95;
2532   else
2533     font->average_width = font->space_width; /* XXX */
2535   if (!(macfont_info->screen_font
2536         && mac_screen_font_get_metrics (macfont_info->screen_font,
2537                                         &ascent, &descent, &leading)))
2538     {
2539       CFStringRef family_name;
2541       ascent = mac_font_get_ascent (macfont);
2542       descent = mac_font_get_descent (macfont);
2543       leading = mac_font_get_leading (macfont);
2544       /* AppKit and WebKit do some adjustment to the heights of
2545          Courier, Helvetica, and Times.  */
2546       family_name = mac_font_copy_family_name (macfont);
2547       if (family_name)
2548         {
2549           if (CFEqual (family_name, CFSTR ("Courier"))
2550               || CFEqual (family_name, CFSTR ("Helvetica"))
2551               || CFEqual (family_name, CFSTR ("Times")))
2552             ascent += (ascent + descent) * .15f;
2553           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2554             {
2555               leading *= .25f;
2556               ascent += leading;
2557             }
2558           CFRelease (family_name);
2559         }
2560     }
2561   font->ascent = ascent + 0.5f;
2562   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2563   if (CONSP (val) && !NILP (XCDR (val)))
2564     font->descent = descent + 0.5f;
2565   else
2566     font->descent = descent + leading + 0.5f;
2567   font->height = font->ascent + font->descent;
2569   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2570   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2572   unblock_input ();
2574   /* Unfortunately Xft doesn't provide a way to get minimum char
2575      width.  So, we use space_width instead.  */
2576   font->min_width = font->max_width = font->space_width; /* XXX */
2578   font->baseline_offset = 0;
2579   font->relative_compose = 0;
2580   font->default_ascent = 0;
2581   font->vertical_centering = 0;
2583   return font_object;
2586 static void
2587 macfont_close (struct font *font)
2589   struct macfont_info *macfont_info = (struct macfont_info *) font;
2591   if (macfont_info->cache)
2592     {
2593       int i;
2595       block_input ();
2596       CFRelease (macfont_info->macfont);
2597       CGFontRelease (macfont_info->cgfont);
2598       if (macfont_info->screen_font)
2599         CFRelease (macfont_info->screen_font);
2600       macfont_release_cache (macfont_info->cache);
2601       for (i = 0; i < macfont_info->metrics_nrows; i++)
2602         if (macfont_info->metrics[i])
2603           xfree (macfont_info->metrics[i]);
2604       if (macfont_info->metrics)
2605         xfree (macfont_info->metrics);
2606       macfont_info->cache = NULL;
2607       unblock_input ();
2608     }
2611 static int
2612 macfont_has_char (Lisp_Object font, int c)
2614   int result;
2615   CFCharacterSetRef charset;
2617   block_input ();
2618   if (FONT_ENTITY_P (font))
2619     {
2620       Lisp_Object val;
2621       CFStringRef name;
2623       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2624       val = XCDR (val);
2625       name = XSAVE_POINTER (val, 0);
2626       charset = macfont_get_cf_charset_for_name (name);
2627     }
2628   else
2629     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2631   result = CFCharacterSetIsLongCharacterMember (charset, c);
2632   unblock_input ();
2634   return result;
2637 static unsigned
2638 macfont_encode_char (struct font *font, int c)
2640   struct macfont_info *macfont_info = (struct macfont_info *) font;
2641   CGGlyph glyph;
2643   block_input ();
2644   glyph = macfont_get_glyph_for_character (font, c);
2645   unblock_input ();
2647   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2650 static void
2651 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2652                       struct font_metrics *metrics)
2654   int width, i;
2656   block_input ();
2657   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2658   for (i = 1; i < nglyphs; i++)
2659     {
2660       struct font_metrics m;
2661       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2662                                      NULL, 0);
2664       if (metrics)
2665         {
2666           if (width + m.lbearing < metrics->lbearing)
2667             metrics->lbearing = width + m.lbearing;
2668           if (width + m.rbearing > metrics->rbearing)
2669             metrics->rbearing = width + m.rbearing;
2670           if (m.ascent > metrics->ascent)
2671             metrics->ascent = m.ascent;
2672           if (m.descent > metrics->descent)
2673             metrics->descent = m.descent;
2674         }
2675       width += w;
2676     }
2677   unblock_input ();
2679   if (metrics)
2680     metrics->width = width;
2683 static int
2684 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2685               bool with_background)
2687   struct frame * f = s->f;
2688   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2689   CGRect background_rect;
2690   CGPoint text_position;
2691   CGGlyph *glyphs;
2692   CGPoint *positions;
2693   CGFloat font_size = mac_font_get_size (macfont_info->macfont);
2694   bool no_antialias_p =
2695     (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2696      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2697          && font_size <= macfont_antialias_threshold));
2698   int len = to - from;
2699   struct face *face = s->face;
2700   CGContextRef context;
2702   block_input ();
2704   if (with_background)
2705     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2706                                   s->width, FONT_HEIGHT (s->font));
2707   else
2708     background_rect = CGRectNull;
2710   text_position = CGPointMake (x, -y);
2711   glyphs = xmalloc (sizeof (CGGlyph) * len);
2712   {
2713     CGFloat advance_delta = 0;
2714     int i;
2715     CGFloat total_width = 0;
2717     positions = xmalloc (sizeof (CGPoint) * len);
2718     for (i = 0; i < len; i++)
2719       {
2720         int width;
2722         glyphs[i] = s->char2b[from + i];
2723         width = (s->padding_p ? 1
2724                  : macfont_glyph_extents (s->font, glyphs[i],
2725                                           NULL, &advance_delta,
2726                                           no_antialias_p));
2727         positions[i].x = total_width + advance_delta;
2728         positions[i].y = 0;
2729         total_width += width;
2730       }
2731   }
2733   context = [[NSGraphicsContext currentContext] graphicsPort];
2734   CGContextSaveGState (context);
2736   if (!CGRectIsNull (background_rect))
2737     {
2738       if (s->hl == DRAW_MOUSE_FACE)
2739         {
2740           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2741           if (!face)
2742             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2743         }
2744       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2745       CGContextFillRects (context, &background_rect, 1);
2746     }
2748   if (macfont_info->cgfont)
2749     {
2750       CGAffineTransform atfm;
2752       CGContextScaleCTM (context, 1, -1);
2753       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2754       if (macfont_info->synthetic_italic_p)
2755         atfm = synthetic_italic_atfm;
2756       else
2757         atfm = CGAffineTransformIdentity;
2758       if (macfont_info->synthetic_bold_p)
2759         {
2760           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2761           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2762           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2763         }
2764       if (no_antialias_p)
2765         CGContextSetShouldAntialias (context, false);
2767       CGContextSetTextMatrix (context, atfm);
2768       CGContextSetTextPosition (context, text_position.x, text_position.y);
2770 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2771       if (macfont_info->color_bitmap_p
2772 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2773           && CTFontDrawGlyphs != NULL
2774 #endif
2775           )
2776         {
2777           if (len > 0)
2778             {
2779               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2780                                 context);
2781             }
2782         }
2783       else
2784 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2785         {
2786           CGContextSetFont (context, macfont_info->cgfont);
2787           CGContextSetFontSize (context, font_size);
2788           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2789         }
2790     }
2793   xfree (glyphs);
2794   xfree (positions);
2795   CGContextRestoreGState (context);
2797   unblock_input ();
2799   return len;
2802 static Lisp_Object
2803 macfont_shape (Lisp_Object lgstring)
2805   struct font *font;
2806   struct macfont_info *macfont_info;
2807   FontRef macfont;
2808   ptrdiff_t glyph_len, len, i, j;
2809   CFIndex nonbmp_len;
2810   UniChar *unichars;
2811   CFIndex *nonbmp_indices;
2812   CFStringRef string;
2813   CFIndex used = 0;
2814   struct mac_glyph_layout *glyph_layouts;
2816   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2817   macfont_info = (struct macfont_info *) font;
2818   macfont = macfont_info->macfont;
2820   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2821   nonbmp_len = 0;
2822   for (i = 0; i < glyph_len; i++)
2823     {
2824       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2826       if (NILP (lglyph))
2827         break;
2828       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2829         nonbmp_len++;
2830     }
2832   len = i;
2834   if (INT_MAX / 2 < len)
2835     memory_full (SIZE_MAX);
2837   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2838   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2839   for (i = j = 0; i < len; i++)
2840     {
2841       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2843       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2844         {
2845           nonbmp_indices[j] = i + j;
2846           j++;
2847         }
2848     }
2849   nonbmp_indices[j] = len + j;  /* sentinel */
2851   block_input ();
2853   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2854                                                kCFAllocatorNull);
2855   if (string)
2856     {
2857       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2858       if (macfont_info->screen_font)
2859         used = mac_screen_font_shape (macfont_info->screen_font, string,
2860                                       glyph_layouts, glyph_len);
2861       else
2862         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2863       CFRelease (string);
2864     }
2866   unblock_input ();
2868   if (used == 0)
2869     return Qnil;
2871   block_input ();
2873   for (i = 0; i < used; i++)
2874     {
2875       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2876       struct mac_glyph_layout *gl = glyph_layouts + i;
2877       EMACS_INT from, to;
2878       struct font_metrics metrics;
2879       int xoff, yoff, wadjust;
2881       if (NILP (lglyph))
2882         {
2883           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2884           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2885         }
2887       from = gl->comp_range.location;
2888       /* Convert UTF-16 index to UTF-32.  */
2889       j = 0;
2890       while (nonbmp_indices[j] < from)
2891         j++;
2892       from -= j;
2893       LGLYPH_SET_FROM (lglyph, from);
2895       to = gl->comp_range.location + gl->comp_range.length;
2896       /* Convert UTF-16 index to UTF-32.  */
2897       while (nonbmp_indices[j] < to)
2898         j++;
2899       to -= j;
2900       LGLYPH_SET_TO (lglyph, to - 1);
2902       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2903          the composition is trivial.  */
2904       {
2905         UTF32Char c;
2907         if (unichars[gl->string_index] >= 0xD800
2908             && unichars[gl->string_index] < 0xDC00)
2909           c = (((unichars[gl->string_index] - 0xD800) << 10)
2910                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2911         else
2912           c = unichars[gl->string_index];
2913         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2914           c = 0;
2915         LGLYPH_SET_CHAR (lglyph, c);
2916       }
2918       {
2919         unsigned long cc = gl->glyph_id;
2920         LGLYPH_SET_CODE (lglyph, cc);
2921       }
2923       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2924       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2925       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2926       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2927       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2928       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2930       xoff = lround (gl->advance_delta);
2931       yoff = lround (- gl->baseline_delta);
2932       wadjust = lround (gl->advance);
2933       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2934         {
2935           Lisp_Object vec;
2937           vec = Fmake_vector (make_number (3), Qnil);
2938           ASET (vec, 0, make_number (xoff));
2939           ASET (vec, 1, make_number (yoff));
2940           ASET (vec, 2, make_number (wadjust));
2941           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2942         }
2943     }
2945   unblock_input ();
2947   return make_number (used);
2950 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2951 typedef UInt8 UINT24[3];
2953 #pragma pack(push, 1)
2954 struct variation_selector_record
2956   UINT24 var_selector;
2957   UInt32 default_uvs_offset, non_default_uvs_offset;
2959 struct uvs_table
2961   UInt16 format;
2962   UInt32 length, num_var_selector_records;
2963   struct variation_selector_record variation_selector_records[1];
2965 #define SIZEOF_UVS_TABLE_HEADER                                         \
2966   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2968 struct unicode_value_range
2970   UINT24 start_unicode_value;
2971   UInt8 additional_count;
2973 struct default_uvs_table {
2974   UInt32 num_unicode_value_ranges;
2975   struct unicode_value_range unicode_value_ranges[1];
2977 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
2978   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
2980 struct uvs_mapping
2982   UINT24 unicode_value;
2983   UInt16 glyph_id;
2985 struct non_default_uvs_table
2987   UInt32 num_uvs_mappings;
2988   struct uvs_mapping uvs_mappings[1];
2990 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
2991   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
2992 #pragma pack(pop)
2994 /* Read big endian values.  The argument LVAL must be an lvalue.  */
2995 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
2996    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
2997    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
2998 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
2999 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3000 /* Succeeding one byte should also be accessible.  */
3001 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3002 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3004 /* Return UVS subtable for the specified FONT.  If the subtable is not
3005    found or ill-formatted, then return NULL.  */
3007 static CFDataRef
3008 mac_font_copy_uvs_table (FontRef font)
3010   CFDataRef cmap_table, uvs_table = NULL;
3012   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3013   if (cmap_table)
3014     {
3015       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3016       struct uvs_table *uvs;
3017       struct variation_selector_record *records;
3018       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3020 #if __LP64__
3021       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3022         goto finish;
3023 #endif
3025       cmap_len = CFDataGetLength (cmap_table);
3026       if (sizeof_sfntCMapHeader > cmap_len)
3027         goto finish;
3029       ntables = BUINT16_VALUE (cmap->numTables);
3030       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3031                      / sizeof_sfntCMapEncoding))
3032         goto finish;
3034       for (i = 0; i < ntables; i++)
3035         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3036              == kFontUnicodePlatform)
3037             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3038                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3039           {
3040             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3041             break;
3042           }
3043       if (i == ntables
3044           || uvs_offset > cmap_len
3045           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3046         goto finish;
3048       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3049       uvs_len = BUINT32_VALUE (uvs->length);
3050       if (uvs_len > cmap_len - uvs_offset
3051           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3052         goto finish;
3054       if (BUINT16_VALUE (uvs->format) != 14)
3055         goto finish;
3057       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3058       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3059                       / sizeof (struct variation_selector_record)))
3060         goto finish;
3062       records = uvs->variation_selector_records;
3063       for (i = 0; i < nrecords; i++)
3064         {
3065           UInt32 default_uvs_offset, non_default_uvs_offset;
3067           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3068           if (default_uvs_offset)
3069             {
3070               struct default_uvs_table *default_uvs;
3071               UInt32 nranges;
3073               if (default_uvs_offset > uvs_len
3074                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3075                       > uvs_len - default_uvs_offset))
3076                 goto finish;
3078               default_uvs = ((struct default_uvs_table *)
3079                              ((UInt8 *) uvs + default_uvs_offset));
3080               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3081               if (nranges > ((uvs_len - default_uvs_offset
3082                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3083                              / sizeof (struct unicode_value_range)))
3084                 goto finish;
3085               /* Now 2 * nranges can't overflow, so we can safely use
3086                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3087                  mac_font_get_glyphs_for_variants.  */
3088             }
3090           non_default_uvs_offset =
3091             BUINT32_VALUE (records[i].non_default_uvs_offset);
3092           if (non_default_uvs_offset)
3093             {
3094               struct non_default_uvs_table *non_default_uvs;
3095               UInt32 nmappings;
3097               if (non_default_uvs_offset > uvs_len
3098                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3099                       > uvs_len - non_default_uvs_offset))
3100                 goto finish;
3102               non_default_uvs = ((struct non_default_uvs_table *)
3103                                  ((UInt8 *) uvs + non_default_uvs_offset));
3104               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3105               if (nmappings > ((uvs_len - non_default_uvs_offset
3106                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3107                                / sizeof (struct uvs_mapping)))
3108                 goto finish;
3109               /* Now 2 * nmappings can't overflow, so we can safely
3110                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3111                  in mac_font_get_glyphs_for_variants.  */
3112             }
3113         }
3115       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3117     finish:
3118       CFRelease (cmap_table);
3119     }
3121   return uvs_table;
3124 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3125    sequence consisting of the given base character C and each
3126    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3127    result (explained below) into the corresponding GLYPHS[i].  If the
3128    entry is found in the Default UVS Table, then the result is 0.  If
3129    the entry is found in the Non-Default UVS Table, then the result is
3130    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3131    elements in SELECTORS must be sorted in strictly increasing
3132    order.  */
3134 static void
3135 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3136                                   const UTF32Char selectors[], CGGlyph glyphs[],
3137                                   CFIndex count)
3139   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3140   struct variation_selector_record *records = uvs->variation_selector_records;
3141   CFIndex i;
3142   UInt32 ir, nrecords;
3143   dispatch_queue_t queue =
3144     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3145   dispatch_group_t group = dispatch_group_create ();
3147   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3148   i = 0;
3149   ir = 0;
3150   while (i < count && ir < nrecords)
3151     {
3152       UInt32 default_uvs_offset, non_default_uvs_offset;
3154       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3155         {
3156           glyphs[i++] = kCGFontIndexInvalid;
3157           continue;
3158         }
3159       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3160         {
3161           ir++;
3162           continue;
3163         }
3165       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3166       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3167       non_default_uvs_offset =
3168         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3169       dispatch_group_async (group, queue, ^{
3170           glyphs[i] = kCGFontIndexInvalid;
3172           if (default_uvs_offset)
3173             {
3174               struct default_uvs_table *default_uvs =
3175                 (struct default_uvs_table *) ((UInt8 *) uvs
3176                                               + default_uvs_offset);
3177               struct unicode_value_range *ranges =
3178                 default_uvs->unicode_value_ranges;
3179               UInt32 lo, hi;
3181               lo = 0;
3182               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3183               while (lo < hi)
3184                 {
3185                   UInt32 mid = (lo + hi) / 2;
3187                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3188                     hi = mid;
3189                   else
3190                     lo = mid + 1;
3191                 }
3192               if (hi > 0
3193                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3194                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3195                 glyphs[i] = 0;
3196             }
3198           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3199             {
3200               struct non_default_uvs_table *non_default_uvs =
3201                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3202                                                   + non_default_uvs_offset);
3203               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3204               UInt32 lo, hi;
3206               lo = 0;
3207               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3208               while (lo < hi)
3209                 {
3210                   UInt32 mid = (lo + hi) / 2;
3212                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3213                     hi = mid;
3214                   else
3215                     lo = mid + 1;
3216                 }
3217               if (hi > 0 &&
3218                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3219                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3220             }
3221         });
3222       i++;
3223       ir++;
3224     }
3225   while (i < count)
3226     glyphs[i++] = kCGFontIndexInvalid;
3227   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3228   dispatch_release (group);
3231 static int
3232 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3234   CFDataRef uvs_table;
3235   CharacterCollection uvs_collection;
3236   int i, n = 0;
3238   block_input ();
3239   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3241   if (uvs_table)
3242     {
3243       UTF32Char selectors[256];
3244       CGGlyph glyphs[256];
3246       for (i = 0; i < 16; i++)
3247         selectors[i] = 0xFE00 + i;
3248       for (; i < 256; i++)
3249         selectors[i] = 0xE0100 + (i - 16);
3250       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3251       for (i = 0; i < 256; i++)
3252         {
3253           CGGlyph glyph = glyphs[i];
3255           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3256               && glyph != kCGFontIndexInvalid)
3257             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3258           if (glyph == kCGFontIndexInvalid)
3259             variations[i] = 0;
3260           else
3261             {
3262               variations[i] = (glyph ? glyph
3263                                : macfont_get_glyph_for_character (font, c));
3264               n++;
3265             }
3266         }
3267     }
3268   unblock_input ();
3270   return n;
3273 static const char *const macfont_booleans[] = {
3274   ":antialias",
3275   ":minspace",
3276   NULL,
3279 static const char *const macfont_non_booleans[] = {
3280   ":lang",
3281   ":script",
3282   ":destination",
3283   NULL,
3286 static void
3287 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3289   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3292 static Boolean
3293 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3294                                           CFArrayRef languages)
3296   Boolean result = true;
3297   CFArrayRef desc_languages =
3298     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3300   if (desc_languages == NULL)
3301     result = false;
3302   else
3303     {
3304       CFIndex desc_languages_count, i, languages_count;
3306       desc_languages_count = CFArrayGetCount (desc_languages);
3307       languages_count = CFArrayGetCount (languages);
3308       for (i = 0; i < languages_count; i++)
3309         if (!CFArrayContainsValue (desc_languages,
3310                                    CFRangeMake (0, desc_languages_count),
3311                                    CFArrayGetValueAtIndex (languages, i)))
3312           {
3313             result = false;
3314             break;
3315           }
3316       CFRelease (desc_languages);
3317     }
3319   return result;
3322 static CFStringRef
3323 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3325   CFStringRef result = NULL;
3326   CFStringRef charset_string =
3327     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3329   if (charset_string && CFStringGetLength (charset_string) > 0)
3330     {
3331       CFStringRef keys[] = {
3332 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3333         kCTLanguageAttributeName
3334 #else
3335         CFSTR ("NSLanguage")
3336 #endif
3337       };
3338       CFTypeRef values[] = {NULL};
3339       CFIndex num_values = 0;
3340       CFArrayRef languages
3341         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3343       if (languages && CFArrayGetCount (languages) > 0)
3344         {
3345           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3346             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3347           else
3348             {
3349               CFCharacterSetRef charset =
3350                 CFDictionaryGetValue (attributes,
3351                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3353               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3354             }
3355         }
3356       if (result == NULL)
3357         {
3358           CFAttributedStringRef attr_string = NULL;
3359           CTLineRef ctline = NULL;
3360           CFDictionaryRef attrs
3361             = CFDictionaryCreate (NULL, (const void **) keys,
3362                                   (const void **) values, num_values,
3363                                   &kCFTypeDictionaryKeyCallBacks,
3364                                   &kCFTypeDictionaryValueCallBacks);
3366           if (attrs)
3367             {
3368               attr_string = CFAttributedStringCreate (NULL, charset_string,
3369                                                       attrs);
3370               CFRelease (attrs);
3371             }
3372           if (attr_string)
3373             {
3374               ctline = CTLineCreateWithAttributedString (attr_string);
3375               CFRelease (attr_string);
3376             }
3377           if (ctline)
3378             {
3379               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3380               CFIndex i, nruns = CFArrayGetCount (runs);
3381               CTFontRef font;
3383               for (i = 0; i < nruns; i++)
3384                 {
3385                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3386                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3387                   CTFontRef font_in_run;
3389                   if (attributes == NULL)
3390                     break;
3391                   font_in_run =
3392                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3393                   if (font_in_run == NULL)
3394                     break;
3395                   if (i == 0)
3396                     font = font_in_run;
3397                   else if (!mac_ctfont_equal_in_postscript_name (font,
3398                                                                  font_in_run))
3399                     break;
3400                 }
3401               if (nruns > 0 && i == nruns)
3402                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3403               CFRelease (ctline);
3404             }
3405         }
3406     }
3408   return result;
3411 static inline double
3412 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3414   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3415                                      &glyph, NULL, 1);
3418 static inline CGRect
3419 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3421   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3422                                           &glyph, NULL, 1);
3425 static CFArrayRef
3426 mac_ctfont_create_available_families (void)
3428   CFMutableArrayRef families = NULL;
3430     {
3431       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3433       if (orig_families)
3434         {
3435           CFIndex i, count = CFArrayGetCount (orig_families);
3437           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3438           if (families)
3439             for (i = 0; i < count; i++)
3440               {
3441                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3443                 if (!CFStringHasPrefix (family, CFSTR ("."))
3444                     && (CTFontManagerCompareFontFamilyNames (family,
3445                                                              CFSTR ("LastResort"),
3446                                                              NULL)
3447                         != kCFCompareEqualTo))
3448                   CFArrayAppendValue (families, family);
3449               }
3450           CFRelease (orig_families);
3451         }
3452     }
3454     return families;
3457 static Boolean
3458 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3460   Boolean result;
3461   CFStringRef name1, name2;
3463   if (font1 == font2)
3464     return true;
3466   result = false;
3467   name1 = CTFontCopyPostScriptName (font1);
3468   if (name1)
3469     {
3470       name2 = CTFontCopyPostScriptName (font2);
3471       if (name2)
3472         {
3473           result = CFEqual (name1, name2);
3474           CFRelease (name2);
3475         }
3476       CFRelease (name1);
3477     }
3479   return result;
3482 static CTLineRef
3483 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3484                                              CTFontRef macfont)
3486   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3487   CFTypeRef values[] = {NULL, NULL};
3488   CFDictionaryRef attributes = NULL;
3489   CFAttributedStringRef attr_string = NULL;
3490   CTLineRef ctline = NULL;
3491   float float_zero = 0.0f;
3493   values[0] = macfont;
3494   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3495   if (values[1])
3496     {
3497       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3498                                        (const void **) values,
3499                                        ARRAYELTS (keys),
3500                                        &kCFTypeDictionaryKeyCallBacks,
3501                                        &kCFTypeDictionaryValueCallBacks);
3502       CFRelease (values[1]);
3503     }
3504   if (attributes)
3505     {
3506       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3507       CFRelease (attributes);
3508     }
3509   if (attr_string)
3510     {
3511       ctline = CTLineCreateWithAttributedString (attr_string);
3512       CFRelease (attr_string);
3513     }
3514   if (ctline)
3515     {
3516       /* Abandon if ctline contains some fonts other than the
3517          specified one.  */
3518       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3519       CFIndex i, nruns = CFArrayGetCount (runs);
3521       for (i = 0; i < nruns; i++)
3522         {
3523           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3524           CFDictionaryRef attributes = CTRunGetAttributes (run);
3525           CTFontRef font_in_run;
3527           if (attributes == NULL)
3528             break;
3529           font_in_run =
3530             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3531           if (font_in_run == NULL)
3532             break;
3533           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3534             break;
3535         }
3536       if (i < nruns)
3537         {
3538           CFRelease (ctline);
3539           ctline = NULL;
3540         }
3541     }
3543   return ctline;
3546 static CFIndex
3547 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3548                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3550   CFIndex used, result = 0;
3551   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3553   if (ctline == NULL)
3554     return 0;
3556   used = CTLineGetGlyphCount (ctline);
3557   if (used <= glyph_len)
3558     {
3559       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3560       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3561       CGFloat total_advance = 0;
3562       CFIndex total_glyph_count = 0;
3564       for (k = 0; k < ctrun_count; k++)
3565         {
3566           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3567           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3568           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3569           CFRange string_range, comp_range, range;
3570           CFIndex *permutation;
3572           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3573             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3574           else
3575             permutation = NULL;
3577 #define RIGHT_TO_LEFT_P permutation
3579           /* Now the `comp_range' member of struct mac_glyph_layout is
3580              temporarily used as a work area such that:
3581              glbuf[i].comp_range.location =
3582              min {compRange[i + 1].location, ...,
3583                      compRange[glyph_count - 1].location,
3584                      maxRange (stringRangeForCTRun)}
3585              glbuf[i].comp_range.length = maxRange (compRange[i])
3586              where compRange[i] is the range of composed characters
3587              containing i-th glyph.  */
3588           string_range = CTRunGetStringRange (ctrun);
3589           min_location = string_range.location + string_range.length;
3590           for (i = 0; i < glyph_count; i++)
3591             {
3592               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3593               CFIndex glyph_index;
3594               CFRange rng;
3596               if (!RIGHT_TO_LEFT_P)
3597                 glyph_index = glyph_count - i - 1;
3598               else
3599                 glyph_index = i;
3600               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3601                                      &gl->string_index);
3602               rng =
3603                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3604                                                              gl->string_index);
3605               gl->comp_range.location = min_location;
3606               gl->comp_range.length = rng.location + rng.length;
3607               if (rng.location < min_location)
3608                 min_location = rng.location;
3609             }
3611           /* Fill the `comp_range' member of struct mac_glyph_layout,
3612              and setup a permutation for right-to-left text.  */
3613           comp_range = CFRangeMake (string_range.location, 0);
3614           range = CFRangeMake (0, 0);
3615           while (1)
3616             {
3617               struct mac_glyph_layout *gl =
3618                 glbuf + range.location + range.length;
3620               if (gl->comp_range.length
3621                   > comp_range.location + comp_range.length)
3622                 comp_range.length = gl->comp_range.length - comp_range.location;
3623               min_location = gl->comp_range.location;
3624               range.length++;
3626               if (min_location >= comp_range.location + comp_range.length)
3627                 {
3628                   comp_range.length = min_location - comp_range.location;
3629                   for (i = 0; i < range.length; i++)
3630                     {
3631                       glbuf[range.location + i].comp_range = comp_range;
3632                       if (RIGHT_TO_LEFT_P)
3633                         permutation[range.location + i] =
3634                           range.location + range.length - i - 1;
3635                     }
3637                   comp_range = CFRangeMake (min_location, 0);
3638                   range.location += range.length;
3639                   range.length = 0;
3640                   if (range.location == glyph_count)
3641                     break;
3642                 }
3643             }
3645           /* Then fill the remaining members.  */
3646           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3647                range.location++)
3648             {
3649               struct mac_glyph_layout *gl;
3650               CGPoint position;
3652               if (!RIGHT_TO_LEFT_P)
3653                 gl = glbuf + range.location;
3654               else
3655                 {
3656                   CFIndex src, dest;
3658                   src = glyph_count - 1 - range.location;
3659                   dest = permutation[src];
3660                   gl = glbuf + dest;
3661                   if (src < dest)
3662                     {
3663                       CFIndex tmp = gl->string_index;
3665                       gl->string_index = glbuf[src].string_index;
3666                       glbuf[src].string_index = tmp;
3667                     }
3668                 }
3669               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3671               CTRunGetPositions (ctrun, range, &position);
3672               gl->advance_delta = position.x - total_advance;
3673               gl->baseline_delta = position.y;
3674               gl->advance = (gl->advance_delta
3675                              + CTRunGetTypographicBounds (ctrun, range,
3676                                                           NULL, NULL, NULL));
3677               total_advance += gl->advance;
3678             }
3680           if (RIGHT_TO_LEFT_P)
3681             xfree (permutation);
3683 #undef RIGHT_TO_LEFT_P
3685           total_glyph_count += glyph_count;
3686         }
3688       result = used;
3689     }
3690   CFRelease (ctline);
3692   return result;
3695 /* The function below seems to cause a memory leak for the CFString
3696    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3697    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3698 #if USE_CT_GLYPH_INFO
3699 static CGGlyph
3700 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3701                               CGFontIndex cid)
3703   CGGlyph result = kCGFontIndexInvalid;
3704   UniChar characters[] = {0xfffd};
3705   CFStringRef string;
3706   CFAttributedStringRef attr_string = NULL;
3707   CTLineRef ctline = NULL;
3709   string = CFStringCreateWithCharacters (NULL, characters,
3710                                          ARRAYELTS (characters));
3712   if (string)
3713     {
3714       CTGlyphInfoRef glyph_info =
3715         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3716       CFDictionaryRef attributes = NULL;
3718       if (glyph_info)
3719         {
3720           CFStringRef keys[] = {kCTFontAttributeName,
3721                                 kCTGlyphInfoAttributeName};
3722           CFTypeRef values[] = {font, glyph_info};
3724           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3725                                            (const void **) values,
3726                                            ARRAYELTS (keys),
3727                                            &kCFTypeDictionaryKeyCallBacks,
3728                                            &kCFTypeDictionaryValueCallBacks);
3729           CFRelease (glyph_info);
3730         }
3731       if (attributes)
3732         {
3733           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3734           CFRelease (attributes);
3735         }
3736       CFRelease (string);
3737     }
3738   if (attr_string)
3739     {
3740       ctline = CTLineCreateWithAttributedString (attr_string);
3741       CFRelease (attr_string);
3742     }
3743   if (ctline)
3744     {
3745       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3747       if (CFArrayGetCount (runs) > 0)
3748         {
3749           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3750           CFDictionaryRef attributes = CTRunGetAttributes (run);
3752           if (attributes)
3753             {
3754               CTFontRef font_in_run =
3755                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3757               if (font_in_run
3758                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3759                 {
3760                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3761                   if (result >= CTFontGetGlyphCount (font))
3762                     result = kCGFontIndexInvalid;
3763                 }
3764             }
3765         }
3766       CFRelease (ctline);
3767     }
3769   return result;
3771 #endif
3773 static CFArrayRef
3774 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3776   CFArrayRef result = NULL;
3778 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3779 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3780   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3781 #endif
3782     {
3783       CTFontRef user_font =
3784         CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3786       if (user_font)
3787         {
3788           CFArrayRef languages =
3789             CFArrayCreate (NULL, (const void **) &language, 1,
3790                            &kCFTypeArrayCallBacks);
3792           if (languages)
3793             {
3794               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3795                                                                  languages);
3796               CFRelease (languages);
3797             }
3798           CFRelease (user_font);
3799         }
3800     }
3801 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3802   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3803 #endif
3804 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3805 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3806     {
3807       CFIndex i;
3809       for (i = 0; macfont_language_default_font_names[i].language; i++)
3810         {
3811           if (CFEqual (macfont_language_default_font_names[i].language,
3812                        language))
3813             {
3814               CFMutableArrayRef descriptors =
3815                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3817               if (descriptors)
3818                 {
3819                   CFIndex j;
3821                   for (j = 0;
3822                        macfont_language_default_font_names[i].font_names[j];
3823                        j++)
3824                     {
3825                       CFDictionaryRef attributes =
3826                         CFDictionaryCreate (NULL,
3827                                             ((const void **)
3828                                              &MAC_FONT_NAME_ATTRIBUTE),
3829                                             ((const void **)
3830                                              &macfont_language_default_font_names[i].font_names[j]),
3831                                             1, &kCFTypeDictionaryKeyCallBacks,
3832                                             &kCFTypeDictionaryValueCallBacks);
3834                       if (attributes)
3835                         {
3836                           FontDescriptorRef pat_desc =
3837                             mac_font_descriptor_create_with_attributes (attributes);
3839                           if (pat_desc)
3840                             {
3841                               FontDescriptorRef descriptor =
3842                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3844                               if (descriptor)
3845                                 {
3846                                   CFArrayAppendValue (descriptors, descriptor);
3847                                   CFRelease (descriptor);
3848                                 }
3849                               CFRelease (pat_desc);
3850                             }
3851                           CFRelease (attributes);
3852                         }
3853                     }
3854                   result = descriptors;
3855                 }
3856               break;
3857             }
3858         }
3859     }
3860 #endif
3862   return result;
3865 static CFStringRef
3866 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3867                                                       CFArrayRef languages)
3869   CFStringRef result = NULL;
3870   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3871   CFArrayRef descriptors =
3872     mac_font_copy_default_descriptors_for_language (language);
3874   if (descriptors)
3875     {
3876       CFIndex i, count = CFArrayGetCount (descriptors);
3878       for (i = 0; i < count; i++)
3879         {
3880           FontDescriptorRef descriptor =
3881             CFArrayGetValueAtIndex (descriptors, i);
3883           if (macfont_supports_charset_and_languages_p (descriptor, charset,
3884                                                         Qnil, languages))
3885             {
3886               CFStringRef family =
3887                 mac_font_descriptor_copy_attribute (descriptor,
3888                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3889               if (family)
3890                 {
3891                   if (!CFStringHasPrefix (family, CFSTR ("."))
3892                       && !CFEqual (family, CFSTR ("LastResort")))
3893                     {
3894                       result = family;
3895                       break;
3896                     }
3897                   else
3898                     CFRelease (family);
3899                 }
3900             }
3901         }
3902       CFRelease (descriptors);
3903     }
3905   return result;
3908 void *
3909 macfont_get_nsctfont (struct font *font)
3911   struct macfont_info *macfont_info = (struct macfont_info *) font;
3912   FontRef macfont = macfont_info->macfont;
3914   return (void *) macfont;
3917 void
3918 mac_register_font_driver (struct frame *f)
3920   register_font_driver (&macfont_driver, f);
3924 void
3925 syms_of_macfont (void)
3927   static struct font_driver mac_font_driver;
3929   DEFSYM (Qmac_ct, "mac-ct");
3930   macfont_driver.type = Qmac_ct;
3931   register_font_driver (&macfont_driver, NULL);
3933   DEFSYM (QCdestination, ":destination");
3934   DEFSYM (QCminspace, ":minspace");