Allow 'browse-url-emacs' to fetch URL in the selected window
[emacs.git] / src / macfont.m
blob817071fa44fa65fc7a76e5ed17ef4533d566b837
1 /* Font driver on macOS Core text.
2    Copyright (C) 2009-2018 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           int nkeys;
1446           if (row != 0)
1447             {
1448               CFMutableDictionaryRef dictionary;
1449               uintptr_t key, value;
1450               int nshifts;
1451               CGGlyph glyph;
1453               if (cache->glyph.dictionary == NULL)
1454                 cache->glyph.dictionary =
1455                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1456               dictionary = cache->glyph.dictionary;
1457               key = c / NGLYPHS_IN_VALUE;
1458               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1459               value = ((uintptr_t)
1460                        CFDictionaryGetValue (dictionary, (const void *) key));
1461               glyph = (value >> nshifts);
1462               if (glyph)
1463                 return glyph;
1465               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1466                 {
1467                   ch = c;
1468                   if (!CTFontGetGlyphsForCharacters (macfont, &ch, &glyph, 1)
1469                       || glyph == 0)
1470                     glyph = kCGFontIndexInvalid;
1472                   if (value == 0)
1473                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1474                   value |= ((uintptr_t) glyph << nshifts);
1475                   CFDictionarySetValue (dictionary, (const void *) key,
1476                                         (const void *) value);
1478                   return glyph;
1479                 }
1481               nkeys = nkeys_or_perm;
1482               for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1483                 if (CFDictionaryContainsKey (dictionary,
1484                                              (const void *) key))
1485                   {
1486                     CFDictionaryRemoveValue (dictionary,
1487                                              (const void *) key);
1488                     if (--nkeys == 0)
1489                       break;
1490                   }
1491             }
1493           len = 0;
1494           for (i = 0; i < 256; i++)
1495             {
1496               ch = row * 256 + i;
1497               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1498                 unichars[len++] = ch;
1499             }
1501           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1502           if (len > 0)
1503             {
1504               CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, len);
1505               while (i > len)
1506                 {
1507                   int next = unichars[len - 1] % 256;
1509                   while (--i > next)
1510                     glyphs[i] = kCGFontIndexInvalid;
1512                   len--;
1513                   glyphs[i] = glyphs[len];
1514                   if (len == 0)
1515                     break;
1516                 }
1517             }
1518           if (i > len)
1519             while (i-- > 0)
1520               glyphs[i] = kCGFontIndexInvalid;
1522           nrows = cache->glyph.nrows;
1523           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1524           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1525           nrows++;
1526           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1527                                           sizeof (CGGlyph *) * nrows);
1528           cache->glyph.matrix[nrows - 1] = glyphs;
1529           cache->glyph.nrows = nrows;
1530         }
1532       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1533     }
1534   else
1535     {
1536       uintptr_t key, value;
1537       int nshifts;
1538       CGGlyph glyph;
1540       if (cache->glyph.dictionary == NULL)
1541         cache->glyph.dictionary =
1542           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1543       key = c / NGLYPHS_IN_VALUE;
1544       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1545       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1546                                                 (const void *) key);
1547       glyph = (value >> nshifts);
1548       if (glyph == 0)
1549         {
1550           UniChar unichars[2];
1551           CGGlyph glyphs[2];
1552           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1554           if (CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, count))
1555             glyph = glyphs[0];
1556           if (glyph == 0)
1557             glyph = kCGFontIndexInvalid;
1559           value |= ((uintptr_t) glyph << nshifts);
1560           CFDictionarySetValue (cache->glyph.dictionary,
1561                                 (const void *) key, (const void *) value);
1562         }
1564       return glyph;
1565     }
1568 static CGGlyph
1569 macfont_get_glyph_for_cid (struct font *font, NSCharacterCollection collection,
1570                            CGFontIndex cid)
1572   struct macfont_info *macfont_info = (struct macfont_info *) font;
1573   CTFontRef macfont = macfont_info->macfont;
1575   /* Cache it? */
1576   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1579 static CFDataRef
1580 macfont_get_uvs_table (struct font *font, NSCharacterCollection *collection)
1582   struct macfont_info *macfont_info = (struct macfont_info *) font;
1583   CTFontRef macfont = macfont_info->macfont;
1584   struct macfont_cache *cache = macfont_info->cache;
1585   CFDataRef result = NULL;
1587   if (cache->uvs.table == NULL)
1588     {
1589       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1590       NSCharacterCollection uvs_collection =
1591         NSIdentityMappingCharacterCollection;
1593       if (uvs_table == NULL
1594           && mac_font_get_glyph_for_cid (macfont,
1595                                          NSAdobeJapan1CharacterCollection,
1596                                          6480) != kCGFontIndexInvalid)
1597         {
1598           /* If the glyph for U+4E55 is accessible via its CID 6480,
1599              then we use the Adobe-Japan1 UVS table, which maps a
1600              variation sequence to a CID, as a fallback.  */
1601           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1603           if (mac_uvs_table_adobe_japan1 == NULL)
1604             mac_uvs_table_adobe_japan1 =
1605               CFDataCreateWithBytesNoCopy (NULL,
1606                                            mac_uvs_table_adobe_japan1_bytes,
1607                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1608                                            kCFAllocatorNull);
1609           if (mac_uvs_table_adobe_japan1)
1610             {
1611               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1612               uvs_collection = NSAdobeJapan1CharacterCollection;
1613             }
1614         }
1615       if (uvs_table == NULL)
1616         cache->uvs.table = kCFNull;
1617       else
1618         cache->uvs.table = uvs_table;
1619       cache->uvs.collection = uvs_collection;
1620     }
1622   if (cache->uvs.table != kCFNull)
1623     {
1624       result = cache->uvs.table;
1625       *collection = cache->uvs.collection;
1626     }
1628   return result;
1631 static Lisp_Object macfont_get_cache (struct frame *);
1632 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1633 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1634 static Lisp_Object macfont_list_family (struct frame *);
1635 static void macfont_free_entity (Lisp_Object);
1636 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1637 static void macfont_close (struct font *);
1638 static int macfont_has_char (Lisp_Object, int);
1639 static unsigned macfont_encode_char (struct font *, int);
1640 static void macfont_text_extents (struct font *, unsigned int *, int,
1641                                   struct font_metrics *);
1642 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1643 static Lisp_Object macfont_shape (Lisp_Object);
1644 static int macfont_variation_glyphs (struct font *, int c,
1645                                      unsigned variations[256]);
1646 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1648 static struct font_driver const macfont_driver =
1649   {
1650   .type = LISPSYM_INITIALLY (Qmac_ct),
1651   .get_cache = macfont_get_cache,
1652   .list = macfont_list,
1653   .match = macfont_match,
1654   .list_family = macfont_list_family,
1655   .free_entity = macfont_free_entity,
1656   .open = macfont_open,
1657   .close = macfont_close,
1658   .has_char = macfont_has_char,
1659   .encode_char = macfont_encode_char,
1660   .text_extents = macfont_text_extents,
1661   .draw = macfont_draw,
1662   .shape = macfont_shape,
1663   .get_variation_glyphs = macfont_variation_glyphs,
1664   .filter_properties = macfont_filter_properties,
1665   };
1667 static Lisp_Object
1668 macfont_get_cache (struct frame * f)
1670   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1672   return (dpyinfo->name_list_element);
1675 static int
1676 macfont_get_charset (Lisp_Object registry)
1678   char *str = SSDATA (SYMBOL_NAME (registry));
1679   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1680   Lisp_Object regexp;
1681   int i, j;
1683   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1684     {
1685       if (str[i] == '.')
1686         re[j++] = '\\';
1687       else if (str[i] == '*')
1688         re[j++] = '.';
1689       re[j] = str[i];
1690       if (re[j] == '?')
1691         re[j] = '.';
1692     }
1693   re[j] = '\0';
1694   regexp = make_unibyte_string (re, j);
1695   for (i = 0; cf_charset_table[i].name; i++)
1696     if (fast_c_string_match_ignore_case
1697         (regexp, cf_charset_table[i].name,
1698          strlen (cf_charset_table[i].name)) >= 0)
1699       break;
1700   if (! cf_charset_table[i].name)
1701     return -1;
1702   if (! cf_charset_table[i].cf_charset)
1703     {
1704       int *uniquifier = cf_charset_table[i].uniquifier;
1705       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1706       CFIndex count = 0;
1707       CFStringRef string;
1708       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1710       if (! charset)
1711         return -1;
1712       for (j = 0; uniquifier[j]; j++)
1713         {
1714           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1715                                                         unichars + count);
1716           CFCharacterSetAddCharactersInRange (charset,
1717                                               CFRangeMake (uniquifier[j], 1));
1718         }
1720       string = CFStringCreateWithCharacters (NULL, unichars, count);
1721       if (! string)
1722         {
1723           CFRelease (charset);
1724           return -1;
1725         }
1726       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1727                                                                  charset);
1728       CFRelease (charset);
1729       /* CFCharacterSetCreateWithCharactersInString does not handle
1730          surrogate pairs properly as of Mac OS X 10.5.  */
1731       cf_charset_table[i].cf_charset_string = string;
1732     }
1733   return i;
1736 struct OpenTypeSpec
1738   Lisp_Object script;
1739   unsigned int script_tag, langsys_tag;
1740   int nfeatures[2];
1741   unsigned int *features[2];
1744 #define OTF_SYM_TAG(SYM, TAG)                               \
1745   do {                                                      \
1746     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1747     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1748   } while (0)
1750 #define OTF_TAG_STR(TAG, P)                     \
1751   do {                                          \
1752     (P)[0] = (char) (TAG >> 24);                \
1753     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1754     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1755     (P)[3] = (char) (TAG & 0xFF);               \
1756     (P)[4] = '\0';                              \
1757   } while (0)
1759 static struct OpenTypeSpec *
1760 macfont_get_open_type_spec (Lisp_Object otf_spec)
1762   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1763   Lisp_Object val;
1764   int i, j;
1765   bool negative;
1767   if (! spec)
1768     return NULL;
1769   spec->script = XCAR (otf_spec);
1770   if (! NILP (spec->script))
1771     {
1772       OTF_SYM_TAG (spec->script, spec->script_tag);
1773       val = assq_no_quit (spec->script, Votf_script_alist);
1774       if (CONSP (val) && SYMBOLP (XCDR (val)))
1775         spec->script = XCDR (val);
1776       else
1777         spec->script = Qnil;
1778     }
1779   else
1780     spec->script_tag = 0x44464C54;      /* "DFLT" */
1781   otf_spec = XCDR (otf_spec);
1782   spec->langsys_tag = 0;
1783   if (! NILP (otf_spec))
1784     {
1785       val = XCAR (otf_spec);
1786       if (! NILP (val))
1787         OTF_SYM_TAG (val, spec->langsys_tag);
1788       otf_spec = XCDR (otf_spec);
1789     }
1790   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1791   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1792     {
1793       Lisp_Object len;
1795       val = XCAR (otf_spec);
1796       if (NILP (val))
1797         continue;
1798       len = Flength (val);
1799       spec->features[i] =
1800         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1801          ? 0
1802          : malloc (XINT (len) * sizeof *spec->features[i]));
1803       if (! spec->features[i])
1804         {
1805           if (i > 0 && spec->features[0])
1806             free (spec->features[0]);
1807           free (spec);
1808           return NULL;
1809         }
1810       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1811         {
1812           if (NILP (XCAR (val)))
1813             negative = 1;
1814           else
1815             {
1816               unsigned int tag;
1818               OTF_SYM_TAG (XCAR (val), tag);
1819               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1820             }
1821         }
1822       spec->nfeatures[i] = j;
1823     }
1824   return spec;
1827 static CFMutableDictionaryRef
1828 macfont_create_attributes_with_spec (Lisp_Object spec)
1830   Lisp_Object tmp, extra;
1831   CFMutableArrayRef langarray = NULL;
1832   CFCharacterSetRef charset = NULL;
1833   CFStringRef charset_string = NULL;
1834   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1835   Lisp_Object script = Qnil;
1836   Lisp_Object registry;
1837   int cf_charset_idx, i;
1838   struct OpenTypeSpec *otspec = NULL;
1839   struct {
1840     enum font_property_index index;
1841     CFStringRef trait;
1842     CGPoint points[6];
1843   } numeric_traits[] =
1844       {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
1845         {{-0.4, 50},            /* light */
1846          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1847          {0, 100},              /* normal */
1848          {0.24, 140},           /* (semi-bold + normal) / 2 */
1849          {0.4, 200},            /* bold */
1850          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1851        {FONT_SLANT_INDEX, kCTFontSlantTrait,
1852         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1853        {FONT_WIDTH_INDEX, kCTFontWidthTrait,
1854         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1856   registry = AREF (spec, FONT_REGISTRY_INDEX);
1857   if (NILP (registry)
1858       || EQ (registry, Qascii_0)
1859       || EQ (registry, Qiso10646_1)
1860       || EQ (registry, Qunicode_bmp))
1861     cf_charset_idx = -1;
1862   else
1863     {
1864       CFStringRef lang;
1866       cf_charset_idx = macfont_get_charset (registry);
1867       if (cf_charset_idx < 0)
1868         goto err;
1869       charset = cf_charset_table[cf_charset_idx].cf_charset;
1870       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1871       lang = cf_charset_table[cf_charset_idx].lang;
1872       if (lang)
1873         {
1874           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1875           if (! langarray)
1876             goto err;
1877           CFArrayAppendValue (langarray, lang);
1878         }
1879     }
1881   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1882        CONSP (extra); extra = XCDR (extra))
1883     {
1884       Lisp_Object key, val;
1886       tmp = XCAR (extra);
1887       key = XCAR (tmp), val = XCDR (tmp);
1888       if (EQ (key, QClang))
1889         {
1890           if (! langarray)
1891             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1892           if (! langarray)
1893             goto err;
1894           if (SYMBOLP (val))
1895             val = list1 (val);
1896           for (; CONSP (val); val = XCDR (val))
1897             if (SYMBOLP (XCAR (val)))
1898               {
1899                 CFStringRef lang =
1900                   cfstring_create_with_string_noencode (SYMBOL_NAME
1901                                                         (XCAR (val)));
1903                 if (lang == NULL)
1904                   goto err;
1905                 CFArrayAppendValue (langarray, lang);
1906                 CFRelease (lang);
1907               }
1908         }
1909       else if (EQ (key, QCotf))
1910         {
1911           otspec = macfont_get_open_type_spec (val);
1912           if (! otspec)
1913             goto err;
1914           script = otspec->script;
1915         }
1916       else if (EQ (key, QCscript))
1917         script = val;
1918     }
1920   if (! NILP (script) && ! charset)
1921     {
1922       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1924       if (CONSP (chars) && CONSP (CDR (chars)))
1925         {
1926           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1927           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1929           if (! string || !cs)
1930             {
1931               if (string)
1932                 CFRelease (string);
1933               else if (cs)
1934                 CFRelease (cs);
1935               goto err;
1936             }
1937           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1938             if (CHARACTERP (XCAR (chars)))
1939               {
1940                 UniChar unichars[2];
1941                 CFIndex count =
1942                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1943                                                        unichars);
1944                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1946                 CFStringAppendCharacters (string, unichars, count);
1947                 CFCharacterSetAddCharactersInRange (cs, range);
1948               }
1949           charset = cs;
1950           /* CFCharacterSetCreateWithCharactersInString does not
1951              handle surrogate pairs properly as of Mac OS X 10.5.  */
1952           charset_string = string;
1953         }
1954     }
1956   attributes = CFDictionaryCreateMutable (NULL, 0,
1957                                           &kCFTypeDictionaryKeyCallBacks,
1958                                           &kCFTypeDictionaryValueCallBacks);
1959   if (! attributes)
1960     goto err;
1962   tmp = AREF (spec, FONT_FAMILY_INDEX);
1963   if (SYMBOLP (tmp) && ! NILP (tmp))
1964     {
1965       CFStringRef family = macfont_create_family_with_symbol (tmp);
1967       if (! family)
1968         goto err;
1969       CFDictionaryAddValue (attributes, kCTFontFamilyNameAttribute,
1970                             family);
1971       CFRelease (family);
1972     }
1974   traits = CFDictionaryCreateMutable (NULL, 4,
1975                                       &kCFTypeDictionaryKeyCallBacks,
1976                                       &kCFTypeDictionaryValueCallBacks);
1977   if (! traits)
1978     goto err;
1980   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1981     {
1982       tmp = AREF (spec, numeric_traits[i].index);
1983       if (INTEGERP (tmp))
1984         {
1985           CGPoint *point = numeric_traits[i].points;
1986           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1987           CFNumberRef num;
1989           while (point->y < floatval)
1990             point++;
1991           if (point == numeric_traits[i].points)
1992             point++;
1993           else if (point->y == CGFLOAT_MAX)
1994             point--;
1995           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1996                                        * ((point->x - (point - 1)->x)
1997                                           / (point->y - (point - 1)->y)));
1998           if (floatval > 1.0)
1999             floatval = 1.0;
2000           else if (floatval < -1.0)
2001             floatval = -1.0;
2002           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
2003           if (! num)
2004             goto err;
2005           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2006           CFRelease (num);
2007         }
2008     }
2009   if (CFDictionaryGetCount (traits))
2010     CFDictionaryAddValue (attributes, kCTFontTraitsAttribute, traits);
2012   if (charset)
2013     CFDictionaryAddValue (attributes, kCTFontCharacterSetAttribute,
2014                           charset);
2015   if (charset_string)
2016     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2017                           charset_string);
2018   if (langarray)
2019     CFDictionaryAddValue (attributes, kCTFontLanguagesAttribute, langarray);
2021   goto finish;
2023  err:
2024   if (attributes)
2025     {
2026       CFRelease (attributes);
2027       attributes = NULL;
2028     }
2030  finish:
2031   if (langarray) CFRelease (langarray);
2032   if (charset && cf_charset_idx < 0) CFRelease (charset);
2033   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2034   if (traits) CFRelease (traits);
2035   if (otspec)
2036     {
2037       if (otspec->nfeatures[0] > 0)
2038         free (otspec->features[0]);
2039       if (otspec->nfeatures[1] > 0)
2040         free (otspec->features[1]);
2041       free (otspec);
2042     }
2044   return attributes;
2047 static Boolean
2048 macfont_supports_charset_and_languages_p (CTFontDescriptorRef desc,
2049                                           CFCharacterSetRef charset,
2050                                           Lisp_Object chars,
2051                                           CFArrayRef languages)
2053   Boolean result = true;
2055   if (charset || VECTORP (chars))
2056     {
2057       CFCharacterSetRef desc_charset =
2058         CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
2060       if (desc_charset == NULL)
2061         result = false;
2062       else
2063         {
2064           if (charset)
2065             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2066           else                  /* VECTORP (chars) */
2067             {
2068               ptrdiff_t j;
2070               for (j = 0; j < ASIZE (chars); j++)
2071                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2072                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2073                                                             XFASTINT (AREF (chars, j))))
2074                   break;
2075               if (j == ASIZE (chars))
2076                 result = false;
2077             }
2078           CFRelease (desc_charset);
2079         }
2080     }
2081   if (result && languages)
2082     result = mac_font_descriptor_supports_languages (desc, languages);
2084   return result;
2087 static int
2088 macfont_traits_distance (CTFontSymbolicTraits sym_traits1,
2089                          CTFontSymbolicTraits sym_traits2)
2091   CTFontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2092   int distance = 0;
2094   /* We prefer synthetic bold of italic to synthetic italic of bold
2095      when both bold and italic are available but bold-italic is not
2096      available.  */
2097   if (diff & kCTFontTraitBold)
2098     distance |= (1 << 0);
2099   if (diff & kCTFontTraitItalic)
2100     distance |= (1 << 1);
2101   if (diff & kCTFontTraitMonoSpace)
2102     distance |= (1 << 2);
2104   return distance;
2107 static Boolean
2108 macfont_closest_traits_index_p (CFArrayRef traits_array,
2109                                 CTFontSymbolicTraits target,
2110                                 CFIndex index)
2112   CFIndex i, count = CFArrayGetCount (traits_array);
2113   CTFontSymbolicTraits traits;
2114   int my_distance;
2116   traits = ((CTFontSymbolicTraits) (uintptr_t)
2117             CFArrayGetValueAtIndex (traits_array, index));
2118   my_distance = macfont_traits_distance (target, traits);
2120   for (i = 0; i < count; i++)
2121     if (i != index)
2122       {
2123         traits = ((CTFontSymbolicTraits) (uintptr_t)
2124                   CFArrayGetValueAtIndex (traits_array, i));
2125         if (macfont_traits_distance (target, traits) < my_distance)
2126           return false;
2127       }
2129   return true;
2132 static Lisp_Object
2133 macfont_list (struct frame *f, Lisp_Object spec)
2135   Lisp_Object val = Qnil, family, extra;
2136   int i, n;
2137   CFStringRef family_name = NULL;
2138   CFMutableDictionaryRef attributes = NULL, traits;
2139   Lisp_Object chars = Qnil;
2140   int spacing = -1;
2141   CTFontSymbolicTraits synth_sym_traits = 0;
2142   CFArrayRef families;
2143   CFIndex families_count;
2144   CFCharacterSetRef charset = NULL;
2145   CFArrayRef languages = NULL;
2147   block_input ();
2149   family = AREF (spec, FONT_FAMILY_INDEX);
2150   if (! NILP (family))
2151     {
2152       family_name = macfont_create_family_with_symbol (family);
2153       if (family_name == NULL)
2154         goto finish;
2155     }
2157   attributes = macfont_create_attributes_with_spec (spec);
2158   if (! attributes)
2159     goto finish;
2161   languages = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
2163   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2164     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2166   traits = ((CFMutableDictionaryRef)
2167             CFDictionaryGetValue (attributes, kCTFontTraitsAttribute));
2169   n = FONT_SLANT_NUMERIC (spec);
2170   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2171     {
2172       synth_sym_traits |= kCTFontTraitItalic;
2173       if (traits)
2174         CFDictionaryRemoveValue (traits, kCTFontSlantTrait);
2175     }
2177   n = FONT_WEIGHT_NUMERIC (spec);
2178   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2179     {
2180       synth_sym_traits |= kCTFontTraitBold;
2181       if (traits)
2182         CFDictionaryRemoveValue (traits, kCTFontWeightTrait);
2183     }
2185   if (languages
2186       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2187     {
2188       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2190       if (CFStringHasPrefix (language, CFSTR ("ja"))
2191           || CFStringHasPrefix (language, CFSTR ("ko"))
2192           || CFStringHasPrefix (language, CFSTR ("zh")))
2193         synth_sym_traits |= kCTFontTraitMonoSpace;
2194     }
2196   /* Create array of families.  */
2197   if (family_name)
2198     families = CFArrayCreate (NULL, (const void **) &family_name,
2199                               1, &kCFTypeArrayCallBacks);
2200   else
2201     {
2202       CFStringRef pref_family;
2203       CFIndex families_count, pref_family_index = -1;
2205       families = macfont_copy_available_families_cache ();
2206       if (families == NULL)
2207         goto err;
2209       families_count = CFArrayGetCount (families);
2211       /* Move preferred family to the front if exists.  */
2212       pref_family =
2213         mac_font_create_preferred_family_for_attributes (attributes);
2214       if (pref_family)
2215         {
2216           pref_family_index =
2217             CFArrayGetFirstIndexOfValue (families,
2218                                          CFRangeMake (0, families_count),
2219                                          pref_family);
2220           CFRelease (pref_family);
2221         }
2222       if (pref_family_index > 0)
2223         {
2224           CFMutableArrayRef mutable_families =
2225             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2227           if (mutable_families)
2228             {
2229               CFArrayAppendValue (mutable_families,
2230                                   CFArrayGetValueAtIndex (families,
2231                                                           pref_family_index));
2232               CFArrayAppendArray (mutable_families, families,
2233                                   CFRangeMake (0, pref_family_index));
2234               if (pref_family_index + 1 < families_count)
2235                 CFArrayAppendArray (mutable_families, families,
2236                                     CFRangeMake (pref_family_index + 1,
2237                                                  families_count
2238                                                  - (pref_family_index + 1)));
2239               CFRelease (families);
2240               families = mutable_families;
2241             }
2242         }
2243     }
2245   charset = CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
2246   if (charset)
2247     {
2248       CFRetain (charset);
2249       CFDictionaryRemoveValue (attributes, kCTFontCharacterSetAttribute);
2250     }
2251   else
2252     {
2253       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2254       if (! NILP (val))
2255         {
2256           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2257           if (CONSP (val) && VECTORP (XCDR (val)))
2258             chars = XCDR (val);
2259         }
2260       val = Qnil;
2261     }
2263   if (languages)
2264     {
2265       CFRetain (languages);
2266       CFDictionaryRemoveValue (attributes, kCTFontLanguagesAttribute);
2267     }
2269   val = Qnil;
2270   extra = AREF (spec, FONT_EXTRA_INDEX);
2271   families_count = CFArrayGetCount (families);
2272   for (i = 0; i < families_count; i++)
2273     {
2274       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2275       CTFontDescriptorRef pat_desc;
2276       CFArrayRef descs;
2277       CFIndex descs_count;
2278       CFMutableArrayRef filtered_descs, traits_array;
2279       Lisp_Object entity;
2280       int j;
2282       CFDictionarySetValue (attributes, kCTFontFamilyNameAttribute,
2283                             family_name);
2284       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2285       if (! pat_desc)
2286         goto err;
2288       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2289          10.7 returns NULL if pat_desc represents the LastResort font.
2290          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2291          trailing "s") for such a font.  */
2292       if (!CFEqual (family_name, CFSTR ("LastResort")))
2293         descs = CTFontDescriptorCreateMatchingFontDescriptors (pat_desc, NULL);
2294       else
2295         {
2296           CTFontDescriptorRef lr_desc =
2297             CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2298           if (lr_desc)
2299             {
2300               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2301                                      &kCFTypeArrayCallBacks);
2302               CFRelease (lr_desc);
2303             }
2304           else
2305             descs = NULL;
2306         }
2307       CFRelease (pat_desc);
2308       if (! descs)
2309         continue;
2311       descs_count = CFArrayGetCount (descs);
2312       if (descs_count == 0
2313           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2314                                                         charset, chars,
2315                                                         languages))
2316         {
2317           CFRelease (descs);
2318           continue;
2319         }
2321       filtered_descs =
2322         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2323       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2324       for (j = 0; j < descs_count; j++)
2325         {
2326           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2327           CFDictionaryRef dict;
2328           CFNumberRef num;
2329           CTFontSymbolicTraits sym_traits;
2331           dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
2332           if (dict == NULL)
2333             continue;
2335           num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
2336           CFRelease (dict);
2337           if (num == NULL
2338               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2339             continue;
2341           if (spacing >= 0
2342               && !(synth_sym_traits & kCTFontTraitMonoSpace)
2343               && (((sym_traits & kCTFontTraitMonoSpace) != 0)
2344                   != (spacing >= FONT_SPACING_MONO)))
2345             continue;
2347           /* Don't use a color bitmap font until it is supported on
2348              free platforms.  */
2349           if (sym_traits & kCTFontTraitColorGlyphs)
2350             continue;
2352           if (j > 0
2353               && !macfont_supports_charset_and_languages_p (desc, charset,
2354                                                             chars, languages))
2355             continue;
2357           CFArrayAppendValue (filtered_descs, desc);
2358           CFArrayAppendValue (traits_array,
2359                               (const void *) (uintptr_t) sym_traits);
2360         }
2362       CFRelease (descs);
2363       descs = filtered_descs;
2364       descs_count = CFArrayGetCount (descs);
2366       for (j = 0; j < descs_count; j++)
2367         {
2368           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2369           CTFontSymbolicTraits sym_traits =
2370             ((CTFontSymbolicTraits) (uintptr_t)
2371              CFArrayGetValueAtIndex (traits_array, j));
2372           CTFontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2374           mask_min = ((synth_sym_traits ^ sym_traits)
2375                       & (kCTFontTraitItalic | kCTFontTraitBold));
2376           if (FONT_SLANT_NUMERIC (spec) < 0)
2377             mask_min &= ~kCTFontTraitItalic;
2378           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2379             mask_min &= ~kCTFontTraitBold;
2381           mask_max = (synth_sym_traits & ~sym_traits);
2382           /* Synthetic bold does not work for bitmap-only fonts on Mac
2383              OS X 10.6.  */
2384           if ((mask_min ^ mask_max) & kCTFontTraitBold)
2385             {
2386               CFNumberRef format =
2387                 CTFontDescriptorCopyAttribute (desc, kCTFontFormatAttribute);
2389               if (format)
2390                 {
2391                   uint32_t format_val;
2393                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2394                                         &format_val)
2395                       && format_val == kCTFontFormatBitmap)
2396                     mask_max &= ~kCTFontTraitBold;
2397                 }
2398             }
2399           if (spacing >= 0)
2400             mask_min |= (mask_max & kCTFontTraitMonoSpace);
2402           for (mmask = (mask_min & kCTFontTraitMonoSpace);
2403                mmask <= (mask_max & kCTFontTraitMonoSpace);
2404                mmask += kCTFontTraitMonoSpace)
2405             for (bmask = (mask_min & kCTFontTraitBold);
2406                  bmask <= (mask_max & kCTFontTraitBold);
2407                  bmask += kCTFontTraitBold)
2408               for (imask = (mask_min & kCTFontTraitItalic);
2409                    imask <= (mask_max & kCTFontTraitItalic);
2410                    imask += kCTFontTraitItalic)
2411                 {
2412                   CTFontSymbolicTraits synth = (imask | bmask | mmask);
2414                   if (synth == 0
2415                       || macfont_closest_traits_index_p (traits_array,
2416                                                          (sym_traits | synth),
2417                                                          j))
2418                     {
2419                       entity = macfont_descriptor_entity (desc, extra, synth);
2420                       if (! NILP (entity))
2421                         val = Fcons (entity, val);
2422                     }
2423                 }
2424         }
2426       CFRelease (traits_array);
2427       CFRelease (descs);
2428     }
2430   CFRelease (families);
2431   val = Fnreverse (val);
2432   goto finish;
2433  err:
2434   val = Qnil;
2436  finish:
2437   FONT_ADD_LOG ("macfont-list", spec, val);
2438   if (charset) CFRelease (charset);
2439   if (languages) CFRelease (languages);
2440   if (attributes) CFRelease (attributes);
2441   if (family_name) CFRelease (family_name);
2443   unblock_input ();
2445   return val;
2448 static Lisp_Object
2449 macfont_match (struct frame * frame, Lisp_Object spec)
2451   Lisp_Object entity = Qnil;
2452   CFMutableDictionaryRef attributes;
2453   CTFontDescriptorRef pat_desc = NULL, desc = NULL;
2455   block_input ();
2457   attributes = macfont_create_attributes_with_spec (spec);
2458   if (attributes)
2459     {
2460       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2461       CFRelease (attributes);
2462     }
2463   if (pat_desc)
2464     {
2465       desc = CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2466       CFRelease (pat_desc);
2467     }
2468   if (desc)
2469     {
2470       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2471                                           0);
2472       CFRelease (desc);
2473     }
2474   unblock_input ();
2476   FONT_ADD_LOG ("macfont-match", spec, entity);
2477   return entity;
2480 static Lisp_Object
2481 macfont_list_family (struct frame *frame)
2483   Lisp_Object list = Qnil;
2484   CFArrayRef families;
2486   block_input ();
2488   families = macfont_copy_available_families_cache ();
2489   if (families)
2490     {
2491       CFIndex i, count = CFArrayGetCount (families);
2493       for (i = 0; i < count; i++)
2494         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2495       CFRelease (families);
2496     }
2498   unblock_input ();
2500   return list;
2503 static void
2504 macfont_free_entity (Lisp_Object entity)
2506   Lisp_Object val = assq_no_quit (QCfont_entity,
2507                                   AREF (entity, FONT_EXTRA_INDEX));
2508   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2510   block_input ();
2511   CFRelease (name);
2512   unblock_input ();
2515 static Lisp_Object
2516 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2518   Lisp_Object val, font_object;
2519   CFStringRef font_name;
2520   struct macfont_info *macfont_info = NULL;
2521   struct font *font;
2522   int size;
2523   CTFontRef macfont;
2524   CTFontSymbolicTraits sym_traits;
2525   int i, total_width;
2526   CGGlyph glyph;
2527   CGFloat ascent, descent, leading;
2529   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2530   if (! CONSP (val)
2531       || XTYPE (XCDR (val)) != Lisp_Misc
2532       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2533     return Qnil;
2534   font_name = XSAVE_POINTER (XCDR (val), 0);
2535   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2537   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2538   if (size == 0)
2539     size = pixel_size;
2541   block_input ();
2542   macfont = CTFontCreateWithName (font_name, size, NULL);
2543   if (macfont)
2544     {
2545       int fontsize = (int) [((NSFont *) macfont) pointSize];
2546       if (fontsize != size) size = fontsize;
2547     }
2548   unblock_input ();
2549   if (! macfont)
2550     return Qnil;
2552   font_object = font_build_object (VECSIZE (struct macfont_info),
2553                                    Qmac_ct, entity, size);
2554   font = XFONT_OBJECT (font_object);
2555   font->pixel_size = size;
2556   font->driver = &macfont_driver;
2557   font->encoding_charset = font->repertory_charset = -1;
2559   block_input ();
2561   macfont_info = (struct macfont_info *) font;
2562   macfont_info->macfont = macfont;
2563   macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
2565   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2566   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2567     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2568                                                                   size);
2569   else
2570     macfont_info->screen_font = NULL;
2571   macfont_info->cache = macfont_lookup_cache (font_name);
2572   macfont_retain_cache (macfont_info->cache);
2573   macfont_info->metrics = NULL;
2574   macfont_info->metrics_nrows = 0;
2575   macfont_info->synthetic_italic_p = 0;
2576   macfont_info->synthetic_bold_p = 0;
2577   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2578   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2579   if (!(sym_traits & kCTFontTraitItalic)
2580       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2581     macfont_info->synthetic_italic_p = 1;
2582   if (!(sym_traits & kCTFontTraitBold)
2583       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2584     macfont_info->synthetic_bold_p = 1;
2585   if (sym_traits & kCTFontTraitMonoSpace)
2586     macfont_info->spacing = MACFONT_SPACING_MONO;
2587   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2588            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2589                == FONT_SPACING_SYNTHETIC_MONO))
2590     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2591   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2592     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2593   else
2594     {
2595       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2596       if (CONSP (val))
2597         macfont_info->antialias =
2598           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2599     }
2600   macfont_info->color_bitmap_p = 0;
2601   if (sym_traits & kCTFontTraitColorGlyphs)
2602     macfont_info->color_bitmap_p = 1;
2604   glyph = macfont_get_glyph_for_character (font, ' ');
2605   if (glyph != kCGFontIndexInvalid)
2606     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2607   else
2608     /* dirty workaround */
2609     font->space_width = pixel_size;
2611   total_width = font->space_width;
2612   for (i = 1; i < 95; i++)
2613     {
2614       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2615       if (glyph == kCGFontIndexInvalid)
2616         break;
2617       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2618     }
2619   if (i == 95)
2620     font->average_width = total_width / 95;
2621   else
2622     font->average_width = font->space_width; /* XXX */
2624   if (!(macfont_info->screen_font
2625         && mac_screen_font_get_metrics (macfont_info->screen_font,
2626                                         &ascent, &descent, &leading)))
2627     {
2628       CFStringRef family_name;
2630       ascent = CTFontGetAscent (macfont);
2631       descent = CTFontGetDescent (macfont);
2632       leading = CTFontGetLeading (macfont);
2633       /* AppKit and WebKit do some adjustment to the heights of
2634          Courier, Helvetica, and Times.  */
2635       family_name = CTFontCopyFamilyName (macfont);
2636       if (family_name)
2637         {
2638           if (CFEqual (family_name, CFSTR ("Courier"))
2639               || CFEqual (family_name, CFSTR ("Helvetica"))
2640               || CFEqual (family_name, CFSTR ("Times")))
2641             ascent += (ascent + descent) * .15f;
2642           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2643             {
2644               leading *= .25f;
2645               ascent += leading;
2646             }
2647           CFRelease (family_name);
2648         }
2649     }
2650   font->ascent = ascent + 0.5f;
2651   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2652   if (CONSP (val) && !NILP (XCDR (val)))
2653     font->descent = descent + 0.5f;
2654   else
2655     font->descent = descent + leading + 0.5f;
2656   font->height = font->ascent + font->descent;
2658   font->underline_position = - CTFontGetUnderlinePosition (macfont) + 0.5f;
2659   font->underline_thickness = CTFontGetUnderlineThickness (macfont) + 0.5f;
2661   unblock_input ();
2663   /* Unfortunately Xft doesn't provide a way to get minimum char
2664      width.  So, we use space_width instead.  */
2665   font->min_width = font->max_width = font->space_width; /* XXX */
2667   font->baseline_offset = 0;
2668   font->relative_compose = 0;
2669   font->default_ascent = 0;
2670   font->vertical_centering = 0;
2672   return font_object;
2675 static void
2676 macfont_close (struct font *font)
2678   struct macfont_info *macfont_info = (struct macfont_info *) font;
2680   if (macfont_info->cache)
2681     {
2682       int i;
2684       block_input ();
2685       CFRelease (macfont_info->macfont);
2686       CGFontRelease (macfont_info->cgfont);
2687       if (macfont_info->screen_font)
2688         CFRelease (macfont_info->screen_font);
2689       macfont_release_cache (macfont_info->cache);
2690       for (i = 0; i < macfont_info->metrics_nrows; i++)
2691         if (macfont_info->metrics[i])
2692           xfree (macfont_info->metrics[i]);
2693       if (macfont_info->metrics)
2694         xfree (macfont_info->metrics);
2695       macfont_info->cache = NULL;
2696       unblock_input ();
2697     }
2700 static int
2701 macfont_has_char (Lisp_Object font, int c)
2703   int result;
2704   CFCharacterSetRef charset;
2706   block_input ();
2707   if (FONT_ENTITY_P (font))
2708     {
2709       Lisp_Object val;
2710       CFStringRef name;
2712       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2713       val = XCDR (val);
2714       name = XSAVE_POINTER (val, 0);
2715       charset = macfont_get_cf_charset_for_name (name);
2716     }
2717   else
2718     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2720   result = CFCharacterSetIsLongCharacterMember (charset, c);
2721   unblock_input ();
2723   return result;
2726 static unsigned
2727 macfont_encode_char (struct font *font, int c)
2729   CGGlyph glyph;
2731   block_input ();
2732   glyph = macfont_get_glyph_for_character (font, c);
2733   unblock_input ();
2735   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2738 static void
2739 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2740                       struct font_metrics *metrics)
2742   int width, i;
2744   block_input ();
2745   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2746   for (i = 1; i < nglyphs; i++)
2747     {
2748       struct font_metrics m;
2749       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2750                                      NULL, 0);
2752       if (metrics)
2753         {
2754           if (width + m.lbearing < metrics->lbearing)
2755             metrics->lbearing = width + m.lbearing;
2756           if (width + m.rbearing > metrics->rbearing)
2757             metrics->rbearing = width + m.rbearing;
2758           if (m.ascent > metrics->ascent)
2759             metrics->ascent = m.ascent;
2760           if (m.descent > metrics->descent)
2761             metrics->descent = m.descent;
2762         }
2763       width += w;
2764     }
2765   unblock_input ();
2767   if (metrics)
2768     metrics->width = width;
2771 static int
2772 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2773               bool with_background)
2775   struct frame * f = s->f;
2776   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2777   CGRect background_rect;
2778   CGPoint text_position;
2779   CGGlyph *glyphs;
2780   CGPoint *positions;
2781   CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2782   bool no_antialias_p =
2783     (NILP (ns_antialias_text)
2784      || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2785      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2786          && font_size <= macfont_antialias_threshold));
2787   int len = to - from;
2788   struct face *face = s->face;
2789   CGContextRef context;
2791   block_input ();
2793   if (with_background)
2794     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2795                                   s->width, FONT_HEIGHT (s->font));
2796   else
2797     background_rect = CGRectNull;
2799   text_position = CGPointMake (x, -y);
2800   glyphs = xmalloc (sizeof (CGGlyph) * len);
2801   {
2802     CGFloat advance_delta = 0;
2803     int i;
2804     CGFloat total_width = 0;
2806     positions = xmalloc (sizeof (CGPoint) * len);
2807     for (i = 0; i < len; i++)
2808       {
2809         int width;
2811         glyphs[i] = s->char2b[from + i];
2812         width = (s->padding_p ? 1
2813                  : macfont_glyph_extents (s->font, glyphs[i],
2814                                           NULL, &advance_delta,
2815                                           no_antialias_p));
2816         positions[i].x = total_width + advance_delta;
2817         positions[i].y = 0;
2818         total_width += width;
2819       }
2820   }
2822   context = [[NSGraphicsContext currentContext] graphicsPort];
2823   CGContextSaveGState (context);
2825   if (!CGRectIsNull (background_rect))
2826     {
2827       if (s->hl == DRAW_MOUSE_FACE)
2828         {
2829           face = FACE_FROM_ID_OR_NULL (s->f,
2830                                        MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2831           if (!face)
2832             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2833         }
2834       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2835       CGContextFillRects (context, &background_rect, 1);
2836     }
2838   if (macfont_info->cgfont)
2839     {
2840       CGAffineTransform atfm;
2842       CGContextScaleCTM (context, 1, -1);
2843       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2844       if (macfont_info->synthetic_italic_p)
2845         atfm = synthetic_italic_atfm;
2846       else
2847         atfm = CGAffineTransformIdentity;
2848       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2849         {
2850           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2852           /* Stroke line width for text drawing is not correctly
2853              scaled on Retina display/HiDPI mode when drawn to screen
2854              (whereas it is correctly scaled when drawn to bitmaps),
2855              and synthetic bold looks thinner on such environments.
2856              Apple says there are no plans to address this issue
2857              (rdar://11644870) currently.  So we add a workaround.  */
2858 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2859 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2860           if ([[FRAME_NS_VIEW(f) window] respondsToSelector:
2861                                            @selector(backingScaleFactor)])
2862 #endif
2863             CGContextSetLineWidth (context, synthetic_bold_factor * font_size
2864                                    * [[FRAME_NS_VIEW(f) window] backingScaleFactor]);
2865 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2866           else
2867 #endif
2868 #endif
2869 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2870             CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2871 #endif
2872           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2873         }
2874       if (no_antialias_p)
2875         CGContextSetShouldAntialias (context, false);
2877       if (!NILP (ns_use_thin_smoothing))
2878         {
2879           CGContextSetShouldSmoothFonts(context, YES);
2880           CGContextSetFontSmoothingStyle(context, 16);
2881         }
2883       CGContextSetTextMatrix (context, atfm);
2884       CGContextSetTextPosition (context, text_position.x, text_position.y);
2886 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2887       if (macfont_info->color_bitmap_p
2888 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2889           && CTFontDrawGlyphs != NULL
2890 #endif
2891           )
2892         {
2893           if (len > 0)
2894             {
2895               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2896                                 context);
2897             }
2898         }
2899       else
2900 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2901         {
2902           CGContextSetFont (context, macfont_info->cgfont);
2903           CGContextSetFontSize (context, font_size);
2904           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2905         }
2906     }
2909   xfree (glyphs);
2910   xfree (positions);
2911   CGContextRestoreGState (context);
2913   unblock_input ();
2915   return len;
2918 static Lisp_Object
2919 macfont_shape (Lisp_Object lgstring)
2921   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2922   struct macfont_info *macfont_info = (struct macfont_info *) font;
2923   CTFontRef macfont = macfont_info->macfont;
2924   ptrdiff_t glyph_len, len, i, j;
2925   CFIndex nonbmp_len;
2926   UniChar *unichars;
2927   CFIndex *nonbmp_indices;
2928   CFStringRef string;
2929   CFIndex used = 0;
2930   struct mac_glyph_layout *glyph_layouts;
2932   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2933   nonbmp_len = 0;
2934   for (i = 0; i < glyph_len; i++)
2935     {
2936       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2938       if (NILP (lglyph))
2939         break;
2940       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2941         nonbmp_len++;
2942     }
2944   len = i;
2946   if (INT_MAX / 2 < len)
2947     memory_full (SIZE_MAX);
2949   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2950   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2951   for (i = j = 0; i < len; i++)
2952     {
2953       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2955       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2956         {
2957           nonbmp_indices[j] = i + j;
2958           j++;
2959         }
2960     }
2961   nonbmp_indices[j] = len + j;  /* sentinel */
2963   block_input ();
2965   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2966                                                kCFAllocatorNull);
2967   if (string)
2968     {
2969       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2970       if (macfont_info->screen_font)
2971         used = mac_screen_font_shape (macfont_info->screen_font, string,
2972                                       glyph_layouts, glyph_len);
2973       else
2974         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2975       CFRelease (string);
2976     }
2978   unblock_input ();
2980   if (used == 0)
2981     return Qnil;
2983   block_input ();
2985   for (i = 0; i < used; i++)
2986     {
2987       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2988       struct mac_glyph_layout *gl = glyph_layouts + i;
2989       EMACS_INT from, to;
2990       struct font_metrics metrics;
2991       int xoff, yoff, wadjust;
2993       if (NILP (lglyph))
2994         {
2995           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2996           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2997         }
2999       from = gl->comp_range.location;
3000       /* Convert UTF-16 index to UTF-32.  */
3001       j = 0;
3002       while (nonbmp_indices[j] < from)
3003         j++;
3004       from -= j;
3005       LGLYPH_SET_FROM (lglyph, from);
3007       to = gl->comp_range.location + gl->comp_range.length;
3008       /* Convert UTF-16 index to UTF-32.  */
3009       while (nonbmp_indices[j] < to)
3010         j++;
3011       to -= j;
3012       LGLYPH_SET_TO (lglyph, to - 1);
3014       /* LGLYPH_CHAR is used in `describe-char' for checking whether
3015          the composition is trivial.  */
3016       {
3017         UTF32Char c;
3019         if (unichars[gl->string_index] >= 0xD800
3020             && unichars[gl->string_index] < 0xDC00)
3021           c = (((unichars[gl->string_index] - 0xD800) << 10)
3022                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3023         else
3024           c = unichars[gl->string_index];
3025         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3026           c = 0;
3027         LGLYPH_SET_CHAR (lglyph, c);
3028       }
3030       {
3031         unsigned long cc = gl->glyph_id;
3032         LGLYPH_SET_CODE (lglyph, cc);
3033       }
3035       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3036       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3037       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3038       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3039       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3040       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3042       xoff = lround (gl->advance_delta);
3043       yoff = lround (- gl->baseline_delta);
3044       wadjust = lround (gl->advance);
3045       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3046         {
3047           Lisp_Object vec;
3049           vec = Fmake_vector (make_number (3), Qnil);
3050           ASET (vec, 0, make_number (xoff));
3051           ASET (vec, 1, make_number (yoff));
3052           ASET (vec, 2, make_number (wadjust));
3053           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3054         }
3055     }
3057   unblock_input ();
3059   return make_number (used);
3062 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3063 typedef UInt8 UINT24[3];
3065 #pragma pack(push, 1)
3066 struct variation_selector_record
3068   UINT24 var_selector;
3069   UInt32 default_uvs_offset, non_default_uvs_offset;
3071 struct uvs_table
3073   UInt16 format;
3074   UInt32 length, num_var_selector_records;
3075   struct variation_selector_record variation_selector_records[1];
3077 #define SIZEOF_UVS_TABLE_HEADER                                         \
3078   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3080 struct unicode_value_range
3082   UINT24 start_unicode_value;
3083   UInt8 additional_count;
3085 struct default_uvs_table {
3086   UInt32 num_unicode_value_ranges;
3087   struct unicode_value_range unicode_value_ranges[1];
3089 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3090   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3092 struct uvs_mapping
3094   UINT24 unicode_value;
3095   UInt16 glyph_id;
3097 struct non_default_uvs_table
3099   UInt32 num_uvs_mappings;
3100   struct uvs_mapping uvs_mappings[1];
3102 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3103   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3104 #pragma pack(pop)
3106 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3107 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3108    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3109    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3110 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3111 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3112 /* Succeeding one byte should also be accessible.  */
3113 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3114 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3116 /* Return UVS subtable for the specified FONT.  If the subtable is not
3117    found or ill-formatted, then return NULL.  */
3119 static CFDataRef
3120 mac_font_copy_uvs_table (CTFontRef font)
3122   CFDataRef cmap_table, uvs_table = NULL;
3124   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3125                                 kCTFontTableOptionNoOptions);
3126   if (cmap_table)
3127     {
3128       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3129       struct uvs_table *uvs;
3130       struct variation_selector_record *records;
3131       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3133 #if __LP64__
3134       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3135         goto finish;
3136 #endif
3138       cmap_len = CFDataGetLength (cmap_table);
3139       if (sizeof_sfntCMapHeader > cmap_len)
3140         goto finish;
3142       ntables = BUINT16_VALUE (cmap->numTables);
3143       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3144                      / sizeof_sfntCMapEncoding))
3145         goto finish;
3147       for (i = 0; i < ntables; i++)
3148         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3149              == kFontUnicodePlatform)
3150             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3151                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3152           {
3153             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3154             break;
3155           }
3156       if (i == ntables
3157           || uvs_offset > cmap_len
3158           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3159         goto finish;
3161       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3162       uvs_len = BUINT32_VALUE (uvs->length);
3163       if (uvs_len > cmap_len - uvs_offset
3164           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3165         goto finish;
3167       if (BUINT16_VALUE (uvs->format) != 14)
3168         goto finish;
3170       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3171       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3172                       / sizeof (struct variation_selector_record)))
3173         goto finish;
3175       records = uvs->variation_selector_records;
3176       for (i = 0; i < nrecords; i++)
3177         {
3178           UInt32 default_uvs_offset, non_default_uvs_offset;
3180           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3181           if (default_uvs_offset)
3182             {
3183               struct default_uvs_table *default_uvs;
3184               UInt32 nranges;
3186               if (default_uvs_offset > uvs_len
3187                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3188                       > uvs_len - default_uvs_offset))
3189                 goto finish;
3191               default_uvs = ((struct default_uvs_table *)
3192                              ((UInt8 *) uvs + default_uvs_offset));
3193               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3194               if (nranges > ((uvs_len - default_uvs_offset
3195                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3196                              / sizeof (struct unicode_value_range)))
3197                 goto finish;
3198               /* Now 2 * nranges can't overflow, so we can safely use
3199                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3200                  mac_font_get_glyphs_for_variants.  */
3201             }
3203           non_default_uvs_offset =
3204             BUINT32_VALUE (records[i].non_default_uvs_offset);
3205           if (non_default_uvs_offset)
3206             {
3207               struct non_default_uvs_table *non_default_uvs;
3208               UInt32 nmappings;
3210               if (non_default_uvs_offset > uvs_len
3211                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3212                       > uvs_len - non_default_uvs_offset))
3213                 goto finish;
3215               non_default_uvs = ((struct non_default_uvs_table *)
3216                                  ((UInt8 *) uvs + non_default_uvs_offset));
3217               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3218               if (nmappings > ((uvs_len - non_default_uvs_offset
3219                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3220                                / sizeof (struct uvs_mapping)))
3221                 goto finish;
3222               /* Now 2 * nmappings can't overflow, so we can safely
3223                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3224                  in mac_font_get_glyphs_for_variants.  */
3225             }
3226         }
3228       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3230     finish:
3231       CFRelease (cmap_table);
3232     }
3234   return uvs_table;
3237 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3238    sequence consisting of the given base character C and each
3239    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3240    result (explained below) into the corresponding GLYPHS[i].  If the
3241    entry is found in the Default UVS Table, then the result is 0.  If
3242    the entry is found in the Non-Default UVS Table, then the result is
3243    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3244    elements in SELECTORS must be sorted in strictly increasing
3245    order.  */
3247 static void
3248 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3249                                   const UTF32Char selectors[], CGGlyph glyphs[],
3250                                   CFIndex count)
3252   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3253   struct variation_selector_record *records = uvs->variation_selector_records;
3254   CFIndex i;
3255   UInt32 ir, nrecords;
3257   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3258   i = 0;
3259   ir = 0;
3260   while (i < count && ir < nrecords)
3261     {
3262       UInt32 default_uvs_offset, non_default_uvs_offset;
3264       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3265         {
3266           glyphs[i++] = kCGFontIndexInvalid;
3267           continue;
3268         }
3269       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3270         {
3271           ir++;
3272           continue;
3273         }
3275       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3276       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3277       non_default_uvs_offset =
3278         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3280       glyphs[i] = kCGFontIndexInvalid;
3282       if (default_uvs_offset)
3283         {
3284           struct default_uvs_table *default_uvs =
3285             (struct default_uvs_table *) ((UInt8 *) uvs
3286                                           + default_uvs_offset);
3287           struct unicode_value_range *ranges =
3288             default_uvs->unicode_value_ranges;
3289           UInt32 lo, hi;
3291           lo = 0;
3292           hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3293           while (lo < hi)
3294             {
3295               UInt32 mid = (lo + hi) / 2;
3297               if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3298                 hi = mid;
3299               else
3300                 lo = mid + 1;
3301             }
3302           if (hi > 0
3303               && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3304                         + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3305             glyphs[i] = 0;
3306         }
3308       if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3309         {
3310           struct non_default_uvs_table *non_default_uvs =
3311             (struct non_default_uvs_table *) ((UInt8 *) uvs
3312                                               + non_default_uvs_offset);
3313           struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3314           UInt32 lo, hi;
3316           lo = 0;
3317           hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3318           while (lo < hi)
3319             {
3320               UInt32 mid = (lo + hi) / 2;
3322               if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3323                 hi = mid;
3324               else
3325                 lo = mid + 1;
3326             }
3327           if (hi > 0 &&
3328               BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3329             glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3330         }
3331       i++;
3332       ir++;
3333     }
3334   while (i < count)
3335     glyphs[i++] = kCGFontIndexInvalid;
3338 static int
3339 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3341   CFDataRef uvs_table;
3342   NSCharacterCollection uvs_collection;
3343   int i, n = 0;
3345   block_input ();
3346   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3348   if (uvs_table)
3349     {
3350       UTF32Char selectors[256];
3351       CGGlyph glyphs[256];
3353       for (i = 0; i < 16; i++)
3354         selectors[i] = 0xFE00 + i;
3355       for (; i < 256; i++)
3356         selectors[i] = 0xE0100 + (i - 16);
3357       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3358       for (i = 0; i < 256; i++)
3359         {
3360           CGGlyph glyph = glyphs[i];
3362           if (uvs_collection != NSIdentityMappingCharacterCollection
3363               && glyph != kCGFontIndexInvalid)
3364             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3365           if (glyph == kCGFontIndexInvalid)
3366             variations[i] = 0;
3367           else
3368             {
3369               variations[i] = (glyph ? glyph
3370                                : macfont_get_glyph_for_character (font, c));
3371               n++;
3372             }
3373         }
3374     }
3375   unblock_input ();
3377   return n;
3380 static const char *const macfont_booleans[] = {
3381   ":antialias",
3382   ":minspace",
3383   NULL,
3386 static const char *const macfont_non_booleans[] = {
3387   ":lang",
3388   ":script",
3389   ":destination",
3390   NULL,
3393 static void
3394 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3396   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3399 static Boolean
3400 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3401                                         CFArrayRef languages)
3403   Boolean result = true;
3404   CFArrayRef desc_languages =
3405     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3407   if (desc_languages == NULL)
3408     result = false;
3409   else
3410     {
3411       CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3412       CFIndex i, languages_count = CFArrayGetCount (languages);
3414       for (i = 0; i < languages_count; i++)
3415         {
3416           CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3418           if (!CFArrayContainsValue (desc_languages, range, language)
3419               /* PingFang SC contains "zh" and "zh-Hant" as covered
3420                  languages, but does not contain "zh-Hans".  */
3421               && !(CFEqual (language, CFSTR ("zh-Hans"))
3422                    && CFArrayContainsValue (desc_languages, range,
3423                                             CFSTR ("zh"))))
3424             {
3425               result = false;
3426               break;
3427             }
3428         }
3429       CFRelease (desc_languages);
3430     }
3432   return result;
3435 static CFStringRef
3436 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3438   CFStringRef result = NULL;
3439   CFStringRef charset_string =
3440     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3442   if (charset_string && CFStringGetLength (charset_string) > 0)
3443     {
3444       CFStringRef keys[] = {
3445 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3446         kCTLanguageAttributeName
3447 #else
3448         CFSTR ("NSLanguage")
3449 #endif
3450       };
3451       CFTypeRef values[] = {NULL};
3452       CFIndex num_values = 0;
3453       CFArrayRef languages
3454         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3456       if (languages && CFArrayGetCount (languages) > 0)
3457         {
3458           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3459             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3460           else
3461             {
3462               CFCharacterSetRef charset =
3463                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3465               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3466             }
3467         }
3468       if (result == NULL)
3469         {
3470           CFAttributedStringRef attr_string = NULL;
3471           CTLineRef ctline = NULL;
3472           CFDictionaryRef attrs
3473             = CFDictionaryCreate (NULL, (const void **) keys,
3474                                   (const void **) values, num_values,
3475                                   &kCFTypeDictionaryKeyCallBacks,
3476                                   &kCFTypeDictionaryValueCallBacks);
3478           if (attrs)
3479             {
3480               attr_string = CFAttributedStringCreate (NULL, charset_string,
3481                                                       attrs);
3482               CFRelease (attrs);
3483             }
3484           if (attr_string)
3485             {
3486               ctline = CTLineCreateWithAttributedString (attr_string);
3487               CFRelease (attr_string);
3488             }
3489           if (ctline)
3490             {
3491               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3492               CFIndex i, nruns = CFArrayGetCount (runs);
3493               CTFontRef font;
3495               for (i = 0; i < nruns; i++)
3496                 {
3497                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3498                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3499                   CTFontRef font_in_run;
3501                   if (attributes == NULL)
3502                     break;
3503                   font_in_run =
3504                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3505                   if (font_in_run == NULL)
3506                     break;
3507                   if (i == 0)
3508                     font = font_in_run;
3509                   else if (!mac_font_equal_in_postscript_name (font,
3510                                                                font_in_run))
3511                     break;
3512                 }
3513               if (nruns > 0 && i == nruns)
3514                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3515               CFRelease (ctline);
3516             }
3517         }
3518     }
3520   return result;
3523 static inline double
3524 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3526   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3527                                      &glyph, NULL, 1);
3530 static inline CGRect
3531 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3533   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3534                                           &glyph, NULL, 1);
3537 static CFArrayRef
3538 mac_font_create_available_families (void)
3540   CFMutableArrayRef families = NULL;
3541   CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3543   if (orig_families)
3544     {
3545       CFIndex i, count = CFArrayGetCount (orig_families);
3547       families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3548       if (families)
3549         for (i = 0; i < count; i++)
3550           {
3551             CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3553             if (!CFStringHasPrefix (family, CFSTR ("."))
3554                 && (CTFontManagerCompareFontFamilyNames (family,
3555                                                          CFSTR ("LastResort"),
3556                                                          NULL)
3557                     != kCFCompareEqualTo))
3558               CFArrayAppendValue (families, family);
3559           }
3560       CFRelease (orig_families);
3561     }
3563   return families;
3566 static Boolean
3567 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3569   Boolean result;
3570   CFStringRef name1, name2;
3572   if (font1 == font2)
3573     return true;
3575   result = false;
3576   name1 = CTFontCopyPostScriptName (font1);
3577   if (name1)
3578     {
3579       name2 = CTFontCopyPostScriptName (font2);
3580       if (name2)
3581         {
3582           result = CFEqual (name1, name2);
3583           CFRelease (name2);
3584         }
3585       CFRelease (name1);
3586     }
3588   return result;
3591 static CTLineRef
3592 mac_font_create_line_with_string_and_font (CFStringRef string,
3593                                            CTFontRef macfont)
3595   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3596   CFTypeRef values[] = {NULL, NULL};
3597   CFDictionaryRef attributes = NULL;
3598   CFAttributedStringRef attr_string = NULL;
3599   CTLineRef ctline = NULL;
3600   float float_zero = 0.0f;
3602   values[0] = macfont;
3603   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3604   if (values[1])
3605     {
3606       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3607                                        (const void **) values,
3608                                        ARRAYELTS (keys),
3609                                        &kCFTypeDictionaryKeyCallBacks,
3610                                        &kCFTypeDictionaryValueCallBacks);
3611       CFRelease (values[1]);
3612     }
3613   if (attributes)
3614     {
3615       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3616       CFRelease (attributes);
3617     }
3618   if (attr_string)
3619     {
3620       ctline = CTLineCreateWithAttributedString (attr_string);
3621       CFRelease (attr_string);
3622     }
3623   if (ctline)
3624     {
3625       /* Abandon if ctline contains some fonts other than the
3626          specified one.  */
3627       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3628       CFIndex i, nruns = CFArrayGetCount (runs);
3630       for (i = 0; i < nruns; i++)
3631         {
3632           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3633           CFDictionaryRef attributes = CTRunGetAttributes (run);
3634           CTFontRef font_in_run;
3636           if (attributes == NULL)
3637             break;
3638           font_in_run =
3639             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3640           if (font_in_run == NULL)
3641             break;
3642           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3643             break;
3644         }
3645       if (i < nruns)
3646         {
3647           CFRelease (ctline);
3648           ctline = NULL;
3649         }
3650     }
3652   return ctline;
3655 static CFIndex
3656 mac_font_shape (CTFontRef font, CFStringRef string,
3657                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3659   CFIndex used, result = 0;
3660   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3662   if (ctline == NULL)
3663     return 0;
3665   used = CTLineGetGlyphCount (ctline);
3666   if (used <= glyph_len)
3667     {
3668       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3669       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3670       CGFloat total_advance = 0;
3671       CFIndex total_glyph_count = 0;
3673       for (k = 0; k < ctrun_count; k++)
3674         {
3675           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3676           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3677           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3678           CFRange string_range, comp_range, range;
3679           CFIndex *permutation;
3681           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3682             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3683           else
3684             permutation = NULL;
3686 #define RIGHT_TO_LEFT_P permutation
3688           /* Now the `comp_range' member of struct mac_glyph_layout is
3689              temporarily used as a work area such that:
3690              glbuf[i].comp_range.location =
3691              min {compRange[i + 1].location, ...,
3692                      compRange[glyph_count - 1].location,
3693                      maxRange (stringRangeForCTRun)}
3694              glbuf[i].comp_range.length = maxRange (compRange[i])
3695              where compRange[i] is the range of composed characters
3696              containing i-th glyph.  */
3697           string_range = CTRunGetStringRange (ctrun);
3698           min_location = string_range.location + string_range.length;
3699           for (i = 0; i < glyph_count; i++)
3700             {
3701               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3702               CFIndex glyph_index;
3703               CFRange rng;
3705               if (!RIGHT_TO_LEFT_P)
3706                 glyph_index = glyph_count - i - 1;
3707               else
3708                 glyph_index = i;
3709               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3710                                      &gl->string_index);
3711               rng =
3712                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3713                                                              gl->string_index);
3714               gl->comp_range.location = min_location;
3715               gl->comp_range.length = rng.location + rng.length;
3716               if (rng.location < min_location)
3717                 min_location = rng.location;
3718             }
3720           /* Fill the `comp_range' member of struct mac_glyph_layout,
3721              and setup a permutation for right-to-left text.  */
3722           comp_range = CFRangeMake (string_range.location, 0);
3723           range = CFRangeMake (0, 0);
3724           while (1)
3725             {
3726               struct mac_glyph_layout *gl =
3727                 glbuf + range.location + range.length;
3729               if (gl->comp_range.length
3730                   > comp_range.location + comp_range.length)
3731                 comp_range.length = gl->comp_range.length - comp_range.location;
3732               min_location = gl->comp_range.location;
3733               range.length++;
3735               if (min_location >= comp_range.location + comp_range.length)
3736                 {
3737                   comp_range.length = min_location - comp_range.location;
3738                   for (i = 0; i < range.length; i++)
3739                     {
3740                       glbuf[range.location + i].comp_range = comp_range;
3741                       if (RIGHT_TO_LEFT_P)
3742                         permutation[range.location + i] =
3743                           range.location + range.length - i - 1;
3744                     }
3746                   comp_range = CFRangeMake (min_location, 0);
3747                   range.location += range.length;
3748                   range.length = 0;
3749                   if (range.location == glyph_count)
3750                     break;
3751                 }
3752             }
3754           /* Then fill the remaining members.  */
3755           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3756                range.location++)
3757             {
3758               struct mac_glyph_layout *gl;
3759               CGPoint position;
3760               CGFloat max_x;
3762               if (!RIGHT_TO_LEFT_P)
3763                 gl = glbuf + range.location;
3764               else
3765                 {
3766                   CFIndex src, dest;
3768                   src = glyph_count - 1 - range.location;
3769                   dest = permutation[src];
3770                   gl = glbuf + dest;
3771                   if (src < dest)
3772                     {
3773                       CFIndex tmp = gl->string_index;
3775                       gl->string_index = glbuf[src].string_index;
3776                       glbuf[src].string_index = tmp;
3777                     }
3778                 }
3779               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3781               CTRunGetPositions (ctrun, range, &position);
3782               max_x = position.x + CTRunGetTypographicBounds (ctrun, range,
3783                                                               NULL, NULL, NULL);
3784               max_x = max (max_x, total_advance);
3785               gl->advance_delta = position.x - total_advance;
3786               gl->baseline_delta = position.y;
3787               gl->advance = max_x - total_advance;
3788               total_advance = max_x;
3789             }
3791           if (RIGHT_TO_LEFT_P)
3792             xfree (permutation);
3794 #undef RIGHT_TO_LEFT_P
3796           total_glyph_count += glyph_count;
3797         }
3799       result = used;
3800     }
3801   CFRelease (ctline);
3803   return result;
3806 /* The function below seems to cause a memory leak for the CFString
3807    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3808    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3809 #if USE_CT_GLYPH_INFO
3810 static CGGlyph
3811 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3812                               CGFontIndex cid)
3814   CGGlyph result = kCGFontIndexInvalid;
3815   UniChar characters[] = {0xfffd};
3816   CFStringRef string;
3817   CFAttributedStringRef attr_string = NULL;
3818   CTLineRef ctline = NULL;
3820   string = CFStringCreateWithCharacters (NULL, characters,
3821                                          ARRAYELTS (characters));
3823   if (string)
3824     {
3825       CTGlyphInfoRef glyph_info =
3826         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3827       CFDictionaryRef attributes = NULL;
3829       if (glyph_info)
3830         {
3831           CFStringRef keys[] = {kCTFontAttributeName,
3832                                 kCTGlyphInfoAttributeName};
3833           CFTypeRef values[] = {font, glyph_info};
3835           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3836                                            (const void **) values,
3837                                            ARRAYELTS (keys),
3838                                            &kCFTypeDictionaryKeyCallBacks,
3839                                            &kCFTypeDictionaryValueCallBacks);
3840           CFRelease (glyph_info);
3841         }
3842       if (attributes)
3843         {
3844           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3845           CFRelease (attributes);
3846         }
3847       CFRelease (string);
3848     }
3849   if (attr_string)
3850     {
3851       ctline = CTLineCreateWithAttributedString (attr_string);
3852       CFRelease (attr_string);
3853     }
3854   if (ctline)
3855     {
3856       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3858       if (CFArrayGetCount (runs) > 0)
3859         {
3860           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3861           CFDictionaryRef attributes = CTRunGetAttributes (run);
3863           if (attributes)
3864             {
3865               CTFontRef font_in_run =
3866                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3868               if (font_in_run
3869                   && mac_font_equal_in_postscript_name (font_in_run, font))
3870                 {
3871                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3872                   if (result >= CTFontGetGlyphCount (font))
3873                     result = kCGFontIndexInvalid;
3874                 }
3875             }
3876         }
3877       CFRelease (ctline);
3878     }
3880   return result;
3882 #endif
3884 static CFArrayRef
3885 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3887   CFArrayRef result = NULL;
3889 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3890 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3891   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3892 #endif
3893     {
3894       CTFontRef user_font =
3895         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3897       if (user_font)
3898         {
3899           CFArrayRef languages =
3900             CFArrayCreate (NULL, (const void **) &language, 1,
3901                            &kCFTypeArrayCallBacks);
3903           if (languages)
3904             {
3905               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3906                                                                  languages);
3907               CFRelease (languages);
3908             }
3909           CFRelease (user_font);
3910         }
3911     }
3912 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3913   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3914 #endif
3915 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3916 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3917     {
3918       CFIndex i;
3920       for (i = 0; macfont_language_default_font_names[i].language; i++)
3921         {
3922           if (CFEqual (macfont_language_default_font_names[i].language,
3923                        language))
3924             {
3925               CFMutableArrayRef descriptors =
3926                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3928               if (descriptors)
3929                 {
3930                   CFIndex j;
3932                   for (j = 0;
3933                        macfont_language_default_font_names[i].font_names[j];
3934                        j++)
3935                     {
3936                       CFDictionaryRef attributes =
3937                         CFDictionaryCreate (NULL,
3938                                             ((const void **)
3939                                              &kCTFontNameAttribute),
3940                                             ((const void **)
3941                                              &macfont_language_default_font_names[i].font_names[j]),
3942                                             1, &kCFTypeDictionaryKeyCallBacks,
3943                                             &kCFTypeDictionaryValueCallBacks);
3945                       if (attributes)
3946                         {
3947                           CTFontDescriptorRef pat_desc =
3948                             CTFontDescriptorCreateWithAttributes (attributes);
3950                           if (pat_desc)
3951                             {
3952                               CTFontDescriptorRef descriptor =
3953                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3955                               if (descriptor)
3956                                 {
3957                                   CFArrayAppendValue (descriptors, descriptor);
3958                                   CFRelease (descriptor);
3959                                 }
3960                               CFRelease (pat_desc);
3961                             }
3962                           CFRelease (attributes);
3963                         }
3964                     }
3965                   result = descriptors;
3966                 }
3967               break;
3968             }
3969         }
3970     }
3971 #endif
3973   return result;
3976 static CFStringRef
3977 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3978                                                       CFArrayRef languages)
3980   CFStringRef result = NULL;
3981   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3982   CFArrayRef descriptors =
3983     mac_font_copy_default_descriptors_for_language (language);
3985   if (descriptors)
3986     {
3987       CFIndex i, count = CFArrayGetCount (descriptors);
3989       for (i = 0; i < count; i++)
3990         {
3991           CTFontDescriptorRef descriptor =
3992             CFArrayGetValueAtIndex (descriptors, i);
3994           if (macfont_supports_charset_and_languages_p (descriptor, charset,
3995                                                         Qnil, languages))
3996             {
3997               CFStringRef family =
3998                 CTFontDescriptorCopyAttribute (descriptor,
3999                                                kCTFontFamilyNameAttribute);
4000               if (family)
4001                 {
4002                   if (!CFStringHasPrefix (family, CFSTR ("."))
4003                       && !CFEqual (family, CFSTR ("LastResort")))
4004                     {
4005                       result = family;
4006                       break;
4007                     }
4008                   else
4009                     CFRelease (family);
4010                 }
4011             }
4012         }
4013       CFRelease (descriptors);
4014     }
4016   return result;
4019 void *
4020 macfont_get_nsctfont (struct font *font)
4022   struct macfont_info *macfont_info = (struct macfont_info *) font;
4023   CTFontRef macfont = macfont_info->macfont;
4025   return (void *) macfont;
4028 void
4029 mac_register_font_driver (struct frame *f)
4031   register_font_driver (&macfont_driver, f);
4035 void
4036 syms_of_macfont (void)
4038   /* Core Text, for macOS.  */
4039   DEFSYM (Qmac_ct, "mac-ct");
4040   register_font_driver (&macfont_driver, NULL);
4042   /* The font property key specifying the font design destination.  The
4043      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4044      text.  (See the documentation of X Logical Font Description
4045      Conventions.)  In the Mac font driver, 1 means the screen font is
4046      used for calculating some glyph metrics.  You can see the
4047      difference with Monaco 8pt or 9pt, for example.  */
4048   DEFSYM (QCdestination, ":destination");
4050   /* The boolean-valued font property key specifying the use of leading.  */
4051   DEFSYM (QCminspace, ":minspace");
4053   macfont_family_cache = Qnil;
4054   staticpro (&macfont_family_cache);