Improve responsiveness while in 'replace-buffer-contents'
[emacs.git] / src / macfont.m
blobdd7c50f27193abac8aa2407f4989264129e4710c
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           dispatch_queue_t queue;
1445           dispatch_group_t group = NULL;
1446           int nkeys;
1448           if (row != 0)
1449             {
1450               CFMutableDictionaryRef dictionary;
1451               uintptr_t key, value;
1452               int nshifts;
1453               CGGlyph glyph;
1455               if (cache->glyph.dictionary == NULL)
1456                 cache->glyph.dictionary =
1457                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1458               dictionary = cache->glyph.dictionary;
1459               key = c / NGLYPHS_IN_VALUE;
1460               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1461               value = ((uintptr_t)
1462                        CFDictionaryGetValue (dictionary, (const void *) key));
1463               glyph = (value >> nshifts);
1464               if (glyph)
1465                 return glyph;
1467               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1468                 {
1469                   ch = c;
1470                   if (!CTFontGetGlyphsForCharacters (macfont, &ch, &glyph, 1)
1471                       || glyph == 0)
1472                     glyph = kCGFontIndexInvalid;
1474                   if (value == 0)
1475                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1476                   value |= ((uintptr_t) glyph << nshifts);
1477                   CFDictionarySetValue (dictionary, (const void *) key,
1478                                         (const void *) value);
1480                   return glyph;
1481                 }
1483               nkeys = nkeys_or_perm;
1484               for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1485                 if (CFDictionaryContainsKey (dictionary,
1486                                              (const void *) key))
1487                   {
1488                     CFDictionaryRemoveValue (dictionary,
1489                                              (const void *) key);
1490                     if (--nkeys == 0)
1491                       break;
1492                   }
1493             }
1495           len = 0;
1496           for (i = 0; i < 256; i++)
1497             {
1498               ch = row * 256 + i;
1499               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1500                 unichars[len++] = ch;
1501             }
1503           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1504           if (len > 0)
1505             {
1506               CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, len);
1507               while (i > len)
1508                 {
1509                   int next = unichars[len - 1] % 256;
1511                   while (--i > next)
1512                     glyphs[i] = kCGFontIndexInvalid;
1514                   len--;
1515                   glyphs[i] = glyphs[len];
1516                   if (len == 0)
1517                     break;
1518                 }
1519             }
1520           if (i > len)
1521             while (i-- > 0)
1522               glyphs[i] = kCGFontIndexInvalid;
1524           nrows = cache->glyph.nrows;
1525           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1526           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1527           nrows++;
1528           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1529                                           sizeof (CGGlyph *) * nrows);
1530           cache->glyph.matrix[nrows - 1] = glyphs;
1531           cache->glyph.nrows = nrows;
1532         }
1534       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1535     }
1536   else
1537     {
1538       uintptr_t key, value;
1539       int nshifts;
1540       CGGlyph glyph;
1542       if (cache->glyph.dictionary == NULL)
1543         cache->glyph.dictionary =
1544           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1545       key = c / NGLYPHS_IN_VALUE;
1546       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1547       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1548                                                 (const void *) key);
1549       glyph = (value >> nshifts);
1550       if (glyph == 0)
1551         {
1552           UniChar unichars[2];
1553           CGGlyph glyphs[2];
1554           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1556           if (CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, count))
1557             glyph = glyphs[0];
1558           if (glyph == 0)
1559             glyph = kCGFontIndexInvalid;
1561           value |= ((uintptr_t) glyph << nshifts);
1562           CFDictionarySetValue (cache->glyph.dictionary,
1563                                 (const void *) key, (const void *) value);
1564         }
1566       return glyph;
1567     }
1570 static CGGlyph
1571 macfont_get_glyph_for_cid (struct font *font, NSCharacterCollection collection,
1572                            CGFontIndex cid)
1574   struct macfont_info *macfont_info = (struct macfont_info *) font;
1575   CTFontRef macfont = macfont_info->macfont;
1577   /* Cache it? */
1578   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1581 static CFDataRef
1582 macfont_get_uvs_table (struct font *font, NSCharacterCollection *collection)
1584   struct macfont_info *macfont_info = (struct macfont_info *) font;
1585   CTFontRef macfont = macfont_info->macfont;
1586   struct macfont_cache *cache = macfont_info->cache;
1587   CFDataRef result = NULL;
1589   if (cache->uvs.table == NULL)
1590     {
1591       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1592       NSCharacterCollection uvs_collection =
1593         NSIdentityMappingCharacterCollection;
1595       if (uvs_table == NULL
1596           && mac_font_get_glyph_for_cid (macfont,
1597                                          NSAdobeJapan1CharacterCollection,
1598                                          6480) != kCGFontIndexInvalid)
1599         {
1600           /* If the glyph for U+4E55 is accessible via its CID 6480,
1601              then we use the Adobe-Japan1 UVS table, which maps a
1602              variation sequence to a CID, as a fallback.  */
1603           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1605           if (mac_uvs_table_adobe_japan1 == NULL)
1606             mac_uvs_table_adobe_japan1 =
1607               CFDataCreateWithBytesNoCopy (NULL,
1608                                            mac_uvs_table_adobe_japan1_bytes,
1609                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1610                                            kCFAllocatorNull);
1611           if (mac_uvs_table_adobe_japan1)
1612             {
1613               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1614               uvs_collection = NSAdobeJapan1CharacterCollection;
1615             }
1616         }
1617       if (uvs_table == NULL)
1618         cache->uvs.table = kCFNull;
1619       else
1620         cache->uvs.table = uvs_table;
1621       cache->uvs.collection = uvs_collection;
1622     }
1624   if (cache->uvs.table != kCFNull)
1625     {
1626       result = cache->uvs.table;
1627       *collection = cache->uvs.collection;
1628     }
1630   return result;
1633 static Lisp_Object macfont_get_cache (struct frame *);
1634 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1635 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1636 static Lisp_Object macfont_list_family (struct frame *);
1637 static void macfont_free_entity (Lisp_Object);
1638 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1639 static void macfont_close (struct font *);
1640 static int macfont_has_char (Lisp_Object, int);
1641 static unsigned macfont_encode_char (struct font *, int);
1642 static void macfont_text_extents (struct font *, unsigned int *, int,
1643                                   struct font_metrics *);
1644 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1645 static Lisp_Object macfont_shape (Lisp_Object);
1646 static int macfont_variation_glyphs (struct font *, int c,
1647                                      unsigned variations[256]);
1648 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1650 static struct font_driver const macfont_driver =
1651   {
1652   .type = LISPSYM_INITIALLY (Qmac_ct),
1653   .get_cache = macfont_get_cache,
1654   .list = macfont_list,
1655   .match = macfont_match,
1656   .list_family = macfont_list_family,
1657   .free_entity = macfont_free_entity,
1658   .open = macfont_open,
1659   .close = macfont_close,
1660   .has_char = macfont_has_char,
1661   .encode_char = macfont_encode_char,
1662   .text_extents = macfont_text_extents,
1663   .draw = macfont_draw,
1664   .shape = macfont_shape,
1665   .get_variation_glyphs = macfont_variation_glyphs,
1666   .filter_properties = macfont_filter_properties,
1667   };
1669 static Lisp_Object
1670 macfont_get_cache (struct frame * f)
1672   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1674   return (dpyinfo->name_list_element);
1677 static int
1678 macfont_get_charset (Lisp_Object registry)
1680   char *str = SSDATA (SYMBOL_NAME (registry));
1681   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1682   Lisp_Object regexp;
1683   int i, j;
1685   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1686     {
1687       if (str[i] == '.')
1688         re[j++] = '\\';
1689       else if (str[i] == '*')
1690         re[j++] = '.';
1691       re[j] = str[i];
1692       if (re[j] == '?')
1693         re[j] = '.';
1694     }
1695   re[j] = '\0';
1696   regexp = make_unibyte_string (re, j);
1697   for (i = 0; cf_charset_table[i].name; i++)
1698     if (fast_c_string_match_ignore_case
1699         (regexp, cf_charset_table[i].name,
1700          strlen (cf_charset_table[i].name)) >= 0)
1701       break;
1702   if (! cf_charset_table[i].name)
1703     return -1;
1704   if (! cf_charset_table[i].cf_charset)
1705     {
1706       int *uniquifier = cf_charset_table[i].uniquifier;
1707       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1708       CFIndex count = 0;
1709       CFStringRef string;
1710       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1712       if (! charset)
1713         return -1;
1714       for (j = 0; uniquifier[j]; j++)
1715         {
1716           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1717                                                         unichars + count);
1718           CFCharacterSetAddCharactersInRange (charset,
1719                                               CFRangeMake (uniquifier[j], 1));
1720         }
1722       string = CFStringCreateWithCharacters (NULL, unichars, count);
1723       if (! string)
1724         {
1725           CFRelease (charset);
1726           return -1;
1727         }
1728       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1729                                                                  charset);
1730       CFRelease (charset);
1731       /* CFCharacterSetCreateWithCharactersInString does not handle
1732          surrogate pairs properly as of Mac OS X 10.5.  */
1733       cf_charset_table[i].cf_charset_string = string;
1734     }
1735   return i;
1738 struct OpenTypeSpec
1740   Lisp_Object script;
1741   unsigned int script_tag, langsys_tag;
1742   int nfeatures[2];
1743   unsigned int *features[2];
1746 #define OTF_SYM_TAG(SYM, TAG)                               \
1747   do {                                                      \
1748     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1749     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1750   } while (0)
1752 #define OTF_TAG_STR(TAG, P)                     \
1753   do {                                          \
1754     (P)[0] = (char) (TAG >> 24);                \
1755     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1756     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1757     (P)[3] = (char) (TAG & 0xFF);               \
1758     (P)[4] = '\0';                              \
1759   } while (0)
1761 static struct OpenTypeSpec *
1762 macfont_get_open_type_spec (Lisp_Object otf_spec)
1764   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1765   Lisp_Object val;
1766   int i, j;
1767   bool negative;
1769   if (! spec)
1770     return NULL;
1771   spec->script = XCAR (otf_spec);
1772   if (! NILP (spec->script))
1773     {
1774       OTF_SYM_TAG (spec->script, spec->script_tag);
1775       val = assq_no_quit (spec->script, Votf_script_alist);
1776       if (CONSP (val) && SYMBOLP (XCDR (val)))
1777         spec->script = XCDR (val);
1778       else
1779         spec->script = Qnil;
1780     }
1781   else
1782     spec->script_tag = 0x44464C54;      /* "DFLT" */
1783   otf_spec = XCDR (otf_spec);
1784   spec->langsys_tag = 0;
1785   if (! NILP (otf_spec))
1786     {
1787       val = XCAR (otf_spec);
1788       if (! NILP (val))
1789         OTF_SYM_TAG (val, spec->langsys_tag);
1790       otf_spec = XCDR (otf_spec);
1791     }
1792   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1793   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1794     {
1795       Lisp_Object len;
1797       val = XCAR (otf_spec);
1798       if (NILP (val))
1799         continue;
1800       len = Flength (val);
1801       spec->features[i] =
1802         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1803          ? 0
1804          : malloc (XINT (len) * sizeof *spec->features[i]));
1805       if (! spec->features[i])
1806         {
1807           if (i > 0 && spec->features[0])
1808             free (spec->features[0]);
1809           free (spec);
1810           return NULL;
1811         }
1812       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1813         {
1814           if (NILP (XCAR (val)))
1815             negative = 1;
1816           else
1817             {
1818               unsigned int tag;
1820               OTF_SYM_TAG (XCAR (val), tag);
1821               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1822             }
1823         }
1824       spec->nfeatures[i] = j;
1825     }
1826   return spec;
1829 static CFMutableDictionaryRef
1830 macfont_create_attributes_with_spec (Lisp_Object spec)
1832   Lisp_Object tmp, extra;
1833   CFMutableArrayRef langarray = NULL;
1834   CFCharacterSetRef charset = NULL;
1835   CFStringRef charset_string = NULL;
1836   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1837   Lisp_Object script = Qnil;
1838   Lisp_Object registry;
1839   int cf_charset_idx, i;
1840   struct OpenTypeSpec *otspec = NULL;
1841   struct {
1842     enum font_property_index index;
1843     CFStringRef trait;
1844     CGPoint points[6];
1845   } numeric_traits[] =
1846       {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
1847         {{-0.4, 50},            /* light */
1848          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1849          {0, 100},              /* normal */
1850          {0.24, 140},           /* (semi-bold + normal) / 2 */
1851          {0.4, 200},            /* bold */
1852          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1853        {FONT_SLANT_INDEX, kCTFontSlantTrait,
1854         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1855        {FONT_WIDTH_INDEX, kCTFontWidthTrait,
1856         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1858   registry = AREF (spec, FONT_REGISTRY_INDEX);
1859   if (NILP (registry)
1860       || EQ (registry, Qascii_0)
1861       || EQ (registry, Qiso10646_1)
1862       || EQ (registry, Qunicode_bmp))
1863     cf_charset_idx = -1;
1864   else
1865     {
1866       CFStringRef lang;
1868       cf_charset_idx = macfont_get_charset (registry);
1869       if (cf_charset_idx < 0)
1870         goto err;
1871       charset = cf_charset_table[cf_charset_idx].cf_charset;
1872       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1873       lang = cf_charset_table[cf_charset_idx].lang;
1874       if (lang)
1875         {
1876           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1877           if (! langarray)
1878             goto err;
1879           CFArrayAppendValue (langarray, lang);
1880         }
1881     }
1883   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1884        CONSP (extra); extra = XCDR (extra))
1885     {
1886       Lisp_Object key, val;
1888       tmp = XCAR (extra);
1889       key = XCAR (tmp), val = XCDR (tmp);
1890       if (EQ (key, QClang))
1891         {
1892           if (! langarray)
1893             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1894           if (! langarray)
1895             goto err;
1896           if (SYMBOLP (val))
1897             val = list1 (val);
1898           for (; CONSP (val); val = XCDR (val))
1899             if (SYMBOLP (XCAR (val)))
1900               {
1901                 CFStringRef lang =
1902                   cfstring_create_with_string_noencode (SYMBOL_NAME
1903                                                         (XCAR (val)));
1905                 if (lang == NULL)
1906                   goto err;
1907                 CFArrayAppendValue (langarray, lang);
1908                 CFRelease (lang);
1909               }
1910         }
1911       else if (EQ (key, QCotf))
1912         {
1913           otspec = macfont_get_open_type_spec (val);
1914           if (! otspec)
1915             goto err;
1916           script = otspec->script;
1917         }
1918       else if (EQ (key, QCscript))
1919         script = val;
1920     }
1922   if (! NILP (script) && ! charset)
1923     {
1924       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1926       if (CONSP (chars) && CONSP (CDR (chars)))
1927         {
1928           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1929           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1931           if (! string || !cs)
1932             {
1933               if (string)
1934                 CFRelease (string);
1935               else if (cs)
1936                 CFRelease (cs);
1937               goto err;
1938             }
1939           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1940             if (CHARACTERP (XCAR (chars)))
1941               {
1942                 UniChar unichars[2];
1943                 CFIndex count =
1944                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1945                                                        unichars);
1946                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1948                 CFStringAppendCharacters (string, unichars, count);
1949                 CFCharacterSetAddCharactersInRange (cs, range);
1950               }
1951           charset = cs;
1952           /* CFCharacterSetCreateWithCharactersInString does not
1953              handle surrogate pairs properly as of Mac OS X 10.5.  */
1954           charset_string = string;
1955         }
1956     }
1958   attributes = CFDictionaryCreateMutable (NULL, 0,
1959                                           &kCFTypeDictionaryKeyCallBacks,
1960                                           &kCFTypeDictionaryValueCallBacks);
1961   if (! attributes)
1962     goto err;
1964   tmp = AREF (spec, FONT_FAMILY_INDEX);
1965   if (SYMBOLP (tmp) && ! NILP (tmp))
1966     {
1967       CFStringRef family = macfont_create_family_with_symbol (tmp);
1969       if (! family)
1970         goto err;
1971       CFDictionaryAddValue (attributes, kCTFontFamilyNameAttribute,
1972                             family);
1973       CFRelease (family);
1974     }
1976   traits = CFDictionaryCreateMutable (NULL, 4,
1977                                       &kCFTypeDictionaryKeyCallBacks,
1978                                       &kCFTypeDictionaryValueCallBacks);
1979   if (! traits)
1980     goto err;
1982   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1983     {
1984       tmp = AREF (spec, numeric_traits[i].index);
1985       if (INTEGERP (tmp))
1986         {
1987           CGPoint *point = numeric_traits[i].points;
1988           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1989           CFNumberRef num;
1991           while (point->y < floatval)
1992             point++;
1993           if (point == numeric_traits[i].points)
1994             point++;
1995           else if (point->y == CGFLOAT_MAX)
1996             point--;
1997           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1998                                        * ((point->x - (point - 1)->x)
1999                                           / (point->y - (point - 1)->y)));
2000           if (floatval > 1.0)
2001             floatval = 1.0;
2002           else if (floatval < -1.0)
2003             floatval = -1.0;
2004           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
2005           if (! num)
2006             goto err;
2007           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2008           CFRelease (num);
2009         }
2010     }
2011   if (CFDictionaryGetCount (traits))
2012     CFDictionaryAddValue (attributes, kCTFontTraitsAttribute, traits);
2014   if (charset)
2015     CFDictionaryAddValue (attributes, kCTFontCharacterSetAttribute,
2016                           charset);
2017   if (charset_string)
2018     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2019                           charset_string);
2020   if (langarray)
2021     CFDictionaryAddValue (attributes, kCTFontLanguagesAttribute, langarray);
2023   goto finish;
2025  err:
2026   if (attributes)
2027     {
2028       CFRelease (attributes);
2029       attributes = NULL;
2030     }
2032  finish:
2033   if (langarray) CFRelease (langarray);
2034   if (charset && cf_charset_idx < 0) CFRelease (charset);
2035   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2036   if (traits) CFRelease (traits);
2037   if (otspec)
2038     {
2039       if (otspec->nfeatures[0] > 0)
2040         free (otspec->features[0]);
2041       if (otspec->nfeatures[1] > 0)
2042         free (otspec->features[1]);
2043       free (otspec);
2044     }
2046   return attributes;
2049 static Boolean
2050 macfont_supports_charset_and_languages_p (CTFontDescriptorRef desc,
2051                                           CFCharacterSetRef charset,
2052                                           Lisp_Object chars,
2053                                           CFArrayRef languages)
2055   Boolean result = true;
2057   if (charset || VECTORP (chars))
2058     {
2059       CFCharacterSetRef desc_charset =
2060         CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
2062       if (desc_charset == NULL)
2063         result = false;
2064       else
2065         {
2066           if (charset)
2067             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2068           else                  /* VECTORP (chars) */
2069             {
2070               ptrdiff_t j;
2072               for (j = 0; j < ASIZE (chars); j++)
2073                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2074                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2075                                                             XFASTINT (AREF (chars, j))))
2076                   break;
2077               if (j == ASIZE (chars))
2078                 result = false;
2079             }
2080           CFRelease (desc_charset);
2081         }
2082     }
2083   if (result && languages)
2084     result = mac_font_descriptor_supports_languages (desc, languages);
2086   return result;
2089 static int
2090 macfont_traits_distance (CTFontSymbolicTraits sym_traits1,
2091                          CTFontSymbolicTraits sym_traits2)
2093   CTFontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2094   int distance = 0;
2096   /* We prefer synthetic bold of italic to synthetic italic of bold
2097      when both bold and italic are available but bold-italic is not
2098      available.  */
2099   if (diff & kCTFontTraitBold)
2100     distance |= (1 << 0);
2101   if (diff & kCTFontTraitItalic)
2102     distance |= (1 << 1);
2103   if (diff & kCTFontTraitMonoSpace)
2104     distance |= (1 << 2);
2106   return distance;
2109 static Boolean
2110 macfont_closest_traits_index_p (CFArrayRef traits_array,
2111                                 CTFontSymbolicTraits target,
2112                                 CFIndex index)
2114   CFIndex i, count = CFArrayGetCount (traits_array);
2115   CTFontSymbolicTraits traits;
2116   int my_distance;
2118   traits = ((CTFontSymbolicTraits) (uintptr_t)
2119             CFArrayGetValueAtIndex (traits_array, index));
2120   my_distance = macfont_traits_distance (target, traits);
2122   for (i = 0; i < count; i++)
2123     if (i != index)
2124       {
2125         traits = ((CTFontSymbolicTraits) (uintptr_t)
2126                   CFArrayGetValueAtIndex (traits_array, i));
2127         if (macfont_traits_distance (target, traits) < my_distance)
2128           return false;
2129       }
2131   return true;
2134 static Lisp_Object
2135 macfont_list (struct frame *f, Lisp_Object spec)
2137   Lisp_Object val = Qnil, family, extra;
2138   int i, n;
2139   CFStringRef family_name = NULL;
2140   CFMutableDictionaryRef attributes = NULL, traits;
2141   Lisp_Object chars = Qnil;
2142   int spacing = -1;
2143   CTFontSymbolicTraits synth_sym_traits = 0;
2144   CFArrayRef families;
2145   CFIndex families_count;
2146   CFCharacterSetRef charset = NULL;
2147   CFArrayRef languages = NULL;
2149   block_input ();
2151   family = AREF (spec, FONT_FAMILY_INDEX);
2152   if (! NILP (family))
2153     {
2154       family_name = macfont_create_family_with_symbol (family);
2155       if (family_name == NULL)
2156         goto finish;
2157     }
2159   attributes = macfont_create_attributes_with_spec (spec);
2160   if (! attributes)
2161     goto finish;
2163   languages = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
2165   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2166     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2168   traits = ((CFMutableDictionaryRef)
2169             CFDictionaryGetValue (attributes, kCTFontTraitsAttribute));
2171   n = FONT_SLANT_NUMERIC (spec);
2172   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2173     {
2174       synth_sym_traits |= kCTFontTraitItalic;
2175       if (traits)
2176         CFDictionaryRemoveValue (traits, kCTFontSlantTrait);
2177     }
2179   n = FONT_WEIGHT_NUMERIC (spec);
2180   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2181     {
2182       synth_sym_traits |= kCTFontTraitBold;
2183       if (traits)
2184         CFDictionaryRemoveValue (traits, kCTFontWeightTrait);
2185     }
2187   if (languages
2188       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2189     {
2190       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2192       if (CFStringHasPrefix (language, CFSTR ("ja"))
2193           || CFStringHasPrefix (language, CFSTR ("ko"))
2194           || CFStringHasPrefix (language, CFSTR ("zh")))
2195         synth_sym_traits |= kCTFontTraitMonoSpace;
2196     }
2198   /* Create array of families.  */
2199   if (family_name)
2200     families = CFArrayCreate (NULL, (const void **) &family_name,
2201                               1, &kCFTypeArrayCallBacks);
2202   else
2203     {
2204       CFStringRef pref_family;
2205       CFIndex families_count, pref_family_index = -1;
2207       families = macfont_copy_available_families_cache ();
2208       if (families == NULL)
2209         goto err;
2211       families_count = CFArrayGetCount (families);
2213       /* Move preferred family to the front if exists.  */
2214       pref_family =
2215         mac_font_create_preferred_family_for_attributes (attributes);
2216       if (pref_family)
2217         {
2218           pref_family_index =
2219             CFArrayGetFirstIndexOfValue (families,
2220                                          CFRangeMake (0, families_count),
2221                                          pref_family);
2222           CFRelease (pref_family);
2223         }
2224       if (pref_family_index > 0)
2225         {
2226           CFMutableArrayRef mutable_families =
2227             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2229           if (mutable_families)
2230             {
2231               CFArrayAppendValue (mutable_families,
2232                                   CFArrayGetValueAtIndex (families,
2233                                                           pref_family_index));
2234               CFArrayAppendArray (mutable_families, families,
2235                                   CFRangeMake (0, pref_family_index));
2236               if (pref_family_index + 1 < families_count)
2237                 CFArrayAppendArray (mutable_families, families,
2238                                     CFRangeMake (pref_family_index + 1,
2239                                                  families_count
2240                                                  - (pref_family_index + 1)));
2241               CFRelease (families);
2242               families = mutable_families;
2243             }
2244         }
2245     }
2247   charset = CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
2248   if (charset)
2249     {
2250       CFRetain (charset);
2251       CFDictionaryRemoveValue (attributes, kCTFontCharacterSetAttribute);
2252     }
2253   else
2254     {
2255       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2256       if (! NILP (val))
2257         {
2258           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2259           if (CONSP (val) && VECTORP (XCDR (val)))
2260             chars = XCDR (val);
2261         }
2262       val = Qnil;
2263     }
2265   if (languages)
2266     {
2267       CFRetain (languages);
2268       CFDictionaryRemoveValue (attributes, kCTFontLanguagesAttribute);
2269     }
2271   val = Qnil;
2272   extra = AREF (spec, FONT_EXTRA_INDEX);
2273   families_count = CFArrayGetCount (families);
2274   for (i = 0; i < families_count; i++)
2275     {
2276       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2277       CTFontDescriptorRef pat_desc;
2278       CFArrayRef descs;
2279       CFIndex descs_count;
2280       CFMutableArrayRef filtered_descs, traits_array;
2281       Lisp_Object entity;
2282       int j;
2284       CFDictionarySetValue (attributes, kCTFontFamilyNameAttribute,
2285                             family_name);
2286       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2287       if (! pat_desc)
2288         goto err;
2290       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2291          10.7 returns NULL if pat_desc represents the LastResort font.
2292          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2293          trailing "s") for such a font.  */
2294       if (!CFEqual (family_name, CFSTR ("LastResort")))
2295         descs = CTFontDescriptorCreateMatchingFontDescriptors (pat_desc, NULL);
2296       else
2297         {
2298           CTFontDescriptorRef lr_desc =
2299             CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2300           if (lr_desc)
2301             {
2302               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2303                                      &kCFTypeArrayCallBacks);
2304               CFRelease (lr_desc);
2305             }
2306           else
2307             descs = NULL;
2308         }
2309       CFRelease (pat_desc);
2310       if (! descs)
2311         continue;
2313       descs_count = CFArrayGetCount (descs);
2314       if (descs_count == 0
2315           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2316                                                         charset, chars,
2317                                                         languages))
2318         {
2319           CFRelease (descs);
2320           continue;
2321         }
2323       filtered_descs =
2324         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2325       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2326       for (j = 0; j < descs_count; j++)
2327         {
2328           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2329           CFDictionaryRef dict;
2330           CFNumberRef num;
2331           CTFontSymbolicTraits sym_traits;
2333           dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
2334           if (dict == NULL)
2335             continue;
2337           num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
2338           CFRelease (dict);
2339           if (num == NULL
2340               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2341             continue;
2343           if (spacing >= 0
2344               && !(synth_sym_traits & kCTFontTraitMonoSpace)
2345               && (((sym_traits & kCTFontTraitMonoSpace) != 0)
2346                   != (spacing >= FONT_SPACING_MONO)))
2347             continue;
2349           /* Don't use a color bitmap font until it is supported on
2350              free platforms.  */
2351           if (sym_traits & kCTFontTraitColorGlyphs)
2352             continue;
2354           if (j > 0
2355               && !macfont_supports_charset_and_languages_p (desc, charset,
2356                                                             chars, languages))
2357             continue;
2359           CFArrayAppendValue (filtered_descs, desc);
2360           CFArrayAppendValue (traits_array,
2361                               (const void *) (uintptr_t) sym_traits);
2362         }
2364       CFRelease (descs);
2365       descs = filtered_descs;
2366       descs_count = CFArrayGetCount (descs);
2368       for (j = 0; j < descs_count; j++)
2369         {
2370           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2371           CTFontSymbolicTraits sym_traits =
2372             ((CTFontSymbolicTraits) (uintptr_t)
2373              CFArrayGetValueAtIndex (traits_array, j));
2374           CTFontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2376           mask_min = ((synth_sym_traits ^ sym_traits)
2377                       & (kCTFontTraitItalic | kCTFontTraitBold));
2378           if (FONT_SLANT_NUMERIC (spec) < 0)
2379             mask_min &= ~kCTFontTraitItalic;
2380           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2381             mask_min &= ~kCTFontTraitBold;
2383           mask_max = (synth_sym_traits & ~sym_traits);
2384           /* Synthetic bold does not work for bitmap-only fonts on Mac
2385              OS X 10.6.  */
2386           if ((mask_min ^ mask_max) & kCTFontTraitBold)
2387             {
2388               CFNumberRef format =
2389                 CTFontDescriptorCopyAttribute (desc, kCTFontFormatAttribute);
2391               if (format)
2392                 {
2393                   uint32_t format_val;
2395                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2396                                         &format_val)
2397                       && format_val == kCTFontFormatBitmap)
2398                     mask_max &= ~kCTFontTraitBold;
2399                 }
2400             }
2401           if (spacing >= 0)
2402             mask_min |= (mask_max & kCTFontTraitMonoSpace);
2404           for (mmask = (mask_min & kCTFontTraitMonoSpace);
2405                mmask <= (mask_max & kCTFontTraitMonoSpace);
2406                mmask += kCTFontTraitMonoSpace)
2407             for (bmask = (mask_min & kCTFontTraitBold);
2408                  bmask <= (mask_max & kCTFontTraitBold);
2409                  bmask += kCTFontTraitBold)
2410               for (imask = (mask_min & kCTFontTraitItalic);
2411                    imask <= (mask_max & kCTFontTraitItalic);
2412                    imask += kCTFontTraitItalic)
2413                 {
2414                   CTFontSymbolicTraits synth = (imask | bmask | mmask);
2416                   if (synth == 0
2417                       || macfont_closest_traits_index_p (traits_array,
2418                                                          (sym_traits | synth),
2419                                                          j))
2420                     {
2421                       entity = macfont_descriptor_entity (desc, extra, synth);
2422                       if (! NILP (entity))
2423                         val = Fcons (entity, val);
2424                     }
2425                 }
2426         }
2428       CFRelease (traits_array);
2429       CFRelease (descs);
2430     }
2432   CFRelease (families);
2433   val = Fnreverse (val);
2434   goto finish;
2435  err:
2436   val = Qnil;
2438  finish:
2439   FONT_ADD_LOG ("macfont-list", spec, val);
2440   if (charset) CFRelease (charset);
2441   if (languages) CFRelease (languages);
2442   if (attributes) CFRelease (attributes);
2443   if (family_name) CFRelease (family_name);
2445   unblock_input ();
2447   return val;
2450 static Lisp_Object
2451 macfont_match (struct frame * frame, Lisp_Object spec)
2453   Lisp_Object entity = Qnil;
2454   CFMutableDictionaryRef attributes;
2455   CTFontDescriptorRef pat_desc = NULL, desc = NULL;
2457   block_input ();
2459   attributes = macfont_create_attributes_with_spec (spec);
2460   if (attributes)
2461     {
2462       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2463       CFRelease (attributes);
2464     }
2465   if (pat_desc)
2466     {
2467       desc = CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2468       CFRelease (pat_desc);
2469     }
2470   if (desc)
2471     {
2472       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2473                                           0);
2474       CFRelease (desc);
2475     }
2476   unblock_input ();
2478   FONT_ADD_LOG ("macfont-match", spec, entity);
2479   return entity;
2482 static Lisp_Object
2483 macfont_list_family (struct frame *frame)
2485   Lisp_Object list = Qnil;
2486   CFArrayRef families;
2488   block_input ();
2490   families = macfont_copy_available_families_cache ();
2491   if (families)
2492     {
2493       CFIndex i, count = CFArrayGetCount (families);
2495       for (i = 0; i < count; i++)
2496         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2497       CFRelease (families);
2498     }
2500   unblock_input ();
2502   return list;
2505 static void
2506 macfont_free_entity (Lisp_Object entity)
2508   Lisp_Object val = assq_no_quit (QCfont_entity,
2509                                   AREF (entity, FONT_EXTRA_INDEX));
2510   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2512   block_input ();
2513   CFRelease (name);
2514   unblock_input ();
2517 static Lisp_Object
2518 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2520   Lisp_Object val, font_object;
2521   CFStringRef font_name;
2522   struct macfont_info *macfont_info = NULL;
2523   struct font *font;
2524   int size;
2525   CTFontRef macfont;
2526   CTFontSymbolicTraits sym_traits;
2527   int i, total_width;
2528   CGGlyph glyph;
2529   CGFloat ascent, descent, leading;
2531   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2532   if (! CONSP (val)
2533       || XTYPE (XCDR (val)) != Lisp_Misc
2534       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2535     return Qnil;
2536   font_name = XSAVE_POINTER (XCDR (val), 0);
2537   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2539   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2540   if (size == 0)
2541     size = pixel_size;
2543   block_input ();
2544   macfont = CTFontCreateWithName (font_name, size, NULL);
2545   if (macfont)
2546     {
2547       int fontsize = (int) [((NSFont *) macfont) pointSize];
2548       if (fontsize != size) size = fontsize;
2549     }
2550   unblock_input ();
2551   if (! macfont)
2552     return Qnil;
2554   font_object = font_build_object (VECSIZE (struct macfont_info),
2555                                    Qmac_ct, entity, size);
2556   font = XFONT_OBJECT (font_object);
2557   font->pixel_size = size;
2558   font->driver = &macfont_driver;
2559   font->encoding_charset = font->repertory_charset = -1;
2561   block_input ();
2563   macfont_info = (struct macfont_info *) font;
2564   macfont_info->macfont = macfont;
2565   macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
2567   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2568   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2569     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2570                                                                   size);
2571   else
2572     macfont_info->screen_font = NULL;
2573   macfont_info->cache = macfont_lookup_cache (font_name);
2574   macfont_retain_cache (macfont_info->cache);
2575   macfont_info->metrics = NULL;
2576   macfont_info->metrics_nrows = 0;
2577   macfont_info->synthetic_italic_p = 0;
2578   macfont_info->synthetic_bold_p = 0;
2579   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2580   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2581   if (!(sym_traits & kCTFontTraitItalic)
2582       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2583     macfont_info->synthetic_italic_p = 1;
2584   if (!(sym_traits & kCTFontTraitBold)
2585       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2586     macfont_info->synthetic_bold_p = 1;
2587   if (sym_traits & kCTFontTraitMonoSpace)
2588     macfont_info->spacing = MACFONT_SPACING_MONO;
2589   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2590            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2591                == FONT_SPACING_SYNTHETIC_MONO))
2592     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2593   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2594     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2595   else
2596     {
2597       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2598       if (CONSP (val))
2599         macfont_info->antialias =
2600           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2601     }
2602   macfont_info->color_bitmap_p = 0;
2603   if (sym_traits & kCTFontTraitColorGlyphs)
2604     macfont_info->color_bitmap_p = 1;
2606   glyph = macfont_get_glyph_for_character (font, ' ');
2607   if (glyph != kCGFontIndexInvalid)
2608     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2609   else
2610     /* dirty workaround */
2611     font->space_width = pixel_size;
2613   total_width = font->space_width;
2614   for (i = 1; i < 95; i++)
2615     {
2616       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2617       if (glyph == kCGFontIndexInvalid)
2618         break;
2619       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2620     }
2621   if (i == 95)
2622     font->average_width = total_width / 95;
2623   else
2624     font->average_width = font->space_width; /* XXX */
2626   if (!(macfont_info->screen_font
2627         && mac_screen_font_get_metrics (macfont_info->screen_font,
2628                                         &ascent, &descent, &leading)))
2629     {
2630       CFStringRef family_name;
2632       ascent = CTFontGetAscent (macfont);
2633       descent = CTFontGetDescent (macfont);
2634       leading = CTFontGetLeading (macfont);
2635       /* AppKit and WebKit do some adjustment to the heights of
2636          Courier, Helvetica, and Times.  */
2637       family_name = CTFontCopyFamilyName (macfont);
2638       if (family_name)
2639         {
2640           if (CFEqual (family_name, CFSTR ("Courier"))
2641               || CFEqual (family_name, CFSTR ("Helvetica"))
2642               || CFEqual (family_name, CFSTR ("Times")))
2643             ascent += (ascent + descent) * .15f;
2644           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2645             {
2646               leading *= .25f;
2647               ascent += leading;
2648             }
2649           CFRelease (family_name);
2650         }
2651     }
2652   font->ascent = ascent + 0.5f;
2653   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2654   if (CONSP (val) && !NILP (XCDR (val)))
2655     font->descent = descent + 0.5f;
2656   else
2657     font->descent = descent + leading + 0.5f;
2658   font->height = font->ascent + font->descent;
2660   font->underline_position = - CTFontGetUnderlinePosition (macfont) + 0.5f;
2661   font->underline_thickness = CTFontGetUnderlineThickness (macfont) + 0.5f;
2663   unblock_input ();
2665   /* Unfortunately Xft doesn't provide a way to get minimum char
2666      width.  So, we use space_width instead.  */
2667   font->min_width = font->max_width = font->space_width; /* XXX */
2669   font->baseline_offset = 0;
2670   font->relative_compose = 0;
2671   font->default_ascent = 0;
2672   font->vertical_centering = 0;
2674   return font_object;
2677 static void
2678 macfont_close (struct font *font)
2680   struct macfont_info *macfont_info = (struct macfont_info *) font;
2682   if (macfont_info->cache)
2683     {
2684       int i;
2686       block_input ();
2687       CFRelease (macfont_info->macfont);
2688       CGFontRelease (macfont_info->cgfont);
2689       if (macfont_info->screen_font)
2690         CFRelease (macfont_info->screen_font);
2691       macfont_release_cache (macfont_info->cache);
2692       for (i = 0; i < macfont_info->metrics_nrows; i++)
2693         if (macfont_info->metrics[i])
2694           xfree (macfont_info->metrics[i]);
2695       if (macfont_info->metrics)
2696         xfree (macfont_info->metrics);
2697       macfont_info->cache = NULL;
2698       unblock_input ();
2699     }
2702 static int
2703 macfont_has_char (Lisp_Object font, int c)
2705   int result;
2706   CFCharacterSetRef charset;
2708   block_input ();
2709   if (FONT_ENTITY_P (font))
2710     {
2711       Lisp_Object val;
2712       CFStringRef name;
2714       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2715       val = XCDR (val);
2716       name = XSAVE_POINTER (val, 0);
2717       charset = macfont_get_cf_charset_for_name (name);
2718     }
2719   else
2720     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2722   result = CFCharacterSetIsLongCharacterMember (charset, c);
2723   unblock_input ();
2725   return result;
2728 static unsigned
2729 macfont_encode_char (struct font *font, int c)
2731   CGGlyph glyph;
2733   block_input ();
2734   glyph = macfont_get_glyph_for_character (font, c);
2735   unblock_input ();
2737   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2740 static void
2741 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2742                       struct font_metrics *metrics)
2744   int width, i;
2746   block_input ();
2747   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2748   for (i = 1; i < nglyphs; i++)
2749     {
2750       struct font_metrics m;
2751       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2752                                      NULL, 0);
2754       if (metrics)
2755         {
2756           if (width + m.lbearing < metrics->lbearing)
2757             metrics->lbearing = width + m.lbearing;
2758           if (width + m.rbearing > metrics->rbearing)
2759             metrics->rbearing = width + m.rbearing;
2760           if (m.ascent > metrics->ascent)
2761             metrics->ascent = m.ascent;
2762           if (m.descent > metrics->descent)
2763             metrics->descent = m.descent;
2764         }
2765       width += w;
2766     }
2767   unblock_input ();
2769   if (metrics)
2770     metrics->width = width;
2773 static int
2774 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2775               bool with_background)
2777   struct frame * f = s->f;
2778   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2779   CGRect background_rect;
2780   CGPoint text_position;
2781   CGGlyph *glyphs;
2782   CGPoint *positions;
2783   CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2784   bool no_antialias_p =
2785     (NILP (ns_antialias_text)
2786      || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2787      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2788          && font_size <= macfont_antialias_threshold));
2789   int len = to - from;
2790   struct face *face = s->face;
2791   CGContextRef context;
2793   block_input ();
2795   if (with_background)
2796     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2797                                   s->width, FONT_HEIGHT (s->font));
2798   else
2799     background_rect = CGRectNull;
2801   text_position = CGPointMake (x, -y);
2802   glyphs = xmalloc (sizeof (CGGlyph) * len);
2803   {
2804     CGFloat advance_delta = 0;
2805     int i;
2806     CGFloat total_width = 0;
2808     positions = xmalloc (sizeof (CGPoint) * len);
2809     for (i = 0; i < len; i++)
2810       {
2811         int width;
2813         glyphs[i] = s->char2b[from + i];
2814         width = (s->padding_p ? 1
2815                  : macfont_glyph_extents (s->font, glyphs[i],
2816                                           NULL, &advance_delta,
2817                                           no_antialias_p));
2818         positions[i].x = total_width + advance_delta;
2819         positions[i].y = 0;
2820         total_width += width;
2821       }
2822   }
2824   context = [[NSGraphicsContext currentContext] graphicsPort];
2825   CGContextSaveGState (context);
2827   if (!CGRectIsNull (background_rect))
2828     {
2829       if (s->hl == DRAW_MOUSE_FACE)
2830         {
2831           face = FACE_FROM_ID_OR_NULL (s->f,
2832                                        MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2833           if (!face)
2834             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2835         }
2836       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2837       CGContextFillRects (context, &background_rect, 1);
2838     }
2840   if (macfont_info->cgfont)
2841     {
2842       CGAffineTransform atfm;
2844       CGContextScaleCTM (context, 1, -1);
2845       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2846       if (macfont_info->synthetic_italic_p)
2847         atfm = synthetic_italic_atfm;
2848       else
2849         atfm = CGAffineTransformIdentity;
2850       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2851         {
2852           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2854           /* Stroke line width for text drawing is not correctly
2855              scaled on Retina display/HiDPI mode when drawn to screen
2856              (whereas it is correctly scaled when drawn to bitmaps),
2857              and synthetic bold looks thinner on such environments.
2858              Apple says there are no plans to address this issue
2859              (rdar://11644870) currently.  So we add a workaround.  */
2860 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2861 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2862           if ([[FRAME_NS_VIEW(f) window] respondsToSelector:
2863                                            @selector(backingScaleFactor)])
2864 #endif
2865             CGContextSetLineWidth (context, synthetic_bold_factor * font_size
2866                                    * [[FRAME_NS_VIEW(f) window] backingScaleFactor]);
2867 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2868           else
2869 #endif
2870 #endif
2871 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2872             CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2873 #endif
2874           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2875         }
2876       if (no_antialias_p)
2877         CGContextSetShouldAntialias (context, false);
2879       if (!NILP (ns_use_thin_smoothing))
2880         {
2881           CGContextSetShouldSmoothFonts(context, YES);
2882           CGContextSetFontSmoothingStyle(context, 16);
2883         }
2885       CGContextSetTextMatrix (context, atfm);
2886       CGContextSetTextPosition (context, text_position.x, text_position.y);
2888 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2889       if (macfont_info->color_bitmap_p
2890 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2891           && CTFontDrawGlyphs != NULL
2892 #endif
2893           )
2894         {
2895           if (len > 0)
2896             {
2897               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2898                                 context);
2899             }
2900         }
2901       else
2902 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2903         {
2904           CGContextSetFont (context, macfont_info->cgfont);
2905           CGContextSetFontSize (context, font_size);
2906           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2907         }
2908     }
2911   xfree (glyphs);
2912   xfree (positions);
2913   CGContextRestoreGState (context);
2915   unblock_input ();
2917   return len;
2920 static Lisp_Object
2921 macfont_shape (Lisp_Object lgstring)
2923   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2924   struct macfont_info *macfont_info = (struct macfont_info *) font;
2925   CTFontRef macfont = macfont_info->macfont;
2926   ptrdiff_t glyph_len, len, i, j;
2927   CFIndex nonbmp_len;
2928   UniChar *unichars;
2929   CFIndex *nonbmp_indices;
2930   CFStringRef string;
2931   CFIndex used = 0;
2932   struct mac_glyph_layout *glyph_layouts;
2934   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2935   nonbmp_len = 0;
2936   for (i = 0; i < glyph_len; i++)
2937     {
2938       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2940       if (NILP (lglyph))
2941         break;
2942       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2943         nonbmp_len++;
2944     }
2946   len = i;
2948   if (INT_MAX / 2 < len)
2949     memory_full (SIZE_MAX);
2951   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2952   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2953   for (i = j = 0; i < len; i++)
2954     {
2955       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2957       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2958         {
2959           nonbmp_indices[j] = i + j;
2960           j++;
2961         }
2962     }
2963   nonbmp_indices[j] = len + j;  /* sentinel */
2965   block_input ();
2967   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2968                                                kCFAllocatorNull);
2969   if (string)
2970     {
2971       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2972       if (macfont_info->screen_font)
2973         used = mac_screen_font_shape (macfont_info->screen_font, string,
2974                                       glyph_layouts, glyph_len);
2975       else
2976         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2977       CFRelease (string);
2978     }
2980   unblock_input ();
2982   if (used == 0)
2983     return Qnil;
2985   block_input ();
2987   for (i = 0; i < used; i++)
2988     {
2989       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2990       struct mac_glyph_layout *gl = glyph_layouts + i;
2991       EMACS_INT from, to;
2992       struct font_metrics metrics;
2993       int xoff, yoff, wadjust;
2995       if (NILP (lglyph))
2996         {
2997           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2998           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2999         }
3001       from = gl->comp_range.location;
3002       /* Convert UTF-16 index to UTF-32.  */
3003       j = 0;
3004       while (nonbmp_indices[j] < from)
3005         j++;
3006       from -= j;
3007       LGLYPH_SET_FROM (lglyph, from);
3009       to = gl->comp_range.location + gl->comp_range.length;
3010       /* Convert UTF-16 index to UTF-32.  */
3011       while (nonbmp_indices[j] < to)
3012         j++;
3013       to -= j;
3014       LGLYPH_SET_TO (lglyph, to - 1);
3016       /* LGLYPH_CHAR is used in `describe-char' for checking whether
3017          the composition is trivial.  */
3018       {
3019         UTF32Char c;
3021         if (unichars[gl->string_index] >= 0xD800
3022             && unichars[gl->string_index] < 0xDC00)
3023           c = (((unichars[gl->string_index] - 0xD800) << 10)
3024                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3025         else
3026           c = unichars[gl->string_index];
3027         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3028           c = 0;
3029         LGLYPH_SET_CHAR (lglyph, c);
3030       }
3032       {
3033         unsigned long cc = gl->glyph_id;
3034         LGLYPH_SET_CODE (lglyph, cc);
3035       }
3037       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3038       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3039       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3040       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3041       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3042       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3044       xoff = lround (gl->advance_delta);
3045       yoff = lround (- gl->baseline_delta);
3046       wadjust = lround (gl->advance);
3047       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3048         {
3049           Lisp_Object vec;
3051           vec = Fmake_vector (make_number (3), Qnil);
3052           ASET (vec, 0, make_number (xoff));
3053           ASET (vec, 1, make_number (yoff));
3054           ASET (vec, 2, make_number (wadjust));
3055           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3056         }
3057     }
3059   unblock_input ();
3061   return make_number (used);
3064 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3065 typedef UInt8 UINT24[3];
3067 #pragma pack(push, 1)
3068 struct variation_selector_record
3070   UINT24 var_selector;
3071   UInt32 default_uvs_offset, non_default_uvs_offset;
3073 struct uvs_table
3075   UInt16 format;
3076   UInt32 length, num_var_selector_records;
3077   struct variation_selector_record variation_selector_records[1];
3079 #define SIZEOF_UVS_TABLE_HEADER                                         \
3080   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3082 struct unicode_value_range
3084   UINT24 start_unicode_value;
3085   UInt8 additional_count;
3087 struct default_uvs_table {
3088   UInt32 num_unicode_value_ranges;
3089   struct unicode_value_range unicode_value_ranges[1];
3091 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3092   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3094 struct uvs_mapping
3096   UINT24 unicode_value;
3097   UInt16 glyph_id;
3099 struct non_default_uvs_table
3101   UInt32 num_uvs_mappings;
3102   struct uvs_mapping uvs_mappings[1];
3104 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3105   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3106 #pragma pack(pop)
3108 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3109 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3110    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3111    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3112 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3113 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3114 /* Succeeding one byte should also be accessible.  */
3115 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3116 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3118 /* Return UVS subtable for the specified FONT.  If the subtable is not
3119    found or ill-formatted, then return NULL.  */
3121 static CFDataRef
3122 mac_font_copy_uvs_table (CTFontRef font)
3124   CFDataRef cmap_table, uvs_table = NULL;
3126   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3127                                 kCTFontTableOptionNoOptions);
3128   if (cmap_table)
3129     {
3130       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3131       struct uvs_table *uvs;
3132       struct variation_selector_record *records;
3133       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3135 #if __LP64__
3136       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3137         goto finish;
3138 #endif
3140       cmap_len = CFDataGetLength (cmap_table);
3141       if (sizeof_sfntCMapHeader > cmap_len)
3142         goto finish;
3144       ntables = BUINT16_VALUE (cmap->numTables);
3145       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3146                      / sizeof_sfntCMapEncoding))
3147         goto finish;
3149       for (i = 0; i < ntables; i++)
3150         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3151              == kFontUnicodePlatform)
3152             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3153                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3154           {
3155             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3156             break;
3157           }
3158       if (i == ntables
3159           || uvs_offset > cmap_len
3160           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3161         goto finish;
3163       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3164       uvs_len = BUINT32_VALUE (uvs->length);
3165       if (uvs_len > cmap_len - uvs_offset
3166           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3167         goto finish;
3169       if (BUINT16_VALUE (uvs->format) != 14)
3170         goto finish;
3172       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3173       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3174                       / sizeof (struct variation_selector_record)))
3175         goto finish;
3177       records = uvs->variation_selector_records;
3178       for (i = 0; i < nrecords; i++)
3179         {
3180           UInt32 default_uvs_offset, non_default_uvs_offset;
3182           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3183           if (default_uvs_offset)
3184             {
3185               struct default_uvs_table *default_uvs;
3186               UInt32 nranges;
3188               if (default_uvs_offset > uvs_len
3189                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3190                       > uvs_len - default_uvs_offset))
3191                 goto finish;
3193               default_uvs = ((struct default_uvs_table *)
3194                              ((UInt8 *) uvs + default_uvs_offset));
3195               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3196               if (nranges > ((uvs_len - default_uvs_offset
3197                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3198                              / sizeof (struct unicode_value_range)))
3199                 goto finish;
3200               /* Now 2 * nranges can't overflow, so we can safely use
3201                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3202                  mac_font_get_glyphs_for_variants.  */
3203             }
3205           non_default_uvs_offset =
3206             BUINT32_VALUE (records[i].non_default_uvs_offset);
3207           if (non_default_uvs_offset)
3208             {
3209               struct non_default_uvs_table *non_default_uvs;
3210               UInt32 nmappings;
3212               if (non_default_uvs_offset > uvs_len
3213                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3214                       > uvs_len - non_default_uvs_offset))
3215                 goto finish;
3217               non_default_uvs = ((struct non_default_uvs_table *)
3218                                  ((UInt8 *) uvs + non_default_uvs_offset));
3219               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3220               if (nmappings > ((uvs_len - non_default_uvs_offset
3221                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3222                                / sizeof (struct uvs_mapping)))
3223                 goto finish;
3224               /* Now 2 * nmappings can't overflow, so we can safely
3225                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3226                  in mac_font_get_glyphs_for_variants.  */
3227             }
3228         }
3230       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3232     finish:
3233       CFRelease (cmap_table);
3234     }
3236   return uvs_table;
3239 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3240    sequence consisting of the given base character C and each
3241    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3242    result (explained below) into the corresponding GLYPHS[i].  If the
3243    entry is found in the Default UVS Table, then the result is 0.  If
3244    the entry is found in the Non-Default UVS Table, then the result is
3245    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3246    elements in SELECTORS must be sorted in strictly increasing
3247    order.  */
3249 static void
3250 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3251                                   const UTF32Char selectors[], CGGlyph glyphs[],
3252                                   CFIndex count)
3254   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3255   struct variation_selector_record *records = uvs->variation_selector_records;
3256   CFIndex i;
3257   UInt32 ir, nrecords;
3259   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3260   i = 0;
3261   ir = 0;
3262   while (i < count && ir < nrecords)
3263     {
3264       UInt32 default_uvs_offset, non_default_uvs_offset;
3266       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3267         {
3268           glyphs[i++] = kCGFontIndexInvalid;
3269           continue;
3270         }
3271       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3272         {
3273           ir++;
3274           continue;
3275         }
3277       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3278       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3279       non_default_uvs_offset =
3280         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3282       glyphs[i] = kCGFontIndexInvalid;
3284       if (default_uvs_offset)
3285         {
3286           struct default_uvs_table *default_uvs =
3287             (struct default_uvs_table *) ((UInt8 *) uvs
3288                                           + default_uvs_offset);
3289           struct unicode_value_range *ranges =
3290             default_uvs->unicode_value_ranges;
3291           UInt32 lo, hi;
3293           lo = 0;
3294           hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3295           while (lo < hi)
3296             {
3297               UInt32 mid = (lo + hi) / 2;
3299               if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3300                 hi = mid;
3301               else
3302                 lo = mid + 1;
3303             }
3304           if (hi > 0
3305               && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3306                         + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3307             glyphs[i] = 0;
3308         }
3310       if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3311         {
3312           struct non_default_uvs_table *non_default_uvs =
3313             (struct non_default_uvs_table *) ((UInt8 *) uvs
3314                                               + non_default_uvs_offset);
3315           struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3316           UInt32 lo, hi;
3318           lo = 0;
3319           hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3320           while (lo < hi)
3321             {
3322               UInt32 mid = (lo + hi) / 2;
3324               if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3325                 hi = mid;
3326               else
3327                 lo = mid + 1;
3328             }
3329           if (hi > 0 &&
3330               BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3331             glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3332         }
3333       i++;
3334       ir++;
3335     }
3336   while (i < count)
3337     glyphs[i++] = kCGFontIndexInvalid;
3340 static int
3341 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3343   CFDataRef uvs_table;
3344   NSCharacterCollection uvs_collection;
3345   int i, n = 0;
3347   block_input ();
3348   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3350   if (uvs_table)
3351     {
3352       UTF32Char selectors[256];
3353       CGGlyph glyphs[256];
3355       for (i = 0; i < 16; i++)
3356         selectors[i] = 0xFE00 + i;
3357       for (; i < 256; i++)
3358         selectors[i] = 0xE0100 + (i - 16);
3359       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3360       for (i = 0; i < 256; i++)
3361         {
3362           CGGlyph glyph = glyphs[i];
3364           if (uvs_collection != NSIdentityMappingCharacterCollection
3365               && glyph != kCGFontIndexInvalid)
3366             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3367           if (glyph == kCGFontIndexInvalid)
3368             variations[i] = 0;
3369           else
3370             {
3371               variations[i] = (glyph ? glyph
3372                                : macfont_get_glyph_for_character (font, c));
3373               n++;
3374             }
3375         }
3376     }
3377   unblock_input ();
3379   return n;
3382 static const char *const macfont_booleans[] = {
3383   ":antialias",
3384   ":minspace",
3385   NULL,
3388 static const char *const macfont_non_booleans[] = {
3389   ":lang",
3390   ":script",
3391   ":destination",
3392   NULL,
3395 static void
3396 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3398   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3401 static Boolean
3402 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3403                                         CFArrayRef languages)
3405   Boolean result = true;
3406   CFArrayRef desc_languages =
3407     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3409   if (desc_languages == NULL)
3410     result = false;
3411   else
3412     {
3413       CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3414       CFIndex i, languages_count = CFArrayGetCount (languages);
3416       for (i = 0; i < languages_count; i++)
3417         {
3418           CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3420           if (!CFArrayContainsValue (desc_languages, range, language)
3421               /* PingFang SC contains "zh" and "zh-Hant" as covered
3422                  languages, but does not contain "zh-Hans".  */
3423               && !(CFEqual (language, CFSTR ("zh-Hans"))
3424                    && CFArrayContainsValue (desc_languages, range,
3425                                             CFSTR ("zh"))))
3426             {
3427               result = false;
3428               break;
3429             }
3430         }
3431       CFRelease (desc_languages);
3432     }
3434   return result;
3437 static CFStringRef
3438 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3440   CFStringRef result = NULL;
3441   CFStringRef charset_string =
3442     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3444   if (charset_string && CFStringGetLength (charset_string) > 0)
3445     {
3446       CFStringRef keys[] = {
3447 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3448         kCTLanguageAttributeName
3449 #else
3450         CFSTR ("NSLanguage")
3451 #endif
3452       };
3453       CFTypeRef values[] = {NULL};
3454       CFIndex num_values = 0;
3455       CFArrayRef languages
3456         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3458       if (languages && CFArrayGetCount (languages) > 0)
3459         {
3460           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3461             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3462           else
3463             {
3464               CFCharacterSetRef charset =
3465                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3467               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3468             }
3469         }
3470       if (result == NULL)
3471         {
3472           CFAttributedStringRef attr_string = NULL;
3473           CTLineRef ctline = NULL;
3474           CFDictionaryRef attrs
3475             = CFDictionaryCreate (NULL, (const void **) keys,
3476                                   (const void **) values, num_values,
3477                                   &kCFTypeDictionaryKeyCallBacks,
3478                                   &kCFTypeDictionaryValueCallBacks);
3480           if (attrs)
3481             {
3482               attr_string = CFAttributedStringCreate (NULL, charset_string,
3483                                                       attrs);
3484               CFRelease (attrs);
3485             }
3486           if (attr_string)
3487             {
3488               ctline = CTLineCreateWithAttributedString (attr_string);
3489               CFRelease (attr_string);
3490             }
3491           if (ctline)
3492             {
3493               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3494               CFIndex i, nruns = CFArrayGetCount (runs);
3495               CTFontRef font;
3497               for (i = 0; i < nruns; i++)
3498                 {
3499                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3500                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3501                   CTFontRef font_in_run;
3503                   if (attributes == NULL)
3504                     break;
3505                   font_in_run =
3506                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3507                   if (font_in_run == NULL)
3508                     break;
3509                   if (i == 0)
3510                     font = font_in_run;
3511                   else if (!mac_font_equal_in_postscript_name (font,
3512                                                                font_in_run))
3513                     break;
3514                 }
3515               if (nruns > 0 && i == nruns)
3516                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3517               CFRelease (ctline);
3518             }
3519         }
3520     }
3522   return result;
3525 static inline double
3526 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3528   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3529                                      &glyph, NULL, 1);
3532 static inline CGRect
3533 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3535   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3536                                           &glyph, NULL, 1);
3539 static CFArrayRef
3540 mac_font_create_available_families (void)
3542   CFMutableArrayRef families = NULL;
3543   CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3545   if (orig_families)
3546     {
3547       CFIndex i, count = CFArrayGetCount (orig_families);
3549       families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3550       if (families)
3551         for (i = 0; i < count; i++)
3552           {
3553             CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3555             if (!CFStringHasPrefix (family, CFSTR ("."))
3556                 && (CTFontManagerCompareFontFamilyNames (family,
3557                                                          CFSTR ("LastResort"),
3558                                                          NULL)
3559                     != kCFCompareEqualTo))
3560               CFArrayAppendValue (families, family);
3561           }
3562       CFRelease (orig_families);
3563     }
3565   return families;
3568 static Boolean
3569 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3571   Boolean result;
3572   CFStringRef name1, name2;
3574   if (font1 == font2)
3575     return true;
3577   result = false;
3578   name1 = CTFontCopyPostScriptName (font1);
3579   if (name1)
3580     {
3581       name2 = CTFontCopyPostScriptName (font2);
3582       if (name2)
3583         {
3584           result = CFEqual (name1, name2);
3585           CFRelease (name2);
3586         }
3587       CFRelease (name1);
3588     }
3590   return result;
3593 static CTLineRef
3594 mac_font_create_line_with_string_and_font (CFStringRef string,
3595                                            CTFontRef macfont)
3597   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3598   CFTypeRef values[] = {NULL, NULL};
3599   CFDictionaryRef attributes = NULL;
3600   CFAttributedStringRef attr_string = NULL;
3601   CTLineRef ctline = NULL;
3602   float float_zero = 0.0f;
3604   values[0] = macfont;
3605   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3606   if (values[1])
3607     {
3608       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3609                                        (const void **) values,
3610                                        ARRAYELTS (keys),
3611                                        &kCFTypeDictionaryKeyCallBacks,
3612                                        &kCFTypeDictionaryValueCallBacks);
3613       CFRelease (values[1]);
3614     }
3615   if (attributes)
3616     {
3617       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3618       CFRelease (attributes);
3619     }
3620   if (attr_string)
3621     {
3622       ctline = CTLineCreateWithAttributedString (attr_string);
3623       CFRelease (attr_string);
3624     }
3625   if (ctline)
3626     {
3627       /* Abandon if ctline contains some fonts other than the
3628          specified one.  */
3629       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3630       CFIndex i, nruns = CFArrayGetCount (runs);
3632       for (i = 0; i < nruns; i++)
3633         {
3634           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3635           CFDictionaryRef attributes = CTRunGetAttributes (run);
3636           CTFontRef font_in_run;
3638           if (attributes == NULL)
3639             break;
3640           font_in_run =
3641             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3642           if (font_in_run == NULL)
3643             break;
3644           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3645             break;
3646         }
3647       if (i < nruns)
3648         {
3649           CFRelease (ctline);
3650           ctline = NULL;
3651         }
3652     }
3654   return ctline;
3657 static CFIndex
3658 mac_font_shape (CTFontRef font, CFStringRef string,
3659                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3661   CFIndex used, result = 0;
3662   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3664   if (ctline == NULL)
3665     return 0;
3667   used = CTLineGetGlyphCount (ctline);
3668   if (used <= glyph_len)
3669     {
3670       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3671       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3672       CGFloat total_advance = 0;
3673       CFIndex total_glyph_count = 0;
3675       for (k = 0; k < ctrun_count; k++)
3676         {
3677           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3678           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3679           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3680           CFRange string_range, comp_range, range;
3681           CFIndex *permutation;
3683           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3684             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3685           else
3686             permutation = NULL;
3688 #define RIGHT_TO_LEFT_P permutation
3690           /* Now the `comp_range' member of struct mac_glyph_layout is
3691              temporarily used as a work area such that:
3692              glbuf[i].comp_range.location =
3693              min {compRange[i + 1].location, ...,
3694                      compRange[glyph_count - 1].location,
3695                      maxRange (stringRangeForCTRun)}
3696              glbuf[i].comp_range.length = maxRange (compRange[i])
3697              where compRange[i] is the range of composed characters
3698              containing i-th glyph.  */
3699           string_range = CTRunGetStringRange (ctrun);
3700           min_location = string_range.location + string_range.length;
3701           for (i = 0; i < glyph_count; i++)
3702             {
3703               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3704               CFIndex glyph_index;
3705               CFRange rng;
3707               if (!RIGHT_TO_LEFT_P)
3708                 glyph_index = glyph_count - i - 1;
3709               else
3710                 glyph_index = i;
3711               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3712                                      &gl->string_index);
3713               rng =
3714                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3715                                                              gl->string_index);
3716               gl->comp_range.location = min_location;
3717               gl->comp_range.length = rng.location + rng.length;
3718               if (rng.location < min_location)
3719                 min_location = rng.location;
3720             }
3722           /* Fill the `comp_range' member of struct mac_glyph_layout,
3723              and setup a permutation for right-to-left text.  */
3724           comp_range = CFRangeMake (string_range.location, 0);
3725           range = CFRangeMake (0, 0);
3726           while (1)
3727             {
3728               struct mac_glyph_layout *gl =
3729                 glbuf + range.location + range.length;
3731               if (gl->comp_range.length
3732                   > comp_range.location + comp_range.length)
3733                 comp_range.length = gl->comp_range.length - comp_range.location;
3734               min_location = gl->comp_range.location;
3735               range.length++;
3737               if (min_location >= comp_range.location + comp_range.length)
3738                 {
3739                   comp_range.length = min_location - comp_range.location;
3740                   for (i = 0; i < range.length; i++)
3741                     {
3742                       glbuf[range.location + i].comp_range = comp_range;
3743                       if (RIGHT_TO_LEFT_P)
3744                         permutation[range.location + i] =
3745                           range.location + range.length - i - 1;
3746                     }
3748                   comp_range = CFRangeMake (min_location, 0);
3749                   range.location += range.length;
3750                   range.length = 0;
3751                   if (range.location == glyph_count)
3752                     break;
3753                 }
3754             }
3756           /* Then fill the remaining members.  */
3757           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3758                range.location++)
3759             {
3760               struct mac_glyph_layout *gl;
3761               CGPoint position;
3762               CGFloat max_x;
3764               if (!RIGHT_TO_LEFT_P)
3765                 gl = glbuf + range.location;
3766               else
3767                 {
3768                   CFIndex src, dest;
3770                   src = glyph_count - 1 - range.location;
3771                   dest = permutation[src];
3772                   gl = glbuf + dest;
3773                   if (src < dest)
3774                     {
3775                       CFIndex tmp = gl->string_index;
3777                       gl->string_index = glbuf[src].string_index;
3778                       glbuf[src].string_index = tmp;
3779                     }
3780                 }
3781               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3783               CTRunGetPositions (ctrun, range, &position);
3784               max_x = position.x + CTRunGetTypographicBounds (ctrun, range,
3785                                                               NULL, NULL, NULL);
3786               max_x = max (max_x, total_advance);
3787               gl->advance_delta = position.x - total_advance;
3788               gl->baseline_delta = position.y;
3789               gl->advance = max_x - total_advance;
3790               total_advance = max_x;
3791             }
3793           if (RIGHT_TO_LEFT_P)
3794             xfree (permutation);
3796 #undef RIGHT_TO_LEFT_P
3798           total_glyph_count += glyph_count;
3799         }
3801       result = used;
3802     }
3803   CFRelease (ctline);
3805   return result;
3808 /* The function below seems to cause a memory leak for the CFString
3809    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3810    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3811 #if USE_CT_GLYPH_INFO
3812 static CGGlyph
3813 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3814                               CGFontIndex cid)
3816   CGGlyph result = kCGFontIndexInvalid;
3817   UniChar characters[] = {0xfffd};
3818   CFStringRef string;
3819   CFAttributedStringRef attr_string = NULL;
3820   CTLineRef ctline = NULL;
3822   string = CFStringCreateWithCharacters (NULL, characters,
3823                                          ARRAYELTS (characters));
3825   if (string)
3826     {
3827       CTGlyphInfoRef glyph_info =
3828         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3829       CFDictionaryRef attributes = NULL;
3831       if (glyph_info)
3832         {
3833           CFStringRef keys[] = {kCTFontAttributeName,
3834                                 kCTGlyphInfoAttributeName};
3835           CFTypeRef values[] = {font, glyph_info};
3837           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3838                                            (const void **) values,
3839                                            ARRAYELTS (keys),
3840                                            &kCFTypeDictionaryKeyCallBacks,
3841                                            &kCFTypeDictionaryValueCallBacks);
3842           CFRelease (glyph_info);
3843         }
3844       if (attributes)
3845         {
3846           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3847           CFRelease (attributes);
3848         }
3849       CFRelease (string);
3850     }
3851   if (attr_string)
3852     {
3853       ctline = CTLineCreateWithAttributedString (attr_string);
3854       CFRelease (attr_string);
3855     }
3856   if (ctline)
3857     {
3858       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3860       if (CFArrayGetCount (runs) > 0)
3861         {
3862           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3863           CFDictionaryRef attributes = CTRunGetAttributes (run);
3865           if (attributes)
3866             {
3867               CTFontRef font_in_run =
3868                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3870               if (font_in_run
3871                   && mac_font_equal_in_postscript_name (font_in_run, font))
3872                 {
3873                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3874                   if (result >= CTFontGetGlyphCount (font))
3875                     result = kCGFontIndexInvalid;
3876                 }
3877             }
3878         }
3879       CFRelease (ctline);
3880     }
3882   return result;
3884 #endif
3886 static CFArrayRef
3887 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3889   CFArrayRef result = NULL;
3891 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3892 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3893   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3894 #endif
3895     {
3896       CTFontRef user_font =
3897         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3899       if (user_font)
3900         {
3901           CFArrayRef languages =
3902             CFArrayCreate (NULL, (const void **) &language, 1,
3903                            &kCFTypeArrayCallBacks);
3905           if (languages)
3906             {
3907               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3908                                                                  languages);
3909               CFRelease (languages);
3910             }
3911           CFRelease (user_font);
3912         }
3913     }
3914 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3915   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3916 #endif
3917 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3918 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3919     {
3920       CFIndex i;
3922       for (i = 0; macfont_language_default_font_names[i].language; i++)
3923         {
3924           if (CFEqual (macfont_language_default_font_names[i].language,
3925                        language))
3926             {
3927               CFMutableArrayRef descriptors =
3928                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3930               if (descriptors)
3931                 {
3932                   CFIndex j;
3934                   for (j = 0;
3935                        macfont_language_default_font_names[i].font_names[j];
3936                        j++)
3937                     {
3938                       CFDictionaryRef attributes =
3939                         CFDictionaryCreate (NULL,
3940                                             ((const void **)
3941                                              &kCTFontNameAttribute),
3942                                             ((const void **)
3943                                              &macfont_language_default_font_names[i].font_names[j]),
3944                                             1, &kCFTypeDictionaryKeyCallBacks,
3945                                             &kCFTypeDictionaryValueCallBacks);
3947                       if (attributes)
3948                         {
3949                           CTFontDescriptorRef pat_desc =
3950                             CTFontDescriptorCreateWithAttributes (attributes);
3952                           if (pat_desc)
3953                             {
3954                               CTFontDescriptorRef descriptor =
3955                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3957                               if (descriptor)
3958                                 {
3959                                   CFArrayAppendValue (descriptors, descriptor);
3960                                   CFRelease (descriptor);
3961                                 }
3962                               CFRelease (pat_desc);
3963                             }
3964                           CFRelease (attributes);
3965                         }
3966                     }
3967                   result = descriptors;
3968                 }
3969               break;
3970             }
3971         }
3972     }
3973 #endif
3975   return result;
3978 static CFStringRef
3979 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3980                                                       CFArrayRef languages)
3982   CFStringRef result = NULL;
3983   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3984   CFArrayRef descriptors =
3985     mac_font_copy_default_descriptors_for_language (language);
3987   if (descriptors)
3988     {
3989       CFIndex i, count = CFArrayGetCount (descriptors);
3991       for (i = 0; i < count; i++)
3992         {
3993           CTFontDescriptorRef descriptor =
3994             CFArrayGetValueAtIndex (descriptors, i);
3996           if (macfont_supports_charset_and_languages_p (descriptor, charset,
3997                                                         Qnil, languages))
3998             {
3999               CFStringRef family =
4000                 CTFontDescriptorCopyAttribute (descriptor,
4001                                                kCTFontFamilyNameAttribute);
4002               if (family)
4003                 {
4004                   if (!CFStringHasPrefix (family, CFSTR ("."))
4005                       && !CFEqual (family, CFSTR ("LastResort")))
4006                     {
4007                       result = family;
4008                       break;
4009                     }
4010                   else
4011                     CFRelease (family);
4012                 }
4013             }
4014         }
4015       CFRelease (descriptors);
4016     }
4018   return result;
4021 void *
4022 macfont_get_nsctfont (struct font *font)
4024   struct macfont_info *macfont_info = (struct macfont_info *) font;
4025   CTFontRef macfont = macfont_info->macfont;
4027   return (void *) macfont;
4030 void
4031 mac_register_font_driver (struct frame *f)
4033   register_font_driver (&macfont_driver, f);
4037 void
4038 syms_of_macfont (void)
4040   /* Core Text, for macOS.  */
4041   DEFSYM (Qmac_ct, "mac-ct");
4042   register_font_driver (&macfont_driver, NULL);
4044   /* The font property key specifying the font design destination.  The
4045      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4046      text.  (See the documentation of X Logical Font Description
4047      Conventions.)  In the Mac font driver, 1 means the screen font is
4048      used for calculating some glyph metrics.  You can see the
4049      difference with Monaco 8pt or 9pt, for example.  */
4050   DEFSYM (QCdestination, ":destination");
4052   /* The boolean-valued font property key specifying the use of leading.  */
4053   DEFSYM (QCminspace, ":minspace");
4055   macfont_family_cache = Qnil;
4056   staticpro (&macfont_family_cache);