; NEWS: Update Org version number
[emacs.git] / src / macfont.m
blob97879506ba4cae74e5d3d53feab75ef67adbc9e3
1 /* Font driver on macOS Core text.
2    Copyright (C) 2009-2017 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 (at
9 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 <https://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 double mac_font_get_advance_width_for_glyph (CTFontRef, CGGlyph);
42 static CGRect mac_font_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
43 static CFArrayRef mac_font_create_available_families (void);
44 static Boolean mac_font_equal_in_postscript_name (CTFontRef, CTFontRef);
45 static CTLineRef mac_font_create_line_with_string_and_font (CFStringRef,
46                                                             CTFontRef);
47 static Boolean mac_font_descriptor_supports_languages (CTFontDescriptorRef,
48                                                        CFArrayRef);
49 static CFStringRef mac_font_create_preferred_family_for_attributes (CFDictionaryRef);
50 static CFIndex mac_font_shape (CTFontRef, CFStringRef,
51                                struct mac_glyph_layout *, CFIndex);
52 static CFArrayRef mac_font_copy_default_descriptors_for_language (CFStringRef);
53 static CFStringRef mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef, CFArrayRef);
54 #if USE_CT_GLYPH_INFO
55 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef, CTCharacterCollection,
56                                              CGFontIndex);
57 #endif
59 struct macfont_metrics;
61 /* The actual structure for Mac font that can be cast to struct font.  */
63 struct macfont_info
65   struct font font;
66   CTFontRef macfont;
67   CGFontRef cgfont;
68   ScreenFontRef screen_font;
69   struct macfont_cache *cache;
70   struct macfont_metrics **metrics;
71   short metrics_nrows;
72   bool_bf synthetic_italic_p : 1;
73   bool_bf synthetic_bold_p : 1;
74   unsigned spacing : 2;
75   unsigned antialias : 2;
76   bool_bf color_bitmap_p : 1;
79 /* Values for the `spacing' member in `struct macfont_info'.  */
81 enum
82   {
83     MACFONT_SPACING_PROPORTIONAL,
84     MACFONT_SPACING_MONO,
85     MACFONT_SPACING_SYNTHETIC_MONO,
86   };
88 /* Values for the `antialias' member in `struct macfont_info'.  */
90 enum
91   {
92     MACFONT_ANTIALIAS_DEFAULT,
93     MACFONT_ANTIALIAS_OFF,
94     MACFONT_ANTIALIAS_ON,
95   };
97 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
98 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
99 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
101 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
102 static const CGFloat synthetic_bold_factor = 0.024;
104 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
105                                                         CTFontSymbolicTraits *);
106 static void macfont_store_descriptor_attributes (CTFontDescriptorRef,
107                                                  Lisp_Object);
108 static Lisp_Object macfont_descriptor_entity (CTFontDescriptorRef, Lisp_Object,
109                                               CTFontSymbolicTraits);
110 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
111 static int macfont_glyph_extents (struct font *, CGGlyph,
112                                   struct font_metrics *, CGFloat *, int);
113 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
114 static Boolean macfont_supports_charset_and_languages_p (CTFontDescriptorRef,
115                                                          CFCharacterSetRef,
116                                                          Lisp_Object,
117                                                          CFArrayRef);
118 static Boolean macfont_closest_traits_index_p (CFArrayRef, CTFontSymbolicTraits,
119                                                CFIndex);
120 static CFDataRef mac_font_copy_uvs_table (CTFontRef);
121 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
122                                               const UTF32Char [],
123                                               CGGlyph [], CFIndex);
125 /* From CFData to a lisp string.  Always returns a unibyte string.  */
127 static Lisp_Object
128 cfdata_to_lisp (CFDataRef data)
130   CFIndex len = CFDataGetLength (data);
131   Lisp_Object result = make_uninit_string (len);
133   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
135   return result;
140 /* From CFString to a lisp string.  Returns a unibyte string
141    containing a UTF-8 byte sequence.  */
143 static Lisp_Object
144 cfstring_to_lisp_nodecode (CFStringRef string)
146   Lisp_Object result = Qnil;
147   CFDataRef data;
148   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
150   if (s)
151     {
152       CFIndex i, length = CFStringGetLength (string);
154       for (i = 0; i < length; i++)
155         if (CFStringGetCharacterAtIndex (string, i) == 0)
156           break;
158       if (i == length)
159         return make_unibyte_string (s, strlen (s));
160     }
162   data = CFStringCreateExternalRepresentation (NULL, string,
163                                                kCFStringEncodingUTF8, '?');
164   if (data)
165     {
166       result = cfdata_to_lisp (data);
167       CFRelease (data);
168     }
170   return result;
173 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
174    cfstring_create_with_utf8_cstring, this function preserves NUL
175    characters.  */
177 static CFStringRef
178 cfstring_create_with_string_noencode (Lisp_Object s)
180   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
181                                                 kCFStringEncodingUTF8, false);
183   if (string == NULL)
184     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
185     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
186                                       kCFStringEncodingMacRoman, false);
188   return string;
191 static CFIndex
192 mac_font_get_weight (CTFontRef font)
194   NSFont *nsFont = (NSFont *) font;
196   return [[NSFontManager sharedFontManager] weightOfFont:nsFont];
199 static CGFloat
200 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
202   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
204   return advancement.width;
207 #if !USE_CT_GLYPH_INFO
208 static CGGlyph
209 mac_font_get_glyph_for_cid (CTFontRef font, NSCharacterCollection collection,
210                             CGFontIndex cid)
212   CGGlyph result = kCGFontIndexInvalid;
213   NSFont *nsFont = (NSFont *) font;
214   unichar characters[] = {0xfffd};
215   NSString *string =
216     [NSString stringWithCharacters:characters
217                             length:ARRAYELTS (characters)];
218   NSGlyphInfo *glyphInfo =
219     [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
220                                        collection:collection
221                                        baseString:string];
222   NSDictionary *attributes =
223     [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
224                   glyphInfo,NSGlyphInfoAttributeName,nil];
225   NSTextStorage *textStorage =
226     [[NSTextStorage alloc] initWithString:string
227                                attributes:attributes];
228   NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
229   NSTextContainer *textContainer = [[NSTextContainer alloc] init];
230   NSFont *fontInTextStorage;
232   [layoutManager addTextContainer:textContainer];
233   [textContainer release];
234   [textStorage addLayoutManager:layoutManager];
235   [layoutManager release];
237   /* Force layout.  */
238   (void) [layoutManager glyphRangeForTextContainer:textContainer];
240   fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
241                               effectiveRange:NULL];
242   if (fontInTextStorage == nsFont
243       || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
244     {
245       NSGlyph glyph = [layoutManager glyphAtIndex:0];
247       if (glyph < [nsFont numberOfGlyphs])
248         result = glyph;
249     }
251   [textStorage release];
253   return result;
255 #endif
257 static ScreenFontRef
258 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
260   NSFont *result, *font;
262   font = [NSFont fontWithName:((NSString *) name) size:size];
263   result = [font screenFont];
265   return (ScreenFontRef)[result retain];
269 static Boolean
270 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
271                              CGFloat *descent, CGFloat *leading)
273   NSFont *nsFont = [(NSFont *)font printerFont];
274   NSTextStorage *textStorage;
275   NSLayoutManager *layoutManager;
276   NSTextContainer *textContainer;
277   NSRect usedRect;
278   NSPoint spaceLocation;
279   CGFloat descender;
281   textStorage = [[NSTextStorage alloc] initWithString:@" "];
282   layoutManager = [[NSLayoutManager alloc] init];
283   textContainer = [[NSTextContainer alloc] init];
285   [textStorage setFont:nsFont];
286   [textContainer setLineFragmentPadding:0];
288   [layoutManager addTextContainer:textContainer];
289   [textContainer release];
290   [textStorage addLayoutManager:layoutManager];
291   [layoutManager release];
293   if (!(textStorage && layoutManager && textContainer))
294     {
295       [textStorage release];
297       return false;
298     }
300   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
301                                                  effectiveRange:NULL];
302   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
303   [textStorage release];
305   *ascent = spaceLocation.y;
306   *descent = NSHeight (usedRect) - spaceLocation.y;
307   *leading = 0;
308   descender = [nsFont descender];
309   if (- descender < *descent)
310     {
311       *leading = *descent + descender;
312       *descent = - descender;
313     }
315   return true;
318 static CFIndex
319 mac_font_shape_1 (NSFont *font, NSString *string,
320                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
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];
341   [layoutManager addTextContainer:textContainer];
342   [textContainer release];
343   [textStorage addLayoutManager:layoutManager];
344   [layoutManager release];
346   if (!(textStorage && layoutManager && textContainer))
347     {
348       [textStorage release];
350       return 0;
351     }
353   stringLength = [string length];
355   /* Force layout.  */
356   (void) [layoutManager glyphRangeForTextContainer:textContainer];
358   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
360   /* Remove the appended trailing space because otherwise it may
361      generate a wrong result for a right-to-left text.  */
362   [textStorage beginEditing];
363   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
364   [textStorage endEditing];
365   (void) [layoutManager glyphRangeForTextContainer:textContainer];
367   i = 0;
368   while (i < stringLength)
369     {
370       NSRange range;
371       NSFont *fontInTextStorage =
372         [textStorage attribute:NSFontAttributeName atIndex:i
373                      longestEffectiveRange:&range
374                        inRange:(NSMakeRange (0, stringLength))];
376       if (!(fontInTextStorage == font
377             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
378         break;
379       i = NSMaxRange (range);
380     }
381   if (i < stringLength)
382     /* Make the test `used <= glyph_len' below fail if textStorage
383        contained some fonts other than the specified one.  */
384     used = glyph_len + 1;
385   else
386     {
387       NSRange range = NSMakeRange (0, stringLength);
389       range = [layoutManager glyphRangeForCharacterRange:range
390                                     actualCharacterRange:NULL];
391       numberOfGlyphs = NSMaxRange (range);
392       used = numberOfGlyphs;
393       for (i = 0; i < numberOfGlyphs; i++)
394         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
395           used--;
396     }
398   if (0 < used && used <= glyph_len)
399     {
400       NSUInteger glyphIndex, prevGlyphIndex;
401       unsigned char bidiLevel;
402       NSUInteger *permutation;
403       NSRange compRange, range;
404       CGFloat totalAdvance;
406       glyphIndex = 0;
407       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
408         glyphIndex++;
410       /* For now we assume the direction is not changed within the
411          string.  */
412       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
413                                glyphs:NULL
414                            properties:NULL
415                      characterIndexes: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);
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 CGFloat
766 mac_font_descriptor_get_adjusted_weight (CTFontDescriptorRef desc, CGFloat val)
768   long percent_val = lround (val * 100);
770   if (percent_val == -40)
771     {
772       CTFontRef font = NULL;
773       CFStringRef name =
774         CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
776       if (name)
777         {
778           font = CTFontCreateWithName (name, 0, NULL);
779           CFRelease (name);
780         }
781       if (font)
782         {
783           CFIndex weight = mac_font_get_weight (font);
785           /* Workaround for crash when displaying Oriya characters
786              with Arial Unicode MS on OS X 10.11.  */
787           if (weight == 5)
788             val = 0;
789           CFRelease (font);
790         }
791     }
793   return val;
796 static void
797 macfont_store_descriptor_attributes (CTFontDescriptorRef desc,
798                                      Lisp_Object spec_or_entity)
800   CFStringRef str;
801   CFDictionaryRef dict;
802   CFNumberRef num;
803   CGFloat floatval;
805   str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
806   if (str)
807     {
808       ASET (spec_or_entity, FONT_FAMILY_INDEX,
809             macfont_intern_prop_cfstring (str));
810       CFRelease (str);
811     }
812   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
813   if (dict)
814     {
815       struct {
816         enum font_property_index index;
817         CFStringRef trait;
818         CGPoint points[6];
819         CGFloat (*adjust_func) (CTFontDescriptorRef, CGFloat);
820       } numeric_traits[] =
821           {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
822             {{-0.4, 50},        /* light */
823              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
824              {0, 100},          /* normal */
825              {0.24, 140},       /* (semi-bold + normal) / 2 */
826              {0.4, 200},        /* bold */
827              {CGFLOAT_MAX, CGFLOAT_MAX}},
828             mac_font_descriptor_get_adjusted_weight},
829            {FONT_SLANT_INDEX, kCTFontSlantTrait,
830             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL},
831            {FONT_WIDTH_INDEX, kCTFontWidthTrait,
832             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL}};
833       int i;
835       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
836         {
837           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
838           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
839             {
840               CGPoint *point = numeric_traits[i].points;
842               if (numeric_traits[i].adjust_func)
843                 floatval = (*numeric_traits[i].adjust_func) (desc, floatval);
844               while (point->x < floatval)
845                 point++;
846               if (point == numeric_traits[i].points)
847                 point++;
848               else if (point->x == CGFLOAT_MAX)
849                 point--;
850               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
851                                            * ((point->y - (point - 1)->y)
852                                               / (point->x - (point - 1)->x)));
853               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
854                               make_number (lround (floatval)));
855             }
856         }
858       num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
859       if (num)
860         {
861           CTFontSymbolicTraits sym_traits;
862           int spacing;
864           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
865           spacing = (sym_traits & kCTFontTraitMonoSpace
866                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
867           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
868         }
870       CFRelease (dict);
871     }
872   num = CTFontDescriptorCopyAttribute (desc, kCTFontSizeAttribute);
873   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
874     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
875   else
876     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
877   if (num)
878     CFRelease (num);
881 static Lisp_Object
882 macfont_descriptor_entity (CTFontDescriptorRef desc, Lisp_Object extra,
883                            CTFontSymbolicTraits synth_sym_traits)
885   Lisp_Object entity;
886   CFDictionaryRef dict;
887   CTFontSymbolicTraits sym_traits = 0;
888   CFStringRef name;
890   entity = font_make_entity ();
892   ASET (entity, FONT_TYPE_INDEX, Qmac_ct);
893   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
895   macfont_store_descriptor_attributes (desc, entity);
897   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
898   if (dict)
899     {
900       CFNumberRef num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
902       if (num)
903         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
904       CFRelease (dict);
905     }
906   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
907     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
908   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
909   name = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
910   font_put_extra (entity, QCfont_entity,
911                   make_save_ptr_int ((void *) name, sym_traits));
912   if (synth_sym_traits & kCTFontTraitItalic)
913     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
914                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
915   if (synth_sym_traits & kCTFontTraitBold)
916     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
917                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
918   if (synth_sym_traits & kCTFontTraitMonoSpace)
919     ASET (entity, FONT_SPACING_INDEX,
920           make_number (FONT_SPACING_SYNTHETIC_MONO));
922   return entity;
925 /* Cache for font family name symbols vs CFStrings.  A value of nil
926 means the cache has been invalidated.  Otherwise the value is a Lisp
927 hash table whose keys are symbols and the value for a key is either
928 nil (no corresponding family name) or a Lisp save value wrapping the
929 corresponding family name in CFString.  */
931 static Lisp_Object macfont_family_cache;
933 static void
934 macfont_invalidate_family_cache (void)
936   if (HASH_TABLE_P (macfont_family_cache))
937     {
938       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
939       ptrdiff_t i, size = HASH_TABLE_SIZE (h);
941       for (i = 0; i < size; ++i)
942         if (!NILP (HASH_HASH (h, i)))
943           {
944             Lisp_Object value = HASH_VALUE (h, i);
946             if (SAVE_VALUEP (value))
947               CFRelease (XSAVE_POINTER (value, 0));
948           }
949       macfont_family_cache = Qnil;
950     }
953 static bool
954 macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string)
956   if (HASH_TABLE_P (macfont_family_cache))
957     {
958       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
959       ptrdiff_t i = hash_lookup (h, symbol, NULL);
961       if (i >= 0)
962         {
963           Lisp_Object value = HASH_VALUE (h, i);
965           *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL;
967           return true;
968         }
969     }
971   return false;
974 static void
975 macfont_set_family_cache (Lisp_Object symbol, CFStringRef string)
977   struct Lisp_Hash_Table *h;
978   ptrdiff_t i;
979   EMACS_UINT hash;
980   Lisp_Object value;
982   if (!HASH_TABLE_P (macfont_family_cache))
983     macfont_family_cache = CALLN (Fmake_hash_table, QCtest, Qeq);
985   h = XHASH_TABLE (macfont_family_cache);
986   i = hash_lookup (h, symbol, &hash);
987   value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil;
988   if (i >= 0)
989     {
990       Lisp_Object old_value = HASH_VALUE (h, i);
992       if (SAVE_VALUEP (old_value))
993         CFRelease (XSAVE_POINTER (old_value, 0));
994       set_hash_value_slot (h, i, value);
995     }
996   else
997     hash_put (h, symbol, value, hash);
1000 /* Cache of all the available font family names except "LastResort"
1001 and those start with ".".  NULL means the cache has been invalidated.
1002 Otherwise, the value is CFArray of CFStrings and the elements are
1003 sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
1004 Mac OS X 10.6 and later).  */
1006 static CFArrayRef macfont_available_families_cache = NULL;
1008 static void
1009 macfont_invalidate_available_families_cache (void)
1011   if (macfont_available_families_cache)
1012     {
1013       CFRelease (macfont_available_families_cache);
1014       macfont_available_families_cache = NULL;
1015     }
1018 static void
1019 macfont_handle_font_change_notification (CFNotificationCenterRef center,
1020                                          void *observer,
1021                                          CFStringRef name, const void *object,
1022                                          CFDictionaryRef userInfo)
1024   macfont_invalidate_family_cache ();
1025   macfont_invalidate_available_families_cache ();
1028 static void
1029 macfont_init_font_change_handler (void)
1031   static bool initialized = false;
1033   if (initialized)
1034     return;
1036   initialized = true;
1037   CFNotificationCenterAddObserver
1038     (CFNotificationCenterGetLocalCenter (), NULL,
1039      macfont_handle_font_change_notification,
1040      kCTFontManagerRegisteredFontsChangedNotification,
1041      NULL, CFNotificationSuspensionBehaviorCoalesce);
1044 static CFArrayRef
1045 macfont_copy_available_families_cache (void)
1047   macfont_init_font_change_handler ();
1049   if (macfont_available_families_cache == NULL)
1050     macfont_available_families_cache = mac_font_create_available_families ();
1052   return (macfont_available_families_cache
1053           ? CFRetain (macfont_available_families_cache) : NULL);
1056 static CFStringRef
1057 macfont_create_family_with_symbol (Lisp_Object symbol)
1059   CFStringRef result = NULL, family_name;
1060   CFDictionaryRef attributes = NULL;
1061   CTFontDescriptorRef pat_desc = NULL;
1063   if (macfont_get_family_cache_if_present (symbol, &result))
1064     return result ? CFRetain (result) : NULL;
1066   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
1067   if (family_name)
1068     {
1069       attributes =
1070         CFDictionaryCreate (NULL,
1071                             (const void **) &kCTFontFamilyNameAttribute,
1072                             (const void **) &family_name, 1,
1073                             &kCFTypeDictionaryKeyCallBacks,
1074                             &kCFTypeDictionaryValueCallBacks);
1075       CFRelease (family_name);
1076     }
1077   if (attributes)
1078     {
1079       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
1080       CFRelease (attributes);
1081     }
1082   if (pat_desc)
1083     {
1084       CTFontDescriptorRef desc =
1085         CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
1087       if (desc)
1088         {
1089           result =
1090             CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
1091           CFRelease (desc);
1092         }
1093       macfont_set_family_cache (symbol, result);
1094       CFRelease (pat_desc);
1095     }
1097   return result;
1100 #define WIDTH_FRAC_BITS         (4)
1101 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
1103 struct macfont_metrics
1105   unsigned char lbearing_low, rbearing_low;
1106   signed lbearing_high : 4, rbearing_high : 4;
1107   unsigned char ascent_low, descent_low;
1108   signed ascent_high : 4, descent_high : 4;
1110   /* These two members are used for fixed-point representation of
1111      glyph width.  The `width_int' member is an integer that is
1112      closest to the width.  The `width_frac' member is the fractional
1113      adjustment representing a value in [-.5, .5], multiplied by
1114      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1115      the advance delta for centering instead of the glyph width.  */
1116   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1119 #define METRICS_VALUE(metrics, member)                          \
1120   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1121 #define METRICS_SET_VALUE(metrics, member, value)                   \
1122   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff;    \
1123     (metrics)->member##_high = tmp >> 8;} while (0)
1125 enum metrics_status
1127   METRICS_INVALID = -1,    /* metrics entry is invalid */
1128   METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1131 #define METRICS_STATUS(metrics)                                         \
1132   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1133 #define METRICS_SET_STATUS(metrics, status)                     \
1134   do {METRICS_SET_VALUE (metrics, ascent, 0);                   \
1135     METRICS_SET_VALUE (metrics, descent, status);} while (0)
1137 #define METRICS_NCOLS_PER_ROW   (128)
1138 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1139 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1141 static int
1142 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1143                        struct font_metrics *metrics, CGFloat *advance_delta,
1144                        int force_integral_p)
1146   struct macfont_info *macfont_info = (struct macfont_info *) font;
1147   CTFontRef macfont = macfont_info->macfont;
1148   int row, col;
1149   struct macfont_metrics *cache;
1150   int width;
1152   row = glyph / METRICS_NCOLS_PER_ROW;
1153   col = glyph % METRICS_NCOLS_PER_ROW;
1154   if (row >= macfont_info->metrics_nrows)
1155     {
1156       macfont_info->metrics =
1157         xrealloc (macfont_info->metrics,
1158                   sizeof (struct macfont_metrics *) * (row + 1));
1159       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1160               (sizeof (struct macfont_metrics *)
1161                * (row + 1 - macfont_info->metrics_nrows)));
1162       macfont_info->metrics_nrows = row + 1;
1163     }
1164   if (macfont_info->metrics[row] == NULL)
1165     {
1166       struct macfont_metrics *new;
1167       int i;
1169       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1170       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1171         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1172       macfont_info->metrics[row] = new;
1173     }
1174   cache = macfont_info->metrics[row] + col;
1176   if (METRICS_STATUS (cache) == METRICS_INVALID)
1177     {
1178       CGFloat fwidth;
1180       if (macfont_info->screen_font)
1181         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1182       else
1183         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1185       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1186          advance delta value.  */
1187       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1188         fwidth = (font->pixel_size - fwidth) / 2;
1189       cache->width_int = lround (fwidth);
1190       cache->width_frac = lround ((fwidth - cache->width_int)
1191                                   * WIDTH_FRAC_SCALE);
1192       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1193     }
1194   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1195     width = font->pixel_size;
1196   else
1197     width = cache->width_int;
1199   if (metrics)
1200     {
1201       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1202         {
1203           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1205           if (macfont_info->synthetic_italic_p)
1206             {
1207               /* We assume the members a, b, c, and d in
1208                  synthetic_italic_atfm are non-negative.  */
1209               bounds.origin =
1210                 CGPointApplyAffineTransform (bounds.origin,
1211                                              synthetic_italic_atfm);
1212               bounds.size =
1213                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1214             }
1215           if (macfont_info->synthetic_bold_p && ! force_integral_p)
1216             {
1217               CGFloat d = - synthetic_bold_factor * CTFontGetSize (macfont) / 2;
1219               bounds = CGRectInset (bounds, d, d);
1220             }
1221           switch (macfont_info->spacing)
1222             {
1223             case MACFONT_SPACING_PROPORTIONAL:
1224               bounds.origin.x += - (cache->width_frac
1225                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1226               break;
1227             case MACFONT_SPACING_MONO:
1228               break;
1229             case MACFONT_SPACING_SYNTHETIC_MONO:
1230               bounds.origin.x += (cache->width_int
1231                                   + (cache->width_frac
1232                                      / (CGFloat) WIDTH_FRAC_SCALE));
1233               break;
1234             }
1235           if (bounds.size.width > 0)
1236             {
1237               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1238               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1239                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1240             }
1241           bounds = CGRectIntegral (bounds);
1242           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1243           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1244           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1245           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1246         }
1247       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1248       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1249       metrics->width = width;
1250       metrics->ascent = METRICS_VALUE (cache, ascent);
1251       metrics->descent = METRICS_VALUE (cache, descent);
1252     }
1254   if (advance_delta)
1255     {
1256       switch (macfont_info->spacing)
1257         {
1258         case MACFONT_SPACING_PROPORTIONAL:
1259           *advance_delta = (force_integral_p ? 0
1260                             : - (cache->width_frac
1261                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1262           break;
1263         case MACFONT_SPACING_MONO:
1264           *advance_delta = 0;
1265           break;
1266         case MACFONT_SPACING_SYNTHETIC_MONO:
1267           *advance_delta = (force_integral_p ? cache->width_int
1268                             : (cache->width_int
1269                                + (cache->width_frac
1270                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1271           break;
1272         }
1273     }
1275   return width;
1278 static CFMutableDictionaryRef macfont_cache_dictionary;
1280 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1281    equal to the number of rows that are invalid as BMP (i.e., from
1282    U+D800 to U+DFFF).  */
1283 #define ROW_PERM_OFFSET (8)
1285 /* The number of glyphs that can be stored in a value for a single
1286    entry of CFDictionary.  */
1287 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1289 struct macfont_cache
1291   int reference_count;
1292   CFCharacterSetRef cf_charset;
1293   struct {
1294     /* The cached glyph for a BMP character c is stored in
1295        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1296        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1297     unsigned char row_nkeys_or_perm[256];
1298     CGGlyph **matrix;
1300     /* Number of rows for which the BMP cache is allocated so far.
1301        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1302     int nrows;
1304     /* The cached glyph for a character c is stored as the (c %
1305        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1306        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1307        not stored here if row_nkeys_or_perm[c / 256] >=
1308        ROW_PERM_OFFSET.  */
1309     CFMutableDictionaryRef dictionary;
1310   } glyph;
1312   struct {
1313     /* UVS (Unicode Variation Sequence) subtable data, which is of
1314        type CFDataRef if available.  NULL means it is not initialized
1315        yet.  kCFNull means the subtable is not found and there is no
1316        suitable fallback table for this font.  */
1317     CFTypeRef table;
1319     /* Character collection specifying the destination of the mapping
1320        provided by `table' above.  If `table' is obtained from the UVS
1321        subtable in the font cmap table, then the value of this member
1322        should be NSIdentityMappingCharacterCollection.  */
1323     NSCharacterCollection collection;
1324   } uvs;
1327 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1328 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1329 static void macfont_release_cache (struct macfont_cache *);
1330 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1331 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1332 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1333 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1334                                           NSCharacterCollection, CGFontIndex);
1335 static CFDataRef macfont_get_uvs_table (struct font *, NSCharacterCollection *);
1337 static struct macfont_cache *
1338 macfont_lookup_cache (CFStringRef key)
1340   struct macfont_cache *cache;
1342   if (macfont_cache_dictionary == NULL)
1343     {
1344       macfont_cache_dictionary =
1345         CFDictionaryCreateMutable (NULL, 0,
1346                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1347       cache = NULL;
1348     }
1349   else
1350     cache = ((struct macfont_cache *)
1351              CFDictionaryGetValue (macfont_cache_dictionary, key));
1353   if (cache == NULL)
1354     {
1355       CTFontRef macfont = CTFontCreateWithName (key, 0, NULL);
1357       if (macfont)
1358         {
1359           cache = xzalloc (sizeof (struct macfont_cache));
1360           /* Treat the LastResort font as if it contained glyphs for
1361              all characters.  This may look too rough, but neither
1362              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1363              for this font is correct for non-BMP characters on Mac OS
1364              X 10.5, anyway.  */
1365           if (CFEqual (key, CFSTR ("LastResort")))
1366             {
1367               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1369               cache->cf_charset =
1370                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1371             }
1372           if (cache->cf_charset == NULL)
1373             cache->cf_charset = CTFontCopyCharacterSet (macfont);
1374           CFDictionaryAddValue (macfont_cache_dictionary, key,
1375                                 (const void *) cache);
1376           CFRelease (macfont);
1377         }
1378     }
1380   return cache;
1383 static struct macfont_cache *
1384 macfont_retain_cache (struct macfont_cache *cache)
1386   cache->reference_count++;
1388   return cache;
1391 static void
1392 macfont_release_cache (struct macfont_cache *cache)
1394   if (--cache->reference_count == 0)
1395     {
1396       int i;
1398       for (i = 0; i < cache->glyph.nrows; i++)
1399         xfree (cache->glyph.matrix[i]);
1400       xfree (cache->glyph.matrix);
1401       if (cache->glyph.dictionary)
1402         CFRelease (cache->glyph.dictionary);
1403       memset (&cache->glyph, 0, sizeof (cache->glyph));
1404       if (cache->uvs.table)
1405         CFRelease (cache->uvs.table);
1406       memset (&cache->uvs, 0, sizeof (cache->uvs));
1407     }
1410 static CFCharacterSetRef
1411 macfont_get_cf_charset (struct font *font)
1413   struct macfont_info *macfont_info = (struct macfont_info *) font;
1415   return macfont_info->cache->cf_charset;
1418 static CFCharacterSetRef
1419 macfont_get_cf_charset_for_name (CFStringRef name)
1421   struct macfont_cache *cache = macfont_lookup_cache (name);
1423   return cache->cf_charset;
1426 static CGGlyph
1427 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1429   struct macfont_info *macfont_info = (struct macfont_info *) font;
1430   CTFontRef macfont = macfont_info->macfont;
1431   struct macfont_cache *cache = macfont_info->cache;
1433   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1434     {
1435       int row = c / 256;
1436       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1438       if (nkeys_or_perm < ROW_PERM_OFFSET)
1439         {
1440           UniChar unichars[256], ch;
1441           CGGlyph *glyphs;
1442           int i, len;
1443           int nrows;
1444           dispatch_queue_t queue;
1445           dispatch_group_t group = NULL;
1447           if (row != 0)
1448             {
1449               CFMutableDictionaryRef dictionary;
1450               uintptr_t key, value;
1451               int nshifts;
1452               CGGlyph glyph;
1454               if (cache->glyph.dictionary == NULL)
1455                 cache->glyph.dictionary =
1456                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1457               dictionary = cache->glyph.dictionary;
1458               key = c / NGLYPHS_IN_VALUE;
1459               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1460               value = ((uintptr_t)
1461                        CFDictionaryGetValue (dictionary, (const void *) key));
1462               glyph = (value >> nshifts);
1463               if (glyph)
1464                 return glyph;
1466               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1467                 {
1468                   ch = c;
1469                   if (!CTFontGetGlyphsForCharacters (macfont, &ch, &glyph, 1)
1470                       || glyph == 0)
1471                     glyph = kCGFontIndexInvalid;
1473                   if (value == 0)
1474                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1475                   value |= ((uintptr_t) glyph << nshifts);
1476                   CFDictionarySetValue (dictionary, (const void *) key,
1477                                         (const void *) value);
1479                   return glyph;
1480                 }
1482               queue =
1483                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1484               group = dispatch_group_create ();
1485               dispatch_group_async (group, queue, ^{
1486                   int nkeys;
1487                   uintptr_t key;
1488                   nkeys = nkeys_or_perm;
1489                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1490                     if (CFDictionaryContainsKey (dictionary,
1491                                                  (const void *) key))
1492                       {
1493                         CFDictionaryRemoveValue (dictionary,
1494                                                  (const void *) key);
1495                         if (--nkeys == 0)
1496                           break;
1497                       }
1498                 });
1499             }
1501           len = 0;
1502           for (i = 0; i < 256; i++)
1503             {
1504               ch = row * 256 + i;
1505               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1506                 unichars[len++] = ch;
1507             }
1509           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1510           if (len > 0)
1511             {
1512               CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, len);
1513               while (i > len)
1514                 {
1515                   int next = unichars[len - 1] % 256;
1517                   while (--i > next)
1518                     glyphs[i] = kCGFontIndexInvalid;
1520                   len--;
1521                   glyphs[i] = glyphs[len];
1522                   if (len == 0)
1523                     break;
1524                 }
1525             }
1526           if (i > len)
1527             while (i-- > 0)
1528               glyphs[i] = kCGFontIndexInvalid;
1530           nrows = cache->glyph.nrows;
1531           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1532           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1533           nrows++;
1534           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1535                                           sizeof (CGGlyph *) * nrows);
1536           cache->glyph.matrix[nrows - 1] = glyphs;
1537           cache->glyph.nrows = nrows;
1539           if (group)
1540             {
1541               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1542               dispatch_release (group);
1543             }
1544         }
1546       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1547     }
1548   else
1549     {
1550       uintptr_t key, value;
1551       int nshifts;
1552       CGGlyph glyph;
1554       if (cache->glyph.dictionary == NULL)
1555         cache->glyph.dictionary =
1556           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1557       key = c / NGLYPHS_IN_VALUE;
1558       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1559       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1560                                                 (const void *) key);
1561       glyph = (value >> nshifts);
1562       if (glyph == 0)
1563         {
1564           UniChar unichars[2];
1565           CGGlyph glyphs[2];
1566           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1568           if (CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, count))
1569             glyph = glyphs[0];
1570           if (glyph == 0)
1571             glyph = kCGFontIndexInvalid;
1573           value |= ((uintptr_t) glyph << nshifts);
1574           CFDictionarySetValue (cache->glyph.dictionary,
1575                                 (const void *) key, (const void *) value);
1576         }
1578       return glyph;
1579     }
1582 static CGGlyph
1583 macfont_get_glyph_for_cid (struct font *font, NSCharacterCollection collection,
1584                            CGFontIndex cid)
1586   struct macfont_info *macfont_info = (struct macfont_info *) font;
1587   CTFontRef macfont = macfont_info->macfont;
1589   /* Cache it? */
1590   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1593 static CFDataRef
1594 macfont_get_uvs_table (struct font *font, NSCharacterCollection *collection)
1596   struct macfont_info *macfont_info = (struct macfont_info *) font;
1597   CTFontRef macfont = macfont_info->macfont;
1598   struct macfont_cache *cache = macfont_info->cache;
1599   CFDataRef result = NULL;
1601   if (cache->uvs.table == NULL)
1602     {
1603       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1604       NSCharacterCollection uvs_collection =
1605         NSIdentityMappingCharacterCollection;
1607       if (uvs_table == NULL
1608           && mac_font_get_glyph_for_cid (macfont,
1609                                          NSAdobeJapan1CharacterCollection,
1610                                          6480) != kCGFontIndexInvalid)
1611         {
1612           /* If the glyph for U+4E55 is accessible via its CID 6480,
1613              then we use the Adobe-Japan1 UVS table, which maps a
1614              variation sequence to a CID, as a fallback.  */
1615           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1617           if (mac_uvs_table_adobe_japan1 == NULL)
1618             mac_uvs_table_adobe_japan1 =
1619               CFDataCreateWithBytesNoCopy (NULL,
1620                                            mac_uvs_table_adobe_japan1_bytes,
1621                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1622                                            kCFAllocatorNull);
1623           if (mac_uvs_table_adobe_japan1)
1624             {
1625               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1626               uvs_collection = NSAdobeJapan1CharacterCollection;
1627             }
1628         }
1629       if (uvs_table == NULL)
1630         cache->uvs.table = kCFNull;
1631       else
1632         cache->uvs.table = uvs_table;
1633       cache->uvs.collection = uvs_collection;
1634     }
1636   if (cache->uvs.table != kCFNull)
1637     {
1638       result = cache->uvs.table;
1639       *collection = cache->uvs.collection;
1640     }
1642   return result;
1645 static Lisp_Object macfont_get_cache (struct frame *);
1646 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1647 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1648 static Lisp_Object macfont_list_family (struct frame *);
1649 static void macfont_free_entity (Lisp_Object);
1650 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1651 static void macfont_close (struct font *);
1652 static int macfont_has_char (Lisp_Object, int);
1653 static unsigned macfont_encode_char (struct font *, int);
1654 static void macfont_text_extents (struct font *, unsigned int *, int,
1655                                   struct font_metrics *);
1656 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1657 static Lisp_Object macfont_shape (Lisp_Object);
1658 static int macfont_variation_glyphs (struct font *, int c,
1659                                      unsigned variations[256]);
1660 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1662 static struct font_driver const macfont_driver =
1663   {
1664   .type = LISPSYM_INITIALLY (Qmac_ct),
1665   .get_cache = macfont_get_cache,
1666   .list = macfont_list,
1667   .match = macfont_match,
1668   .list_family = macfont_list_family,
1669   .free_entity = macfont_free_entity,
1670   .open = macfont_open,
1671   .close = macfont_close,
1672   .has_char = macfont_has_char,
1673   .encode_char = macfont_encode_char,
1674   .text_extents = macfont_text_extents,
1675   .draw = macfont_draw,
1676   .shape = macfont_shape,
1677   .get_variation_glyphs = macfont_variation_glyphs,
1678   .filter_properties = macfont_filter_properties,
1679   };
1681 static Lisp_Object
1682 macfont_get_cache (struct frame * f)
1684   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1686   return (dpyinfo->name_list_element);
1689 static int
1690 macfont_get_charset (Lisp_Object registry)
1692   char *str = SSDATA (SYMBOL_NAME (registry));
1693   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1694   Lisp_Object regexp;
1695   int i, j;
1697   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1698     {
1699       if (str[i] == '.')
1700         re[j++] = '\\';
1701       else if (str[i] == '*')
1702         re[j++] = '.';
1703       re[j] = str[i];
1704       if (re[j] == '?')
1705         re[j] = '.';
1706     }
1707   re[j] = '\0';
1708   regexp = make_unibyte_string (re, j);
1709   for (i = 0; cf_charset_table[i].name; i++)
1710     if (fast_c_string_match_ignore_case
1711         (regexp, cf_charset_table[i].name,
1712          strlen (cf_charset_table[i].name)) >= 0)
1713       break;
1714   if (! cf_charset_table[i].name)
1715     return -1;
1716   if (! cf_charset_table[i].cf_charset)
1717     {
1718       int *uniquifier = cf_charset_table[i].uniquifier;
1719       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1720       CFIndex count = 0;
1721       CFStringRef string;
1722       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1724       if (! charset)
1725         return -1;
1726       for (j = 0; uniquifier[j]; j++)
1727         {
1728           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1729                                                         unichars + count);
1730           CFCharacterSetAddCharactersInRange (charset,
1731                                               CFRangeMake (uniquifier[j], 1));
1732         }
1734       string = CFStringCreateWithCharacters (NULL, unichars, count);
1735       if (! string)
1736         {
1737           CFRelease (charset);
1738           return -1;
1739         }
1740       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1741                                                                  charset);
1742       CFRelease (charset);
1743       /* CFCharacterSetCreateWithCharactersInString does not handle
1744          surrogate pairs properly as of Mac OS X 10.5.  */
1745       cf_charset_table[i].cf_charset_string = string;
1746     }
1747   return i;
1750 struct OpenTypeSpec
1752   Lisp_Object script;
1753   unsigned int script_tag, langsys_tag;
1754   int nfeatures[2];
1755   unsigned int *features[2];
1758 #define OTF_SYM_TAG(SYM, TAG)                               \
1759   do {                                                      \
1760     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1761     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1762   } while (0)
1764 #define OTF_TAG_STR(TAG, P)                     \
1765   do {                                          \
1766     (P)[0] = (char) (TAG >> 24);                \
1767     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1768     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1769     (P)[3] = (char) (TAG & 0xFF);               \
1770     (P)[4] = '\0';                              \
1771   } while (0)
1773 static struct OpenTypeSpec *
1774 macfont_get_open_type_spec (Lisp_Object otf_spec)
1776   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1777   Lisp_Object val;
1778   int i, j;
1779   bool negative;
1781   if (! spec)
1782     return NULL;
1783   spec->script = XCAR (otf_spec);
1784   if (! NILP (spec->script))
1785     {
1786       OTF_SYM_TAG (spec->script, spec->script_tag);
1787       val = assq_no_quit (spec->script, Votf_script_alist);
1788       if (CONSP (val) && SYMBOLP (XCDR (val)))
1789         spec->script = XCDR (val);
1790       else
1791         spec->script = Qnil;
1792     }
1793   else
1794     spec->script_tag = 0x44464C54;      /* "DFLT" */
1795   otf_spec = XCDR (otf_spec);
1796   spec->langsys_tag = 0;
1797   if (! NILP (otf_spec))
1798     {
1799       val = XCAR (otf_spec);
1800       if (! NILP (val))
1801         OTF_SYM_TAG (val, spec->langsys_tag);
1802       otf_spec = XCDR (otf_spec);
1803     }
1804   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1805   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1806     {
1807       Lisp_Object len;
1809       val = XCAR (otf_spec);
1810       if (NILP (val))
1811         continue;
1812       len = Flength (val);
1813       spec->features[i] =
1814         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1815          ? 0
1816          : malloc (XINT (len) * sizeof *spec->features[i]));
1817       if (! spec->features[i])
1818         {
1819           if (i > 0 && spec->features[0])
1820             free (spec->features[0]);
1821           free (spec);
1822           return NULL;
1823         }
1824       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1825         {
1826           if (NILP (XCAR (val)))
1827             negative = 1;
1828           else
1829             {
1830               unsigned int tag;
1832               OTF_SYM_TAG (XCAR (val), tag);
1833               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1834             }
1835         }
1836       spec->nfeatures[i] = j;
1837     }
1838   return spec;
1841 static CFMutableDictionaryRef
1842 macfont_create_attributes_with_spec (Lisp_Object spec)
1844   Lisp_Object tmp, extra;
1845   CFMutableArrayRef langarray = NULL;
1846   CFCharacterSetRef charset = NULL;
1847   CFStringRef charset_string = NULL;
1848   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1849   Lisp_Object script = Qnil;
1850   Lisp_Object registry;
1851   int cf_charset_idx, i;
1852   struct OpenTypeSpec *otspec = NULL;
1853   struct {
1854     enum font_property_index index;
1855     CFStringRef trait;
1856     CGPoint points[6];
1857   } numeric_traits[] =
1858       {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
1859         {{-0.4, 50},            /* light */
1860          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1861          {0, 100},              /* normal */
1862          {0.24, 140},           /* (semi-bold + normal) / 2 */
1863          {0.4, 200},            /* bold */
1864          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1865        {FONT_SLANT_INDEX, kCTFontSlantTrait,
1866         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1867        {FONT_WIDTH_INDEX, kCTFontWidthTrait,
1868         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1870   registry = AREF (spec, FONT_REGISTRY_INDEX);
1871   if (NILP (registry)
1872       || EQ (registry, Qascii_0)
1873       || EQ (registry, Qiso10646_1)
1874       || EQ (registry, Qunicode_bmp))
1875     cf_charset_idx = -1;
1876   else
1877     {
1878       CFStringRef lang;
1880       cf_charset_idx = macfont_get_charset (registry);
1881       if (cf_charset_idx < 0)
1882         goto err;
1883       charset = cf_charset_table[cf_charset_idx].cf_charset;
1884       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1885       lang = cf_charset_table[cf_charset_idx].lang;
1886       if (lang)
1887         {
1888           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1889           if (! langarray)
1890             goto err;
1891           CFArrayAppendValue (langarray, lang);
1892         }
1893     }
1895   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1896        CONSP (extra); extra = XCDR (extra))
1897     {
1898       Lisp_Object key, val;
1900       tmp = XCAR (extra);
1901       key = XCAR (tmp), val = XCDR (tmp);
1902       if (EQ (key, QClang))
1903         {
1904           if (! langarray)
1905             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1906           if (! langarray)
1907             goto err;
1908           if (SYMBOLP (val))
1909             val = list1 (val);
1910           for (; CONSP (val); val = XCDR (val))
1911             if (SYMBOLP (XCAR (val)))
1912               {
1913                 CFStringRef lang =
1914                   cfstring_create_with_string_noencode (SYMBOL_NAME
1915                                                         (XCAR (val)));
1917                 if (lang == NULL)
1918                   goto err;
1919                 CFArrayAppendValue (langarray, lang);
1920                 CFRelease (lang);
1921               }
1922         }
1923       else if (EQ (key, QCotf))
1924         {
1925           otspec = macfont_get_open_type_spec (val);
1926           if (! otspec)
1927             goto err;
1928           script = otspec->script;
1929         }
1930       else if (EQ (key, QCscript))
1931         script = val;
1932     }
1934   if (! NILP (script) && ! charset)
1935     {
1936       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1938       if (CONSP (chars) && CONSP (CDR (chars)))
1939         {
1940           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1941           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1943           if (! string || !cs)
1944             {
1945               if (string)
1946                 CFRelease (string);
1947               else if (cs)
1948                 CFRelease (cs);
1949               goto err;
1950             }
1951           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1952             if (CHARACTERP (XCAR (chars)))
1953               {
1954                 UniChar unichars[2];
1955                 CFIndex count =
1956                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1957                                                        unichars);
1958                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1960                 CFStringAppendCharacters (string, unichars, count);
1961                 CFCharacterSetAddCharactersInRange (cs, range);
1962               }
1963           charset = cs;
1964           /* CFCharacterSetCreateWithCharactersInString does not
1965              handle surrogate pairs properly as of Mac OS X 10.5.  */
1966           charset_string = string;
1967         }
1968     }
1970   attributes = CFDictionaryCreateMutable (NULL, 0,
1971                                           &kCFTypeDictionaryKeyCallBacks,
1972                                           &kCFTypeDictionaryValueCallBacks);
1973   if (! attributes)
1974     goto err;
1976   tmp = AREF (spec, FONT_FAMILY_INDEX);
1977   if (SYMBOLP (tmp) && ! NILP (tmp))
1978     {
1979       CFStringRef family = macfont_create_family_with_symbol (tmp);
1981       if (! family)
1982         goto err;
1983       CFDictionaryAddValue (attributes, kCTFontFamilyNameAttribute,
1984                             family);
1985       CFRelease (family);
1986     }
1988   traits = CFDictionaryCreateMutable (NULL, 4,
1989                                       &kCFTypeDictionaryKeyCallBacks,
1990                                       &kCFTypeDictionaryValueCallBacks);
1991   if (! traits)
1992     goto err;
1994   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1995     {
1996       tmp = AREF (spec, numeric_traits[i].index);
1997       if (INTEGERP (tmp))
1998         {
1999           CGPoint *point = numeric_traits[i].points;
2000           CGFloat floatval = (XINT (tmp) >> 8); // XXX
2001           CFNumberRef num;
2003           while (point->y < floatval)
2004             point++;
2005           if (point == numeric_traits[i].points)
2006             point++;
2007           else if (point->y == CGFLOAT_MAX)
2008             point--;
2009           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
2010                                        * ((point->x - (point - 1)->x)
2011                                           / (point->y - (point - 1)->y)));
2012           if (floatval > 1.0)
2013             floatval = 1.0;
2014           else if (floatval < -1.0)
2015             floatval = -1.0;
2016           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
2017           if (! num)
2018             goto err;
2019           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2020           CFRelease (num);
2021         }
2022     }
2023   if (CFDictionaryGetCount (traits))
2024     CFDictionaryAddValue (attributes, kCTFontTraitsAttribute, traits);
2026   if (charset)
2027     CFDictionaryAddValue (attributes, kCTFontCharacterSetAttribute,
2028                           charset);
2029   if (charset_string)
2030     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2031                           charset_string);
2032   if (langarray)
2033     CFDictionaryAddValue (attributes, kCTFontLanguagesAttribute, langarray);
2035   goto finish;
2037  err:
2038   if (attributes)
2039     {
2040       CFRelease (attributes);
2041       attributes = NULL;
2042     }
2044  finish:
2045   if (langarray) CFRelease (langarray);
2046   if (charset && cf_charset_idx < 0) CFRelease (charset);
2047   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2048   if (traits) CFRelease (traits);
2049   if (otspec)
2050     {
2051       if (otspec->nfeatures[0] > 0)
2052         free (otspec->features[0]);
2053       if (otspec->nfeatures[1] > 0)
2054         free (otspec->features[1]);
2055       free (otspec);
2056     }
2058   return attributes;
2061 static Boolean
2062 macfont_supports_charset_and_languages_p (CTFontDescriptorRef desc,
2063                                           CFCharacterSetRef charset,
2064                                           Lisp_Object chars,
2065                                           CFArrayRef languages)
2067   Boolean result = true;
2069   if (charset || VECTORP (chars))
2070     {
2071       CFCharacterSetRef desc_charset =
2072         CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
2074       if (desc_charset == NULL)
2075         result = false;
2076       else
2077         {
2078           if (charset)
2079             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2080           else                  /* VECTORP (chars) */
2081             {
2082               ptrdiff_t j;
2084               for (j = 0; j < ASIZE (chars); j++)
2085                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2086                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2087                                                             XFASTINT (AREF (chars, j))))
2088                   break;
2089               if (j == ASIZE (chars))
2090                 result = false;
2091             }
2092           CFRelease (desc_charset);
2093         }
2094     }
2095   if (result && languages)
2096     result = mac_font_descriptor_supports_languages (desc, languages);
2098   return result;
2101 static int
2102 macfont_traits_distance (CTFontSymbolicTraits sym_traits1,
2103                          CTFontSymbolicTraits sym_traits2)
2105   CTFontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2106   int distance = 0;
2108   /* We prefer synthetic bold of italic to synthetic italic of bold
2109      when both bold and italic are available but bold-italic is not
2110      available.  */
2111   if (diff & kCTFontTraitBold)
2112     distance |= (1 << 0);
2113   if (diff & kCTFontTraitItalic)
2114     distance |= (1 << 1);
2115   if (diff & kCTFontTraitMonoSpace)
2116     distance |= (1 << 2);
2118   return distance;
2121 static Boolean
2122 macfont_closest_traits_index_p (CFArrayRef traits_array,
2123                                 CTFontSymbolicTraits target,
2124                                 CFIndex index)
2126   CFIndex i, count = CFArrayGetCount (traits_array);
2127   CTFontSymbolicTraits traits;
2128   int my_distance;
2130   traits = ((CTFontSymbolicTraits) (uintptr_t)
2131             CFArrayGetValueAtIndex (traits_array, index));
2132   my_distance = macfont_traits_distance (target, traits);
2134   for (i = 0; i < count; i++)
2135     if (i != index)
2136       {
2137         traits = ((CTFontSymbolicTraits) (uintptr_t)
2138                   CFArrayGetValueAtIndex (traits_array, i));
2139         if (macfont_traits_distance (target, traits) < my_distance)
2140           return false;
2141       }
2143   return true;
2146 static Lisp_Object
2147 macfont_list (struct frame *f, Lisp_Object spec)
2149   Lisp_Object val = Qnil, family, extra;
2150   int i, n;
2151   CFStringRef family_name = NULL;
2152   CFMutableDictionaryRef attributes = NULL, traits;
2153   Lisp_Object chars = Qnil;
2154   int spacing = -1;
2155   CTFontSymbolicTraits synth_sym_traits = 0;
2156   CFArrayRef families;
2157   CFIndex families_count;
2158   CFCharacterSetRef charset = NULL;
2159   CFArrayRef languages = NULL;
2161   block_input ();
2163   family = AREF (spec, FONT_FAMILY_INDEX);
2164   if (! NILP (family))
2165     {
2166       family_name = macfont_create_family_with_symbol (family);
2167       if (family_name == NULL)
2168         goto finish;
2169     }
2171   attributes = macfont_create_attributes_with_spec (spec);
2172   if (! attributes)
2173     goto finish;
2175   languages = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
2177   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2178     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2180   traits = ((CFMutableDictionaryRef)
2181             CFDictionaryGetValue (attributes, kCTFontTraitsAttribute));
2183   n = FONT_SLANT_NUMERIC (spec);
2184   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2185     {
2186       synth_sym_traits |= kCTFontTraitItalic;
2187       if (traits)
2188         CFDictionaryRemoveValue (traits, kCTFontSlantTrait);
2189     }
2191   n = FONT_WEIGHT_NUMERIC (spec);
2192   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2193     {
2194       synth_sym_traits |= kCTFontTraitBold;
2195       if (traits)
2196         CFDictionaryRemoveValue (traits, kCTFontWeightTrait);
2197     }
2199   if (languages
2200       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2201     {
2202       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2204       if (CFStringHasPrefix (language, CFSTR ("ja"))
2205           || CFStringHasPrefix (language, CFSTR ("ko"))
2206           || CFStringHasPrefix (language, CFSTR ("zh")))
2207         synth_sym_traits |= kCTFontTraitMonoSpace;
2208     }
2210   /* Create array of families.  */
2211   if (family_name)
2212     families = CFArrayCreate (NULL, (const void **) &family_name,
2213                               1, &kCFTypeArrayCallBacks);
2214   else
2215     {
2216       CFStringRef pref_family;
2217       CFIndex families_count, pref_family_index = -1;
2219       families = macfont_copy_available_families_cache ();
2220       if (families == NULL)
2221         goto err;
2223       families_count = CFArrayGetCount (families);
2225       /* Move preferred family to the front if exists.  */
2226       pref_family =
2227         mac_font_create_preferred_family_for_attributes (attributes);
2228       if (pref_family)
2229         {
2230           pref_family_index =
2231             CFArrayGetFirstIndexOfValue (families,
2232                                          CFRangeMake (0, families_count),
2233                                          pref_family);
2234           CFRelease (pref_family);
2235         }
2236       if (pref_family_index > 0)
2237         {
2238           CFMutableArrayRef mutable_families =
2239             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2241           if (mutable_families)
2242             {
2243               CFArrayAppendValue (mutable_families,
2244                                   CFArrayGetValueAtIndex (families,
2245                                                           pref_family_index));
2246               CFArrayAppendArray (mutable_families, families,
2247                                   CFRangeMake (0, pref_family_index));
2248               if (pref_family_index + 1 < families_count)
2249                 CFArrayAppendArray (mutable_families, families,
2250                                     CFRangeMake (pref_family_index + 1,
2251                                                  families_count
2252                                                  - (pref_family_index + 1)));
2253               CFRelease (families);
2254               families = mutable_families;
2255             }
2256         }
2257     }
2259   charset = CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
2260   if (charset)
2261     {
2262       CFRetain (charset);
2263       CFDictionaryRemoveValue (attributes, kCTFontCharacterSetAttribute);
2264     }
2265   else
2266     {
2267       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2268       if (! NILP (val))
2269         {
2270           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2271           if (CONSP (val) && VECTORP (XCDR (val)))
2272             chars = XCDR (val);
2273         }
2274       val = Qnil;
2275     }
2277   if (languages)
2278     {
2279       CFRetain (languages);
2280       CFDictionaryRemoveValue (attributes, kCTFontLanguagesAttribute);
2281     }
2283   val = Qnil;
2284   extra = AREF (spec, FONT_EXTRA_INDEX);
2285   families_count = CFArrayGetCount (families);
2286   for (i = 0; i < families_count; i++)
2287     {
2288       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2289       CTFontDescriptorRef pat_desc;
2290       CFArrayRef descs;
2291       CFIndex descs_count;
2292       CFMutableArrayRef filtered_descs, traits_array;
2293       Lisp_Object entity;
2294       int j;
2296       CFDictionarySetValue (attributes, kCTFontFamilyNameAttribute,
2297                             family_name);
2298       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2299       if (! pat_desc)
2300         goto err;
2302       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2303          10.7 returns NULL if pat_desc represents the LastResort font.
2304          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2305          trailing "s") for such a font.  */
2306       if (!CFEqual (family_name, CFSTR ("LastResort")))
2307         descs = CTFontDescriptorCreateMatchingFontDescriptors (pat_desc, NULL);
2308       else
2309         {
2310           CTFontDescriptorRef lr_desc =
2311             CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2312           if (lr_desc)
2313             {
2314               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2315                                      &kCFTypeArrayCallBacks);
2316               CFRelease (lr_desc);
2317             }
2318           else
2319             descs = NULL;
2320         }
2321       CFRelease (pat_desc);
2322       if (! descs)
2323         continue;
2325       descs_count = CFArrayGetCount (descs);
2326       if (descs_count == 0
2327           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2328                                                         charset, chars,
2329                                                         languages))
2330         {
2331           CFRelease (descs);
2332           continue;
2333         }
2335       filtered_descs =
2336         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2337       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2338       for (j = 0; j < descs_count; j++)
2339         {
2340           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2341           CFDictionaryRef dict;
2342           CFNumberRef num;
2343           CTFontSymbolicTraits sym_traits;
2345           dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
2346           if (dict == NULL)
2347             continue;
2349           num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
2350           CFRelease (dict);
2351           if (num == NULL
2352               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2353             continue;
2355           if (spacing >= 0
2356               && !(synth_sym_traits & kCTFontTraitMonoSpace)
2357               && (((sym_traits & kCTFontTraitMonoSpace) != 0)
2358                   != (spacing >= FONT_SPACING_MONO)))
2359             continue;
2361           /* Don't use a color bitmap font until it is supported on
2362              free platforms.  */
2363           if (sym_traits & kCTFontTraitColorGlyphs)
2364             continue;
2366           if (j > 0
2367               && !macfont_supports_charset_and_languages_p (desc, charset,
2368                                                             chars, languages))
2369             continue;
2371           CFArrayAppendValue (filtered_descs, desc);
2372           CFArrayAppendValue (traits_array,
2373                               (const void *) (uintptr_t) sym_traits);
2374         }
2376       CFRelease (descs);
2377       descs = filtered_descs;
2378       descs_count = CFArrayGetCount (descs);
2380       for (j = 0; j < descs_count; j++)
2381         {
2382           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2383           CTFontSymbolicTraits sym_traits =
2384             ((CTFontSymbolicTraits) (uintptr_t)
2385              CFArrayGetValueAtIndex (traits_array, j));
2386           CTFontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2388           mask_min = ((synth_sym_traits ^ sym_traits)
2389                       & (kCTFontTraitItalic | kCTFontTraitBold));
2390           if (FONT_SLANT_NUMERIC (spec) < 0)
2391             mask_min &= ~kCTFontTraitItalic;
2392           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2393             mask_min &= ~kCTFontTraitBold;
2395           mask_max = (synth_sym_traits & ~sym_traits);
2396           /* Synthetic bold does not work for bitmap-only fonts on Mac
2397              OS X 10.6.  */
2398           if ((mask_min ^ mask_max) & kCTFontTraitBold)
2399             {
2400               CFNumberRef format =
2401                 CTFontDescriptorCopyAttribute (desc, kCTFontFormatAttribute);
2403               if (format)
2404                 {
2405                   uint32_t format_val;
2407                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2408                                         &format_val)
2409                       && format_val == kCTFontFormatBitmap)
2410                     mask_max &= ~kCTFontTraitBold;
2411                 }
2412             }
2413           if (spacing >= 0)
2414             mask_min |= (mask_max & kCTFontTraitMonoSpace);
2416           for (mmask = (mask_min & kCTFontTraitMonoSpace);
2417                mmask <= (mask_max & kCTFontTraitMonoSpace);
2418                mmask += kCTFontTraitMonoSpace)
2419             for (bmask = (mask_min & kCTFontTraitBold);
2420                  bmask <= (mask_max & kCTFontTraitBold);
2421                  bmask += kCTFontTraitBold)
2422               for (imask = (mask_min & kCTFontTraitItalic);
2423                    imask <= (mask_max & kCTFontTraitItalic);
2424                    imask += kCTFontTraitItalic)
2425                 {
2426                   CTFontSymbolicTraits synth = (imask | bmask | mmask);
2428                   if (synth == 0
2429                       || macfont_closest_traits_index_p (traits_array,
2430                                                          (sym_traits | synth),
2431                                                          j))
2432                     {
2433                       entity = macfont_descriptor_entity (desc, extra, synth);
2434                       if (! NILP (entity))
2435                         val = Fcons (entity, val);
2436                     }
2437                 }
2438         }
2440       CFRelease (traits_array);
2441       CFRelease (descs);
2442     }
2444   CFRelease (families);
2445   val = Fnreverse (val);
2446   goto finish;
2447  err:
2448   val = Qnil;
2450  finish:
2451   FONT_ADD_LOG ("macfont-list", spec, val);
2452   if (charset) CFRelease (charset);
2453   if (languages) CFRelease (languages);
2454   if (attributes) CFRelease (attributes);
2455   if (family_name) CFRelease (family_name);
2457   unblock_input ();
2459   return val;
2462 static Lisp_Object
2463 macfont_match (struct frame * frame, Lisp_Object spec)
2465   Lisp_Object entity = Qnil;
2466   CFMutableDictionaryRef attributes;
2467   CTFontDescriptorRef pat_desc = NULL, desc = NULL;
2469   block_input ();
2471   attributes = macfont_create_attributes_with_spec (spec);
2472   if (attributes)
2473     {
2474       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2475       CFRelease (attributes);
2476     }
2477   if (pat_desc)
2478     {
2479       desc = CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2480       CFRelease (pat_desc);
2481     }
2482   if (desc)
2483     {
2484       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2485                                           0);
2486       CFRelease (desc);
2487     }
2488   unblock_input ();
2490   FONT_ADD_LOG ("macfont-match", spec, entity);
2491   return entity;
2494 static Lisp_Object
2495 macfont_list_family (struct frame *frame)
2497   Lisp_Object list = Qnil;
2498   CFArrayRef families;
2500   block_input ();
2502   families = macfont_copy_available_families_cache ();
2503   if (families)
2504     {
2505       CFIndex i, count = CFArrayGetCount (families);
2507       for (i = 0; i < count; i++)
2508         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2509       CFRelease (families);
2510     }
2512   unblock_input ();
2514   return list;
2517 static void
2518 macfont_free_entity (Lisp_Object entity)
2520   Lisp_Object val = assq_no_quit (QCfont_entity,
2521                                   AREF (entity, FONT_EXTRA_INDEX));
2522   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2524   block_input ();
2525   CFRelease (name);
2526   unblock_input ();
2529 static Lisp_Object
2530 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2532   Lisp_Object val, font_object;
2533   CFStringRef font_name;
2534   struct macfont_info *macfont_info = NULL;
2535   struct font *font;
2536   int size;
2537   CTFontRef macfont;
2538   CTFontSymbolicTraits sym_traits;
2539   int i, total_width;
2540   CGGlyph glyph;
2541   CGFloat ascent, descent, leading;
2543   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2544   if (! CONSP (val)
2545       || XTYPE (XCDR (val)) != Lisp_Misc
2546       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2547     return Qnil;
2548   font_name = XSAVE_POINTER (XCDR (val), 0);
2549   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2551   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2552   if (size == 0)
2553     size = pixel_size;
2555   block_input ();
2556   macfont = CTFontCreateWithName (font_name, size, NULL);
2557   if (macfont)
2558     {
2559       int fontsize = (int) [((NSFont *) macfont) pointSize];
2560       if (fontsize != size) size = fontsize;
2561     }
2562   unblock_input ();
2563   if (! macfont)
2564     return Qnil;
2566   font_object = font_build_object (VECSIZE (struct macfont_info),
2567                                    Qmac_ct, entity, size);
2568   font = XFONT_OBJECT (font_object);
2569   font->pixel_size = size;
2570   font->driver = &macfont_driver;
2571   font->encoding_charset = font->repertory_charset = -1;
2573   block_input ();
2575   macfont_info = (struct macfont_info *) font;
2576   macfont_info->macfont = macfont;
2577   macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
2579   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2580   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2581     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2582                                                                   size);
2583   else
2584     macfont_info->screen_font = NULL;
2585   macfont_info->cache = macfont_lookup_cache (font_name);
2586   macfont_retain_cache (macfont_info->cache);
2587   macfont_info->metrics = NULL;
2588   macfont_info->metrics_nrows = 0;
2589   macfont_info->synthetic_italic_p = 0;
2590   macfont_info->synthetic_bold_p = 0;
2591   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2592   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2593   if (!(sym_traits & kCTFontTraitItalic)
2594       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2595     macfont_info->synthetic_italic_p = 1;
2596   if (!(sym_traits & kCTFontTraitBold)
2597       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2598     macfont_info->synthetic_bold_p = 1;
2599   if (sym_traits & kCTFontTraitMonoSpace)
2600     macfont_info->spacing = MACFONT_SPACING_MONO;
2601   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2602            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2603                == FONT_SPACING_SYNTHETIC_MONO))
2604     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2605   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2606     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2607   else
2608     {
2609       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2610       if (CONSP (val))
2611         macfont_info->antialias =
2612           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2613     }
2614   macfont_info->color_bitmap_p = 0;
2615   if (sym_traits & kCTFontTraitColorGlyphs)
2616     macfont_info->color_bitmap_p = 1;
2618   glyph = macfont_get_glyph_for_character (font, ' ');
2619   if (glyph != kCGFontIndexInvalid)
2620     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2621   else
2622     /* dirty workaround */
2623     font->space_width = pixel_size;
2625   total_width = font->space_width;
2626   for (i = 1; i < 95; i++)
2627     {
2628       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2629       if (glyph == kCGFontIndexInvalid)
2630         break;
2631       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2632     }
2633   if (i == 95)
2634     font->average_width = total_width / 95;
2635   else
2636     font->average_width = font->space_width; /* XXX */
2638   if (!(macfont_info->screen_font
2639         && mac_screen_font_get_metrics (macfont_info->screen_font,
2640                                         &ascent, &descent, &leading)))
2641     {
2642       CFStringRef family_name;
2644       ascent = CTFontGetAscent (macfont);
2645       descent = CTFontGetDescent (macfont);
2646       leading = CTFontGetLeading (macfont);
2647       /* AppKit and WebKit do some adjustment to the heights of
2648          Courier, Helvetica, and Times.  */
2649       family_name = CTFontCopyFamilyName (macfont);
2650       if (family_name)
2651         {
2652           if (CFEqual (family_name, CFSTR ("Courier"))
2653               || CFEqual (family_name, CFSTR ("Helvetica"))
2654               || CFEqual (family_name, CFSTR ("Times")))
2655             ascent += (ascent + descent) * .15f;
2656           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2657             {
2658               leading *= .25f;
2659               ascent += leading;
2660             }
2661           CFRelease (family_name);
2662         }
2663     }
2664   font->ascent = ascent + 0.5f;
2665   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2666   if (CONSP (val) && !NILP (XCDR (val)))
2667     font->descent = descent + 0.5f;
2668   else
2669     font->descent = descent + leading + 0.5f;
2670   font->height = font->ascent + font->descent;
2672   font->underline_position = - CTFontGetUnderlinePosition (macfont) + 0.5f;
2673   font->underline_thickness = CTFontGetUnderlineThickness (macfont) + 0.5f;
2675   unblock_input ();
2677   /* Unfortunately Xft doesn't provide a way to get minimum char
2678      width.  So, we use space_width instead.  */
2679   font->min_width = font->max_width = font->space_width; /* XXX */
2681   font->baseline_offset = 0;
2682   font->relative_compose = 0;
2683   font->default_ascent = 0;
2684   font->vertical_centering = 0;
2686   return font_object;
2689 static void
2690 macfont_close (struct font *font)
2692   struct macfont_info *macfont_info = (struct macfont_info *) font;
2694   if (macfont_info->cache)
2695     {
2696       int i;
2698       block_input ();
2699       CFRelease (macfont_info->macfont);
2700       CGFontRelease (macfont_info->cgfont);
2701       if (macfont_info->screen_font)
2702         CFRelease (macfont_info->screen_font);
2703       macfont_release_cache (macfont_info->cache);
2704       for (i = 0; i < macfont_info->metrics_nrows; i++)
2705         if (macfont_info->metrics[i])
2706           xfree (macfont_info->metrics[i]);
2707       if (macfont_info->metrics)
2708         xfree (macfont_info->metrics);
2709       macfont_info->cache = NULL;
2710       unblock_input ();
2711     }
2714 static int
2715 macfont_has_char (Lisp_Object font, int c)
2717   int result;
2718   CFCharacterSetRef charset;
2720   block_input ();
2721   if (FONT_ENTITY_P (font))
2722     {
2723       Lisp_Object val;
2724       CFStringRef name;
2726       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2727       val = XCDR (val);
2728       name = XSAVE_POINTER (val, 0);
2729       charset = macfont_get_cf_charset_for_name (name);
2730     }
2731   else
2732     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2734   result = CFCharacterSetIsLongCharacterMember (charset, c);
2735   unblock_input ();
2737   return result;
2740 static unsigned
2741 macfont_encode_char (struct font *font, int c)
2743   CGGlyph glyph;
2745   block_input ();
2746   glyph = macfont_get_glyph_for_character (font, c);
2747   unblock_input ();
2749   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2752 static void
2753 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2754                       struct font_metrics *metrics)
2756   int width, i;
2758   block_input ();
2759   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2760   for (i = 1; i < nglyphs; i++)
2761     {
2762       struct font_metrics m;
2763       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2764                                      NULL, 0);
2766       if (metrics)
2767         {
2768           if (width + m.lbearing < metrics->lbearing)
2769             metrics->lbearing = width + m.lbearing;
2770           if (width + m.rbearing > metrics->rbearing)
2771             metrics->rbearing = width + m.rbearing;
2772           if (m.ascent > metrics->ascent)
2773             metrics->ascent = m.ascent;
2774           if (m.descent > metrics->descent)
2775             metrics->descent = m.descent;
2776         }
2777       width += w;
2778     }
2779   unblock_input ();
2781   if (metrics)
2782     metrics->width = width;
2785 static int
2786 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2787               bool with_background)
2789   struct frame * f = s->f;
2790   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2791   CGRect background_rect;
2792   CGPoint text_position;
2793   CGGlyph *glyphs;
2794   CGPoint *positions;
2795   CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2796   bool no_antialias_p =
2797     (NILP (ns_antialias_text)
2798      || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2799      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2800          && font_size <= macfont_antialias_threshold));
2801   int len = to - from;
2802   struct face *face = s->face;
2803   CGContextRef context;
2805   block_input ();
2807   if (with_background)
2808     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2809                                   s->width, FONT_HEIGHT (s->font));
2810   else
2811     background_rect = CGRectNull;
2813   text_position = CGPointMake (x, -y);
2814   glyphs = xmalloc (sizeof (CGGlyph) * len);
2815   {
2816     CGFloat advance_delta = 0;
2817     int i;
2818     CGFloat total_width = 0;
2820     positions = xmalloc (sizeof (CGPoint) * len);
2821     for (i = 0; i < len; i++)
2822       {
2823         int width;
2825         glyphs[i] = s->char2b[from + i];
2826         width = (s->padding_p ? 1
2827                  : macfont_glyph_extents (s->font, glyphs[i],
2828                                           NULL, &advance_delta,
2829                                           no_antialias_p));
2830         positions[i].x = total_width + advance_delta;
2831         positions[i].y = 0;
2832         total_width += width;
2833       }
2834   }
2836   context = [[NSGraphicsContext currentContext] graphicsPort];
2837   CGContextSaveGState (context);
2839   if (!CGRectIsNull (background_rect))
2840     {
2841       if (s->hl == DRAW_MOUSE_FACE)
2842         {
2843           face = FACE_FROM_ID_OR_NULL (s->f,
2844                                        MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2845           if (!face)
2846             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2847         }
2848       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2849       CGContextFillRects (context, &background_rect, 1);
2850     }
2852   if (macfont_info->cgfont)
2853     {
2854       CGAffineTransform atfm;
2856       CGContextScaleCTM (context, 1, -1);
2857       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2858       if (macfont_info->synthetic_italic_p)
2859         atfm = synthetic_italic_atfm;
2860       else
2861         atfm = CGAffineTransformIdentity;
2862       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2863         {
2864           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2866           /* Stroke line width for text drawing is not correctly
2867              scaled on Retina display/HiDPI mode when drawn to screen
2868              (whereas it is correctly scaled when drawn to bitmaps),
2869              and synthetic bold looks thinner on such environments.
2870              Apple says there are no plans to address this issue
2871              (rdar://11644870) currently.  So we add a workaround.  */
2872 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2873 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2874           if ([[FRAME_NS_VIEW(f) window] respondsToSelector:
2875                                            @selector(backingScaleFactor)])
2876 #endif
2877             CGContextSetLineWidth (context, synthetic_bold_factor * font_size
2878                                    * [[FRAME_NS_VIEW(f) window] backingScaleFactor]);
2879 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2880           else
2881 #endif
2882 #endif
2883 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2884             CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2885 #endif
2886           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2887         }
2888       if (no_antialias_p)
2889         CGContextSetShouldAntialias (context, false);
2891       if (!NILP (ns_use_thin_smoothing))
2892         {
2893           CGContextSetShouldSmoothFonts(context, YES);
2894           CGContextSetFontSmoothingStyle(context, 16);
2895         }
2897       CGContextSetTextMatrix (context, atfm);
2898       CGContextSetTextPosition (context, text_position.x, text_position.y);
2900 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2901       if (macfont_info->color_bitmap_p
2902 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2903           && CTFontDrawGlyphs != NULL
2904 #endif
2905           )
2906         {
2907           if (len > 0)
2908             {
2909               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2910                                 context);
2911             }
2912         }
2913       else
2914 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2915         {
2916           CGContextSetFont (context, macfont_info->cgfont);
2917           CGContextSetFontSize (context, font_size);
2918           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2919         }
2920     }
2923   xfree (glyphs);
2924   xfree (positions);
2925   CGContextRestoreGState (context);
2927   unblock_input ();
2929   return len;
2932 static Lisp_Object
2933 macfont_shape (Lisp_Object lgstring)
2935   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2936   struct macfont_info *macfont_info = (struct macfont_info *) font;
2937   CTFontRef macfont = macfont_info->macfont;
2938   ptrdiff_t glyph_len, len, i, j;
2939   CFIndex nonbmp_len;
2940   UniChar *unichars;
2941   CFIndex *nonbmp_indices;
2942   CFStringRef string;
2943   CFIndex used = 0;
2944   struct mac_glyph_layout *glyph_layouts;
2946   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2947   nonbmp_len = 0;
2948   for (i = 0; i < glyph_len; i++)
2949     {
2950       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2952       if (NILP (lglyph))
2953         break;
2954       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2955         nonbmp_len++;
2956     }
2958   len = i;
2960   if (INT_MAX / 2 < len)
2961     memory_full (SIZE_MAX);
2963   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2964   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2965   for (i = j = 0; i < len; i++)
2966     {
2967       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2969       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2970         {
2971           nonbmp_indices[j] = i + j;
2972           j++;
2973         }
2974     }
2975   nonbmp_indices[j] = len + j;  /* sentinel */
2977   block_input ();
2979   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2980                                                kCFAllocatorNull);
2981   if (string)
2982     {
2983       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2984       if (macfont_info->screen_font)
2985         used = mac_screen_font_shape (macfont_info->screen_font, string,
2986                                       glyph_layouts, glyph_len);
2987       else
2988         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2989       CFRelease (string);
2990     }
2992   unblock_input ();
2994   if (used == 0)
2995     return Qnil;
2997   block_input ();
2999   for (i = 0; i < used; i++)
3000     {
3001       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
3002       struct mac_glyph_layout *gl = glyph_layouts + i;
3003       EMACS_INT from, to;
3004       struct font_metrics metrics;
3005       int xoff, yoff, wadjust;
3007       if (NILP (lglyph))
3008         {
3009           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
3010           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
3011         }
3013       from = gl->comp_range.location;
3014       /* Convert UTF-16 index to UTF-32.  */
3015       j = 0;
3016       while (nonbmp_indices[j] < from)
3017         j++;
3018       from -= j;
3019       LGLYPH_SET_FROM (lglyph, from);
3021       to = gl->comp_range.location + gl->comp_range.length;
3022       /* Convert UTF-16 index to UTF-32.  */
3023       while (nonbmp_indices[j] < to)
3024         j++;
3025       to -= j;
3026       LGLYPH_SET_TO (lglyph, to - 1);
3028       /* LGLYPH_CHAR is used in `describe-char' for checking whether
3029          the composition is trivial.  */
3030       {
3031         UTF32Char c;
3033         if (unichars[gl->string_index] >= 0xD800
3034             && unichars[gl->string_index] < 0xDC00)
3035           c = (((unichars[gl->string_index] - 0xD800) << 10)
3036                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3037         else
3038           c = unichars[gl->string_index];
3039         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3040           c = 0;
3041         LGLYPH_SET_CHAR (lglyph, c);
3042       }
3044       {
3045         unsigned long cc = gl->glyph_id;
3046         LGLYPH_SET_CODE (lglyph, cc);
3047       }
3049       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3050       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3051       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3052       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3053       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3054       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3056       xoff = lround (gl->advance_delta);
3057       yoff = lround (- gl->baseline_delta);
3058       wadjust = lround (gl->advance);
3059       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3060         {
3061           Lisp_Object vec;
3063           vec = Fmake_vector (make_number (3), Qnil);
3064           ASET (vec, 0, make_number (xoff));
3065           ASET (vec, 1, make_number (yoff));
3066           ASET (vec, 2, make_number (wadjust));
3067           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3068         }
3069     }
3071   unblock_input ();
3073   return make_number (used);
3076 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3077 typedef UInt8 UINT24[3];
3079 #pragma pack(push, 1)
3080 struct variation_selector_record
3082   UINT24 var_selector;
3083   UInt32 default_uvs_offset, non_default_uvs_offset;
3085 struct uvs_table
3087   UInt16 format;
3088   UInt32 length, num_var_selector_records;
3089   struct variation_selector_record variation_selector_records[1];
3091 #define SIZEOF_UVS_TABLE_HEADER                                         \
3092   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3094 struct unicode_value_range
3096   UINT24 start_unicode_value;
3097   UInt8 additional_count;
3099 struct default_uvs_table {
3100   UInt32 num_unicode_value_ranges;
3101   struct unicode_value_range unicode_value_ranges[1];
3103 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3104   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3106 struct uvs_mapping
3108   UINT24 unicode_value;
3109   UInt16 glyph_id;
3111 struct non_default_uvs_table
3113   UInt32 num_uvs_mappings;
3114   struct uvs_mapping uvs_mappings[1];
3116 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3117   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3118 #pragma pack(pop)
3120 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3121 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3122    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3123    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3124 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3125 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3126 /* Succeeding one byte should also be accessible.  */
3127 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3128 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3130 /* Return UVS subtable for the specified FONT.  If the subtable is not
3131    found or ill-formatted, then return NULL.  */
3133 static CFDataRef
3134 mac_font_copy_uvs_table (CTFontRef font)
3136   CFDataRef cmap_table, uvs_table = NULL;
3138   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3139                                 kCTFontTableOptionNoOptions);
3140   if (cmap_table)
3141     {
3142       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3143       struct uvs_table *uvs;
3144       struct variation_selector_record *records;
3145       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3147 #if __LP64__
3148       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3149         goto finish;
3150 #endif
3152       cmap_len = CFDataGetLength (cmap_table);
3153       if (sizeof_sfntCMapHeader > cmap_len)
3154         goto finish;
3156       ntables = BUINT16_VALUE (cmap->numTables);
3157       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3158                      / sizeof_sfntCMapEncoding))
3159         goto finish;
3161       for (i = 0; i < ntables; i++)
3162         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3163              == kFontUnicodePlatform)
3164             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3165                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3166           {
3167             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3168             break;
3169           }
3170       if (i == ntables
3171           || uvs_offset > cmap_len
3172           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3173         goto finish;
3175       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3176       uvs_len = BUINT32_VALUE (uvs->length);
3177       if (uvs_len > cmap_len - uvs_offset
3178           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3179         goto finish;
3181       if (BUINT16_VALUE (uvs->format) != 14)
3182         goto finish;
3184       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3185       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3186                       / sizeof (struct variation_selector_record)))
3187         goto finish;
3189       records = uvs->variation_selector_records;
3190       for (i = 0; i < nrecords; i++)
3191         {
3192           UInt32 default_uvs_offset, non_default_uvs_offset;
3194           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3195           if (default_uvs_offset)
3196             {
3197               struct default_uvs_table *default_uvs;
3198               UInt32 nranges;
3200               if (default_uvs_offset > uvs_len
3201                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3202                       > uvs_len - default_uvs_offset))
3203                 goto finish;
3205               default_uvs = ((struct default_uvs_table *)
3206                              ((UInt8 *) uvs + default_uvs_offset));
3207               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3208               if (nranges > ((uvs_len - default_uvs_offset
3209                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3210                              / sizeof (struct unicode_value_range)))
3211                 goto finish;
3212               /* Now 2 * nranges can't overflow, so we can safely use
3213                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3214                  mac_font_get_glyphs_for_variants.  */
3215             }
3217           non_default_uvs_offset =
3218             BUINT32_VALUE (records[i].non_default_uvs_offset);
3219           if (non_default_uvs_offset)
3220             {
3221               struct non_default_uvs_table *non_default_uvs;
3222               UInt32 nmappings;
3224               if (non_default_uvs_offset > uvs_len
3225                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3226                       > uvs_len - non_default_uvs_offset))
3227                 goto finish;
3229               non_default_uvs = ((struct non_default_uvs_table *)
3230                                  ((UInt8 *) uvs + non_default_uvs_offset));
3231               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3232               if (nmappings > ((uvs_len - non_default_uvs_offset
3233                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3234                                / sizeof (struct uvs_mapping)))
3235                 goto finish;
3236               /* Now 2 * nmappings can't overflow, so we can safely
3237                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3238                  in mac_font_get_glyphs_for_variants.  */
3239             }
3240         }
3242       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3244     finish:
3245       CFRelease (cmap_table);
3246     }
3248   return uvs_table;
3251 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3252    sequence consisting of the given base character C and each
3253    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3254    result (explained below) into the corresponding GLYPHS[i].  If the
3255    entry is found in the Default UVS Table, then the result is 0.  If
3256    the entry is found in the Non-Default UVS Table, then the result is
3257    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3258    elements in SELECTORS must be sorted in strictly increasing
3259    order.  */
3261 static void
3262 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3263                                   const UTF32Char selectors[], CGGlyph glyphs[],
3264                                   CFIndex count)
3266   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3267   struct variation_selector_record *records = uvs->variation_selector_records;
3268   CFIndex i;
3269   UInt32 ir, nrecords;
3270   dispatch_queue_t queue =
3271     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3272   dispatch_group_t group = dispatch_group_create ();
3274   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3275   i = 0;
3276   ir = 0;
3277   while (i < count && ir < nrecords)
3278     {
3279       UInt32 default_uvs_offset, non_default_uvs_offset;
3281       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3282         {
3283           glyphs[i++] = kCGFontIndexInvalid;
3284           continue;
3285         }
3286       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3287         {
3288           ir++;
3289           continue;
3290         }
3292       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3293       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3294       non_default_uvs_offset =
3295         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3296       dispatch_group_async (group, queue, ^{
3297           glyphs[i] = kCGFontIndexInvalid;
3299           if (default_uvs_offset)
3300             {
3301               struct default_uvs_table *default_uvs =
3302                 (struct default_uvs_table *) ((UInt8 *) uvs
3303                                               + default_uvs_offset);
3304               struct unicode_value_range *ranges =
3305                 default_uvs->unicode_value_ranges;
3306               UInt32 lo, hi;
3308               lo = 0;
3309               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3310               while (lo < hi)
3311                 {
3312                   UInt32 mid = (lo + hi) / 2;
3314                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3315                     hi = mid;
3316                   else
3317                     lo = mid + 1;
3318                 }
3319               if (hi > 0
3320                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3321                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3322                 glyphs[i] = 0;
3323             }
3325           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3326             {
3327               struct non_default_uvs_table *non_default_uvs =
3328                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3329                                                   + non_default_uvs_offset);
3330               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3331               UInt32 lo, hi;
3333               lo = 0;
3334               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3335               while (lo < hi)
3336                 {
3337                   UInt32 mid = (lo + hi) / 2;
3339                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3340                     hi = mid;
3341                   else
3342                     lo = mid + 1;
3343                 }
3344               if (hi > 0 &&
3345                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3346                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3347             }
3348         });
3349       i++;
3350       ir++;
3351     }
3352   while (i < count)
3353     glyphs[i++] = kCGFontIndexInvalid;
3354   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3355   dispatch_release (group);
3358 static int
3359 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3361   CFDataRef uvs_table;
3362   NSCharacterCollection uvs_collection;
3363   int i, n = 0;
3365   block_input ();
3366   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3368   if (uvs_table)
3369     {
3370       UTF32Char selectors[256];
3371       CGGlyph glyphs[256];
3373       for (i = 0; i < 16; i++)
3374         selectors[i] = 0xFE00 + i;
3375       for (; i < 256; i++)
3376         selectors[i] = 0xE0100 + (i - 16);
3377       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3378       for (i = 0; i < 256; i++)
3379         {
3380           CGGlyph glyph = glyphs[i];
3382           if (uvs_collection != NSIdentityMappingCharacterCollection
3383               && glyph != kCGFontIndexInvalid)
3384             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3385           if (glyph == kCGFontIndexInvalid)
3386             variations[i] = 0;
3387           else
3388             {
3389               variations[i] = (glyph ? glyph
3390                                : macfont_get_glyph_for_character (font, c));
3391               n++;
3392             }
3393         }
3394     }
3395   unblock_input ();
3397   return n;
3400 static const char *const macfont_booleans[] = {
3401   ":antialias",
3402   ":minspace",
3403   NULL,
3406 static const char *const macfont_non_booleans[] = {
3407   ":lang",
3408   ":script",
3409   ":destination",
3410   NULL,
3413 static void
3414 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3416   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3419 static Boolean
3420 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3421                                         CFArrayRef languages)
3423   Boolean result = true;
3424   CFArrayRef desc_languages =
3425     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3427   if (desc_languages == NULL)
3428     result = false;
3429   else
3430     {
3431       CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3432       CFIndex i, languages_count = CFArrayGetCount (languages);
3434       for (i = 0; i < languages_count; i++)
3435         {
3436           CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3438           if (!CFArrayContainsValue (desc_languages, range, language)
3439               /* PingFang SC contains "zh" and "zh-Hant" as covered
3440                  languages, but does not contain "zh-Hans".  */
3441               && !(CFEqual (language, CFSTR ("zh-Hans"))
3442                    && CFArrayContainsValue (desc_languages, range,
3443                                             CFSTR ("zh"))))
3444             {
3445               result = false;
3446               break;
3447             }
3448         }
3449       CFRelease (desc_languages);
3450     }
3452   return result;
3455 static CFStringRef
3456 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3458   CFStringRef result = NULL;
3459   CFStringRef charset_string =
3460     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3462   if (charset_string && CFStringGetLength (charset_string) > 0)
3463     {
3464       CFStringRef keys[] = {
3465 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3466         kCTLanguageAttributeName
3467 #else
3468         CFSTR ("NSLanguage")
3469 #endif
3470       };
3471       CFTypeRef values[] = {NULL};
3472       CFIndex num_values = 0;
3473       CFArrayRef languages
3474         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3476       if (languages && CFArrayGetCount (languages) > 0)
3477         {
3478           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3479             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3480           else
3481             {
3482               CFCharacterSetRef charset =
3483                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3485               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3486             }
3487         }
3488       if (result == NULL)
3489         {
3490           CFAttributedStringRef attr_string = NULL;
3491           CTLineRef ctline = NULL;
3492           CFDictionaryRef attrs
3493             = CFDictionaryCreate (NULL, (const void **) keys,
3494                                   (const void **) values, num_values,
3495                                   &kCFTypeDictionaryKeyCallBacks,
3496                                   &kCFTypeDictionaryValueCallBacks);
3498           if (attrs)
3499             {
3500               attr_string = CFAttributedStringCreate (NULL, charset_string,
3501                                                       attrs);
3502               CFRelease (attrs);
3503             }
3504           if (attr_string)
3505             {
3506               ctline = CTLineCreateWithAttributedString (attr_string);
3507               CFRelease (attr_string);
3508             }
3509           if (ctline)
3510             {
3511               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3512               CFIndex i, nruns = CFArrayGetCount (runs);
3513               CTFontRef font;
3515               for (i = 0; i < nruns; i++)
3516                 {
3517                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3518                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3519                   CTFontRef font_in_run;
3521                   if (attributes == NULL)
3522                     break;
3523                   font_in_run =
3524                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3525                   if (font_in_run == NULL)
3526                     break;
3527                   if (i == 0)
3528                     font = font_in_run;
3529                   else if (!mac_font_equal_in_postscript_name (font,
3530                                                                font_in_run))
3531                     break;
3532                 }
3533               if (nruns > 0 && i == nruns)
3534                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3535               CFRelease (ctline);
3536             }
3537         }
3538     }
3540   return result;
3543 static inline double
3544 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3546   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3547                                      &glyph, NULL, 1);
3550 static inline CGRect
3551 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3553   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3554                                           &glyph, NULL, 1);
3557 static CFArrayRef
3558 mac_font_create_available_families (void)
3560   CFMutableArrayRef families = NULL;
3561   CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3563   if (orig_families)
3564     {
3565       CFIndex i, count = CFArrayGetCount (orig_families);
3567       families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3568       if (families)
3569         for (i = 0; i < count; i++)
3570           {
3571             CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3573             if (!CFStringHasPrefix (family, CFSTR ("."))
3574                 && (CTFontManagerCompareFontFamilyNames (family,
3575                                                          CFSTR ("LastResort"),
3576                                                          NULL)
3577                     != kCFCompareEqualTo))
3578               CFArrayAppendValue (families, family);
3579           }
3580       CFRelease (orig_families);
3581     }
3583   return families;
3586 static Boolean
3587 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3589   Boolean result;
3590   CFStringRef name1, name2;
3592   if (font1 == font2)
3593     return true;
3595   result = false;
3596   name1 = CTFontCopyPostScriptName (font1);
3597   if (name1)
3598     {
3599       name2 = CTFontCopyPostScriptName (font2);
3600       if (name2)
3601         {
3602           result = CFEqual (name1, name2);
3603           CFRelease (name2);
3604         }
3605       CFRelease (name1);
3606     }
3608   return result;
3611 static CTLineRef
3612 mac_font_create_line_with_string_and_font (CFStringRef string,
3613                                            CTFontRef macfont)
3615   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3616   CFTypeRef values[] = {NULL, NULL};
3617   CFDictionaryRef attributes = NULL;
3618   CFAttributedStringRef attr_string = NULL;
3619   CTLineRef ctline = NULL;
3620   float float_zero = 0.0f;
3622   values[0] = macfont;
3623   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3624   if (values[1])
3625     {
3626       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3627                                        (const void **) values,
3628                                        ARRAYELTS (keys),
3629                                        &kCFTypeDictionaryKeyCallBacks,
3630                                        &kCFTypeDictionaryValueCallBacks);
3631       CFRelease (values[1]);
3632     }
3633   if (attributes)
3634     {
3635       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3636       CFRelease (attributes);
3637     }
3638   if (attr_string)
3639     {
3640       ctline = CTLineCreateWithAttributedString (attr_string);
3641       CFRelease (attr_string);
3642     }
3643   if (ctline)
3644     {
3645       /* Abandon if ctline contains some fonts other than the
3646          specified one.  */
3647       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3648       CFIndex i, nruns = CFArrayGetCount (runs);
3650       for (i = 0; i < nruns; i++)
3651         {
3652           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3653           CFDictionaryRef attributes = CTRunGetAttributes (run);
3654           CTFontRef font_in_run;
3656           if (attributes == NULL)
3657             break;
3658           font_in_run =
3659             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3660           if (font_in_run == NULL)
3661             break;
3662           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3663             break;
3664         }
3665       if (i < nruns)
3666         {
3667           CFRelease (ctline);
3668           ctline = NULL;
3669         }
3670     }
3672   return ctline;
3675 static CFIndex
3676 mac_font_shape (CTFontRef font, CFStringRef string,
3677                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3679   CFIndex used, result = 0;
3680   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3682   if (ctline == NULL)
3683     return 0;
3685   used = CTLineGetGlyphCount (ctline);
3686   if (used <= glyph_len)
3687     {
3688       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3689       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3690       CGFloat total_advance = 0;
3691       CFIndex total_glyph_count = 0;
3693       for (k = 0; k < ctrun_count; k++)
3694         {
3695           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3696           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3697           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3698           CFRange string_range, comp_range, range;
3699           CFIndex *permutation;
3701           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3702             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3703           else
3704             permutation = NULL;
3706 #define RIGHT_TO_LEFT_P permutation
3708           /* Now the `comp_range' member of struct mac_glyph_layout is
3709              temporarily used as a work area such that:
3710              glbuf[i].comp_range.location =
3711              min {compRange[i + 1].location, ...,
3712                      compRange[glyph_count - 1].location,
3713                      maxRange (stringRangeForCTRun)}
3714              glbuf[i].comp_range.length = maxRange (compRange[i])
3715              where compRange[i] is the range of composed characters
3716              containing i-th glyph.  */
3717           string_range = CTRunGetStringRange (ctrun);
3718           min_location = string_range.location + string_range.length;
3719           for (i = 0; i < glyph_count; i++)
3720             {
3721               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3722               CFIndex glyph_index;
3723               CFRange rng;
3725               if (!RIGHT_TO_LEFT_P)
3726                 glyph_index = glyph_count - i - 1;
3727               else
3728                 glyph_index = i;
3729               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3730                                      &gl->string_index);
3731               rng =
3732                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3733                                                              gl->string_index);
3734               gl->comp_range.location = min_location;
3735               gl->comp_range.length = rng.location + rng.length;
3736               if (rng.location < min_location)
3737                 min_location = rng.location;
3738             }
3740           /* Fill the `comp_range' member of struct mac_glyph_layout,
3741              and setup a permutation for right-to-left text.  */
3742           comp_range = CFRangeMake (string_range.location, 0);
3743           range = CFRangeMake (0, 0);
3744           while (1)
3745             {
3746               struct mac_glyph_layout *gl =
3747                 glbuf + range.location + range.length;
3749               if (gl->comp_range.length
3750                   > comp_range.location + comp_range.length)
3751                 comp_range.length = gl->comp_range.length - comp_range.location;
3752               min_location = gl->comp_range.location;
3753               range.length++;
3755               if (min_location >= comp_range.location + comp_range.length)
3756                 {
3757                   comp_range.length = min_location - comp_range.location;
3758                   for (i = 0; i < range.length; i++)
3759                     {
3760                       glbuf[range.location + i].comp_range = comp_range;
3761                       if (RIGHT_TO_LEFT_P)
3762                         permutation[range.location + i] =
3763                           range.location + range.length - i - 1;
3764                     }
3766                   comp_range = CFRangeMake (min_location, 0);
3767                   range.location += range.length;
3768                   range.length = 0;
3769                   if (range.location == glyph_count)
3770                     break;
3771                 }
3772             }
3774           /* Then fill the remaining members.  */
3775           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3776                range.location++)
3777             {
3778               struct mac_glyph_layout *gl;
3779               CGPoint position;
3780               CGFloat max_x;
3782               if (!RIGHT_TO_LEFT_P)
3783                 gl = glbuf + range.location;
3784               else
3785                 {
3786                   CFIndex src, dest;
3788                   src = glyph_count - 1 - range.location;
3789                   dest = permutation[src];
3790                   gl = glbuf + dest;
3791                   if (src < dest)
3792                     {
3793                       CFIndex tmp = gl->string_index;
3795                       gl->string_index = glbuf[src].string_index;
3796                       glbuf[src].string_index = tmp;
3797                     }
3798                 }
3799               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3801               CTRunGetPositions (ctrun, range, &position);
3802               max_x = position.x + CTRunGetTypographicBounds (ctrun, range,
3803                                                               NULL, NULL, NULL);
3804               max_x = max (max_x, total_advance);
3805               gl->advance_delta = position.x - total_advance;
3806               gl->baseline_delta = position.y;
3807               gl->advance = max_x - total_advance;
3808               total_advance = max_x;
3809             }
3811           if (RIGHT_TO_LEFT_P)
3812             xfree (permutation);
3814 #undef RIGHT_TO_LEFT_P
3816           total_glyph_count += glyph_count;
3817         }
3819       result = used;
3820     }
3821   CFRelease (ctline);
3823   return result;
3826 /* The function below seems to cause a memory leak for the CFString
3827    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3828    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3829 #if USE_CT_GLYPH_INFO
3830 static CGGlyph
3831 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3832                               CGFontIndex cid)
3834   CGGlyph result = kCGFontIndexInvalid;
3835   UniChar characters[] = {0xfffd};
3836   CFStringRef string;
3837   CFAttributedStringRef attr_string = NULL;
3838   CTLineRef ctline = NULL;
3840   string = CFStringCreateWithCharacters (NULL, characters,
3841                                          ARRAYELTS (characters));
3843   if (string)
3844     {
3845       CTGlyphInfoRef glyph_info =
3846         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3847       CFDictionaryRef attributes = NULL;
3849       if (glyph_info)
3850         {
3851           CFStringRef keys[] = {kCTFontAttributeName,
3852                                 kCTGlyphInfoAttributeName};
3853           CFTypeRef values[] = {font, glyph_info};
3855           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3856                                            (const void **) values,
3857                                            ARRAYELTS (keys),
3858                                            &kCFTypeDictionaryKeyCallBacks,
3859                                            &kCFTypeDictionaryValueCallBacks);
3860           CFRelease (glyph_info);
3861         }
3862       if (attributes)
3863         {
3864           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3865           CFRelease (attributes);
3866         }
3867       CFRelease (string);
3868     }
3869   if (attr_string)
3870     {
3871       ctline = CTLineCreateWithAttributedString (attr_string);
3872       CFRelease (attr_string);
3873     }
3874   if (ctline)
3875     {
3876       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3878       if (CFArrayGetCount (runs) > 0)
3879         {
3880           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3881           CFDictionaryRef attributes = CTRunGetAttributes (run);
3883           if (attributes)
3884             {
3885               CTFontRef font_in_run =
3886                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3888               if (font_in_run
3889                   && mac_font_equal_in_postscript_name (font_in_run, font))
3890                 {
3891                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3892                   if (result >= CTFontGetGlyphCount (font))
3893                     result = kCGFontIndexInvalid;
3894                 }
3895             }
3896         }
3897       CFRelease (ctline);
3898     }
3900   return result;
3902 #endif
3904 static CFArrayRef
3905 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3907   CFArrayRef result = NULL;
3909 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3910 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3911   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3912 #endif
3913     {
3914       CTFontRef user_font =
3915         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3917       if (user_font)
3918         {
3919           CFArrayRef languages =
3920             CFArrayCreate (NULL, (const void **) &language, 1,
3921                            &kCFTypeArrayCallBacks);
3923           if (languages)
3924             {
3925               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3926                                                                  languages);
3927               CFRelease (languages);
3928             }
3929           CFRelease (user_font);
3930         }
3931     }
3932 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3933   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3934 #endif
3935 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3936 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3937     {
3938       CFIndex i;
3940       for (i = 0; macfont_language_default_font_names[i].language; i++)
3941         {
3942           if (CFEqual (macfont_language_default_font_names[i].language,
3943                        language))
3944             {
3945               CFMutableArrayRef descriptors =
3946                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3948               if (descriptors)
3949                 {
3950                   CFIndex j;
3952                   for (j = 0;
3953                        macfont_language_default_font_names[i].font_names[j];
3954                        j++)
3955                     {
3956                       CFDictionaryRef attributes =
3957                         CFDictionaryCreate (NULL,
3958                                             ((const void **)
3959                                              &kCTFontNameAttribute),
3960                                             ((const void **)
3961                                              &macfont_language_default_font_names[i].font_names[j]),
3962                                             1, &kCFTypeDictionaryKeyCallBacks,
3963                                             &kCFTypeDictionaryValueCallBacks);
3965                       if (attributes)
3966                         {
3967                           CTFontDescriptorRef pat_desc =
3968                             CTFontDescriptorCreateWithAttributes (attributes);
3970                           if (pat_desc)
3971                             {
3972                               CTFontDescriptorRef descriptor =
3973                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3975                               if (descriptor)
3976                                 {
3977                                   CFArrayAppendValue (descriptors, descriptor);
3978                                   CFRelease (descriptor);
3979                                 }
3980                               CFRelease (pat_desc);
3981                             }
3982                           CFRelease (attributes);
3983                         }
3984                     }
3985                   result = descriptors;
3986                 }
3987               break;
3988             }
3989         }
3990     }
3991 #endif
3993   return result;
3996 static CFStringRef
3997 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3998                                                       CFArrayRef languages)
4000   CFStringRef result = NULL;
4001   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
4002   CFArrayRef descriptors =
4003     mac_font_copy_default_descriptors_for_language (language);
4005   if (descriptors)
4006     {
4007       CFIndex i, count = CFArrayGetCount (descriptors);
4009       for (i = 0; i < count; i++)
4010         {
4011           CTFontDescriptorRef descriptor =
4012             CFArrayGetValueAtIndex (descriptors, i);
4014           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4015                                                         Qnil, languages))
4016             {
4017               CFStringRef family =
4018                 CTFontDescriptorCopyAttribute (descriptor,
4019                                                kCTFontFamilyNameAttribute);
4020               if (family)
4021                 {
4022                   if (!CFStringHasPrefix (family, CFSTR ("."))
4023                       && !CFEqual (family, CFSTR ("LastResort")))
4024                     {
4025                       result = family;
4026                       break;
4027                     }
4028                   else
4029                     CFRelease (family);
4030                 }
4031             }
4032         }
4033       CFRelease (descriptors);
4034     }
4036   return result;
4039 void *
4040 macfont_get_nsctfont (struct font *font)
4042   struct macfont_info *macfont_info = (struct macfont_info *) font;
4043   CTFontRef macfont = macfont_info->macfont;
4045   return (void *) macfont;
4048 void
4049 mac_register_font_driver (struct frame *f)
4051   register_font_driver (&macfont_driver, f);
4055 void
4056 syms_of_macfont (void)
4058   /* Core Text, for macOS.  */
4059   DEFSYM (Qmac_ct, "mac-ct");
4060   register_font_driver (&macfont_driver, NULL);
4062   /* The font property key specifying the font design destination.  The
4063      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4064      text.  (See the documentation of X Logical Font Description
4065      Conventions.)  In the Mac font driver, 1 means the screen font is
4066      used for calculating some glyph metrics.  You can see the
4067      difference with Monaco 8pt or 9pt, for example.  */
4068   DEFSYM (QCdestination, ":destination");
4070   /* The boolean-valued font property key specifying the use of leading.  */
4071   DEFSYM (QCminspace, ":minspace");
4073   macfont_family_cache = Qnil;
4074   staticpro (&macfont_family_cache);