Add separator.pbm tool-bar image
[emacs.git] / src / macfont.m
blob23d272c91298ced6a76c12c9a6dfe072e6c89c81
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2015 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 static double mac_font_get_advance_width_for_glyph (CTFontRef, CGGlyph);
44 static CGRect mac_font_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
45 static CFArrayRef mac_font_create_available_families (void);
46 static Boolean mac_font_equal_in_postscript_name (CTFontRef, CTFontRef);
47 static CTLineRef mac_font_create_line_with_string_and_font (CFStringRef,
48                                                             CTFontRef);
49 static Boolean mac_font_descriptor_supports_languages (CTFontDescriptorRef,
50                                                        CFArrayRef);
51 static CFStringRef mac_font_create_preferred_family_for_attributes (CFDictionaryRef);
52 static CFIndex mac_font_shape (CTFontRef, CFStringRef,
53                                struct mac_glyph_layout *, CFIndex);
54 static CFArrayRef mac_font_copy_default_descriptors_for_language (CFStringRef);
55 static CFStringRef mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef, CFArrayRef);
56 #if USE_CT_GLYPH_INFO
57 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef, CTCharacterCollection,
58                                              CGFontIndex);
59 #endif
61 struct macfont_metrics;
63 /* The actual structure for Mac font that can be cast to struct font.  */
65 struct macfont_info
67   struct font font;
68   CTFontRef macfont;
69   CGFontRef cgfont;
70   ScreenFontRef screen_font;
71   struct macfont_cache *cache;
72   struct macfont_metrics **metrics;
73   short metrics_nrows;
74   bool_bf synthetic_italic_p : 1;
75   bool_bf synthetic_bold_p : 1;
76   unsigned spacing : 2;
77   unsigned antialias : 2;
78   bool_bf color_bitmap_p : 1;
81 /* Values for the `spacing' member in `struct macfont_info'.  */
83 enum
84   {
85     MACFONT_SPACING_PROPORTIONAL,
86     MACFONT_SPACING_MONO,
87     MACFONT_SPACING_SYNTHETIC_MONO,
88   };
90 /* Values for the `antialias' member in `struct macfont_info'.  */
92 enum
93   {
94     MACFONT_ANTIALIAS_DEFAULT,
95     MACFONT_ANTIALIAS_OFF,
96     MACFONT_ANTIALIAS_ON,
97   };
99 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
100 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
101 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
103 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
104 static const CGFloat synthetic_bold_factor = 0.024;
106 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
107                                                         CTFontSymbolicTraits *);
108 static void macfont_store_descriptor_attributes (CTFontDescriptorRef,
109                                                  Lisp_Object);
110 static Lisp_Object macfont_descriptor_entity (CTFontDescriptorRef, Lisp_Object,
111                                               CTFontSymbolicTraits);
112 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
113 static int macfont_glyph_extents (struct font *, CGGlyph,
114                                   struct font_metrics *, CGFloat *, int);
115 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
116 static Boolean macfont_supports_charset_and_languages_p (CTFontDescriptorRef,
117                                                          CFCharacterSetRef,
118                                                          Lisp_Object,
119                                                          CFArrayRef);
120 static Boolean macfont_closest_traits_index_p (CFArrayRef, CTFontSymbolicTraits,
121                                                CFIndex);
122 static CFDataRef mac_font_copy_uvs_table (CTFontRef);
123 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
124                                               const UTF32Char [],
125                                               CGGlyph [], CFIndex);
127 /* From CFData to a lisp string.  Always returns a unibyte string.  */
129 static Lisp_Object
130 cfdata_to_lisp (CFDataRef data)
132   CFIndex len = CFDataGetLength (data);
133   Lisp_Object result = make_uninit_string (len);
135   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
137   return result;
142 /* From CFString to a lisp string.  Returns a unibyte string
143    containing a UTF-8 byte sequence.  */
145 static Lisp_Object
146 cfstring_to_lisp_nodecode (CFStringRef string)
148   Lisp_Object result = Qnil;
149   CFDataRef data;
150   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
152   if (s)
153     {
154       CFIndex i, length = CFStringGetLength (string);
156       for (i = 0; i < length; i++)
157         if (CFStringGetCharacterAtIndex (string, i) == 0)
158           break;
160       if (i == length)
161         return make_unibyte_string (s, strlen (s));
162     }
164   data = CFStringCreateExternalRepresentation (NULL, string,
165                                                kCFStringEncodingUTF8, '?');
166   if (data)
167     {
168       result = cfdata_to_lisp (data);
169       CFRelease (data);
170     }
172   return result;
175 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
176    cfstring_create_with_utf8_cstring, this function preserves NUL
177    characters.  */
179 static CFStringRef
180 cfstring_create_with_string_noencode (Lisp_Object s)
182   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
183                                                 kCFStringEncodingUTF8, false);
185   if (string == NULL)
186     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
187     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
188                                       kCFStringEncodingMacRoman, false);
190   return string;
193 static CGFloat
194 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
196   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
198   return advancement.width;
201 static CGGlyph
202 mac_font_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
203                             CGFontIndex cid)
205 #if USE_CT_GLYPH_INFO
206   return mac_ctfont_get_glyph_for_cid ((CTFontRef) font, collection, cid);
207 #else
208   {
209     CGGlyph result = kCGFontIndexInvalid;
210     NSFont *nsFont = (NSFont *) font;
211     unichar characters[] = {0xfffd};
212     NSString *string =
213       [NSString stringWithCharacters:characters
214                               length:ARRAYELTS (characters)];
215     NSGlyphInfo *glyphInfo =
216       [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
217                                          collection:collection
218                                          baseString:string];
219     NSDictionary *attributes =
220       [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
221                     glyphInfo,NSGlyphInfoAttributeName,nil];
222     NSTextStorage *textStorage =
223       [[NSTextStorage alloc] initWithString:string
224                                  attributes:attributes];
225     NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
226     NSTextContainer *textContainer = [[NSTextContainer alloc] init];
227     NSFont *fontInTextStorage;
229     [layoutManager addTextContainer:textContainer];
230     [textContainer release];
231     [textStorage addLayoutManager:layoutManager];
232     [layoutManager release];
234     /* Force layout.  */
235     (void) [layoutManager glyphRangeForTextContainer:textContainer];
237     fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
238                                 effectiveRange:NULL];
239     if (fontInTextStorage == nsFont
240         || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
241       {
242         NSGlyph glyph = [layoutManager glyphAtIndex:0];
244         if (glyph < [nsFont numberOfGlyphs])
245           result = glyph;
246       }
248     [textStorage release];
250     return result;
251   }
253 #endif
255 static ScreenFontRef
256 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
258   NSFont *result, *font;
260   font = [NSFont fontWithName:((NSString *) name) size:size];
261   result = [font screenFont];
263   return (ScreenFontRef)[result retain];
267 static Boolean
268 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
269                              CGFloat *descent, CGFloat *leading)
271   NSFont *nsFont = [(NSFont *)font printerFont];
272   NSTextStorage *textStorage;
273   NSLayoutManager *layoutManager;
274   NSTextContainer *textContainer;
275   NSRect usedRect;
276   NSPoint spaceLocation;
277   CGFloat descender;
279   textStorage = [[NSTextStorage alloc] initWithString:@" "];
280   layoutManager = [[NSLayoutManager alloc] init];
281   textContainer = [[NSTextContainer alloc] init];
283   [textStorage setFont:nsFont];
284   [textContainer setLineFragmentPadding:0];
285   [layoutManager setUsesScreenFonts:YES];
287   [layoutManager addTextContainer:textContainer];
288   [textContainer release];
289   [textStorage addLayoutManager:layoutManager];
290   [layoutManager release];
292   if (!(textStorage && layoutManager && textContainer))
293     {
294       [textStorage release];
296       return false;
297     }
299   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
300                                                  effectiveRange:NULL];
301   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
302   [textStorage release];
304   *ascent = spaceLocation.y;
305   *descent = NSHeight (usedRect) - spaceLocation.y;
306   *leading = 0;
307   descender = [nsFont descender];
308   if (- descender < *descent)
309     {
310       *leading = *descent + descender;
311       *descent = - descender;
312     }
314   return true;
317 static CFIndex
318 mac_font_shape_1 (NSFont *font, NSString *string,
319                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
320                   BOOL screen_font_p)
322   NSUInteger i;
323   CFIndex result = 0;
324   NSTextStorage *textStorage;
325   NSLayoutManager *layoutManager;
326   NSTextContainer *textContainer;
327   NSUInteger stringLength;
328   NSPoint spaceLocation;
329   NSUInteger used, numberOfGlyphs;
331   textStorage = [[NSTextStorage alloc] initWithString:string];
332   layoutManager = [[NSLayoutManager alloc] init];
333   textContainer = [[NSTextContainer alloc] init];
335   /* Append a trailing space to measure baseline position.  */
336   [textStorage appendAttributedString:([[[NSAttributedString alloc]
337                                           initWithString:@" "] autorelease])];
338   [textStorage setFont:font];
339   [textContainer setLineFragmentPadding:0];
340   [layoutManager setUsesScreenFonts:screen_font_p];
342   [layoutManager addTextContainer:textContainer];
343   [textContainer release];
344   [textStorage addLayoutManager:layoutManager];
345   [layoutManager release];
347   if (!(textStorage && layoutManager && textContainer))
348     {
349       [textStorage release];
351       return 0;
352     }
354   stringLength = [string length];
356   /* Force layout.  */
357   (void) [layoutManager glyphRangeForTextContainer:textContainer];
359   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
361   /* Remove the appended trailing space because otherwise it may
362      generate a wrong result for a right-to-left text.  */
363   [textStorage beginEditing];
364   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
365   [textStorage endEditing];
366   (void) [layoutManager glyphRangeForTextContainer:textContainer];
368   i = 0;
369   while (i < stringLength)
370     {
371       NSRange range;
372       NSFont *fontInTextStorage =
373         [textStorage attribute:NSFontAttributeName atIndex:i
374                      longestEffectiveRange:&range
375                        inRange:(NSMakeRange (0, stringLength))];
377       if (!(fontInTextStorage == font
378             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
379         break;
380       i = NSMaxRange (range);
381     }
382   if (i < stringLength)
383     /* Make the test `used <= glyph_len' below fail if textStorage
384        contained some fonts other than the specified one.  */
385     used = glyph_len + 1;
386   else
387     {
388       NSRange range = NSMakeRange (0, stringLength);
390       range = [layoutManager glyphRangeForCharacterRange:range
391                                     actualCharacterRange:NULL];
392       numberOfGlyphs = NSMaxRange (range);
393       used = numberOfGlyphs;
394       for (i = 0; i < numberOfGlyphs; i++)
395         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
396           used--;
397     }
399   if (0 < used && used <= glyph_len)
400     {
401       NSUInteger glyphIndex, prevGlyphIndex;
402       unsigned char bidiLevel;
403       NSUInteger *permutation;
404       NSRange compRange, range;
405       CGFloat totalAdvance;
407       glyphIndex = 0;
408       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
409         glyphIndex++;
411       /* For now we assume the direction is not changed within the
412          string.  */
413       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
414                                glyphs:NULL characterIndexes:NULL
415                     glyphInscriptions:NULL elasticBits:NULL
416                            bidiLevels:&bidiLevel];
417       if (bidiLevel & 1)
418         permutation = xmalloc (sizeof (NSUInteger) * used);
419       else
420         permutation = NULL;
422 #define RIGHT_TO_LEFT_P permutation
424       /* Fill the `comp_range' member of struct mac_glyph_layout, and
425          setup a permutation for right-to-left text.  */
426       compRange = NSMakeRange (0, 0);
427       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
428            range.length++)
429         {
430           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
431           NSUInteger characterIndex =
432             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
434           gl->string_index = characterIndex;
436           if (characterIndex >= NSMaxRange (compRange))
437             {
438               compRange.location = NSMaxRange (compRange);
439               do
440                 {
441                   NSRange characterRange =
442                     [string
443                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
445                   compRange.length =
446                     NSMaxRange (characterRange) - compRange.location;
447                   [layoutManager glyphRangeForCharacterRange:compRange
448                                         actualCharacterRange:&characterRange];
449                   characterIndex = NSMaxRange (characterRange) - 1;
450                 }
451               while (characterIndex >= NSMaxRange (compRange));
453               if (RIGHT_TO_LEFT_P)
454                 for (i = 0; i < range.length; i++)
455                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
457               range = NSMakeRange (NSMaxRange (range), 0);
458             }
460           gl->comp_range.location = compRange.location;
461           gl->comp_range.length = compRange.length;
463           while (++glyphIndex < numberOfGlyphs)
464             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
465               break;
466         }
467       if (RIGHT_TO_LEFT_P)
468         for (i = 0; i < range.length; i++)
469           permutation[range.location + i] = NSMaxRange (range) - i - 1;
471       /* Then fill the remaining members.  */
472       glyphIndex = prevGlyphIndex = 0;
473       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
474         glyphIndex++;
476       if (!RIGHT_TO_LEFT_P)
477         totalAdvance = 0;
478       else
479         {
480           NSUInteger nrects;
481           NSRect *glyphRects =
482             [layoutManager
483               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
484               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
485                      inTextContainer:textContainer rectCount:&nrects];
487           totalAdvance = NSMaxX (glyphRects[0]);
488         }
490       for (i = 0; i < used; i++)
491         {
492           struct mac_glyph_layout *gl;
493           NSPoint location;
494           NSUInteger nextGlyphIndex;
495           NSRange glyphRange;
496           NSRect *glyphRects;
497           NSUInteger nrects;
499           if (!RIGHT_TO_LEFT_P)
500             gl = glyph_layouts + i;
501           else
502             {
503               NSUInteger dest = permutation[i];
505               gl = glyph_layouts + dest;
506               if (i < dest)
507                 {
508                   CFIndex tmp = gl->string_index;
510                   gl->string_index = glyph_layouts[i].string_index;
511                   glyph_layouts[i].string_index = tmp;
512                 }
513             }
514           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
516           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
517           gl->baseline_delta = spaceLocation.y - location.y;
519           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
520                nextGlyphIndex++)
521             if (![layoutManager
522                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
523               break;
525           if (!RIGHT_TO_LEFT_P)
526             {
527               CGFloat maxX;
529               if (prevGlyphIndex == 0)
530                 glyphRange = NSMakeRange (0, nextGlyphIndex);
531               else
532                 glyphRange = NSMakeRange (glyphIndex,
533                                           nextGlyphIndex - glyphIndex);
534               glyphRects =
535                 [layoutManager
536                   rectArrayForGlyphRange:glyphRange
537                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
538                          inTextContainer:textContainer rectCount:&nrects];
539               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
540               gl->advance_delta = location.x - totalAdvance;
541               gl->advance = maxX - totalAdvance;
542               totalAdvance = maxX;
543             }
544           else
545             {
546               CGFloat minX;
548               if (nextGlyphIndex == numberOfGlyphs)
549                 glyphRange = NSMakeRange (prevGlyphIndex,
550                                           numberOfGlyphs - prevGlyphIndex);
551               else
552                 glyphRange = NSMakeRange (prevGlyphIndex,
553                                           glyphIndex + 1 - prevGlyphIndex);
554               glyphRects =
555                 [layoutManager
556                   rectArrayForGlyphRange:glyphRange
557                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
558                          inTextContainer:textContainer rectCount:&nrects];
559               minX = min (NSMinX (glyphRects[0]), totalAdvance);
560               gl->advance = totalAdvance - minX;
561               totalAdvance = minX;
562               gl->advance_delta = location.x - totalAdvance;
563             }
565           prevGlyphIndex = glyphIndex + 1;
566           glyphIndex = nextGlyphIndex;
567         }
569       if (RIGHT_TO_LEFT_P)
570         xfree (permutation);
572 #undef RIGHT_TO_LEFT_P
574       result = used;
575     }
576   [textStorage release];
578   return result;
581 static CFIndex
582 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
583                        struct mac_glyph_layout *glyph_layouts,
584                        CFIndex glyph_len)
586   return mac_font_shape_1 ([(NSFont *)font printerFont],
587                            (NSString *) string,
588                            glyph_layouts, glyph_len, YES);
591 static CGColorRef
592 get_cgcolor(unsigned long idx, struct frame *f)
594   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
595   [nsColor set];
596   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
597   NSInteger noc = [nsColor numberOfComponents];
598   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
599   CGColorRef cgColor;
601   [nsColor getComponents: components];
602   cgColor = CGColorCreate (colorSpace, components);
603   xfree (components);
604   return cgColor;
607 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
608   do {                                                                  \
609     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
610     CGContextSetFillColorWithColor (context, refcol_) ;                 \
611     CGColorRelease (refcol_);                                           \
612   } while (0)
613 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f)        \
614   do {                                                                  \
615     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f);    \
616     CGContextSetFillColorWithColor (context, refcol_);                  \
617     CGColorRelease (refcol_);                                           \
618   } while (0)
619 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f)      \
620   do {                                                                  \
621     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
622     CGContextSetStrokeColorWithColor (context, refcol_);                \
623     CGColorRelease (refcol_);                                           \
624   } while (0)
628 /* Mac font driver.  */
630 static struct
632   /* registry name */
633   const char *name;
634   /* characters to distinguish the charset from the others */
635   int uniquifier[6];
636   /* additional constraint by language */
637   CFStringRef lang;
638   /* set on demand */
639   CFCharacterSetRef cf_charset;
640   CFStringRef cf_charset_string;
641 } cf_charset_table[] =
642   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
643     { "iso8859-2", { 0x00A0, 0x010E }},
644     { "iso8859-3", { 0x00A0, 0x0108 }},
645     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
646     { "iso8859-5", { 0x00A0, 0x0401 }},
647     { "iso8859-6", { 0x00A0, 0x060C }},
648     { "iso8859-7", { 0x00A0, 0x0384 }},
649     { "iso8859-8", { 0x00A0, 0x05D0 }},
650     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
651     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
652     { "iso8859-11", { 0x00A0, 0x0E01 }},
653     { "iso8859-13", { 0x00A0, 0x201C }},
654     { "iso8859-14", { 0x00A0, 0x0174 }},
655     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
656     { "iso8859-16", { 0x00A0, 0x0218}},
657     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
658     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
659     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
660     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
661     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
662     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
663     { "cns11643.1992-3", { 0x201A9 }},
664     { "cns11643.1992-4", { 0x20057 }},
665     { "cns11643.1992-5", { 0x20000 }},
666     { "cns11643.1992-6", { 0x20003 }},
667     { "cns11643.1992-7", { 0x20055 }},
668     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
669     { "jisx0212.1990-0", { 0x4E44 }},
670     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
671     { "jisx0213.2000-2", { 0xFA49 }},
672     { "jisx0213.2004-1", { 0x20B9F }},
673     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
674     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
675     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
676     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
677     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
678     { "unicode-sip", { 0x20000 }},
679     { NULL }
680   };
682 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
683 static const struct
685   CFStringRef language;
686   CFStringRef font_names[3];
687 } macfont_language_default_font_names[] = {
688   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
689                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
690                     NULL }},
691   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
692                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
693                     NULL }},
694   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
695                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
696                          NULL }},
697   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
698                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
699                          NULL }},
700   { NULL }
702 #endif
704 static CGFloat macfont_antialias_threshold;
706 void
707 macfont_update_antialias_threshold (void)
709   int threshold;
710   Boolean valid_p;
712   threshold =
713     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
714                                      kCFPreferencesCurrentApplication,
715                                      &valid_p);
716   if (valid_p)
717     macfont_antialias_threshold = threshold;
720 static inline Lisp_Object
721 macfont_intern_prop_cfstring (CFStringRef cfstring)
723   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
725   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
728 static inline CFIndex
729 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
731   if (c < 0x10000)
732     {
733       unichars[0] = c;
735       return 1;
736     }
737   else
738     {
739       c -= 0x10000;
740       unichars[0] = (c >> 10) + 0xD800;
741       unichars[1] = (c & 0x3FF) + 0xDC00;
743       return 2;
744     }
747 static Boolean
748 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
749                                          CTFontSymbolicTraits *sym_traits)
751   SInt64 sint64_value;
753   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
754      OS X 10.6 when the value is greater than or equal to 1 << 31.  */
755   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
756     {
757       *sym_traits = (CTFontSymbolicTraits) sint64_value;
759       return true;
760     }
762   return false;
765 static void
766 macfont_store_descriptor_attributes (CTFontDescriptorRef desc,
767                                      Lisp_Object spec_or_entity)
769   CFStringRef str;
770   CFDictionaryRef dict;
771   CFNumberRef num;
772   CGFloat floatval;
774   str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
775   if (str)
776     {
777       ASET (spec_or_entity, FONT_FAMILY_INDEX,
778             macfont_intern_prop_cfstring (str));
779       CFRelease (str);
780     }
781   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
782   if (dict)
783     {
784       struct {
785         enum font_property_index index;
786         CFStringRef trait;
787         CGPoint points[6];
788       } numeric_traits[] =
789           {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
790             {{-0.4, 50},        /* light */
791              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
792              {0, 100},          /* normal */
793              {0.24, 140},       /* (semi-bold + normal) / 2 */
794              {0.4, 200},        /* bold */
795              {CGFLOAT_MAX, CGFLOAT_MAX}}},
796            {FONT_SLANT_INDEX, kCTFontSlantTrait,
797             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
798            {FONT_WIDTH_INDEX, kCTFontWidthTrait,
799             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
800       int i;
802       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
803         {
804           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
805           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
806             {
807               CGPoint *point = numeric_traits[i].points;
809               while (point->x < floatval)
810                 point++;
811               if (point == numeric_traits[i].points)
812                 point++;
813               else if (point->x == CGFLOAT_MAX)
814                 point--;
815               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
816                                            * ((point->y - (point - 1)->y)
817                                               / (point->x - (point - 1)->x)));
818               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
819                               make_number (lround (floatval)));
820             }
821         }
823       num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
824       if (num)
825         {
826           CTFontSymbolicTraits sym_traits;
827           int spacing;
829           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
830           spacing = (sym_traits & kCTFontTraitMonoSpace
831                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
832           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
833         }
835       CFRelease (dict);
836     }
837   num = CTFontDescriptorCopyAttribute (desc, kCTFontSizeAttribute);
838   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
839     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
840   else
841     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
842   if (num)
843     CFRelease (num);
846 static Lisp_Object
847 macfont_descriptor_entity (CTFontDescriptorRef desc, Lisp_Object extra,
848                            CTFontSymbolicTraits synth_sym_traits)
850   Lisp_Object entity;
851   CFDictionaryRef dict;
852   CTFontSymbolicTraits sym_traits = 0;
853   CFStringRef name;
855   entity = font_make_entity ();
857   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
858   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
860   macfont_store_descriptor_attributes (desc, entity);
862   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
863   if (dict)
864     {
865       CFNumberRef num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
867       if (num)
868         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
869       CFRelease (dict);
870     }
871   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
872     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
873   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
874   name = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
875   font_put_extra (entity, QCfont_entity,
876                   make_save_ptr_int ((void *) name, sym_traits));
877   if (synth_sym_traits & kCTFontTraitItalic)
878     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
879                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
880   if (synth_sym_traits & kCTFontTraitBold)
881     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
882                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
883   if (synth_sym_traits & kCTFontTraitMonoSpace)
884     ASET (entity, FONT_SPACING_INDEX,
885           make_number (FONT_SPACING_SYNTHETIC_MONO));
887   return entity;
890 /* Cache for font family name symbols vs CFStrings.  A value of nil
891 means the cache has been invalidated.  Otherwise the value is a Lisp
892 hash table whose keys are symbols and the value for a key is either
893 nil (no corresponding family name) or a Lisp save value wrapping the
894 corresponding family name in CFString.  */
896 static Lisp_Object macfont_family_cache;
898 static void
899 macfont_invalidate_family_cache (void)
901   if (HASH_TABLE_P (macfont_family_cache))
902     {
903       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
904       ptrdiff_t i, size = HASH_TABLE_SIZE (h);
906       for (i = 0; i < size; ++i)
907         if (!NILP (HASH_HASH (h, i)))
908           {
909             Lisp_Object value = HASH_VALUE (h, i);
911             if (SAVE_VALUEP (value))
912               CFRelease (XSAVE_POINTER (value, 0));
913           }
914       macfont_family_cache = Qnil;
915     }
918 static bool
919 macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string)
921   if (HASH_TABLE_P (macfont_family_cache))
922     {
923       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
924       ptrdiff_t i = hash_lookup (h, symbol, NULL);
926       if (i >= 0)
927         {
928           Lisp_Object value = HASH_VALUE (h, i);
930           *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL;
932           return true;
933         }
934     }
936   return false;
939 static void
940 macfont_set_family_cache (Lisp_Object symbol, CFStringRef string)
942   struct Lisp_Hash_Table *h;
943   ptrdiff_t i;
944   EMACS_UINT hash;
945   Lisp_Object value;
947   if (!HASH_TABLE_P (macfont_family_cache))
948     {
949       Lisp_Object args[2];
951       args[0] = QCtest;
952       args[1] = Qeq;
953       macfont_family_cache = Fmake_hash_table (2, args);
954     }
956   h = XHASH_TABLE (macfont_family_cache);
957   i = hash_lookup (h, symbol, &hash);
958   value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil;
959   if (i >= 0)
960     {
961       Lisp_Object old_value = HASH_VALUE (h, i);
963       if (SAVE_VALUEP (old_value))
964         CFRelease (XSAVE_POINTER (old_value, 0));
965       set_hash_value_slot (h, i, value);
966     }
967   else
968     hash_put (h, symbol, value, hash);
971 /* Cache of all the available font family names except "LastResort"
972 and those start with ".".  NULL means the cache has been invalidated.
973 Otherwise, the value is CFArray of CFStrings and the elements are
974 sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
975 OS X 10.6 and later).  */
977 static CFArrayRef macfont_available_families_cache = NULL;
979 static void
980 macfont_invalidate_available_families_cache (void)
982   if (macfont_available_families_cache)
983     {
984       CFRelease (macfont_available_families_cache);
985       macfont_available_families_cache = NULL;
986     }
989 static void
990 macfont_handle_font_change_notification (CFNotificationCenterRef center,
991                                          void *observer,
992                                          CFStringRef name, const void *object,
993                                          CFDictionaryRef userInfo)
995   macfont_invalidate_family_cache ();
996   macfont_invalidate_available_families_cache ();
999 static void
1000 macfont_init_font_change_handler (void)
1002   static bool initialized = false;
1004   if (initialized)
1005     return;
1007   initialized = true;
1008   CFNotificationCenterAddObserver
1009     (CFNotificationCenterGetLocalCenter (), NULL,
1010      macfont_handle_font_change_notification,
1011      kCTFontManagerRegisteredFontsChangedNotification,
1012      NULL, CFNotificationSuspensionBehaviorCoalesce);
1015 static CFArrayRef
1016 macfont_copy_available_families_cache (void)
1018   macfont_init_font_change_handler ();
1020   if (macfont_available_families_cache == NULL)
1021     macfont_available_families_cache = mac_font_create_available_families ();
1023   return (macfont_available_families_cache
1024           ? CFRetain (macfont_available_families_cache) : NULL);
1027 static CFStringRef
1028 macfont_create_family_with_symbol (Lisp_Object symbol)
1030   CFStringRef result = NULL, family_name;
1031   CFDictionaryRef attributes = NULL;
1032   CTFontDescriptorRef pat_desc = NULL;
1034   if (macfont_get_family_cache_if_present (symbol, &result))
1035     return result ? CFRetain (result) : NULL;
1037   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
1038   if (family_name)
1039     {
1040       attributes =
1041         CFDictionaryCreate (NULL,
1042                             (const void **) &kCTFontFamilyNameAttribute,
1043                             (const void **) &family_name, 1,
1044                             &kCFTypeDictionaryKeyCallBacks,
1045                             &kCFTypeDictionaryValueCallBacks);
1046       CFRelease (family_name);
1047     }
1048   if (attributes)
1049     {
1050       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
1051       CFRelease (attributes);
1052     }
1053   if (pat_desc)
1054     {
1055       CTFontDescriptorRef desc =
1056         CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
1058       if (desc)
1059         {
1060           result =
1061             CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
1062           CFRelease (desc);
1063         }
1064       macfont_set_family_cache (symbol, result);
1065       CFRelease (pat_desc);
1066     }
1068   return result;
1071 #define WIDTH_FRAC_BITS         (4)
1072 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
1074 struct macfont_metrics
1076   unsigned char lbearing_low, rbearing_low;
1077   signed lbearing_high : 4, rbearing_high : 4;
1078   unsigned char ascent_low, descent_low;
1079   signed ascent_high : 4, descent_high : 4;
1081   /* These two members are used for fixed-point representation of
1082      glyph width.  The `width_int' member is an integer that is
1083      closest to the width.  The `width_frac' member is the fractional
1084      adjustment representing a value in [-.5, .5], multiplied by
1085      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1086      the advance delta for centering instead of the glyph width.  */
1087   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1090 #define METRICS_VALUE(metrics, member)                          \
1091   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1092 #define METRICS_SET_VALUE(metrics, member, value)                   \
1093   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff;    \
1094     (metrics)->member##_high = tmp >> 8;} while (0)
1096 enum metrics_status
1098   METRICS_INVALID = -1,    /* metrics entry is invalid */
1099   METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1102 #define METRICS_STATUS(metrics)                                         \
1103   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1104 #define METRICS_SET_STATUS(metrics, status)                     \
1105   do {METRICS_SET_VALUE (metrics, ascent, 0);                   \
1106     METRICS_SET_VALUE (metrics, descent, status);} while (0)
1108 #define METRICS_NCOLS_PER_ROW   (128)
1109 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1110 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1112 static int
1113 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1114                        struct font_metrics *metrics, CGFloat *advance_delta,
1115                        int force_integral_p)
1117   struct macfont_info *macfont_info = (struct macfont_info *) font;
1118   CTFontRef macfont = macfont_info->macfont;
1119   int row, col;
1120   struct macfont_metrics *cache;
1121   int width;
1123   row = glyph / METRICS_NCOLS_PER_ROW;
1124   col = glyph % METRICS_NCOLS_PER_ROW;
1125   if (row >= macfont_info->metrics_nrows)
1126     {
1127       macfont_info->metrics =
1128         xrealloc (macfont_info->metrics,
1129                   sizeof (struct macfont_metrics *) * (row + 1));
1130       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1131               (sizeof (struct macfont_metrics *)
1132                * (row + 1 - macfont_info->metrics_nrows)));
1133       macfont_info->metrics_nrows = row + 1;
1134     }
1135   if (macfont_info->metrics[row] == NULL)
1136     {
1137       struct macfont_metrics *new;
1138       int i;
1140       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1141       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1142         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1143       macfont_info->metrics[row] = new;
1144     }
1145   cache = macfont_info->metrics[row] + col;
1147   if (METRICS_STATUS (cache) == METRICS_INVALID)
1148     {
1149       CGFloat fwidth;
1151       if (macfont_info->screen_font)
1152         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1153       else
1154         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1156       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1157          advance delta value.  */
1158       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1159         fwidth = (font->pixel_size - fwidth) / 2;
1160       cache->width_int = lround (fwidth);
1161       cache->width_frac = lround ((fwidth - cache->width_int)
1162                                   * WIDTH_FRAC_SCALE);
1163       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1164     }
1165   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1166     width = font->pixel_size;
1167   else
1168     width = cache->width_int;
1170   if (metrics)
1171     {
1172       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1173         {
1174           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1176           if (macfont_info->synthetic_italic_p)
1177             {
1178               /* We assume the members a, b, c, and d in
1179                  synthetic_italic_atfm are non-negative.  */
1180               bounds.origin =
1181                 CGPointApplyAffineTransform (bounds.origin,
1182                                              synthetic_italic_atfm);
1183               bounds.size =
1184                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1185             }
1186           if (macfont_info->synthetic_bold_p && ! force_integral_p)
1187             {
1188               CGFloat d = - synthetic_bold_factor * CTFontGetSize (macfont) / 2;
1190               bounds = CGRectInset (bounds, d, d);
1191             }
1192           switch (macfont_info->spacing)
1193             {
1194             case MACFONT_SPACING_PROPORTIONAL:
1195               bounds.origin.x += - (cache->width_frac
1196                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1197               break;
1198             case MACFONT_SPACING_MONO:
1199               break;
1200             case MACFONT_SPACING_SYNTHETIC_MONO:
1201               bounds.origin.x += (cache->width_int
1202                                   + (cache->width_frac
1203                                      / (CGFloat) WIDTH_FRAC_SCALE));
1204               break;
1205             }
1206           if (bounds.size.width > 0)
1207             {
1208               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1209               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1210                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1211             }
1212           bounds = CGRectIntegral (bounds);
1213           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1214           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1215           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1216           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1217         }
1218       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1219       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1220       metrics->width = width;
1221       metrics->ascent = METRICS_VALUE (cache, ascent);
1222       metrics->descent = METRICS_VALUE (cache, descent);
1223     }
1225   if (advance_delta)
1226     {
1227       switch (macfont_info->spacing)
1228         {
1229         case MACFONT_SPACING_PROPORTIONAL:
1230           *advance_delta = (force_integral_p ? 0
1231                             : - (cache->width_frac
1232                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1233           break;
1234         case MACFONT_SPACING_MONO:
1235           *advance_delta = 0;
1236           break;
1237         case MACFONT_SPACING_SYNTHETIC_MONO:
1238           *advance_delta = (force_integral_p ? cache->width_int
1239                             : (cache->width_int
1240                                + (cache->width_frac
1241                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1242           break;
1243         }
1244     }
1246   return width;
1249 static CFMutableDictionaryRef macfont_cache_dictionary;
1251 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1252    equal to the number of rows that are invalid as BMP (i.e., from
1253    U+D800 to U+DFFF).  */
1254 #define ROW_PERM_OFFSET (8)
1256 /* The number of glyphs that can be stored in a value for a single
1257    entry of CFDictionary.  */
1258 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1260 struct macfont_cache
1262   int reference_count;
1263   CFCharacterSetRef cf_charset;
1264   struct {
1265     /* The cached glyph for a BMP character c is stored in
1266        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1267        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1268     unsigned char row_nkeys_or_perm[256];
1269     CGGlyph **matrix;
1271     /* Number of rows for which the BMP cache is allocated so far.
1272        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1273     int nrows;
1275     /* The cached glyph for a character c is stored as the (c %
1276        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1277        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1278        not stored here if row_nkeys_or_perm[c / 256] >=
1279        ROW_PERM_OFFSET.  */
1280     CFMutableDictionaryRef dictionary;
1281   } glyph;
1283   struct {
1284     /* UVS (Unicode Variation Sequence) subtable data, which is of
1285        type CFDataRef if available.  NULL means it is not initialized
1286        yet.  kCFNull means the subtable is not found and there is no
1287        suitable fallback table for this font.  */
1288     CFTypeRef table;
1290     /* Character collection specifying the destination of the mapping
1291        provided by `table' above.  If `table' is obtained from the UVS
1292        subtable in the font cmap table, then the value of this member
1293        should be kCTCharacterCollectionIdentityMapping.  */
1294     CTCharacterCollection collection;
1295   } uvs;
1298 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1299 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1300 static void macfont_release_cache (struct macfont_cache *);
1301 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1302 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1303 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1304 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1305                                           CTCharacterCollection, CGFontIndex);
1306 static CFDataRef macfont_get_uvs_table (struct font *, CTCharacterCollection *);
1308 static struct macfont_cache *
1309 macfont_lookup_cache (CFStringRef key)
1311   struct macfont_cache *cache;
1313   if (macfont_cache_dictionary == NULL)
1314     {
1315       macfont_cache_dictionary =
1316         CFDictionaryCreateMutable (NULL, 0,
1317                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1318       cache = NULL;
1319     }
1320   else
1321     cache = ((struct macfont_cache *)
1322              CFDictionaryGetValue (macfont_cache_dictionary, key));
1324   if (cache == NULL)
1325     {
1326       CTFontRef macfont = CTFontCreateWithName (key, 0, NULL);
1328       if (macfont)
1329         {
1330           cache = xzalloc (sizeof (struct macfont_cache));
1331           /* Treat the LastResort font as if it contained glyphs for
1332              all characters.  This may look too rough, but neither
1333              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1334              for this font is correct for non-BMP characters on Mac OS
1335              X 10.5, anyway.  */
1336           if (CFEqual (key, CFSTR ("LastResort")))
1337             {
1338               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1340               cache->cf_charset =
1341                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1342             }
1343           if (cache->cf_charset == NULL)
1344             cache->cf_charset = CTFontCopyCharacterSet (macfont);
1345           CFDictionaryAddValue (macfont_cache_dictionary, key,
1346                                 (const void *) cache);
1347           CFRelease (macfont);
1348         }
1349     }
1351   return cache;
1354 static struct macfont_cache *
1355 macfont_retain_cache (struct macfont_cache *cache)
1357   cache->reference_count++;
1359   return cache;
1362 static void
1363 macfont_release_cache (struct macfont_cache *cache)
1365   if (--cache->reference_count == 0)
1366     {
1367       int i;
1369       for (i = 0; i < cache->glyph.nrows; i++)
1370         xfree (cache->glyph.matrix[i]);
1371       xfree (cache->glyph.matrix);
1372       if (cache->glyph.dictionary)
1373         CFRelease (cache->glyph.dictionary);
1374       memset (&cache->glyph, 0, sizeof (cache->glyph));
1375       if (cache->uvs.table)
1376         CFRelease (cache->uvs.table);
1377       memset (&cache->uvs, 0, sizeof (cache->uvs));
1378     }
1381 static CFCharacterSetRef
1382 macfont_get_cf_charset (struct font *font)
1384   struct macfont_info *macfont_info = (struct macfont_info *) font;
1386   return macfont_info->cache->cf_charset;
1389 static CFCharacterSetRef
1390 macfont_get_cf_charset_for_name (CFStringRef name)
1392   struct macfont_cache *cache = macfont_lookup_cache (name);
1394   return cache->cf_charset;
1397 static CGGlyph
1398 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1400   struct macfont_info *macfont_info = (struct macfont_info *) font;
1401   CTFontRef macfont = macfont_info->macfont;
1402   struct macfont_cache *cache = macfont_info->cache;
1404   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1405     {
1406       int row = c / 256;
1407       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1409       if (nkeys_or_perm < ROW_PERM_OFFSET)
1410         {
1411           UniChar unichars[256], ch;
1412           CGGlyph *glyphs;
1413           int i, len;
1414           int nrows;
1415           dispatch_queue_t queue;
1416           dispatch_group_t group = NULL;
1418           if (row != 0)
1419             {
1420               CFMutableDictionaryRef dictionary;
1421               uintptr_t key, value;
1422               int nshifts;
1423               CGGlyph glyph;
1425               if (cache->glyph.dictionary == NULL)
1426                 cache->glyph.dictionary =
1427                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1428               dictionary = cache->glyph.dictionary;
1429               key = c / NGLYPHS_IN_VALUE;
1430               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1431               value = ((uintptr_t)
1432                        CFDictionaryGetValue (dictionary, (const void *) key));
1433               glyph = (value >> nshifts);
1434               if (glyph)
1435                 return glyph;
1437               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1438                 {
1439                   ch = c;
1440                   if (!CTFontGetGlyphsForCharacters (macfont, &ch, &glyph, 1)
1441                       || glyph == 0)
1442                     glyph = kCGFontIndexInvalid;
1444                   if (value == 0)
1445                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1446                   value |= ((uintptr_t) glyph << nshifts);
1447                   CFDictionarySetValue (dictionary, (const void *) key,
1448                                         (const void *) value);
1450                   return glyph;
1451                 }
1453               queue =
1454                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1455               group = dispatch_group_create ();
1456               dispatch_group_async (group, queue, ^{
1457                   int nkeys;
1458                   uintptr_t key;
1459                   nkeys = nkeys_or_perm;
1460                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1461                     if (CFDictionaryContainsKey (dictionary,
1462                                                  (const void *) key))
1463                       {
1464                         CFDictionaryRemoveValue (dictionary,
1465                                                  (const void *) key);
1466                         if (--nkeys == 0)
1467                           break;
1468                       }
1469                 });
1470             }
1472           len = 0;
1473           for (i = 0; i < 256; i++)
1474             {
1475               ch = row * 256 + i;
1476               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1477                 unichars[len++] = ch;
1478             }
1480           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1481           if (len > 0)
1482             {
1483               CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, len);
1484               while (i > len)
1485                 {
1486                   int next = unichars[len - 1] % 256;
1488                   while (--i > next)
1489                     glyphs[i] = kCGFontIndexInvalid;
1491                   len--;
1492                   glyphs[i] = glyphs[len];
1493                   if (len == 0)
1494                     break;
1495                 }
1496             }
1497           if (i > len)
1498             while (i-- > 0)
1499               glyphs[i] = kCGFontIndexInvalid;
1501           nrows = cache->glyph.nrows;
1502           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1503           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1504           nrows++;
1505           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1506                                           sizeof (CGGlyph *) * nrows);
1507           cache->glyph.matrix[nrows - 1] = glyphs;
1508           cache->glyph.nrows = nrows;
1510           if (group)
1511             {
1512               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1513               dispatch_release (group);
1514             }
1515         }
1517       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1518     }
1519   else
1520     {
1521       uintptr_t key, value;
1522       int nshifts;
1523       CGGlyph glyph;
1525       if (cache->glyph.dictionary == NULL)
1526         cache->glyph.dictionary =
1527           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1528       key = c / NGLYPHS_IN_VALUE;
1529       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1530       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1531                                                 (const void *) key);
1532       glyph = (value >> nshifts);
1533       if (glyph == 0)
1534         {
1535           UniChar unichars[2];
1536           CGGlyph glyphs[2];
1537           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1539           if (CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, count))
1540             glyph = glyphs[0];
1541           if (glyph == 0)
1542             glyph = kCGFontIndexInvalid;
1544           value |= ((uintptr_t) glyph << nshifts);
1545           CFDictionarySetValue (cache->glyph.dictionary,
1546                                 (const void *) key, (const void *) value);
1547         }
1549       return glyph;
1550     }
1553 static CGGlyph
1554 macfont_get_glyph_for_cid (struct font *font, CTCharacterCollection collection,
1555                            CGFontIndex cid)
1557   struct macfont_info *macfont_info = (struct macfont_info *) font;
1558   CTFontRef macfont = macfont_info->macfont;
1560   /* Cache it? */
1561   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1564 static CFDataRef
1565 macfont_get_uvs_table (struct font *font, CTCharacterCollection *collection)
1567   struct macfont_info *macfont_info = (struct macfont_info *) font;
1568   CTFontRef macfont = macfont_info->macfont;
1569   struct macfont_cache *cache = macfont_info->cache;
1570   CFDataRef result = NULL;
1572   if (cache->uvs.table == NULL)
1573     {
1574       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1575       CTCharacterCollection uvs_collection =
1576         kCTCharacterCollectionIdentityMapping;
1578       if (uvs_table == NULL
1579           && mac_font_get_glyph_for_cid (macfont,
1580                                          kCTCharacterCollectionAdobeJapan1,
1581                                          6480) != kCGFontIndexInvalid)
1582         {
1583           /* If the glyph for U+4E55 is accessible via its CID 6480,
1584              then we use the Adobe-Japan1 UVS table, which maps a
1585              variation sequence to a CID, as a fallback.  */
1586           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1588           if (mac_uvs_table_adobe_japan1 == NULL)
1589             mac_uvs_table_adobe_japan1 =
1590               CFDataCreateWithBytesNoCopy (NULL,
1591                                            mac_uvs_table_adobe_japan1_bytes,
1592                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1593                                            kCFAllocatorNull);
1594           if (mac_uvs_table_adobe_japan1)
1595             {
1596               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1597               uvs_collection = kCTCharacterCollectionAdobeJapan1;
1598             }
1599         }
1600       if (uvs_table == NULL)
1601         cache->uvs.table = kCFNull;
1602       else
1603         cache->uvs.table = uvs_table;
1604       cache->uvs.collection = uvs_collection;
1605     }
1607   if (cache->uvs.table != kCFNull)
1608     {
1609       result = cache->uvs.table;
1610       *collection = cache->uvs.collection;
1611     }
1613   return result;
1616 static Lisp_Object macfont_get_cache (struct frame *);
1617 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1618 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1619 static Lisp_Object macfont_list_family (struct frame *);
1620 static void macfont_free_entity (Lisp_Object);
1621 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1622 static void macfont_close (struct font *);
1623 static int macfont_has_char (Lisp_Object, int);
1624 static unsigned macfont_encode_char (struct font *, int);
1625 static void macfont_text_extents (struct font *, unsigned int *, int,
1626                                   struct font_metrics *);
1627 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1628 static Lisp_Object macfont_shape (Lisp_Object);
1629 static int macfont_variation_glyphs (struct font *, int c,
1630                                      unsigned variations[256]);
1631 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1633 static struct font_driver macfont_driver =
1634   {
1635     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1636     0,                          /* case insensitive */
1637     macfont_get_cache,
1638     macfont_list,
1639     macfont_match,
1640     macfont_list_family,
1641     macfont_free_entity,
1642     macfont_open,
1643     macfont_close,
1644     NULL,                       /* prepare_face */
1645     NULL,                       /* done_face */
1646     macfont_has_char,
1647     macfont_encode_char,
1648     macfont_text_extents,
1649     macfont_draw,
1650     NULL,                       /* get_bitmap */
1651     NULL,                       /* free_bitmap */
1652     NULL,                       /* anchor_point */
1653     NULL,                       /* otf_capability */
1654     NULL,                       /* otf_drive */
1655     NULL,                       /* start_for_frame */
1656     NULL,                       /* end_for_frame */
1657     macfont_shape,
1658     NULL,                       /* check */
1659     macfont_variation_glyphs,
1660     macfont_filter_properties,
1661   };
1663 static Lisp_Object
1664 macfont_get_cache (struct frame * f)
1666   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1668   return (dpyinfo->name_list_element);
1671 static int
1672 macfont_get_charset (Lisp_Object registry)
1674   char *str = SSDATA (SYMBOL_NAME (registry));
1675   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1676   Lisp_Object regexp;
1677   int i, j;
1679   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1680     {
1681       if (str[i] == '.')
1682         re[j++] = '\\';
1683       else if (str[i] == '*')
1684         re[j++] = '.';
1685       re[j] = str[i];
1686       if (re[j] == '?')
1687         re[j] = '.';
1688     }
1689   re[j] = '\0';
1690   regexp = make_unibyte_string (re, j);
1691   for (i = 0; cf_charset_table[i].name; i++)
1692     if (fast_c_string_match_ignore_case
1693         (regexp, cf_charset_table[i].name,
1694          strlen (cf_charset_table[i].name)) >= 0)
1695       break;
1696   if (! cf_charset_table[i].name)
1697     return -1;
1698   if (! cf_charset_table[i].cf_charset)
1699     {
1700       int *uniquifier = cf_charset_table[i].uniquifier;
1701       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1702       CFIndex count = 0;
1703       CFStringRef string;
1704       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1706       if (! charset)
1707         return -1;
1708       for (j = 0; uniquifier[j]; j++)
1709         {
1710           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1711                                                         unichars + count);
1712           CFCharacterSetAddCharactersInRange (charset,
1713                                               CFRangeMake (uniquifier[j], 1));
1714         }
1716       string = CFStringCreateWithCharacters (NULL, unichars, count);
1717       if (! string)
1718         {
1719           CFRelease (charset);
1720           return -1;
1721         }
1722       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1723                                                                  charset);
1724       CFRelease (charset);
1725       /* CFCharacterSetCreateWithCharactersInString does not handle
1726          surrogate pairs properly as of Mac OS X 10.5.  */
1727       cf_charset_table[i].cf_charset_string = string;
1728     }
1729   return i;
1732 struct OpenTypeSpec
1734   Lisp_Object script;
1735   unsigned int script_tag, langsys_tag;
1736   int nfeatures[2];
1737   unsigned int *features[2];
1740 #define OTF_SYM_TAG(SYM, TAG)                               \
1741   do {                                                      \
1742     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1743     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1744   } while (0)
1746 #define OTF_TAG_STR(TAG, P)                     \
1747   do {                                          \
1748     (P)[0] = (char) (TAG >> 24);                \
1749     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1750     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1751     (P)[3] = (char) (TAG & 0xFF);               \
1752     (P)[4] = '\0';                              \
1753   } while (0)
1755 static struct OpenTypeSpec *
1756 macfont_get_open_type_spec (Lisp_Object otf_spec)
1758   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1759   Lisp_Object val;
1760   int i, j;
1761   bool negative;
1763   if (! spec)
1764     return NULL;
1765   spec->script = XCAR (otf_spec);
1766   if (! NILP (spec->script))
1767     {
1768       OTF_SYM_TAG (spec->script, spec->script_tag);
1769       val = assq_no_quit (spec->script, Votf_script_alist);
1770       if (CONSP (val) && SYMBOLP (XCDR (val)))
1771         spec->script = XCDR (val);
1772       else
1773         spec->script = Qnil;
1774     }
1775   else
1776     spec->script_tag = 0x44464C54;      /* "DFLT" */
1777   otf_spec = XCDR (otf_spec);
1778   spec->langsys_tag = 0;
1779   if (! NILP (otf_spec))
1780     {
1781       val = XCAR (otf_spec);
1782       if (! NILP (val))
1783         OTF_SYM_TAG (val, spec->langsys_tag);
1784       otf_spec = XCDR (otf_spec);
1785     }
1786   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1787   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1788     {
1789       Lisp_Object len;
1791       val = XCAR (otf_spec);
1792       if (NILP (val))
1793         continue;
1794       len = Flength (val);
1795       spec->features[i] =
1796         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1797          ? 0
1798          : malloc (XINT (len) * sizeof *spec->features[i]));
1799       if (! spec->features[i])
1800         {
1801           if (i > 0 && spec->features[0])
1802             free (spec->features[0]);
1803           free (spec);
1804           return NULL;
1805         }
1806       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1807         {
1808           if (NILP (XCAR (val)))
1809             negative = 1;
1810           else
1811             {
1812               unsigned int tag;
1814               OTF_SYM_TAG (XCAR (val), tag);
1815               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1816             }
1817         }
1818       spec->nfeatures[i] = j;
1819     }
1820   return spec;
1823 static CFMutableDictionaryRef
1824 macfont_create_attributes_with_spec (Lisp_Object spec)
1826   Lisp_Object tmp, extra;
1827   CFMutableArrayRef langarray = NULL;
1828   CFCharacterSetRef charset = NULL;
1829   CFStringRef charset_string = NULL;
1830   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1831   Lisp_Object script = Qnil;
1832   Lisp_Object registry;
1833   int cf_charset_idx, i;
1834   struct OpenTypeSpec *otspec = NULL;
1835   struct {
1836     enum font_property_index index;
1837     CFStringRef trait;
1838     CGPoint points[6];
1839   } numeric_traits[] =
1840       {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
1841         {{-0.4, 50},            /* light */
1842          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1843          {0, 100},              /* normal */
1844          {0.24, 140},           /* (semi-bold + normal) / 2 */
1845          {0.4, 200},            /* bold */
1846          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1847        {FONT_SLANT_INDEX, kCTFontSlantTrait,
1848         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1849        {FONT_WIDTH_INDEX, kCTFontWidthTrait,
1850         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1852   registry = AREF (spec, FONT_REGISTRY_INDEX);
1853   if (NILP (registry)
1854       || EQ (registry, Qascii_0)
1855       || EQ (registry, Qiso10646_1)
1856       || EQ (registry, Qunicode_bmp))
1857     cf_charset_idx = -1;
1858   else
1859     {
1860       CFStringRef lang;
1862       cf_charset_idx = macfont_get_charset (registry);
1863       if (cf_charset_idx < 0)
1864         goto err;
1865       charset = cf_charset_table[cf_charset_idx].cf_charset;
1866       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1867       lang = cf_charset_table[cf_charset_idx].lang;
1868       if (lang)
1869         {
1870           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1871           if (! langarray)
1872             goto err;
1873           CFArrayAppendValue (langarray, lang);
1874         }
1875     }
1877   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1878        CONSP (extra); extra = XCDR (extra))
1879     {
1880       Lisp_Object key, val;
1882       tmp = XCAR (extra);
1883       key = XCAR (tmp), val = XCDR (tmp);
1884       if (EQ (key, QClang))
1885         {
1886           if (! langarray)
1887             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1888           if (! langarray)
1889             goto err;
1890           if (SYMBOLP (val))
1891             val = list1 (val);
1892           for (; CONSP (val); val = XCDR (val))
1893             if (SYMBOLP (XCAR (val)))
1894               {
1895                 CFStringRef lang =
1896                   cfstring_create_with_string_noencode (SYMBOL_NAME
1897                                                         (XCAR (val)));
1899                 if (lang == NULL)
1900                   goto err;
1901                 CFArrayAppendValue (langarray, lang);
1902                 CFRelease (lang);
1903               }
1904         }
1905       else if (EQ (key, QCotf))
1906         {
1907           otspec = macfont_get_open_type_spec (val);
1908           if (! otspec)
1909             goto err;
1910           script = otspec->script;
1911         }
1912       else if (EQ (key, QCscript))
1913         script = val;
1914     }
1916   if (! NILP (script) && ! charset)
1917     {
1918       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1920       if (CONSP (chars) && CONSP (CDR (chars)))
1921         {
1922           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1923           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1925           if (! string || !cs)
1926             {
1927               if (string)
1928                 CFRelease (string);
1929               else if (cs)
1930                 CFRelease (cs);
1931               goto err;
1932             }
1933           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1934             if (CHARACTERP (XCAR (chars)))
1935               {
1936                 UniChar unichars[2];
1937                 CFIndex count =
1938                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1939                                                        unichars);
1940                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1942                 CFStringAppendCharacters (string, unichars, count);
1943                 CFCharacterSetAddCharactersInRange (cs, range);
1944               }
1945           charset = cs;
1946           /* CFCharacterSetCreateWithCharactersInString does not
1947              handle surrogate pairs properly as of Mac OS X 10.5.  */
1948           charset_string = string;
1949         }
1950     }
1952   attributes = CFDictionaryCreateMutable (NULL, 0,
1953                                           &kCFTypeDictionaryKeyCallBacks,
1954                                           &kCFTypeDictionaryValueCallBacks);
1955   if (! attributes)
1956     goto err;
1958   tmp = AREF (spec, FONT_FAMILY_INDEX);
1959   if (SYMBOLP (tmp) && ! NILP (tmp))
1960     {
1961       CFStringRef family = macfont_create_family_with_symbol (tmp);
1963       if (! family)
1964         goto err;
1965       CFDictionaryAddValue (attributes, kCTFontFamilyNameAttribute,
1966                             family);
1967       CFRelease (family);
1968     }
1970   traits = CFDictionaryCreateMutable (NULL, 4,
1971                                       &kCFTypeDictionaryKeyCallBacks,
1972                                       &kCFTypeDictionaryValueCallBacks);
1973   if (! traits)
1974     goto err;
1976   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1977     {
1978       tmp = AREF (spec, numeric_traits[i].index);
1979       if (INTEGERP (tmp))
1980         {
1981           CGPoint *point = numeric_traits[i].points;
1982           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1983           CFNumberRef num;
1985           while (point->y < floatval)
1986             point++;
1987           if (point == numeric_traits[i].points)
1988             point++;
1989           else if (point->y == CGFLOAT_MAX)
1990             point--;
1991           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1992                                        * ((point->x - (point - 1)->x)
1993                                           / (point->y - (point - 1)->y)));
1994           if (floatval > 1.0)
1995             floatval = 1.0;
1996           else if (floatval < -1.0)
1997             floatval = -1.0;
1998           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1999           if (! num)
2000             goto err;
2001           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2002           CFRelease (num);
2003         }
2004     }
2005   if (CFDictionaryGetCount (traits))
2006     CFDictionaryAddValue (attributes, kCTFontTraitsAttribute, traits);
2008   if (charset)
2009     CFDictionaryAddValue (attributes, kCTFontCharacterSetAttribute,
2010                           charset);
2011   if (charset_string)
2012     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2013                           charset_string);
2014   if (langarray)
2015     CFDictionaryAddValue (attributes, kCTFontLanguagesAttribute, langarray);
2017   goto finish;
2019  err:
2020   if (attributes)
2021     {
2022       CFRelease (attributes);
2023       attributes = NULL;
2024     }
2026  finish:
2027   if (langarray) CFRelease (langarray);
2028   if (charset && cf_charset_idx < 0) CFRelease (charset);
2029   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2030   if (traits) CFRelease (traits);
2031   if (otspec)
2032     {
2033       if (otspec->nfeatures[0] > 0)
2034         free (otspec->features[0]);
2035       if (otspec->nfeatures[1] > 0)
2036         free (otspec->features[1]);
2037       free (otspec);
2038     }
2040   return attributes;
2043 static Boolean
2044 macfont_supports_charset_and_languages_p (CTFontDescriptorRef desc,
2045                                           CFCharacterSetRef charset,
2046                                           Lisp_Object chars,
2047                                           CFArrayRef languages)
2049   Boolean result = true;
2051   if (charset || VECTORP (chars))
2052     {
2053       CFCharacterSetRef desc_charset =
2054         CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
2056       if (desc_charset == NULL)
2057         result = false;
2058       else
2059         {
2060           if (charset)
2061             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2062           else                  /* VECTORP (chars) */
2063             {
2064               ptrdiff_t j;
2066               for (j = 0; j < ASIZE (chars); j++)
2067                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2068                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2069                                                             XFASTINT (AREF (chars, j))))
2070                   break;
2071               if (j == ASIZE (chars))
2072                 result = false;
2073             }
2074           CFRelease (desc_charset);
2075         }
2076     }
2077   if (result && languages)
2078     result = mac_font_descriptor_supports_languages (desc, languages);
2080   return result;
2083 static int
2084 macfont_traits_distance (CTFontSymbolicTraits sym_traits1,
2085                          CTFontSymbolicTraits sym_traits2)
2087   CTFontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2088   int distance = 0;
2090   /* We prefer synthetic bold of italic to synthetic italic of bold
2091      when both bold and italic are available but bold-italic is not
2092      available.  */
2093   if (diff & kCTFontTraitBold)
2094     distance |= (1 << 0);
2095   if (diff & kCTFontTraitItalic)
2096     distance |= (1 << 1);
2097   if (diff & kCTFontTraitMonoSpace)
2098     distance |= (1 << 2);
2100   return distance;
2103 static Boolean
2104 macfont_closest_traits_index_p (CFArrayRef traits_array,
2105                                 CTFontSymbolicTraits target,
2106                                 CFIndex index)
2108   CFIndex i, count = CFArrayGetCount (traits_array);
2109   CTFontSymbolicTraits traits;
2110   int my_distance;
2112   traits = ((CTFontSymbolicTraits) (uintptr_t)
2113             CFArrayGetValueAtIndex (traits_array, index));
2114   my_distance = macfont_traits_distance (target, traits);
2116   for (i = 0; i < count; i++)
2117     if (i != index)
2118       {
2119         traits = ((CTFontSymbolicTraits) (uintptr_t)
2120                   CFArrayGetValueAtIndex (traits_array, i));
2121         if (macfont_traits_distance (target, traits) < my_distance)
2122           return false;
2123       }
2125   return true;
2128 static Lisp_Object
2129 macfont_list (struct frame *f, Lisp_Object spec)
2131   Lisp_Object val = Qnil, family, extra;
2132   int i, n;
2133   CFStringRef family_name = NULL;
2134   CFMutableDictionaryRef attributes = NULL, traits;
2135   Lisp_Object chars = Qnil;
2136   int spacing = -1;
2137   CTFontSymbolicTraits synth_sym_traits = 0;
2138   CFArrayRef families;
2139   CFIndex families_count;
2140   CFCharacterSetRef charset = NULL;
2141   CFArrayRef languages = NULL;
2143   block_input ();
2145   family = AREF (spec, FONT_FAMILY_INDEX);
2146   if (! NILP (family))
2147     {
2148       family_name = macfont_create_family_with_symbol (family);
2149       if (family_name == NULL)
2150         goto finish;
2151     }
2153   attributes = macfont_create_attributes_with_spec (spec);
2154   if (! attributes)
2155     goto finish;
2157   languages = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
2159   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2160     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2162   traits = ((CFMutableDictionaryRef)
2163             CFDictionaryGetValue (attributes, kCTFontTraitsAttribute));
2165   n = FONT_SLANT_NUMERIC (spec);
2166   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2167     {
2168       synth_sym_traits |= kCTFontTraitItalic;
2169       if (traits)
2170         CFDictionaryRemoveValue (traits, kCTFontSlantTrait);
2171     }
2173   n = FONT_WEIGHT_NUMERIC (spec);
2174   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2175     {
2176       synth_sym_traits |= kCTFontTraitBold;
2177       if (traits)
2178         CFDictionaryRemoveValue (traits, kCTFontWeightTrait);
2179     }
2181   if (languages
2182       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2183     {
2184       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2186       if (CFStringHasPrefix (language, CFSTR ("ja"))
2187           || CFStringHasPrefix (language, CFSTR ("ko"))
2188           || CFStringHasPrefix (language, CFSTR ("zh")))
2189         synth_sym_traits |= kCTFontTraitMonoSpace;
2190     }
2192   /* Create array of families.  */
2193   if (family_name)
2194     families = CFArrayCreate (NULL, (const void **) &family_name,
2195                               1, &kCFTypeArrayCallBacks);
2196   else
2197     {
2198       CFStringRef pref_family;
2199       CFIndex families_count, pref_family_index = -1;
2201       families = macfont_copy_available_families_cache ();
2202       if (families == NULL)
2203         goto err;
2205       families_count = CFArrayGetCount (families);
2207       /* Move preferred family to the front if exists.  */
2208       pref_family =
2209         mac_font_create_preferred_family_for_attributes (attributes);
2210       if (pref_family)
2211         {
2212           pref_family_index =
2213             CFArrayGetFirstIndexOfValue (families,
2214                                          CFRangeMake (0, families_count),
2215                                          pref_family);
2216           CFRelease (pref_family);
2217         }
2218       if (pref_family_index > 0)
2219         {
2220           CFMutableArrayRef mutable_families =
2221             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2223           if (mutable_families)
2224             {
2225               CFArrayAppendValue (mutable_families,
2226                                   CFArrayGetValueAtIndex (families,
2227                                                           pref_family_index));
2228               CFArrayAppendArray (mutable_families, families,
2229                                   CFRangeMake (0, pref_family_index));
2230               if (pref_family_index + 1 < families_count)
2231                 CFArrayAppendArray (mutable_families, families,
2232                                     CFRangeMake (pref_family_index + 1,
2233                                                  families_count
2234                                                  - (pref_family_index + 1)));
2235               CFRelease (families);
2236               families = mutable_families;
2237             }
2238         }
2239     }
2241   charset = CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
2242   if (charset)
2243     {
2244       CFRetain (charset);
2245       CFDictionaryRemoveValue (attributes, kCTFontCharacterSetAttribute);
2246     }
2247   else
2248     {
2249       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2250       if (! NILP (val))
2251         {
2252           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2253           if (CONSP (val) && VECTORP (XCDR (val)))
2254             chars = XCDR (val);
2255         }
2256       val = Qnil;
2257     }
2259   if (languages)
2260     {
2261       CFRetain (languages);
2262       CFDictionaryRemoveValue (attributes, kCTFontLanguagesAttribute);
2263     }
2265   val = Qnil;
2266   extra = AREF (spec, FONT_EXTRA_INDEX);
2267   families_count = CFArrayGetCount (families);
2268   for (i = 0; i < families_count; i++)
2269     {
2270       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2271       CTFontDescriptorRef pat_desc;
2272       CFArrayRef descs;
2273       CFIndex descs_count;
2274       CFMutableArrayRef filtered_descs, traits_array;
2275       Lisp_Object entity;
2276       int j;
2278       CFDictionarySetValue (attributes, kCTFontFamilyNameAttribute,
2279                             family_name);
2280       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2281       if (! pat_desc)
2282         goto err;
2284       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2285          10.7 returns NULL if pat_desc represents the LastResort font.
2286          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2287          trailing "s") for such a font.  */
2288       if (!CFEqual (family_name, CFSTR ("LastResort")))
2289         descs = CTFontDescriptorCreateMatchingFontDescriptors (pat_desc, NULL);
2290       else
2291         {
2292           CTFontDescriptorRef lr_desc =
2293             CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2294           if (lr_desc)
2295             {
2296               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2297                                      &kCFTypeArrayCallBacks);
2298               CFRelease (lr_desc);
2299             }
2300           else
2301             descs = NULL;
2302         }
2303       CFRelease (pat_desc);
2304       if (! descs)
2305         continue;
2307       descs_count = CFArrayGetCount (descs);
2308       if (descs_count == 0
2309           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2310                                                         charset, chars,
2311                                                         languages))
2312         {
2313           CFRelease (descs);
2314           continue;
2315         }
2317       filtered_descs =
2318         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2319       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2320       for (j = 0; j < descs_count; j++)
2321         {
2322           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2323           CFDictionaryRef dict;
2324           CFNumberRef num;
2325           CTFontSymbolicTraits sym_traits;
2327           dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
2328           if (dict == NULL)
2329             continue;
2331           num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
2332           CFRelease (dict);
2333           if (num == NULL
2334               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2335             continue;
2337           if (spacing >= 0
2338               && !(synth_sym_traits & kCTFontTraitMonoSpace)
2339               && (((sym_traits & kCTFontTraitMonoSpace) != 0)
2340                   != (spacing >= FONT_SPACING_MONO)))
2341             continue;
2343           /* Don't use a color bitmap font unless its family is
2344              explicitly specified.  */
2345           if ((sym_traits & kCTFontTraitColorGlyphs) && NILP (family))
2346             continue;
2348           if (j > 0
2349               && !macfont_supports_charset_and_languages_p (desc, charset,
2350                                                             chars, languages))
2351             continue;
2353           CFArrayAppendValue (filtered_descs, desc);
2354           CFArrayAppendValue (traits_array,
2355                               (const void *) (uintptr_t) sym_traits);
2356         }
2358       CFRelease (descs);
2359       descs = filtered_descs;
2360       descs_count = CFArrayGetCount (descs);
2362       for (j = 0; j < descs_count; j++)
2363         {
2364           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2365           CTFontSymbolicTraits sym_traits =
2366             ((CTFontSymbolicTraits) (uintptr_t)
2367              CFArrayGetValueAtIndex (traits_array, j));
2368           CTFontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2370           mask_min = ((synth_sym_traits ^ sym_traits)
2371                       & (kCTFontTraitItalic | kCTFontTraitBold));
2372           if (FONT_SLANT_NUMERIC (spec) < 0)
2373             mask_min &= ~kCTFontTraitItalic;
2374           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2375             mask_min &= ~kCTFontTraitBold;
2377           mask_max = (synth_sym_traits & ~sym_traits);
2378           /* Synthetic bold does not work for bitmap-only fonts on Mac
2379              OS X 10.6.  */
2380           if ((mask_min ^ mask_max) & kCTFontTraitBold)
2381             {
2382               CFNumberRef format =
2383                 CTFontDescriptorCopyAttribute (desc, kCTFontFormatAttribute);
2385               if (format)
2386                 {
2387                   uint32_t format_val;
2389                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2390                                         &format_val)
2391                       && format_val == kCTFontFormatBitmap)
2392                     mask_max &= ~kCTFontTraitBold;
2393                 }
2394             }
2395           if (spacing >= 0)
2396             mask_min |= (mask_max & kCTFontTraitMonoSpace);
2398           for (mmask = (mask_min & kCTFontTraitMonoSpace);
2399                mmask <= (mask_max & kCTFontTraitMonoSpace);
2400                mmask += kCTFontTraitMonoSpace)
2401             for (bmask = (mask_min & kCTFontTraitBold);
2402                  bmask <= (mask_max & kCTFontTraitBold);
2403                  bmask += kCTFontTraitBold)
2404               for (imask = (mask_min & kCTFontTraitItalic);
2405                    imask <= (mask_max & kCTFontTraitItalic);
2406                    imask += kCTFontTraitItalic)
2407                 {
2408                   CTFontSymbolicTraits synth = (imask | bmask | mmask);
2410                   if (synth == 0
2411                       || macfont_closest_traits_index_p (traits_array,
2412                                                          (sym_traits | synth),
2413                                                          j))
2414                     {
2415                       entity = macfont_descriptor_entity (desc, extra, synth);
2416                       if (! NILP (entity))
2417                         val = Fcons (entity, val);
2418                     }
2419                 }
2420         }
2422       CFRelease (traits_array);
2423       CFRelease (descs);
2424     }
2426   CFRelease (families);
2427   val = Fnreverse (val);
2428   goto finish;
2429  err:
2430   val = Qnil;
2432  finish:
2433   FONT_ADD_LOG ("macfont-list", spec, val);
2434   if (charset) CFRelease (charset);
2435   if (languages) CFRelease (languages);
2436   if (attributes) CFRelease (attributes);
2437   if (family_name) CFRelease (family_name);
2439   unblock_input ();
2441   return val;
2444 static Lisp_Object
2445 macfont_match (struct frame * frame, Lisp_Object spec)
2447   Lisp_Object entity = Qnil;
2448   CFMutableDictionaryRef attributes;
2449   CTFontDescriptorRef pat_desc = NULL, desc = NULL;
2451   block_input ();
2453   attributes = macfont_create_attributes_with_spec (spec);
2454   if (attributes)
2455     {
2456       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2457       CFRelease (attributes);
2458     }
2459   if (pat_desc)
2460     {
2461       desc = CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2462       CFRelease (pat_desc);
2463     }
2464   if (desc)
2465     {
2466       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2467                                           0);
2468       CFRelease (desc);
2469     }
2470   unblock_input ();
2472   FONT_ADD_LOG ("macfont-match", spec, entity);
2473   return entity;
2476 static Lisp_Object
2477 macfont_list_family (struct frame *frame)
2479   Lisp_Object list = Qnil;
2480   CFArrayRef families;
2482   block_input ();
2484   families = macfont_copy_available_families_cache ();
2485   if (families)
2486     {
2487       CFIndex i, count = CFArrayGetCount (families);
2489       for (i = 0; i < count; i++)
2490         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2491       CFRelease (families);
2492     }
2494   unblock_input ();
2496   return list;
2499 static void
2500 macfont_free_entity (Lisp_Object entity)
2502   Lisp_Object val = assq_no_quit (QCfont_entity,
2503                                   AREF (entity, FONT_EXTRA_INDEX));
2504   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2506   block_input ();
2507   CFRelease (name);
2508   unblock_input ();
2511 static Lisp_Object
2512 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2514   Lisp_Object val, font_object;
2515   CFStringRef font_name;
2516   struct macfont_info *macfont_info = NULL;
2517   struct font *font;
2518   int size;
2519   CTFontRef macfont;
2520   CTFontSymbolicTraits sym_traits;
2521   char name[256];
2522   int len, i, total_width;
2523   CGGlyph glyph;
2524   CGFloat ascent, descent, leading;
2526   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2527   if (! CONSP (val)
2528       || XTYPE (XCDR (val)) != Lisp_Misc
2529       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2530     return Qnil;
2531   font_name = XSAVE_POINTER (XCDR (val), 0);
2532   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2534   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2535   if (size == 0)
2536     size = pixel_size;
2538   block_input ();
2539   macfont = CTFontCreateWithName (font_name, size, NULL);
2540   if (macfont)
2541     {
2542       int fontsize = (int) [((NSFont *) macfont) pointSize];
2543       if (fontsize != size) size = fontsize;
2544     }
2545   unblock_input ();
2546   if (! macfont)
2547     return Qnil;
2549   font_object = font_build_object (VECSIZE (struct macfont_info),
2550                                    Qmac_ct, entity, size);
2551   font = XFONT_OBJECT (font_object);
2552   font->pixel_size = size;
2553   font->driver = &macfont_driver;
2554   font->encoding_charset = font->repertory_charset = -1;
2556   block_input ();
2558   macfont_info = (struct macfont_info *) font;
2559   macfont_info->macfont = macfont;
2560   macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
2562   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2563   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2564     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2565                                                                   size);
2566   else
2567     macfont_info->screen_font = NULL;
2568   macfont_info->cache = macfont_lookup_cache (font_name);
2569   macfont_retain_cache (macfont_info->cache);
2570   macfont_info->metrics = NULL;
2571   macfont_info->metrics_nrows = 0;
2572   macfont_info->synthetic_italic_p = 0;
2573   macfont_info->synthetic_bold_p = 0;
2574   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2575   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2576   if (!(sym_traits & kCTFontTraitItalic)
2577       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2578     macfont_info->synthetic_italic_p = 1;
2579   if (!(sym_traits & kCTFontTraitBold)
2580       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2581     macfont_info->synthetic_bold_p = 1;
2582   if (sym_traits & kCTFontTraitMonoSpace)
2583     macfont_info->spacing = MACFONT_SPACING_MONO;
2584   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2585            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2586                == FONT_SPACING_SYNTHETIC_MONO))
2587     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2588   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2589     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2590   else
2591     {
2592       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2593       if (CONSP (val))
2594         macfont_info->antialias =
2595           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2596     }
2597   macfont_info->color_bitmap_p = 0;
2598   if (sym_traits & kCTFontTraitColorGlyphs)
2599     macfont_info->color_bitmap_p = 1;
2601   glyph = macfont_get_glyph_for_character (font, ' ');
2602   if (glyph != kCGFontIndexInvalid)
2603     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2604   else
2605     /* dirty workaround */
2606     font->space_width = pixel_size;
2608   total_width = font->space_width;
2609   for (i = 1; i < 95; i++)
2610     {
2611       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2612       if (glyph == kCGFontIndexInvalid)
2613         break;
2614       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2615     }
2616   if (i == 95)
2617     font->average_width = total_width / 95;
2618   else
2619     font->average_width = font->space_width; /* XXX */
2621   if (!(macfont_info->screen_font
2622         && mac_screen_font_get_metrics (macfont_info->screen_font,
2623                                         &ascent, &descent, &leading)))
2624     {
2625       CFStringRef family_name;
2627       ascent = CTFontGetAscent (macfont);
2628       descent = CTFontGetDescent (macfont);
2629       leading = CTFontGetLeading (macfont);
2630       /* AppKit and WebKit do some adjustment to the heights of
2631          Courier, Helvetica, and Times.  */
2632       family_name = CTFontCopyFamilyName (macfont);
2633       if (family_name)
2634         {
2635           if (CFEqual (family_name, CFSTR ("Courier"))
2636               || CFEqual (family_name, CFSTR ("Helvetica"))
2637               || CFEqual (family_name, CFSTR ("Times")))
2638             ascent += (ascent + descent) * .15f;
2639           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2640             {
2641               leading *= .25f;
2642               ascent += leading;
2643             }
2644           CFRelease (family_name);
2645         }
2646     }
2647   font->ascent = ascent + 0.5f;
2648   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2649   if (CONSP (val) && !NILP (XCDR (val)))
2650     font->descent = descent + 0.5f;
2651   else
2652     font->descent = descent + leading + 0.5f;
2653   font->height = font->ascent + font->descent;
2655   font->underline_position = - CTFontGetUnderlinePosition (macfont) + 0.5f;
2656   font->underline_thickness = CTFontGetUnderlineThickness (macfont) + 0.5f;
2658   unblock_input ();
2660   /* Unfortunately Xft doesn't provide a way to get minimum char
2661      width.  So, we use space_width instead.  */
2662   font->min_width = font->max_width = font->space_width; /* XXX */
2664   font->baseline_offset = 0;
2665   font->relative_compose = 0;
2666   font->default_ascent = 0;
2667   font->vertical_centering = 0;
2669   return font_object;
2672 static void
2673 macfont_close (struct font *font)
2675   struct macfont_info *macfont_info = (struct macfont_info *) font;
2677   if (macfont_info->cache)
2678     {
2679       int i;
2681       block_input ();
2682       CFRelease (macfont_info->macfont);
2683       CGFontRelease (macfont_info->cgfont);
2684       if (macfont_info->screen_font)
2685         CFRelease (macfont_info->screen_font);
2686       macfont_release_cache (macfont_info->cache);
2687       for (i = 0; i < macfont_info->metrics_nrows; i++)
2688         if (macfont_info->metrics[i])
2689           xfree (macfont_info->metrics[i]);
2690       if (macfont_info->metrics)
2691         xfree (macfont_info->metrics);
2692       macfont_info->cache = NULL;
2693       unblock_input ();
2694     }
2697 static int
2698 macfont_has_char (Lisp_Object font, int c)
2700   int result;
2701   CFCharacterSetRef charset;
2703   block_input ();
2704   if (FONT_ENTITY_P (font))
2705     {
2706       Lisp_Object val;
2707       CFStringRef name;
2709       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2710       val = XCDR (val);
2711       name = XSAVE_POINTER (val, 0);
2712       charset = macfont_get_cf_charset_for_name (name);
2713     }
2714   else
2715     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2717   result = CFCharacterSetIsLongCharacterMember (charset, c);
2718   unblock_input ();
2720   return result;
2723 static unsigned
2724 macfont_encode_char (struct font *font, int c)
2726   struct macfont_info *macfont_info = (struct macfont_info *) font;
2727   CGGlyph glyph;
2729   block_input ();
2730   glyph = macfont_get_glyph_for_character (font, c);
2731   unblock_input ();
2733   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2736 static void
2737 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2738                       struct font_metrics *metrics)
2740   int width, i;
2742   block_input ();
2743   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2744   for (i = 1; i < nglyphs; i++)
2745     {
2746       struct font_metrics m;
2747       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2748                                      NULL, 0);
2750       if (metrics)
2751         {
2752           if (width + m.lbearing < metrics->lbearing)
2753             metrics->lbearing = width + m.lbearing;
2754           if (width + m.rbearing > metrics->rbearing)
2755             metrics->rbearing = width + m.rbearing;
2756           if (m.ascent > metrics->ascent)
2757             metrics->ascent = m.ascent;
2758           if (m.descent > metrics->descent)
2759             metrics->descent = m.descent;
2760         }
2761       width += w;
2762     }
2763   unblock_input ();
2765   if (metrics)
2766     metrics->width = width;
2769 static int
2770 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2771               bool with_background)
2773   struct frame * f = s->f;
2774   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2775   CGRect background_rect;
2776   CGPoint text_position;
2777   CGGlyph *glyphs;
2778   CGPoint *positions;
2779   CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2780   bool no_antialias_p =
2781     (NILP (ns_antialias_text)
2782      || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2783      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2784          && font_size <= macfont_antialias_threshold));
2785   int len = to - from;
2786   struct face *face = s->face;
2787   CGContextRef context;
2789   block_input ();
2791   if (with_background)
2792     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2793                                   s->width, FONT_HEIGHT (s->font));
2794   else
2795     background_rect = CGRectNull;
2797   text_position = CGPointMake (x, -y);
2798   glyphs = xmalloc (sizeof (CGGlyph) * len);
2799   {
2800     CGFloat advance_delta = 0;
2801     int i;
2802     CGFloat total_width = 0;
2804     positions = xmalloc (sizeof (CGPoint) * len);
2805     for (i = 0; i < len; i++)
2806       {
2807         int width;
2809         glyphs[i] = s->char2b[from + i];
2810         width = (s->padding_p ? 1
2811                  : macfont_glyph_extents (s->font, glyphs[i],
2812                                           NULL, &advance_delta,
2813                                           no_antialias_p));
2814         positions[i].x = total_width + advance_delta;
2815         positions[i].y = 0;
2816         total_width += width;
2817       }
2818   }
2820   context = [[NSGraphicsContext currentContext] graphicsPort];
2821   CGContextSaveGState (context);
2823   if (!CGRectIsNull (background_rect))
2824     {
2825       if (s->hl == DRAW_MOUSE_FACE)
2826         {
2827           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2828           if (!face)
2829             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2830         }
2831       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2832       CGContextFillRects (context, &background_rect, 1);
2833     }
2835   if (macfont_info->cgfont)
2836     {
2837       CGAffineTransform atfm;
2839       CGContextScaleCTM (context, 1, -1);
2840       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2841       if (macfont_info->synthetic_italic_p)
2842         atfm = synthetic_italic_atfm;
2843       else
2844         atfm = CGAffineTransformIdentity;
2845       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2846         {
2847           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2848           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2849           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2850         }
2851       if (no_antialias_p)
2852         CGContextSetShouldAntialias (context, false);
2854       CGContextSetTextMatrix (context, atfm);
2855       CGContextSetTextPosition (context, text_position.x, text_position.y);
2857 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2858       if (macfont_info->color_bitmap_p
2859 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2860           && CTFontDrawGlyphs != NULL
2861 #endif
2862           )
2863         {
2864           if (len > 0)
2865             {
2866               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2867                                 context);
2868             }
2869         }
2870       else
2871 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2872         {
2873           CGContextSetFont (context, macfont_info->cgfont);
2874           CGContextSetFontSize (context, font_size);
2875           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2876         }
2877     }
2880   xfree (glyphs);
2881   xfree (positions);
2882   CGContextRestoreGState (context);
2884   unblock_input ();
2886   return len;
2889 static Lisp_Object
2890 macfont_shape (Lisp_Object lgstring)
2892   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2893   struct macfont_info *macfont_info = (struct macfont_info *) font;
2894   CTFontRef macfont = macfont_info->macfont;
2895   ptrdiff_t glyph_len, len, i, j;
2896   CFIndex nonbmp_len;
2897   UniChar *unichars;
2898   CFIndex *nonbmp_indices;
2899   CFStringRef string;
2900   CFIndex used = 0;
2901   struct mac_glyph_layout *glyph_layouts;
2903   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2904   nonbmp_len = 0;
2905   for (i = 0; i < glyph_len; i++)
2906     {
2907       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2909       if (NILP (lglyph))
2910         break;
2911       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2912         nonbmp_len++;
2913     }
2915   len = i;
2917   if (INT_MAX / 2 < len)
2918     memory_full (SIZE_MAX);
2920   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2921   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2922   for (i = j = 0; i < len; i++)
2923     {
2924       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2926       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2927         {
2928           nonbmp_indices[j] = i + j;
2929           j++;
2930         }
2931     }
2932   nonbmp_indices[j] = len + j;  /* sentinel */
2934   block_input ();
2936   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2937                                                kCFAllocatorNull);
2938   if (string)
2939     {
2940       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2941       if (macfont_info->screen_font)
2942         used = mac_screen_font_shape (macfont_info->screen_font, string,
2943                                       glyph_layouts, glyph_len);
2944       else
2945         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2946       CFRelease (string);
2947     }
2949   unblock_input ();
2951   if (used == 0)
2952     return Qnil;
2954   block_input ();
2956   for (i = 0; i < used; i++)
2957     {
2958       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2959       struct mac_glyph_layout *gl = glyph_layouts + i;
2960       EMACS_INT from, to;
2961       struct font_metrics metrics;
2962       int xoff, yoff, wadjust;
2964       if (NILP (lglyph))
2965         {
2966           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2967           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2968         }
2970       from = gl->comp_range.location;
2971       /* Convert UTF-16 index to UTF-32.  */
2972       j = 0;
2973       while (nonbmp_indices[j] < from)
2974         j++;
2975       from -= j;
2976       LGLYPH_SET_FROM (lglyph, from);
2978       to = gl->comp_range.location + gl->comp_range.length;
2979       /* Convert UTF-16 index to UTF-32.  */
2980       while (nonbmp_indices[j] < to)
2981         j++;
2982       to -= j;
2983       LGLYPH_SET_TO (lglyph, to - 1);
2985       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2986          the composition is trivial.  */
2987       {
2988         UTF32Char c;
2990         if (unichars[gl->string_index] >= 0xD800
2991             && unichars[gl->string_index] < 0xDC00)
2992           c = (((unichars[gl->string_index] - 0xD800) << 10)
2993                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2994         else
2995           c = unichars[gl->string_index];
2996         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2997           c = 0;
2998         LGLYPH_SET_CHAR (lglyph, c);
2999       }
3001       {
3002         unsigned long cc = gl->glyph_id;
3003         LGLYPH_SET_CODE (lglyph, cc);
3004       }
3006       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3007       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3008       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3009       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3010       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3011       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3013       xoff = lround (gl->advance_delta);
3014       yoff = lround (- gl->baseline_delta);
3015       wadjust = lround (gl->advance);
3016       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3017         {
3018           Lisp_Object vec;
3020           vec = Fmake_vector (make_number (3), Qnil);
3021           ASET (vec, 0, make_number (xoff));
3022           ASET (vec, 1, make_number (yoff));
3023           ASET (vec, 2, make_number (wadjust));
3024           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3025         }
3026     }
3028   unblock_input ();
3030   return make_number (used);
3033 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3034 typedef UInt8 UINT24[3];
3036 #pragma pack(push, 1)
3037 struct variation_selector_record
3039   UINT24 var_selector;
3040   UInt32 default_uvs_offset, non_default_uvs_offset;
3042 struct uvs_table
3044   UInt16 format;
3045   UInt32 length, num_var_selector_records;
3046   struct variation_selector_record variation_selector_records[1];
3048 #define SIZEOF_UVS_TABLE_HEADER                                         \
3049   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3051 struct unicode_value_range
3053   UINT24 start_unicode_value;
3054   UInt8 additional_count;
3056 struct default_uvs_table {
3057   UInt32 num_unicode_value_ranges;
3058   struct unicode_value_range unicode_value_ranges[1];
3060 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3061   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3063 struct uvs_mapping
3065   UINT24 unicode_value;
3066   UInt16 glyph_id;
3068 struct non_default_uvs_table
3070   UInt32 num_uvs_mappings;
3071   struct uvs_mapping uvs_mappings[1];
3073 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3074   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3075 #pragma pack(pop)
3077 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3078 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3079    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3080    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3081 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3082 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3083 /* Succeeding one byte should also be accessible.  */
3084 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3085 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3087 /* Return UVS subtable for the specified FONT.  If the subtable is not
3088    found or ill-formatted, then return NULL.  */
3090 static CFDataRef
3091 mac_font_copy_uvs_table (CTFontRef font)
3093   CFDataRef cmap_table, uvs_table = NULL;
3095   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3096                                 kCTFontTableOptionNoOptions);
3097   if (cmap_table)
3098     {
3099       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3100       struct uvs_table *uvs;
3101       struct variation_selector_record *records;
3102       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3104 #if __LP64__
3105       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3106         goto finish;
3107 #endif
3109       cmap_len = CFDataGetLength (cmap_table);
3110       if (sizeof_sfntCMapHeader > cmap_len)
3111         goto finish;
3113       ntables = BUINT16_VALUE (cmap->numTables);
3114       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3115                      / sizeof_sfntCMapEncoding))
3116         goto finish;
3118       for (i = 0; i < ntables; i++)
3119         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3120              == kFontUnicodePlatform)
3121             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3122                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3123           {
3124             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3125             break;
3126           }
3127       if (i == ntables
3128           || uvs_offset > cmap_len
3129           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3130         goto finish;
3132       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3133       uvs_len = BUINT32_VALUE (uvs->length);
3134       if (uvs_len > cmap_len - uvs_offset
3135           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3136         goto finish;
3138       if (BUINT16_VALUE (uvs->format) != 14)
3139         goto finish;
3141       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3142       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3143                       / sizeof (struct variation_selector_record)))
3144         goto finish;
3146       records = uvs->variation_selector_records;
3147       for (i = 0; i < nrecords; i++)
3148         {
3149           UInt32 default_uvs_offset, non_default_uvs_offset;
3151           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3152           if (default_uvs_offset)
3153             {
3154               struct default_uvs_table *default_uvs;
3155               UInt32 nranges;
3157               if (default_uvs_offset > uvs_len
3158                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3159                       > uvs_len - default_uvs_offset))
3160                 goto finish;
3162               default_uvs = ((struct default_uvs_table *)
3163                              ((UInt8 *) uvs + default_uvs_offset));
3164               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3165               if (nranges > ((uvs_len - default_uvs_offset
3166                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3167                              / sizeof (struct unicode_value_range)))
3168                 goto finish;
3169               /* Now 2 * nranges can't overflow, so we can safely use
3170                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3171                  mac_font_get_glyphs_for_variants.  */
3172             }
3174           non_default_uvs_offset =
3175             BUINT32_VALUE (records[i].non_default_uvs_offset);
3176           if (non_default_uvs_offset)
3177             {
3178               struct non_default_uvs_table *non_default_uvs;
3179               UInt32 nmappings;
3181               if (non_default_uvs_offset > uvs_len
3182                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3183                       > uvs_len - non_default_uvs_offset))
3184                 goto finish;
3186               non_default_uvs = ((struct non_default_uvs_table *)
3187                                  ((UInt8 *) uvs + non_default_uvs_offset));
3188               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3189               if (nmappings > ((uvs_len - non_default_uvs_offset
3190                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3191                                / sizeof (struct uvs_mapping)))
3192                 goto finish;
3193               /* Now 2 * nmappings can't overflow, so we can safely
3194                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3195                  in mac_font_get_glyphs_for_variants.  */
3196             }
3197         }
3199       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3201     finish:
3202       CFRelease (cmap_table);
3203     }
3205   return uvs_table;
3208 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3209    sequence consisting of the given base character C and each
3210    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3211    result (explained below) into the corresponding GLYPHS[i].  If the
3212    entry is found in the Default UVS Table, then the result is 0.  If
3213    the entry is found in the Non-Default UVS Table, then the result is
3214    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3215    elements in SELECTORS must be sorted in strictly increasing
3216    order.  */
3218 static void
3219 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3220                                   const UTF32Char selectors[], CGGlyph glyphs[],
3221                                   CFIndex count)
3223   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3224   struct variation_selector_record *records = uvs->variation_selector_records;
3225   CFIndex i;
3226   UInt32 ir, nrecords;
3227   dispatch_queue_t queue =
3228     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3229   dispatch_group_t group = dispatch_group_create ();
3231   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3232   i = 0;
3233   ir = 0;
3234   while (i < count && ir < nrecords)
3235     {
3236       UInt32 default_uvs_offset, non_default_uvs_offset;
3238       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3239         {
3240           glyphs[i++] = kCGFontIndexInvalid;
3241           continue;
3242         }
3243       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3244         {
3245           ir++;
3246           continue;
3247         }
3249       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3250       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3251       non_default_uvs_offset =
3252         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3253       dispatch_group_async (group, queue, ^{
3254           glyphs[i] = kCGFontIndexInvalid;
3256           if (default_uvs_offset)
3257             {
3258               struct default_uvs_table *default_uvs =
3259                 (struct default_uvs_table *) ((UInt8 *) uvs
3260                                               + default_uvs_offset);
3261               struct unicode_value_range *ranges =
3262                 default_uvs->unicode_value_ranges;
3263               UInt32 lo, hi;
3265               lo = 0;
3266               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3267               while (lo < hi)
3268                 {
3269                   UInt32 mid = (lo + hi) / 2;
3271                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3272                     hi = mid;
3273                   else
3274                     lo = mid + 1;
3275                 }
3276               if (hi > 0
3277                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3278                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3279                 glyphs[i] = 0;
3280             }
3282           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3283             {
3284               struct non_default_uvs_table *non_default_uvs =
3285                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3286                                                   + non_default_uvs_offset);
3287               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3288               UInt32 lo, hi;
3290               lo = 0;
3291               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3292               while (lo < hi)
3293                 {
3294                   UInt32 mid = (lo + hi) / 2;
3296                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3297                     hi = mid;
3298                   else
3299                     lo = mid + 1;
3300                 }
3301               if (hi > 0 &&
3302                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3303                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3304             }
3305         });
3306       i++;
3307       ir++;
3308     }
3309   while (i < count)
3310     glyphs[i++] = kCGFontIndexInvalid;
3311   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3312   dispatch_release (group);
3315 static int
3316 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3318   CFDataRef uvs_table;
3319   CTCharacterCollection uvs_collection;
3320   int i, n = 0;
3322   block_input ();
3323   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3325   if (uvs_table)
3326     {
3327       UTF32Char selectors[256];
3328       CGGlyph glyphs[256];
3330       for (i = 0; i < 16; i++)
3331         selectors[i] = 0xFE00 + i;
3332       for (; i < 256; i++)
3333         selectors[i] = 0xE0100 + (i - 16);
3334       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3335       for (i = 0; i < 256; i++)
3336         {
3337           CGGlyph glyph = glyphs[i];
3339           if (uvs_collection != kCTCharacterCollectionIdentityMapping
3340               && glyph != kCGFontIndexInvalid)
3341             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3342           if (glyph == kCGFontIndexInvalid)
3343             variations[i] = 0;
3344           else
3345             {
3346               variations[i] = (glyph ? glyph
3347                                : macfont_get_glyph_for_character (font, c));
3348               n++;
3349             }
3350         }
3351     }
3352   unblock_input ();
3354   return n;
3357 static const char *const macfont_booleans[] = {
3358   ":antialias",
3359   ":minspace",
3360   NULL,
3363 static const char *const macfont_non_booleans[] = {
3364   ":lang",
3365   ":script",
3366   ":destination",
3367   NULL,
3370 static void
3371 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3373   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3376 static Boolean
3377 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3378                                         CFArrayRef languages)
3380   Boolean result = true;
3381   CFArrayRef desc_languages =
3382     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3384   if (desc_languages == NULL)
3385     result = false;
3386   else
3387     {
3388       CFIndex desc_languages_count, i, languages_count;
3390       desc_languages_count = CFArrayGetCount (desc_languages);
3391       languages_count = CFArrayGetCount (languages);
3392       for (i = 0; i < languages_count; i++)
3393         if (!CFArrayContainsValue (desc_languages,
3394                                    CFRangeMake (0, desc_languages_count),
3395                                    CFArrayGetValueAtIndex (languages, i)))
3396           {
3397             result = false;
3398             break;
3399           }
3400       CFRelease (desc_languages);
3401     }
3403   return result;
3406 static CFStringRef
3407 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3409   CFStringRef result = NULL;
3410   CFStringRef charset_string =
3411     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3413   if (charset_string && CFStringGetLength (charset_string) > 0)
3414     {
3415       CFStringRef keys[] = {
3416 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3417         kCTLanguageAttributeName
3418 #else
3419         CFSTR ("NSLanguage")
3420 #endif
3421       };
3422       CFTypeRef values[] = {NULL};
3423       CFIndex num_values = 0;
3424       CFArrayRef languages
3425         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3427       if (languages && CFArrayGetCount (languages) > 0)
3428         {
3429           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3430             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3431           else
3432             {
3433               CFCharacterSetRef charset =
3434                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3436               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3437             }
3438         }
3439       if (result == NULL)
3440         {
3441           CFAttributedStringRef attr_string = NULL;
3442           CTLineRef ctline = NULL;
3443           CFDictionaryRef attrs
3444             = CFDictionaryCreate (NULL, (const void **) keys,
3445                                   (const void **) values, num_values,
3446                                   &kCFTypeDictionaryKeyCallBacks,
3447                                   &kCFTypeDictionaryValueCallBacks);
3449           if (attrs)
3450             {
3451               attr_string = CFAttributedStringCreate (NULL, charset_string,
3452                                                       attrs);
3453               CFRelease (attrs);
3454             }
3455           if (attr_string)
3456             {
3457               ctline = CTLineCreateWithAttributedString (attr_string);
3458               CFRelease (attr_string);
3459             }
3460           if (ctline)
3461             {
3462               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3463               CFIndex i, nruns = CFArrayGetCount (runs);
3464               CTFontRef font;
3466               for (i = 0; i < nruns; i++)
3467                 {
3468                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3469                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3470                   CTFontRef font_in_run;
3472                   if (attributes == NULL)
3473                     break;
3474                   font_in_run =
3475                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3476                   if (font_in_run == NULL)
3477                     break;
3478                   if (i == 0)
3479                     font = font_in_run;
3480                   else if (!mac_font_equal_in_postscript_name (font,
3481                                                                font_in_run))
3482                     break;
3483                 }
3484               if (nruns > 0 && i == nruns)
3485                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3486               CFRelease (ctline);
3487             }
3488         }
3489     }
3491   return result;
3494 static inline double
3495 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3497   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3498                                      &glyph, NULL, 1);
3501 static inline CGRect
3502 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3504   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3505                                           &glyph, NULL, 1);
3508 static CFArrayRef
3509 mac_font_create_available_families (void)
3511   CFMutableArrayRef families = NULL;
3512   CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3514   if (orig_families)
3515     {
3516       CFIndex i, count = CFArrayGetCount (orig_families);
3518       families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3519       if (families)
3520         for (i = 0; i < count; i++)
3521           {
3522             CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3524             if (!CFStringHasPrefix (family, CFSTR ("."))
3525                 && (CTFontManagerCompareFontFamilyNames (family,
3526                                                          CFSTR ("LastResort"),
3527                                                          NULL)
3528                     != kCFCompareEqualTo))
3529               CFArrayAppendValue (families, family);
3530           }
3531       CFRelease (orig_families);
3532     }
3534   return families;
3537 static Boolean
3538 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3540   Boolean result;
3541   CFStringRef name1, name2;
3543   if (font1 == font2)
3544     return true;
3546   result = false;
3547   name1 = CTFontCopyPostScriptName (font1);
3548   if (name1)
3549     {
3550       name2 = CTFontCopyPostScriptName (font2);
3551       if (name2)
3552         {
3553           result = CFEqual (name1, name2);
3554           CFRelease (name2);
3555         }
3556       CFRelease (name1);
3557     }
3559   return result;
3562 static CTLineRef
3563 mac_font_create_line_with_string_and_font (CFStringRef string,
3564                                            CTFontRef macfont)
3566   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3567   CFTypeRef values[] = {NULL, NULL};
3568   CFDictionaryRef attributes = NULL;
3569   CFAttributedStringRef attr_string = NULL;
3570   CTLineRef ctline = NULL;
3571   float float_zero = 0.0f;
3573   values[0] = macfont;
3574   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3575   if (values[1])
3576     {
3577       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3578                                        (const void **) values,
3579                                        ARRAYELTS (keys),
3580                                        &kCFTypeDictionaryKeyCallBacks,
3581                                        &kCFTypeDictionaryValueCallBacks);
3582       CFRelease (values[1]);
3583     }
3584   if (attributes)
3585     {
3586       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3587       CFRelease (attributes);
3588     }
3589   if (attr_string)
3590     {
3591       ctline = CTLineCreateWithAttributedString (attr_string);
3592       CFRelease (attr_string);
3593     }
3594   if (ctline)
3595     {
3596       /* Abandon if ctline contains some fonts other than the
3597          specified one.  */
3598       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3599       CFIndex i, nruns = CFArrayGetCount (runs);
3601       for (i = 0; i < nruns; i++)
3602         {
3603           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3604           CFDictionaryRef attributes = CTRunGetAttributes (run);
3605           CTFontRef font_in_run;
3607           if (attributes == NULL)
3608             break;
3609           font_in_run =
3610             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3611           if (font_in_run == NULL)
3612             break;
3613           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3614             break;
3615         }
3616       if (i < nruns)
3617         {
3618           CFRelease (ctline);
3619           ctline = NULL;
3620         }
3621     }
3623   return ctline;
3626 static CFIndex
3627 mac_font_shape (CTFontRef font, CFStringRef string,
3628                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3630   CFIndex used, result = 0;
3631   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3633   if (ctline == NULL)
3634     return 0;
3636   used = CTLineGetGlyphCount (ctline);
3637   if (used <= glyph_len)
3638     {
3639       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3640       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3641       CGFloat total_advance = 0;
3642       CFIndex total_glyph_count = 0;
3644       for (k = 0; k < ctrun_count; k++)
3645         {
3646           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3647           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3648           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3649           CFRange string_range, comp_range, range;
3650           CFIndex *permutation;
3652           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3653             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3654           else
3655             permutation = NULL;
3657 #define RIGHT_TO_LEFT_P permutation
3659           /* Now the `comp_range' member of struct mac_glyph_layout is
3660              temporarily used as a work area such that:
3661              glbuf[i].comp_range.location =
3662              min {compRange[i + 1].location, ...,
3663                      compRange[glyph_count - 1].location,
3664                      maxRange (stringRangeForCTRun)}
3665              glbuf[i].comp_range.length = maxRange (compRange[i])
3666              where compRange[i] is the range of composed characters
3667              containing i-th glyph.  */
3668           string_range = CTRunGetStringRange (ctrun);
3669           min_location = string_range.location + string_range.length;
3670           for (i = 0; i < glyph_count; i++)
3671             {
3672               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3673               CFIndex glyph_index;
3674               CFRange rng;
3676               if (!RIGHT_TO_LEFT_P)
3677                 glyph_index = glyph_count - i - 1;
3678               else
3679                 glyph_index = i;
3680               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3681                                      &gl->string_index);
3682               rng =
3683                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3684                                                              gl->string_index);
3685               gl->comp_range.location = min_location;
3686               gl->comp_range.length = rng.location + rng.length;
3687               if (rng.location < min_location)
3688                 min_location = rng.location;
3689             }
3691           /* Fill the `comp_range' member of struct mac_glyph_layout,
3692              and setup a permutation for right-to-left text.  */
3693           comp_range = CFRangeMake (string_range.location, 0);
3694           range = CFRangeMake (0, 0);
3695           while (1)
3696             {
3697               struct mac_glyph_layout *gl =
3698                 glbuf + range.location + range.length;
3700               if (gl->comp_range.length
3701                   > comp_range.location + comp_range.length)
3702                 comp_range.length = gl->comp_range.length - comp_range.location;
3703               min_location = gl->comp_range.location;
3704               range.length++;
3706               if (min_location >= comp_range.location + comp_range.length)
3707                 {
3708                   comp_range.length = min_location - comp_range.location;
3709                   for (i = 0; i < range.length; i++)
3710                     {
3711                       glbuf[range.location + i].comp_range = comp_range;
3712                       if (RIGHT_TO_LEFT_P)
3713                         permutation[range.location + i] =
3714                           range.location + range.length - i - 1;
3715                     }
3717                   comp_range = CFRangeMake (min_location, 0);
3718                   range.location += range.length;
3719                   range.length = 0;
3720                   if (range.location == glyph_count)
3721                     break;
3722                 }
3723             }
3725           /* Then fill the remaining members.  */
3726           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3727                range.location++)
3728             {
3729               struct mac_glyph_layout *gl;
3730               CGPoint position;
3732               if (!RIGHT_TO_LEFT_P)
3733                 gl = glbuf + range.location;
3734               else
3735                 {
3736                   CFIndex src, dest;
3738                   src = glyph_count - 1 - range.location;
3739                   dest = permutation[src];
3740                   gl = glbuf + dest;
3741                   if (src < dest)
3742                     {
3743                       CFIndex tmp = gl->string_index;
3745                       gl->string_index = glbuf[src].string_index;
3746                       glbuf[src].string_index = tmp;
3747                     }
3748                 }
3749               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3751               CTRunGetPositions (ctrun, range, &position);
3752               gl->advance_delta = position.x - total_advance;
3753               gl->baseline_delta = position.y;
3754               gl->advance = (gl->advance_delta
3755                              + CTRunGetTypographicBounds (ctrun, range,
3756                                                           NULL, NULL, NULL));
3757               total_advance += gl->advance;
3758             }
3760           if (RIGHT_TO_LEFT_P)
3761             xfree (permutation);
3763 #undef RIGHT_TO_LEFT_P
3765           total_glyph_count += glyph_count;
3766         }
3768       result = used;
3769     }
3770   CFRelease (ctline);
3772   return result;
3775 /* The function below seems to cause a memory leak for the CFString
3776    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3777    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3778 #if USE_CT_GLYPH_INFO
3779 static CGGlyph
3780 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3781                               CGFontIndex cid)
3783   CGGlyph result = kCGFontIndexInvalid;
3784   UniChar characters[] = {0xfffd};
3785   CFStringRef string;
3786   CFAttributedStringRef attr_string = NULL;
3787   CTLineRef ctline = NULL;
3789   string = CFStringCreateWithCharacters (NULL, characters,
3790                                          ARRAYELTS (characters));
3792   if (string)
3793     {
3794       CTGlyphInfoRef glyph_info =
3795         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3796       CFDictionaryRef attributes = NULL;
3798       if (glyph_info)
3799         {
3800           CFStringRef keys[] = {kCTFontAttributeName,
3801                                 kCTGlyphInfoAttributeName};
3802           CFTypeRef values[] = {font, glyph_info};
3804           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3805                                            (const void **) values,
3806                                            ARRAYELTS (keys),
3807                                            &kCFTypeDictionaryKeyCallBacks,
3808                                            &kCFTypeDictionaryValueCallBacks);
3809           CFRelease (glyph_info);
3810         }
3811       if (attributes)
3812         {
3813           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3814           CFRelease (attributes);
3815         }
3816       CFRelease (string);
3817     }
3818   if (attr_string)
3819     {
3820       ctline = CTLineCreateWithAttributedString (attr_string);
3821       CFRelease (attr_string);
3822     }
3823   if (ctline)
3824     {
3825       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3827       if (CFArrayGetCount (runs) > 0)
3828         {
3829           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3830           CFDictionaryRef attributes = CTRunGetAttributes (run);
3832           if (attributes)
3833             {
3834               CTFontRef font_in_run =
3835                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3837               if (font_in_run
3838                   && mac_font_equal_in_postscript_name (font_in_run, font))
3839                 {
3840                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3841                   if (result >= CTFontGetGlyphCount (font))
3842                     result = kCGFontIndexInvalid;
3843                 }
3844             }
3845         }
3846       CFRelease (ctline);
3847     }
3849   return result;
3851 #endif
3853 static CFArrayRef
3854 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3856   CFArrayRef result = NULL;
3858 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3859 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3860   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3861 #endif
3862     {
3863       CTFontRef user_font =
3864         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3866       if (user_font)
3867         {
3868           CFArrayRef languages =
3869             CFArrayCreate (NULL, (const void **) &language, 1,
3870                            &kCFTypeArrayCallBacks);
3872           if (languages)
3873             {
3874               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3875                                                                  languages);
3876               CFRelease (languages);
3877             }
3878           CFRelease (user_font);
3879         }
3880     }
3881 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3882   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3883 #endif
3884 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3885 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3886     {
3887       CFIndex i;
3889       for (i = 0; macfont_language_default_font_names[i].language; i++)
3890         {
3891           if (CFEqual (macfont_language_default_font_names[i].language,
3892                        language))
3893             {
3894               CFMutableArrayRef descriptors =
3895                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3897               if (descriptors)
3898                 {
3899                   CFIndex j;
3901                   for (j = 0;
3902                        macfont_language_default_font_names[i].font_names[j];
3903                        j++)
3904                     {
3905                       CFDictionaryRef attributes =
3906                         CFDictionaryCreate (NULL,
3907                                             ((const void **)
3908                                              &kCTFontNameAttribute),
3909                                             ((const void **)
3910                                              &macfont_language_default_font_names[i].font_names[j]),
3911                                             1, &kCFTypeDictionaryKeyCallBacks,
3912                                             &kCFTypeDictionaryValueCallBacks);
3914                       if (attributes)
3915                         {
3916                           CTFontDescriptorRef pat_desc =
3917                             CTFontDescriptorCreateWithAttributes (attributes);
3919                           if (pat_desc)
3920                             {
3921                               CTFontDescriptorRef descriptor =
3922                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3924                               if (descriptor)
3925                                 {
3926                                   CFArrayAppendValue (descriptors, descriptor);
3927                                   CFRelease (descriptor);
3928                                 }
3929                               CFRelease (pat_desc);
3930                             }
3931                           CFRelease (attributes);
3932                         }
3933                     }
3934                   result = descriptors;
3935                 }
3936               break;
3937             }
3938         }
3939     }
3940 #endif
3942   return result;
3945 static CFStringRef
3946 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3947                                                       CFArrayRef languages)
3949   CFStringRef result = NULL;
3950   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3951   CFArrayRef descriptors =
3952     mac_font_copy_default_descriptors_for_language (language);
3954   if (descriptors)
3955     {
3956       CFIndex i, count = CFArrayGetCount (descriptors);
3958       for (i = 0; i < count; i++)
3959         {
3960           CTFontDescriptorRef descriptor =
3961             CFArrayGetValueAtIndex (descriptors, i);
3963           if (macfont_supports_charset_and_languages_p (descriptor, charset,
3964                                                         Qnil, languages))
3965             {
3966               CFStringRef family =
3967                 CTFontDescriptorCopyAttribute (descriptor,
3968                                                kCTFontFamilyNameAttribute);
3969               if (family)
3970                 {
3971                   if (!CFStringHasPrefix (family, CFSTR ("."))
3972                       && !CFEqual (family, CFSTR ("LastResort")))
3973                     {
3974                       result = family;
3975                       break;
3976                     }
3977                   else
3978                     CFRelease (family);
3979                 }
3980             }
3981         }
3982       CFRelease (descriptors);
3983     }
3985   return result;
3988 void *
3989 macfont_get_nsctfont (struct font *font)
3991   struct macfont_info *macfont_info = (struct macfont_info *) font;
3992   CTFontRef macfont = macfont_info->macfont;
3994   return (void *) macfont;
3997 void
3998 mac_register_font_driver (struct frame *f)
4000   register_font_driver (&macfont_driver, f);
4004 void
4005 syms_of_macfont (void)
4007   static struct font_driver mac_font_driver;
4009   /* Core Text, for Mac OS X.  */
4010   DEFSYM (Qmac_ct, "mac-ct");
4011   macfont_driver.type = Qmac_ct;
4012   register_font_driver (&macfont_driver, NULL);
4014   /* The font property key specifying the font design destination.  The
4015      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4016      text.  (See the documentation of X Logical Font Description
4017      Conventions.)  In the Mac font driver, 1 means the screen font is
4018      used for calculating some glyph metrics.  You can see the
4019      difference with Monaco 8pt or 9pt, for example.  */
4020   DEFSYM (QCdestination, ":destination");
4022   /* The boolean-valued font property key specifying the use of leading.  */
4023   DEFSYM (QCminspace, ":minspace");
4025   macfont_family_cache = Qnil;
4026   staticpro (&macfont_family_cache);