Merge branch 'master' into comment-cache
[emacs.git] / src / macfont.m
blobf356842db189d06e90021de7587de917b04ce52c
1 /* Font driver on macOS Core text.
2    Copyright (C) 2009-2017 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or (at
9 your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
19 Original author: YAMAMOTO Mitsuharu
22 #include <config.h>
24 #include "lisp.h"
25 #include "dispextern.h"
26 #include "frame.h"
27 #include "blockinput.h"
28 #include "character.h"
29 #include "charset.h"
30 #include "composite.h"
31 #include "fontset.h"
32 #include "font.h"
33 #include "termchar.h"
34 #include "nsgui.h"
35 #include "nsterm.h"
36 #include "macfont.h"
37 #include "macuvs.h"
39 #include <libkern/OSByteOrder.h>
41 static 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, CTCharacterCollection 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];
287   [layoutManager setUsesScreenFonts:YES];
289   [layoutManager addTextContainer:textContainer];
290   [textContainer release];
291   [textStorage addLayoutManager:layoutManager];
292   [layoutManager release];
294   if (!(textStorage && layoutManager && textContainer))
295     {
296       [textStorage release];
298       return false;
299     }
301   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
302                                                  effectiveRange:NULL];
303   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
304   [textStorage release];
306   *ascent = spaceLocation.y;
307   *descent = NSHeight (usedRect) - spaceLocation.y;
308   *leading = 0;
309   descender = [nsFont descender];
310   if (- descender < *descent)
311     {
312       *leading = *descent + descender;
313       *descent = - descender;
314     }
316   return true;
319 static CFIndex
320 mac_font_shape_1 (NSFont *font, NSString *string,
321                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
322                   BOOL screen_font_p)
324   NSUInteger i;
325   CFIndex result = 0;
326   NSTextStorage *textStorage;
327   NSLayoutManager *layoutManager;
328   NSTextContainer *textContainer;
329   NSUInteger stringLength;
330   NSPoint spaceLocation;
331   NSUInteger used, numberOfGlyphs;
333   textStorage = [[NSTextStorage alloc] initWithString:string];
334   layoutManager = [[NSLayoutManager alloc] init];
335   textContainer = [[NSTextContainer alloc] init];
337   /* Append a trailing space to measure baseline position.  */
338   [textStorage appendAttributedString:([[[NSAttributedString alloc]
339                                           initWithString:@" "] autorelease])];
340   [textStorage setFont:font];
341   [textContainer setLineFragmentPadding:0];
342   [layoutManager setUsesScreenFonts:screen_font_p];
344   [layoutManager addTextContainer:textContainer];
345   [textContainer release];
346   [textStorage addLayoutManager:layoutManager];
347   [layoutManager release];
349   if (!(textStorage && layoutManager && textContainer))
350     {
351       [textStorage release];
353       return 0;
354     }
356   stringLength = [string length];
358   /* Force layout.  */
359   (void) [layoutManager glyphRangeForTextContainer:textContainer];
361   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
363   /* Remove the appended trailing space because otherwise it may
364      generate a wrong result for a right-to-left text.  */
365   [textStorage beginEditing];
366   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
367   [textStorage endEditing];
368   (void) [layoutManager glyphRangeForTextContainer:textContainer];
370   i = 0;
371   while (i < stringLength)
372     {
373       NSRange range;
374       NSFont *fontInTextStorage =
375         [textStorage attribute:NSFontAttributeName atIndex:i
376                      longestEffectiveRange:&range
377                        inRange:(NSMakeRange (0, stringLength))];
379       if (!(fontInTextStorage == font
380             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
381         break;
382       i = NSMaxRange (range);
383     }
384   if (i < stringLength)
385     /* Make the test `used <= glyph_len' below fail if textStorage
386        contained some fonts other than the specified one.  */
387     used = glyph_len + 1;
388   else
389     {
390       NSRange range = NSMakeRange (0, stringLength);
392       range = [layoutManager glyphRangeForCharacterRange:range
393                                     actualCharacterRange:NULL];
394       numberOfGlyphs = NSMaxRange (range);
395       used = numberOfGlyphs;
396       for (i = 0; i < numberOfGlyphs; i++)
397         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
398           used--;
399     }
401   if (0 < used && used <= glyph_len)
402     {
403       NSUInteger glyphIndex, prevGlyphIndex;
404       unsigned char bidiLevel;
405       NSUInteger *permutation;
406       NSRange compRange, range;
407       CGFloat totalAdvance;
409       glyphIndex = 0;
410       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
411         glyphIndex++;
413       /* For now we assume the direction is not changed within the
414          string.  */
415       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
416                                glyphs:NULL characterIndexes:NULL
417                     glyphInscriptions:NULL elasticBits:NULL
418                            bidiLevels:&bidiLevel];
419       if (bidiLevel & 1)
420         permutation = xmalloc (sizeof (NSUInteger) * used);
421       else
422         permutation = NULL;
424 #define RIGHT_TO_LEFT_P permutation
426       /* Fill the `comp_range' member of struct mac_glyph_layout, and
427          setup a permutation for right-to-left text.  */
428       compRange = NSMakeRange (0, 0);
429       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
430            range.length++)
431         {
432           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
433           NSUInteger characterIndex =
434             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
436           gl->string_index = characterIndex;
438           if (characterIndex >= NSMaxRange (compRange))
439             {
440               compRange.location = NSMaxRange (compRange);
441               do
442                 {
443                   NSRange characterRange =
444                     [string
445                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
447                   compRange.length =
448                     NSMaxRange (characterRange) - compRange.location;
449                   [layoutManager glyphRangeForCharacterRange:compRange
450                                         actualCharacterRange:&characterRange];
451                   characterIndex = NSMaxRange (characterRange) - 1;
452                 }
453               while (characterIndex >= NSMaxRange (compRange));
455               if (RIGHT_TO_LEFT_P)
456                 for (i = 0; i < range.length; i++)
457                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
459               range = NSMakeRange (NSMaxRange (range), 0);
460             }
462           gl->comp_range.location = compRange.location;
463           gl->comp_range.length = compRange.length;
465           while (++glyphIndex < numberOfGlyphs)
466             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
467               break;
468         }
469       if (RIGHT_TO_LEFT_P)
470         for (i = 0; i < range.length; i++)
471           permutation[range.location + i] = NSMaxRange (range) - i - 1;
473       /* Then fill the remaining members.  */
474       glyphIndex = prevGlyphIndex = 0;
475       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
476         glyphIndex++;
478       if (!RIGHT_TO_LEFT_P)
479         totalAdvance = 0;
480       else
481         {
482           NSUInteger nrects;
483           NSRect *glyphRects =
484             [layoutManager
485               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
486               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
487                      inTextContainer:textContainer rectCount:&nrects];
489           totalAdvance = NSMaxX (glyphRects[0]);
490         }
492       for (i = 0; i < used; i++)
493         {
494           struct mac_glyph_layout *gl;
495           NSPoint location;
496           NSUInteger nextGlyphIndex;
497           NSRange glyphRange;
498           NSRect *glyphRects;
499           NSUInteger nrects;
501           if (!RIGHT_TO_LEFT_P)
502             gl = glyph_layouts + i;
503           else
504             {
505               NSUInteger dest = permutation[i];
507               gl = glyph_layouts + dest;
508               if (i < dest)
509                 {
510                   CFIndex tmp = gl->string_index;
512                   gl->string_index = glyph_layouts[i].string_index;
513                   glyph_layouts[i].string_index = tmp;
514                 }
515             }
516           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
518           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
519           gl->baseline_delta = spaceLocation.y - location.y;
521           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
522                nextGlyphIndex++)
523             if (![layoutManager
524                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
525               break;
527           if (!RIGHT_TO_LEFT_P)
528             {
529               CGFloat maxX;
531               if (prevGlyphIndex == 0)
532                 glyphRange = NSMakeRange (0, nextGlyphIndex);
533               else
534                 glyphRange = NSMakeRange (glyphIndex,
535                                           nextGlyphIndex - glyphIndex);
536               glyphRects =
537                 [layoutManager
538                   rectArrayForGlyphRange:glyphRange
539                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
540                          inTextContainer:textContainer rectCount:&nrects];
541               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
542               gl->advance_delta = location.x - totalAdvance;
543               gl->advance = maxX - totalAdvance;
544               totalAdvance = maxX;
545             }
546           else
547             {
548               CGFloat minX;
550               if (nextGlyphIndex == numberOfGlyphs)
551                 glyphRange = NSMakeRange (prevGlyphIndex,
552                                           numberOfGlyphs - prevGlyphIndex);
553               else
554                 glyphRange = NSMakeRange (prevGlyphIndex,
555                                           glyphIndex + 1 - prevGlyphIndex);
556               glyphRects =
557                 [layoutManager
558                   rectArrayForGlyphRange:glyphRange
559                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
560                          inTextContainer:textContainer rectCount:&nrects];
561               minX = min (NSMinX (glyphRects[0]), totalAdvance);
562               gl->advance = totalAdvance - minX;
563               totalAdvance = minX;
564               gl->advance_delta = location.x - totalAdvance;
565             }
567           prevGlyphIndex = glyphIndex + 1;
568           glyphIndex = nextGlyphIndex;
569         }
571       if (RIGHT_TO_LEFT_P)
572         xfree (permutation);
574 #undef RIGHT_TO_LEFT_P
576       result = used;
577     }
578   [textStorage release];
580   return result;
583 static CFIndex
584 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
585                        struct mac_glyph_layout *glyph_layouts,
586                        CFIndex glyph_len)
588   return mac_font_shape_1 ([(NSFont *)font printerFont],
589                            (NSString *) string,
590                            glyph_layouts, glyph_len, YES);
593 static CGColorRef
594 get_cgcolor(unsigned long idx, struct frame *f)
596   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
597   [nsColor set];
598   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
599   NSInteger noc = [nsColor numberOfComponents];
600   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
601   CGColorRef cgColor;
603   [nsColor getComponents: components];
604   cgColor = CGColorCreate (colorSpace, components);
605   xfree (components);
606   return cgColor;
609 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
610   do {                                                                  \
611     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
612     CGContextSetFillColorWithColor (context, refcol_) ;                 \
613     CGColorRelease (refcol_);                                           \
614   } while (0)
615 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f)        \
616   do {                                                                  \
617     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f);    \
618     CGContextSetFillColorWithColor (context, refcol_);                  \
619     CGColorRelease (refcol_);                                           \
620   } while (0)
621 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f)      \
622   do {                                                                  \
623     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
624     CGContextSetStrokeColorWithColor (context, refcol_);                \
625     CGColorRelease (refcol_);                                           \
626   } while (0)
630 /* Mac font driver.  */
632 static struct
634   /* registry name */
635   const char *name;
636   /* characters to distinguish the charset from the others */
637   int uniquifier[6];
638   /* additional constraint by language */
639   CFStringRef lang;
640   /* set on demand */
641   CFCharacterSetRef cf_charset;
642   CFStringRef cf_charset_string;
643 } cf_charset_table[] =
644   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
645     { "iso8859-2", { 0x00A0, 0x010E }},
646     { "iso8859-3", { 0x00A0, 0x0108 }},
647     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
648     { "iso8859-5", { 0x00A0, 0x0401 }},
649     { "iso8859-6", { 0x00A0, 0x060C }},
650     { "iso8859-7", { 0x00A0, 0x0384 }},
651     { "iso8859-8", { 0x00A0, 0x05D0 }},
652     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
653     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
654     { "iso8859-11", { 0x00A0, 0x0E01 }},
655     { "iso8859-13", { 0x00A0, 0x201C }},
656     { "iso8859-14", { 0x00A0, 0x0174 }},
657     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
658     { "iso8859-16", { 0x00A0, 0x0218}},
659     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
660     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
661     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
662     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
663     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
664     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
665     { "cns11643.1992-3", { 0x201A9 }},
666     { "cns11643.1992-4", { 0x20057 }},
667     { "cns11643.1992-5", { 0x20000 }},
668     { "cns11643.1992-6", { 0x20003 }},
669     { "cns11643.1992-7", { 0x20055 }},
670     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
671     { "jisx0212.1990-0", { 0x4E44 }},
672     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
673     { "jisx0213.2000-2", { 0xFA49 }},
674     { "jisx0213.2004-1", { 0x20B9F }},
675     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
676     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
677     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
678     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
679     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
680     { "unicode-sip", { 0x20000 }},
681     { NULL }
682   };
684 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
685 static const struct
687   CFStringRef language;
688   CFStringRef font_names[3];
689 } macfont_language_default_font_names[] = {
690   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
691                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
692                     NULL }},
693   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
694                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
695                     NULL }},
696   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
697                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
698                          NULL }},
699   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
700                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
701                          NULL }},
702   { NULL }
704 #endif
706 static CGFloat macfont_antialias_threshold;
708 void
709 macfont_update_antialias_threshold (void)
711   int threshold;
712   Boolean valid_p;
714   threshold =
715     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
716                                      kCFPreferencesCurrentApplication,
717                                      &valid_p);
718   if (valid_p)
719     macfont_antialias_threshold = threshold;
722 static inline Lisp_Object
723 macfont_intern_prop_cfstring (CFStringRef cfstring)
725   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
727   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
730 static inline CFIndex
731 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
733   if (c < 0x10000)
734     {
735       unichars[0] = c;
737       return 1;
738     }
739   else
740     {
741       c -= 0x10000;
742       unichars[0] = (c >> 10) + 0xD800;
743       unichars[1] = (c & 0x3FF) + 0xDC00;
745       return 2;
746     }
749 static Boolean
750 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
751                                          CTFontSymbolicTraits *sym_traits)
753   SInt64 sint64_value;
755   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
756      OS X 10.6 when the value is greater than or equal to 1 << 31.  */
757   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
758     {
759       *sym_traits = (CTFontSymbolicTraits) sint64_value;
761       return true;
762     }
764   return false;
767 static CGFloat
768 mac_font_descriptor_get_adjusted_weight (CTFontDescriptorRef desc, CGFloat val)
770   long percent_val = lround (val * 100);
772   if (percent_val == -40)
773     {
774       CTFontRef font = NULL;
775       CFStringRef name =
776         CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
778       if (name)
779         {
780           font = CTFontCreateWithName (name, 0, NULL);
781           CFRelease (name);
782         }
783       if (font)
784         {
785           CFIndex weight = mac_font_get_weight (font);
787           /* Workaround for crash when displaying Oriya characters
788              with Arial Unicode MS on OS X 10.11.  */
789           if (weight == 5)
790             val = 0;
791           CFRelease (font);
792         }
793     }
795   return val;
798 static void
799 macfont_store_descriptor_attributes (CTFontDescriptorRef desc,
800                                      Lisp_Object spec_or_entity)
802   CFStringRef str;
803   CFDictionaryRef dict;
804   CFNumberRef num;
805   CGFloat floatval;
807   str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
808   if (str)
809     {
810       ASET (spec_or_entity, FONT_FAMILY_INDEX,
811             macfont_intern_prop_cfstring (str));
812       CFRelease (str);
813     }
814   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
815   if (dict)
816     {
817       struct {
818         enum font_property_index index;
819         CFStringRef trait;
820         CGPoint points[6];
821         CGFloat (*adjust_func) (CTFontDescriptorRef, CGFloat);
822       } numeric_traits[] =
823           {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
824             {{-0.4, 50},        /* light */
825              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
826              {0, 100},          /* normal */
827              {0.24, 140},       /* (semi-bold + normal) / 2 */
828              {0.4, 200},        /* bold */
829              {CGFLOAT_MAX, CGFLOAT_MAX}},
830             mac_font_descriptor_get_adjusted_weight},
831            {FONT_SLANT_INDEX, kCTFontSlantTrait,
832             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL},
833            {FONT_WIDTH_INDEX, kCTFontWidthTrait,
834             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}, NULL}};
835       int i;
837       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
838         {
839           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
840           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
841             {
842               CGPoint *point = numeric_traits[i].points;
844               if (numeric_traits[i].adjust_func)
845                 floatval = (*numeric_traits[i].adjust_func) (desc, floatval);
846               while (point->x < floatval)
847                 point++;
848               if (point == numeric_traits[i].points)
849                 point++;
850               else if (point->x == CGFLOAT_MAX)
851                 point--;
852               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
853                                            * ((point->y - (point - 1)->y)
854                                               / (point->x - (point - 1)->x)));
855               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
856                               make_number (lround (floatval)));
857             }
858         }
860       num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
861       if (num)
862         {
863           CTFontSymbolicTraits sym_traits;
864           int spacing;
866           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
867           spacing = (sym_traits & kCTFontTraitMonoSpace
868                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
869           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
870         }
872       CFRelease (dict);
873     }
874   num = CTFontDescriptorCopyAttribute (desc, kCTFontSizeAttribute);
875   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
876     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
877   else
878     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
879   if (num)
880     CFRelease (num);
883 static Lisp_Object
884 macfont_descriptor_entity (CTFontDescriptorRef desc, Lisp_Object extra,
885                            CTFontSymbolicTraits synth_sym_traits)
887   Lisp_Object entity;
888   CFDictionaryRef dict;
889   CTFontSymbolicTraits sym_traits = 0;
890   CFStringRef name;
892   entity = font_make_entity ();
894   ASET (entity, FONT_TYPE_INDEX, Qmac_ct);
895   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
897   macfont_store_descriptor_attributes (desc, entity);
899   dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
900   if (dict)
901     {
902       CFNumberRef num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
904       if (num)
905         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
906       CFRelease (dict);
907     }
908   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
909     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
910   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
911   name = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
912   font_put_extra (entity, QCfont_entity,
913                   make_save_ptr_int ((void *) name, sym_traits));
914   if (synth_sym_traits & kCTFontTraitItalic)
915     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
916                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
917   if (synth_sym_traits & kCTFontTraitBold)
918     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
919                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
920   if (synth_sym_traits & kCTFontTraitMonoSpace)
921     ASET (entity, FONT_SPACING_INDEX,
922           make_number (FONT_SPACING_SYNTHETIC_MONO));
924   return entity;
927 /* Cache for font family name symbols vs CFStrings.  A value of nil
928 means the cache has been invalidated.  Otherwise the value is a Lisp
929 hash table whose keys are symbols and the value for a key is either
930 nil (no corresponding family name) or a Lisp save value wrapping the
931 corresponding family name in CFString.  */
933 static Lisp_Object macfont_family_cache;
935 static void
936 macfont_invalidate_family_cache (void)
938   if (HASH_TABLE_P (macfont_family_cache))
939     {
940       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
941       ptrdiff_t i, size = HASH_TABLE_SIZE (h);
943       for (i = 0; i < size; ++i)
944         if (!NILP (HASH_HASH (h, i)))
945           {
946             Lisp_Object value = HASH_VALUE (h, i);
948             if (SAVE_VALUEP (value))
949               CFRelease (XSAVE_POINTER (value, 0));
950           }
951       macfont_family_cache = Qnil;
952     }
955 static bool
956 macfont_get_family_cache_if_present (Lisp_Object symbol, CFStringRef *string)
958   if (HASH_TABLE_P (macfont_family_cache))
959     {
960       struct Lisp_Hash_Table *h = XHASH_TABLE (macfont_family_cache);
961       ptrdiff_t i = hash_lookup (h, symbol, NULL);
963       if (i >= 0)
964         {
965           Lisp_Object value = HASH_VALUE (h, i);
967           *string = SAVE_VALUEP (value) ? XSAVE_POINTER (value, 0) : NULL;
969           return true;
970         }
971     }
973   return false;
976 static void
977 macfont_set_family_cache (Lisp_Object symbol, CFStringRef string)
979   struct Lisp_Hash_Table *h;
980   ptrdiff_t i;
981   EMACS_UINT hash;
982   Lisp_Object value;
984   if (!HASH_TABLE_P (macfont_family_cache))
985     macfont_family_cache = CALLN (Fmake_hash_table, QCtest, Qeq);
987   h = XHASH_TABLE (macfont_family_cache);
988   i = hash_lookup (h, symbol, &hash);
989   value = string ? make_save_ptr ((void *) CFRetain (string)) : Qnil;
990   if (i >= 0)
991     {
992       Lisp_Object old_value = HASH_VALUE (h, i);
994       if (SAVE_VALUEP (old_value))
995         CFRelease (XSAVE_POINTER (old_value, 0));
996       set_hash_value_slot (h, i, value);
997     }
998   else
999     hash_put (h, symbol, value, hash);
1002 /* Cache of all the available font family names except "LastResort"
1003 and those start with ".".  NULL means the cache has been invalidated.
1004 Otherwise, the value is CFArray of CFStrings and the elements are
1005 sorted in the canonical order (CTFontManagerCompareFontFamilyNames on
1006 Mac OS X 10.6 and later).  */
1008 static CFArrayRef macfont_available_families_cache = NULL;
1010 static void
1011 macfont_invalidate_available_families_cache (void)
1013   if (macfont_available_families_cache)
1014     {
1015       CFRelease (macfont_available_families_cache);
1016       macfont_available_families_cache = NULL;
1017     }
1020 static void
1021 macfont_handle_font_change_notification (CFNotificationCenterRef center,
1022                                          void *observer,
1023                                          CFStringRef name, const void *object,
1024                                          CFDictionaryRef userInfo)
1026   macfont_invalidate_family_cache ();
1027   macfont_invalidate_available_families_cache ();
1030 static void
1031 macfont_init_font_change_handler (void)
1033   static bool initialized = false;
1035   if (initialized)
1036     return;
1038   initialized = true;
1039   CFNotificationCenterAddObserver
1040     (CFNotificationCenterGetLocalCenter (), NULL,
1041      macfont_handle_font_change_notification,
1042      kCTFontManagerRegisteredFontsChangedNotification,
1043      NULL, CFNotificationSuspensionBehaviorCoalesce);
1046 static CFArrayRef
1047 macfont_copy_available_families_cache (void)
1049   macfont_init_font_change_handler ();
1051   if (macfont_available_families_cache == NULL)
1052     macfont_available_families_cache = mac_font_create_available_families ();
1054   return (macfont_available_families_cache
1055           ? CFRetain (macfont_available_families_cache) : NULL);
1058 static CFStringRef
1059 macfont_create_family_with_symbol (Lisp_Object symbol)
1061   CFStringRef result = NULL, family_name;
1062   CFDictionaryRef attributes = NULL;
1063   CTFontDescriptorRef pat_desc = NULL;
1065   if (macfont_get_family_cache_if_present (symbol, &result))
1066     return result ? CFRetain (result) : NULL;
1068   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
1069   if (family_name)
1070     {
1071       attributes =
1072         CFDictionaryCreate (NULL,
1073                             (const void **) &kCTFontFamilyNameAttribute,
1074                             (const void **) &family_name, 1,
1075                             &kCFTypeDictionaryKeyCallBacks,
1076                             &kCFTypeDictionaryValueCallBacks);
1077       CFRelease (family_name);
1078     }
1079   if (attributes)
1080     {
1081       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
1082       CFRelease (attributes);
1083     }
1084   if (pat_desc)
1085     {
1086       CTFontDescriptorRef desc =
1087         CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
1089       if (desc)
1090         {
1091           result =
1092             CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
1093           CFRelease (desc);
1094         }
1095       macfont_set_family_cache (symbol, result);
1096       CFRelease (pat_desc);
1097     }
1099   return result;
1102 #define WIDTH_FRAC_BITS         (4)
1103 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
1105 struct macfont_metrics
1107   unsigned char lbearing_low, rbearing_low;
1108   signed lbearing_high : 4, rbearing_high : 4;
1109   unsigned char ascent_low, descent_low;
1110   signed ascent_high : 4, descent_high : 4;
1112   /* These two members are used for fixed-point representation of
1113      glyph width.  The `width_int' member is an integer that is
1114      closest to the width.  The `width_frac' member is the fractional
1115      adjustment representing a value in [-.5, .5], multiplied by
1116      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1117      the advance delta for centering instead of the glyph width.  */
1118   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1121 #define METRICS_VALUE(metrics, member)                          \
1122   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1123 #define METRICS_SET_VALUE(metrics, member, value)                   \
1124   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff;    \
1125     (metrics)->member##_high = tmp >> 8;} while (0)
1127 enum metrics_status
1129   METRICS_INVALID = -1,    /* metrics entry is invalid */
1130   METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1133 #define METRICS_STATUS(metrics)                                         \
1134   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1135 #define METRICS_SET_STATUS(metrics, status)                     \
1136   do {METRICS_SET_VALUE (metrics, ascent, 0);                   \
1137     METRICS_SET_VALUE (metrics, descent, status);} while (0)
1139 #define METRICS_NCOLS_PER_ROW   (128)
1140 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1141 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1143 static int
1144 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1145                        struct font_metrics *metrics, CGFloat *advance_delta,
1146                        int force_integral_p)
1148   struct macfont_info *macfont_info = (struct macfont_info *) font;
1149   CTFontRef macfont = macfont_info->macfont;
1150   int row, col;
1151   struct macfont_metrics *cache;
1152   int width;
1154   row = glyph / METRICS_NCOLS_PER_ROW;
1155   col = glyph % METRICS_NCOLS_PER_ROW;
1156   if (row >= macfont_info->metrics_nrows)
1157     {
1158       macfont_info->metrics =
1159         xrealloc (macfont_info->metrics,
1160                   sizeof (struct macfont_metrics *) * (row + 1));
1161       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1162               (sizeof (struct macfont_metrics *)
1163                * (row + 1 - macfont_info->metrics_nrows)));
1164       macfont_info->metrics_nrows = row + 1;
1165     }
1166   if (macfont_info->metrics[row] == NULL)
1167     {
1168       struct macfont_metrics *new;
1169       int i;
1171       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1172       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1173         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1174       macfont_info->metrics[row] = new;
1175     }
1176   cache = macfont_info->metrics[row] + col;
1178   if (METRICS_STATUS (cache) == METRICS_INVALID)
1179     {
1180       CGFloat fwidth;
1182       if (macfont_info->screen_font)
1183         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1184       else
1185         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1187       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1188          advance delta value.  */
1189       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1190         fwidth = (font->pixel_size - fwidth) / 2;
1191       cache->width_int = lround (fwidth);
1192       cache->width_frac = lround ((fwidth - cache->width_int)
1193                                   * WIDTH_FRAC_SCALE);
1194       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1195     }
1196   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1197     width = font->pixel_size;
1198   else
1199     width = cache->width_int;
1201   if (metrics)
1202     {
1203       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1204         {
1205           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1207           if (macfont_info->synthetic_italic_p)
1208             {
1209               /* We assume the members a, b, c, and d in
1210                  synthetic_italic_atfm are non-negative.  */
1211               bounds.origin =
1212                 CGPointApplyAffineTransform (bounds.origin,
1213                                              synthetic_italic_atfm);
1214               bounds.size =
1215                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1216             }
1217           if (macfont_info->synthetic_bold_p && ! force_integral_p)
1218             {
1219               CGFloat d = - synthetic_bold_factor * CTFontGetSize (macfont) / 2;
1221               bounds = CGRectInset (bounds, d, d);
1222             }
1223           switch (macfont_info->spacing)
1224             {
1225             case MACFONT_SPACING_PROPORTIONAL:
1226               bounds.origin.x += - (cache->width_frac
1227                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1228               break;
1229             case MACFONT_SPACING_MONO:
1230               break;
1231             case MACFONT_SPACING_SYNTHETIC_MONO:
1232               bounds.origin.x += (cache->width_int
1233                                   + (cache->width_frac
1234                                      / (CGFloat) WIDTH_FRAC_SCALE));
1235               break;
1236             }
1237           if (bounds.size.width > 0)
1238             {
1239               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1240               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1241                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1242             }
1243           bounds = CGRectIntegral (bounds);
1244           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1245           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1246           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1247           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1248         }
1249       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1250       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1251       metrics->width = width;
1252       metrics->ascent = METRICS_VALUE (cache, ascent);
1253       metrics->descent = METRICS_VALUE (cache, descent);
1254     }
1256   if (advance_delta)
1257     {
1258       switch (macfont_info->spacing)
1259         {
1260         case MACFONT_SPACING_PROPORTIONAL:
1261           *advance_delta = (force_integral_p ? 0
1262                             : - (cache->width_frac
1263                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1264           break;
1265         case MACFONT_SPACING_MONO:
1266           *advance_delta = 0;
1267           break;
1268         case MACFONT_SPACING_SYNTHETIC_MONO:
1269           *advance_delta = (force_integral_p ? cache->width_int
1270                             : (cache->width_int
1271                                + (cache->width_frac
1272                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1273           break;
1274         }
1275     }
1277   return width;
1280 static CFMutableDictionaryRef macfont_cache_dictionary;
1282 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1283    equal to the number of rows that are invalid as BMP (i.e., from
1284    U+D800 to U+DFFF).  */
1285 #define ROW_PERM_OFFSET (8)
1287 /* The number of glyphs that can be stored in a value for a single
1288    entry of CFDictionary.  */
1289 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1291 struct macfont_cache
1293   int reference_count;
1294   CFCharacterSetRef cf_charset;
1295   struct {
1296     /* The cached glyph for a BMP character c is stored in
1297        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1298        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1299     unsigned char row_nkeys_or_perm[256];
1300     CGGlyph **matrix;
1302     /* Number of rows for which the BMP cache is allocated so far.
1303        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1304     int nrows;
1306     /* The cached glyph for a character c is stored as the (c %
1307        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1308        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1309        not stored here if row_nkeys_or_perm[c / 256] >=
1310        ROW_PERM_OFFSET.  */
1311     CFMutableDictionaryRef dictionary;
1312   } glyph;
1314   struct {
1315     /* UVS (Unicode Variation Sequence) subtable data, which is of
1316        type CFDataRef if available.  NULL means it is not initialized
1317        yet.  kCFNull means the subtable is not found and there is no
1318        suitable fallback table for this font.  */
1319     CFTypeRef table;
1321     /* Character collection specifying the destination of the mapping
1322        provided by `table' above.  If `table' is obtained from the UVS
1323        subtable in the font cmap table, then the value of this member
1324        should be kCTCharacterCollectionIdentityMapping.  */
1325     CTCharacterCollection collection;
1326   } uvs;
1329 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1330 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1331 static void macfont_release_cache (struct macfont_cache *);
1332 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1333 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1334 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1335 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1336                                           CTCharacterCollection, CGFontIndex);
1337 static CFDataRef macfont_get_uvs_table (struct font *, CTCharacterCollection *);
1339 static struct macfont_cache *
1340 macfont_lookup_cache (CFStringRef key)
1342   struct macfont_cache *cache;
1344   if (macfont_cache_dictionary == NULL)
1345     {
1346       macfont_cache_dictionary =
1347         CFDictionaryCreateMutable (NULL, 0,
1348                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1349       cache = NULL;
1350     }
1351   else
1352     cache = ((struct macfont_cache *)
1353              CFDictionaryGetValue (macfont_cache_dictionary, key));
1355   if (cache == NULL)
1356     {
1357       CTFontRef macfont = CTFontCreateWithName (key, 0, NULL);
1359       if (macfont)
1360         {
1361           cache = xzalloc (sizeof (struct macfont_cache));
1362           /* Treat the LastResort font as if it contained glyphs for
1363              all characters.  This may look too rough, but neither
1364              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1365              for this font is correct for non-BMP characters on Mac OS
1366              X 10.5, anyway.  */
1367           if (CFEqual (key, CFSTR ("LastResort")))
1368             {
1369               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1371               cache->cf_charset =
1372                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1373             }
1374           if (cache->cf_charset == NULL)
1375             cache->cf_charset = CTFontCopyCharacterSet (macfont);
1376           CFDictionaryAddValue (macfont_cache_dictionary, key,
1377                                 (const void *) cache);
1378           CFRelease (macfont);
1379         }
1380     }
1382   return cache;
1385 static struct macfont_cache *
1386 macfont_retain_cache (struct macfont_cache *cache)
1388   cache->reference_count++;
1390   return cache;
1393 static void
1394 macfont_release_cache (struct macfont_cache *cache)
1396   if (--cache->reference_count == 0)
1397     {
1398       int i;
1400       for (i = 0; i < cache->glyph.nrows; i++)
1401         xfree (cache->glyph.matrix[i]);
1402       xfree (cache->glyph.matrix);
1403       if (cache->glyph.dictionary)
1404         CFRelease (cache->glyph.dictionary);
1405       memset (&cache->glyph, 0, sizeof (cache->glyph));
1406       if (cache->uvs.table)
1407         CFRelease (cache->uvs.table);
1408       memset (&cache->uvs, 0, sizeof (cache->uvs));
1409     }
1412 static CFCharacterSetRef
1413 macfont_get_cf_charset (struct font *font)
1415   struct macfont_info *macfont_info = (struct macfont_info *) font;
1417   return macfont_info->cache->cf_charset;
1420 static CFCharacterSetRef
1421 macfont_get_cf_charset_for_name (CFStringRef name)
1423   struct macfont_cache *cache = macfont_lookup_cache (name);
1425   return cache->cf_charset;
1428 static CGGlyph
1429 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1431   struct macfont_info *macfont_info = (struct macfont_info *) font;
1432   CTFontRef macfont = macfont_info->macfont;
1433   struct macfont_cache *cache = macfont_info->cache;
1435   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1436     {
1437       int row = c / 256;
1438       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1440       if (nkeys_or_perm < ROW_PERM_OFFSET)
1441         {
1442           UniChar unichars[256], ch;
1443           CGGlyph *glyphs;
1444           int i, len;
1445           int nrows;
1446           dispatch_queue_t queue;
1447           dispatch_group_t group = NULL;
1449           if (row != 0)
1450             {
1451               CFMutableDictionaryRef dictionary;
1452               uintptr_t key, value;
1453               int nshifts;
1454               CGGlyph glyph;
1456               if (cache->glyph.dictionary == NULL)
1457                 cache->glyph.dictionary =
1458                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1459               dictionary = cache->glyph.dictionary;
1460               key = c / NGLYPHS_IN_VALUE;
1461               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1462               value = ((uintptr_t)
1463                        CFDictionaryGetValue (dictionary, (const void *) key));
1464               glyph = (value >> nshifts);
1465               if (glyph)
1466                 return glyph;
1468               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1469                 {
1470                   ch = c;
1471                   if (!CTFontGetGlyphsForCharacters (macfont, &ch, &glyph, 1)
1472                       || glyph == 0)
1473                     glyph = kCGFontIndexInvalid;
1475                   if (value == 0)
1476                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1477                   value |= ((uintptr_t) glyph << nshifts);
1478                   CFDictionarySetValue (dictionary, (const void *) key,
1479                                         (const void *) value);
1481                   return glyph;
1482                 }
1484               queue =
1485                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1486               group = dispatch_group_create ();
1487               dispatch_group_async (group, queue, ^{
1488                   int nkeys;
1489                   uintptr_t key;
1490                   nkeys = nkeys_or_perm;
1491                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1492                     if (CFDictionaryContainsKey (dictionary,
1493                                                  (const void *) key))
1494                       {
1495                         CFDictionaryRemoveValue (dictionary,
1496                                                  (const void *) key);
1497                         if (--nkeys == 0)
1498                           break;
1499                       }
1500                 });
1501             }
1503           len = 0;
1504           for (i = 0; i < 256; i++)
1505             {
1506               ch = row * 256 + i;
1507               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1508                 unichars[len++] = ch;
1509             }
1511           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1512           if (len > 0)
1513             {
1514               CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, len);
1515               while (i > len)
1516                 {
1517                   int next = unichars[len - 1] % 256;
1519                   while (--i > next)
1520                     glyphs[i] = kCGFontIndexInvalid;
1522                   len--;
1523                   glyphs[i] = glyphs[len];
1524                   if (len == 0)
1525                     break;
1526                 }
1527             }
1528           if (i > len)
1529             while (i-- > 0)
1530               glyphs[i] = kCGFontIndexInvalid;
1532           nrows = cache->glyph.nrows;
1533           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1534           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1535           nrows++;
1536           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1537                                           sizeof (CGGlyph *) * nrows);
1538           cache->glyph.matrix[nrows - 1] = glyphs;
1539           cache->glyph.nrows = nrows;
1541           if (group)
1542             {
1543               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1544               dispatch_release (group);
1545             }
1546         }
1548       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1549     }
1550   else
1551     {
1552       uintptr_t key, value;
1553       int nshifts;
1554       CGGlyph glyph;
1556       if (cache->glyph.dictionary == NULL)
1557         cache->glyph.dictionary =
1558           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1559       key = c / NGLYPHS_IN_VALUE;
1560       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1561       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1562                                                 (const void *) key);
1563       glyph = (value >> nshifts);
1564       if (glyph == 0)
1565         {
1566           UniChar unichars[2];
1567           CGGlyph glyphs[2];
1568           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1570           if (CTFontGetGlyphsForCharacters (macfont, unichars, glyphs, count))
1571             glyph = glyphs[0];
1572           if (glyph == 0)
1573             glyph = kCGFontIndexInvalid;
1575           value |= ((uintptr_t) glyph << nshifts);
1576           CFDictionarySetValue (cache->glyph.dictionary,
1577                                 (const void *) key, (const void *) value);
1578         }
1580       return glyph;
1581     }
1584 static CGGlyph
1585 macfont_get_glyph_for_cid (struct font *font, CTCharacterCollection collection,
1586                            CGFontIndex cid)
1588   struct macfont_info *macfont_info = (struct macfont_info *) font;
1589   CTFontRef macfont = macfont_info->macfont;
1591   /* Cache it? */
1592   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1595 static CFDataRef
1596 macfont_get_uvs_table (struct font *font, CTCharacterCollection *collection)
1598   struct macfont_info *macfont_info = (struct macfont_info *) font;
1599   CTFontRef macfont = macfont_info->macfont;
1600   struct macfont_cache *cache = macfont_info->cache;
1601   CFDataRef result = NULL;
1603   if (cache->uvs.table == NULL)
1604     {
1605       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1606       CTCharacterCollection uvs_collection =
1607         kCTCharacterCollectionIdentityMapping;
1609       if (uvs_table == NULL
1610           && mac_font_get_glyph_for_cid (macfont,
1611                                          kCTCharacterCollectionAdobeJapan1,
1612                                          6480) != kCGFontIndexInvalid)
1613         {
1614           /* If the glyph for U+4E55 is accessible via its CID 6480,
1615              then we use the Adobe-Japan1 UVS table, which maps a
1616              variation sequence to a CID, as a fallback.  */
1617           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1619           if (mac_uvs_table_adobe_japan1 == NULL)
1620             mac_uvs_table_adobe_japan1 =
1621               CFDataCreateWithBytesNoCopy (NULL,
1622                                            mac_uvs_table_adobe_japan1_bytes,
1623                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1624                                            kCFAllocatorNull);
1625           if (mac_uvs_table_adobe_japan1)
1626             {
1627               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1628               uvs_collection = kCTCharacterCollectionAdobeJapan1;
1629             }
1630         }
1631       if (uvs_table == NULL)
1632         cache->uvs.table = kCFNull;
1633       else
1634         cache->uvs.table = uvs_table;
1635       cache->uvs.collection = uvs_collection;
1636     }
1638   if (cache->uvs.table != kCFNull)
1639     {
1640       result = cache->uvs.table;
1641       *collection = cache->uvs.collection;
1642     }
1644   return result;
1647 static Lisp_Object macfont_get_cache (struct frame *);
1648 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1649 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1650 static Lisp_Object macfont_list_family (struct frame *);
1651 static void macfont_free_entity (Lisp_Object);
1652 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1653 static void macfont_close (struct font *);
1654 static int macfont_has_char (Lisp_Object, int);
1655 static unsigned macfont_encode_char (struct font *, int);
1656 static void macfont_text_extents (struct font *, unsigned int *, int,
1657                                   struct font_metrics *);
1658 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1659 static Lisp_Object macfont_shape (Lisp_Object);
1660 static int macfont_variation_glyphs (struct font *, int c,
1661                                      unsigned variations[256]);
1662 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1664 static struct font_driver const macfont_driver =
1665   {
1666   .type = LISPSYM_INITIALLY (Qmac_ct),
1667   .get_cache = macfont_get_cache,
1668   .list = macfont_list,
1669   .match = macfont_match,
1670   .list_family = macfont_list_family,
1671   .free_entity = macfont_free_entity,
1672   .open = macfont_open,
1673   .close = macfont_close,
1674   .has_char = macfont_has_char,
1675   .encode_char = macfont_encode_char,
1676   .text_extents = macfont_text_extents,
1677   .draw = macfont_draw,
1678   .shape = macfont_shape,
1679   .get_variation_glyphs = macfont_variation_glyphs,
1680   .filter_properties = macfont_filter_properties,
1681   };
1683 static Lisp_Object
1684 macfont_get_cache (struct frame * f)
1686   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1688   return (dpyinfo->name_list_element);
1691 static int
1692 macfont_get_charset (Lisp_Object registry)
1694   char *str = SSDATA (SYMBOL_NAME (registry));
1695   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1696   Lisp_Object regexp;
1697   int i, j;
1699   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1700     {
1701       if (str[i] == '.')
1702         re[j++] = '\\';
1703       else if (str[i] == '*')
1704         re[j++] = '.';
1705       re[j] = str[i];
1706       if (re[j] == '?')
1707         re[j] = '.';
1708     }
1709   re[j] = '\0';
1710   regexp = make_unibyte_string (re, j);
1711   for (i = 0; cf_charset_table[i].name; i++)
1712     if (fast_c_string_match_ignore_case
1713         (regexp, cf_charset_table[i].name,
1714          strlen (cf_charset_table[i].name)) >= 0)
1715       break;
1716   if (! cf_charset_table[i].name)
1717     return -1;
1718   if (! cf_charset_table[i].cf_charset)
1719     {
1720       int *uniquifier = cf_charset_table[i].uniquifier;
1721       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1722       CFIndex count = 0;
1723       CFStringRef string;
1724       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1726       if (! charset)
1727         return -1;
1728       for (j = 0; uniquifier[j]; j++)
1729         {
1730           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1731                                                         unichars + count);
1732           CFCharacterSetAddCharactersInRange (charset,
1733                                               CFRangeMake (uniquifier[j], 1));
1734         }
1736       string = CFStringCreateWithCharacters (NULL, unichars, count);
1737       if (! string)
1738         {
1739           CFRelease (charset);
1740           return -1;
1741         }
1742       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1743                                                                  charset);
1744       CFRelease (charset);
1745       /* CFCharacterSetCreateWithCharactersInString does not handle
1746          surrogate pairs properly as of Mac OS X 10.5.  */
1747       cf_charset_table[i].cf_charset_string = string;
1748     }
1749   return i;
1752 struct OpenTypeSpec
1754   Lisp_Object script;
1755   unsigned int script_tag, langsys_tag;
1756   int nfeatures[2];
1757   unsigned int *features[2];
1760 #define OTF_SYM_TAG(SYM, TAG)                               \
1761   do {                                                      \
1762     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1763     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1764   } while (0)
1766 #define OTF_TAG_STR(TAG, P)                     \
1767   do {                                          \
1768     (P)[0] = (char) (TAG >> 24);                \
1769     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1770     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1771     (P)[3] = (char) (TAG & 0xFF);               \
1772     (P)[4] = '\0';                              \
1773   } while (0)
1775 static struct OpenTypeSpec *
1776 macfont_get_open_type_spec (Lisp_Object otf_spec)
1778   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1779   Lisp_Object val;
1780   int i, j;
1781   bool negative;
1783   if (! spec)
1784     return NULL;
1785   spec->script = XCAR (otf_spec);
1786   if (! NILP (spec->script))
1787     {
1788       OTF_SYM_TAG (spec->script, spec->script_tag);
1789       val = assq_no_quit (spec->script, Votf_script_alist);
1790       if (CONSP (val) && SYMBOLP (XCDR (val)))
1791         spec->script = XCDR (val);
1792       else
1793         spec->script = Qnil;
1794     }
1795   else
1796     spec->script_tag = 0x44464C54;      /* "DFLT" */
1797   otf_spec = XCDR (otf_spec);
1798   spec->langsys_tag = 0;
1799   if (! NILP (otf_spec))
1800     {
1801       val = XCAR (otf_spec);
1802       if (! NILP (val))
1803         OTF_SYM_TAG (val, spec->langsys_tag);
1804       otf_spec = XCDR (otf_spec);
1805     }
1806   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1807   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1808     {
1809       Lisp_Object len;
1811       val = XCAR (otf_spec);
1812       if (NILP (val))
1813         continue;
1814       len = Flength (val);
1815       spec->features[i] =
1816         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1817          ? 0
1818          : malloc (XINT (len) * sizeof *spec->features[i]));
1819       if (! spec->features[i])
1820         {
1821           if (i > 0 && spec->features[0])
1822             free (spec->features[0]);
1823           free (spec);
1824           return NULL;
1825         }
1826       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1827         {
1828           if (NILP (XCAR (val)))
1829             negative = 1;
1830           else
1831             {
1832               unsigned int tag;
1834               OTF_SYM_TAG (XCAR (val), tag);
1835               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1836             }
1837         }
1838       spec->nfeatures[i] = j;
1839     }
1840   return spec;
1843 static CFMutableDictionaryRef
1844 macfont_create_attributes_with_spec (Lisp_Object spec)
1846   Lisp_Object tmp, extra;
1847   CFMutableArrayRef langarray = NULL;
1848   CFCharacterSetRef charset = NULL;
1849   CFStringRef charset_string = NULL;
1850   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1851   Lisp_Object script = Qnil;
1852   Lisp_Object registry;
1853   int cf_charset_idx, i;
1854   struct OpenTypeSpec *otspec = NULL;
1855   struct {
1856     enum font_property_index index;
1857     CFStringRef trait;
1858     CGPoint points[6];
1859   } numeric_traits[] =
1860       {{FONT_WEIGHT_INDEX, kCTFontWeightTrait,
1861         {{-0.4, 50},            /* light */
1862          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1863          {0, 100},              /* normal */
1864          {0.24, 140},           /* (semi-bold + normal) / 2 */
1865          {0.4, 200},            /* bold */
1866          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1867        {FONT_SLANT_INDEX, kCTFontSlantTrait,
1868         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1869        {FONT_WIDTH_INDEX, kCTFontWidthTrait,
1870         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1872   registry = AREF (spec, FONT_REGISTRY_INDEX);
1873   if (NILP (registry)
1874       || EQ (registry, Qascii_0)
1875       || EQ (registry, Qiso10646_1)
1876       || EQ (registry, Qunicode_bmp))
1877     cf_charset_idx = -1;
1878   else
1879     {
1880       CFStringRef lang;
1882       cf_charset_idx = macfont_get_charset (registry);
1883       if (cf_charset_idx < 0)
1884         goto err;
1885       charset = cf_charset_table[cf_charset_idx].cf_charset;
1886       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1887       lang = cf_charset_table[cf_charset_idx].lang;
1888       if (lang)
1889         {
1890           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1891           if (! langarray)
1892             goto err;
1893           CFArrayAppendValue (langarray, lang);
1894         }
1895     }
1897   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1898        CONSP (extra); extra = XCDR (extra))
1899     {
1900       Lisp_Object key, val;
1902       tmp = XCAR (extra);
1903       key = XCAR (tmp), val = XCDR (tmp);
1904       if (EQ (key, QClang))
1905         {
1906           if (! langarray)
1907             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1908           if (! langarray)
1909             goto err;
1910           if (SYMBOLP (val))
1911             val = list1 (val);
1912           for (; CONSP (val); val = XCDR (val))
1913             if (SYMBOLP (XCAR (val)))
1914               {
1915                 CFStringRef lang =
1916                   cfstring_create_with_string_noencode (SYMBOL_NAME
1917                                                         (XCAR (val)));
1919                 if (lang == NULL)
1920                   goto err;
1921                 CFArrayAppendValue (langarray, lang);
1922                 CFRelease (lang);
1923               }
1924         }
1925       else if (EQ (key, QCotf))
1926         {
1927           otspec = macfont_get_open_type_spec (val);
1928           if (! otspec)
1929             goto err;
1930           script = otspec->script;
1931         }
1932       else if (EQ (key, QCscript))
1933         script = val;
1934     }
1936   if (! NILP (script) && ! charset)
1937     {
1938       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1940       if (CONSP (chars) && CONSP (CDR (chars)))
1941         {
1942           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1943           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1945           if (! string || !cs)
1946             {
1947               if (string)
1948                 CFRelease (string);
1949               else if (cs)
1950                 CFRelease (cs);
1951               goto err;
1952             }
1953           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1954             if (CHARACTERP (XCAR (chars)))
1955               {
1956                 UniChar unichars[2];
1957                 CFIndex count =
1958                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1959                                                        unichars);
1960                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1962                 CFStringAppendCharacters (string, unichars, count);
1963                 CFCharacterSetAddCharactersInRange (cs, range);
1964               }
1965           charset = cs;
1966           /* CFCharacterSetCreateWithCharactersInString does not
1967              handle surrogate pairs properly as of Mac OS X 10.5.  */
1968           charset_string = string;
1969         }
1970     }
1972   attributes = CFDictionaryCreateMutable (NULL, 0,
1973                                           &kCFTypeDictionaryKeyCallBacks,
1974                                           &kCFTypeDictionaryValueCallBacks);
1975   if (! attributes)
1976     goto err;
1978   tmp = AREF (spec, FONT_FAMILY_INDEX);
1979   if (SYMBOLP (tmp) && ! NILP (tmp))
1980     {
1981       CFStringRef family = macfont_create_family_with_symbol (tmp);
1983       if (! family)
1984         goto err;
1985       CFDictionaryAddValue (attributes, kCTFontFamilyNameAttribute,
1986                             family);
1987       CFRelease (family);
1988     }
1990   traits = CFDictionaryCreateMutable (NULL, 4,
1991                                       &kCFTypeDictionaryKeyCallBacks,
1992                                       &kCFTypeDictionaryValueCallBacks);
1993   if (! traits)
1994     goto err;
1996   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1997     {
1998       tmp = AREF (spec, numeric_traits[i].index);
1999       if (INTEGERP (tmp))
2000         {
2001           CGPoint *point = numeric_traits[i].points;
2002           CGFloat floatval = (XINT (tmp) >> 8); // XXX
2003           CFNumberRef num;
2005           while (point->y < floatval)
2006             point++;
2007           if (point == numeric_traits[i].points)
2008             point++;
2009           else if (point->y == CGFLOAT_MAX)
2010             point--;
2011           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
2012                                        * ((point->x - (point - 1)->x)
2013                                           / (point->y - (point - 1)->y)));
2014           if (floatval > 1.0)
2015             floatval = 1.0;
2016           else if (floatval < -1.0)
2017             floatval = -1.0;
2018           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
2019           if (! num)
2020             goto err;
2021           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
2022           CFRelease (num);
2023         }
2024     }
2025   if (CFDictionaryGetCount (traits))
2026     CFDictionaryAddValue (attributes, kCTFontTraitsAttribute, traits);
2028   if (charset)
2029     CFDictionaryAddValue (attributes, kCTFontCharacterSetAttribute,
2030                           charset);
2031   if (charset_string)
2032     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
2033                           charset_string);
2034   if (langarray)
2035     CFDictionaryAddValue (attributes, kCTFontLanguagesAttribute, langarray);
2037   goto finish;
2039  err:
2040   if (attributes)
2041     {
2042       CFRelease (attributes);
2043       attributes = NULL;
2044     }
2046  finish:
2047   if (langarray) CFRelease (langarray);
2048   if (charset && cf_charset_idx < 0) CFRelease (charset);
2049   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
2050   if (traits) CFRelease (traits);
2051   if (otspec)
2052     {
2053       if (otspec->nfeatures[0] > 0)
2054         free (otspec->features[0]);
2055       if (otspec->nfeatures[1] > 0)
2056         free (otspec->features[1]);
2057       free (otspec);
2058     }
2060   return attributes;
2063 static Boolean
2064 macfont_supports_charset_and_languages_p (CTFontDescriptorRef desc,
2065                                           CFCharacterSetRef charset,
2066                                           Lisp_Object chars,
2067                                           CFArrayRef languages)
2069   Boolean result = true;
2071   if (charset || VECTORP (chars))
2072     {
2073       CFCharacterSetRef desc_charset =
2074         CTFontDescriptorCopyAttribute (desc, kCTFontCharacterSetAttribute);
2076       if (desc_charset == NULL)
2077         result = false;
2078       else
2079         {
2080           if (charset)
2081             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
2082           else                  /* VECTORP (chars) */
2083             {
2084               ptrdiff_t j;
2086               for (j = 0; j < ASIZE (chars); j++)
2087                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2088                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2089                                                             XFASTINT (AREF (chars, j))))
2090                   break;
2091               if (j == ASIZE (chars))
2092                 result = false;
2093             }
2094           CFRelease (desc_charset);
2095         }
2096     }
2097   if (result && languages)
2098     result = mac_font_descriptor_supports_languages (desc, languages);
2100   return result;
2103 static int
2104 macfont_traits_distance (CTFontSymbolicTraits sym_traits1,
2105                          CTFontSymbolicTraits sym_traits2)
2107   CTFontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2108   int distance = 0;
2110   /* We prefer synthetic bold of italic to synthetic italic of bold
2111      when both bold and italic are available but bold-italic is not
2112      available.  */
2113   if (diff & kCTFontTraitBold)
2114     distance |= (1 << 0);
2115   if (diff & kCTFontTraitItalic)
2116     distance |= (1 << 1);
2117   if (diff & kCTFontTraitMonoSpace)
2118     distance |= (1 << 2);
2120   return distance;
2123 static Boolean
2124 macfont_closest_traits_index_p (CFArrayRef traits_array,
2125                                 CTFontSymbolicTraits target,
2126                                 CFIndex index)
2128   CFIndex i, count = CFArrayGetCount (traits_array);
2129   CTFontSymbolicTraits traits;
2130   int my_distance;
2132   traits = ((CTFontSymbolicTraits) (uintptr_t)
2133             CFArrayGetValueAtIndex (traits_array, index));
2134   my_distance = macfont_traits_distance (target, traits);
2136   for (i = 0; i < count; i++)
2137     if (i != index)
2138       {
2139         traits = ((CTFontSymbolicTraits) (uintptr_t)
2140                   CFArrayGetValueAtIndex (traits_array, i));
2141         if (macfont_traits_distance (target, traits) < my_distance)
2142           return false;
2143       }
2145   return true;
2148 static Lisp_Object
2149 macfont_list (struct frame *f, Lisp_Object spec)
2151   Lisp_Object val = Qnil, family, extra;
2152   int i, n;
2153   CFStringRef family_name = NULL;
2154   CFMutableDictionaryRef attributes = NULL, traits;
2155   Lisp_Object chars = Qnil;
2156   int spacing = -1;
2157   CTFontSymbolicTraits synth_sym_traits = 0;
2158   CFArrayRef families;
2159   CFIndex families_count;
2160   CFCharacterSetRef charset = NULL;
2161   CFArrayRef languages = NULL;
2163   block_input ();
2165   family = AREF (spec, FONT_FAMILY_INDEX);
2166   if (! NILP (family))
2167     {
2168       family_name = macfont_create_family_with_symbol (family);
2169       if (family_name == NULL)
2170         goto finish;
2171     }
2173   attributes = macfont_create_attributes_with_spec (spec);
2174   if (! attributes)
2175     goto finish;
2177   languages = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
2179   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2180     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2182   traits = ((CFMutableDictionaryRef)
2183             CFDictionaryGetValue (attributes, kCTFontTraitsAttribute));
2185   n = FONT_SLANT_NUMERIC (spec);
2186   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2187     {
2188       synth_sym_traits |= kCTFontTraitItalic;
2189       if (traits)
2190         CFDictionaryRemoveValue (traits, kCTFontSlantTrait);
2191     }
2193   n = FONT_WEIGHT_NUMERIC (spec);
2194   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2195     {
2196       synth_sym_traits |= kCTFontTraitBold;
2197       if (traits)
2198         CFDictionaryRemoveValue (traits, kCTFontWeightTrait);
2199     }
2201   if (languages
2202       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2203     {
2204       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2206       if (CFStringHasPrefix (language, CFSTR ("ja"))
2207           || CFStringHasPrefix (language, CFSTR ("ko"))
2208           || CFStringHasPrefix (language, CFSTR ("zh")))
2209         synth_sym_traits |= kCTFontTraitMonoSpace;
2210     }
2212   /* Create array of families.  */
2213   if (family_name)
2214     families = CFArrayCreate (NULL, (const void **) &family_name,
2215                               1, &kCFTypeArrayCallBacks);
2216   else
2217     {
2218       CFStringRef pref_family;
2219       CFIndex families_count, pref_family_index = -1;
2221       families = macfont_copy_available_families_cache ();
2222       if (families == NULL)
2223         goto err;
2225       families_count = CFArrayGetCount (families);
2227       /* Move preferred family to the front if exists.  */
2228       pref_family =
2229         mac_font_create_preferred_family_for_attributes (attributes);
2230       if (pref_family)
2231         {
2232           pref_family_index =
2233             CFArrayGetFirstIndexOfValue (families,
2234                                          CFRangeMake (0, families_count),
2235                                          pref_family);
2236           CFRelease (pref_family);
2237         }
2238       if (pref_family_index > 0)
2239         {
2240           CFMutableArrayRef mutable_families =
2241             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2243           if (mutable_families)
2244             {
2245               CFArrayAppendValue (mutable_families,
2246                                   CFArrayGetValueAtIndex (families,
2247                                                           pref_family_index));
2248               CFArrayAppendArray (mutable_families, families,
2249                                   CFRangeMake (0, pref_family_index));
2250               if (pref_family_index + 1 < families_count)
2251                 CFArrayAppendArray (mutable_families, families,
2252                                     CFRangeMake (pref_family_index + 1,
2253                                                  families_count
2254                                                  - (pref_family_index + 1)));
2255               CFRelease (families);
2256               families = mutable_families;
2257             }
2258         }
2259     }
2261   charset = CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
2262   if (charset)
2263     {
2264       CFRetain (charset);
2265       CFDictionaryRemoveValue (attributes, kCTFontCharacterSetAttribute);
2266     }
2267   else
2268     {
2269       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2270       if (! NILP (val))
2271         {
2272           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2273           if (CONSP (val) && VECTORP (XCDR (val)))
2274             chars = XCDR (val);
2275         }
2276       val = Qnil;
2277     }
2279   if (languages)
2280     {
2281       CFRetain (languages);
2282       CFDictionaryRemoveValue (attributes, kCTFontLanguagesAttribute);
2283     }
2285   val = Qnil;
2286   extra = AREF (spec, FONT_EXTRA_INDEX);
2287   families_count = CFArrayGetCount (families);
2288   for (i = 0; i < families_count; i++)
2289     {
2290       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2291       CTFontDescriptorRef pat_desc;
2292       CFArrayRef descs;
2293       CFIndex descs_count;
2294       CFMutableArrayRef filtered_descs, traits_array;
2295       Lisp_Object entity;
2296       int j;
2298       CFDictionarySetValue (attributes, kCTFontFamilyNameAttribute,
2299                             family_name);
2300       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2301       if (! pat_desc)
2302         goto err;
2304       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2305          10.7 returns NULL if pat_desc represents the LastResort font.
2306          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2307          trailing "s") for such a font.  */
2308       if (!CFEqual (family_name, CFSTR ("LastResort")))
2309         descs = CTFontDescriptorCreateMatchingFontDescriptors (pat_desc, NULL);
2310       else
2311         {
2312           CTFontDescriptorRef lr_desc =
2313             CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2314           if (lr_desc)
2315             {
2316               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2317                                      &kCFTypeArrayCallBacks);
2318               CFRelease (lr_desc);
2319             }
2320           else
2321             descs = NULL;
2322         }
2323       CFRelease (pat_desc);
2324       if (! descs)
2325         continue;
2327       descs_count = CFArrayGetCount (descs);
2328       if (descs_count == 0
2329           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2330                                                         charset, chars,
2331                                                         languages))
2332         {
2333           CFRelease (descs);
2334           continue;
2335         }
2337       filtered_descs =
2338         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2339       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2340       for (j = 0; j < descs_count; j++)
2341         {
2342           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2343           CFDictionaryRef dict;
2344           CFNumberRef num;
2345           CTFontSymbolicTraits sym_traits;
2347           dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
2348           if (dict == NULL)
2349             continue;
2351           num = CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
2352           CFRelease (dict);
2353           if (num == NULL
2354               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2355             continue;
2357           if (spacing >= 0
2358               && !(synth_sym_traits & kCTFontTraitMonoSpace)
2359               && (((sym_traits & kCTFontTraitMonoSpace) != 0)
2360                   != (spacing >= FONT_SPACING_MONO)))
2361             continue;
2363           /* Don't use a color bitmap font until it is supported on
2364              free platforms.  */
2365           if (sym_traits & kCTFontTraitColorGlyphs)
2366             continue;
2368           if (j > 0
2369               && !macfont_supports_charset_and_languages_p (desc, charset,
2370                                                             chars, languages))
2371             continue;
2373           CFArrayAppendValue (filtered_descs, desc);
2374           CFArrayAppendValue (traits_array,
2375                               (const void *) (uintptr_t) sym_traits);
2376         }
2378       CFRelease (descs);
2379       descs = filtered_descs;
2380       descs_count = CFArrayGetCount (descs);
2382       for (j = 0; j < descs_count; j++)
2383         {
2384           CTFontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2385           CTFontSymbolicTraits sym_traits =
2386             ((CTFontSymbolicTraits) (uintptr_t)
2387              CFArrayGetValueAtIndex (traits_array, j));
2388           CTFontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2390           mask_min = ((synth_sym_traits ^ sym_traits)
2391                       & (kCTFontTraitItalic | kCTFontTraitBold));
2392           if (FONT_SLANT_NUMERIC (spec) < 0)
2393             mask_min &= ~kCTFontTraitItalic;
2394           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2395             mask_min &= ~kCTFontTraitBold;
2397           mask_max = (synth_sym_traits & ~sym_traits);
2398           /* Synthetic bold does not work for bitmap-only fonts on Mac
2399              OS X 10.6.  */
2400           if ((mask_min ^ mask_max) & kCTFontTraitBold)
2401             {
2402               CFNumberRef format =
2403                 CTFontDescriptorCopyAttribute (desc, kCTFontFormatAttribute);
2405               if (format)
2406                 {
2407                   uint32_t format_val;
2409                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2410                                         &format_val)
2411                       && format_val == kCTFontFormatBitmap)
2412                     mask_max &= ~kCTFontTraitBold;
2413                 }
2414             }
2415           if (spacing >= 0)
2416             mask_min |= (mask_max & kCTFontTraitMonoSpace);
2418           for (mmask = (mask_min & kCTFontTraitMonoSpace);
2419                mmask <= (mask_max & kCTFontTraitMonoSpace);
2420                mmask += kCTFontTraitMonoSpace)
2421             for (bmask = (mask_min & kCTFontTraitBold);
2422                  bmask <= (mask_max & kCTFontTraitBold);
2423                  bmask += kCTFontTraitBold)
2424               for (imask = (mask_min & kCTFontTraitItalic);
2425                    imask <= (mask_max & kCTFontTraitItalic);
2426                    imask += kCTFontTraitItalic)
2427                 {
2428                   CTFontSymbolicTraits synth = (imask | bmask | mmask);
2430                   if (synth == 0
2431                       || macfont_closest_traits_index_p (traits_array,
2432                                                          (sym_traits | synth),
2433                                                          j))
2434                     {
2435                       entity = macfont_descriptor_entity (desc, extra, synth);
2436                       if (! NILP (entity))
2437                         val = Fcons (entity, val);
2438                     }
2439                 }
2440         }
2442       CFRelease (traits_array);
2443       CFRelease (descs);
2444     }
2446   CFRelease (families);
2447   val = Fnreverse (val);
2448   goto finish;
2449  err:
2450   val = Qnil;
2452  finish:
2453   FONT_ADD_LOG ("macfont-list", spec, val);
2454   if (charset) CFRelease (charset);
2455   if (languages) CFRelease (languages);
2456   if (attributes) CFRelease (attributes);
2457   if (family_name) CFRelease (family_name);
2459   unblock_input ();
2461   return val;
2464 static Lisp_Object
2465 macfont_match (struct frame * frame, Lisp_Object spec)
2467   Lisp_Object entity = Qnil;
2468   CFMutableDictionaryRef attributes;
2469   CTFontDescriptorRef pat_desc = NULL, desc = NULL;
2471   block_input ();
2473   attributes = macfont_create_attributes_with_spec (spec);
2474   if (attributes)
2475     {
2476       pat_desc = CTFontDescriptorCreateWithAttributes (attributes);
2477       CFRelease (attributes);
2478     }
2479   if (pat_desc)
2480     {
2481       desc = CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
2482       CFRelease (pat_desc);
2483     }
2484   if (desc)
2485     {
2486       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2487                                           0);
2488       CFRelease (desc);
2489     }
2490   unblock_input ();
2492   FONT_ADD_LOG ("macfont-match", spec, entity);
2493   return entity;
2496 static Lisp_Object
2497 macfont_list_family (struct frame *frame)
2499   Lisp_Object list = Qnil;
2500   CFArrayRef families;
2502   block_input ();
2504   families = macfont_copy_available_families_cache ();
2505   if (families)
2506     {
2507       CFIndex i, count = CFArrayGetCount (families);
2509       for (i = 0; i < count; i++)
2510         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2511       CFRelease (families);
2512     }
2514   unblock_input ();
2516   return list;
2519 static void
2520 macfont_free_entity (Lisp_Object entity)
2522   Lisp_Object val = assq_no_quit (QCfont_entity,
2523                                   AREF (entity, FONT_EXTRA_INDEX));
2524   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2526   block_input ();
2527   CFRelease (name);
2528   unblock_input ();
2531 static Lisp_Object
2532 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2534   Lisp_Object val, font_object;
2535   CFStringRef font_name;
2536   struct macfont_info *macfont_info = NULL;
2537   struct font *font;
2538   int size;
2539   CTFontRef macfont;
2540   CTFontSymbolicTraits sym_traits;
2541   char name[256];
2542   int len, i, total_width;
2543   CGGlyph glyph;
2544   CGFloat ascent, descent, leading;
2546   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2547   if (! CONSP (val)
2548       || XTYPE (XCDR (val)) != Lisp_Misc
2549       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2550     return Qnil;
2551   font_name = XSAVE_POINTER (XCDR (val), 0);
2552   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2554   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2555   if (size == 0)
2556     size = pixel_size;
2558   block_input ();
2559   macfont = CTFontCreateWithName (font_name, size, NULL);
2560   if (macfont)
2561     {
2562       int fontsize = (int) [((NSFont *) macfont) pointSize];
2563       if (fontsize != size) size = fontsize;
2564     }
2565   unblock_input ();
2566   if (! macfont)
2567     return Qnil;
2569   font_object = font_build_object (VECSIZE (struct macfont_info),
2570                                    Qmac_ct, entity, size);
2571   font = XFONT_OBJECT (font_object);
2572   font->pixel_size = size;
2573   font->driver = &macfont_driver;
2574   font->encoding_charset = font->repertory_charset = -1;
2576   block_input ();
2578   macfont_info = (struct macfont_info *) font;
2579   macfont_info->macfont = macfont;
2580   macfont_info->cgfont = CTFontCopyGraphicsFont (macfont, NULL);
2582   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2583   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2584     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2585                                                                   size);
2586   else
2587     macfont_info->screen_font = NULL;
2588   macfont_info->cache = macfont_lookup_cache (font_name);
2589   macfont_retain_cache (macfont_info->cache);
2590   macfont_info->metrics = NULL;
2591   macfont_info->metrics_nrows = 0;
2592   macfont_info->synthetic_italic_p = 0;
2593   macfont_info->synthetic_bold_p = 0;
2594   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2595   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2596   if (!(sym_traits & kCTFontTraitItalic)
2597       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2598     macfont_info->synthetic_italic_p = 1;
2599   if (!(sym_traits & kCTFontTraitBold)
2600       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2601     macfont_info->synthetic_bold_p = 1;
2602   if (sym_traits & kCTFontTraitMonoSpace)
2603     macfont_info->spacing = MACFONT_SPACING_MONO;
2604   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2605            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2606                == FONT_SPACING_SYNTHETIC_MONO))
2607     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2608   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2609     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2610   else
2611     {
2612       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2613       if (CONSP (val))
2614         macfont_info->antialias =
2615           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2616     }
2617   macfont_info->color_bitmap_p = 0;
2618   if (sym_traits & kCTFontTraitColorGlyphs)
2619     macfont_info->color_bitmap_p = 1;
2621   glyph = macfont_get_glyph_for_character (font, ' ');
2622   if (glyph != kCGFontIndexInvalid)
2623     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2624   else
2625     /* dirty workaround */
2626     font->space_width = pixel_size;
2628   total_width = font->space_width;
2629   for (i = 1; i < 95; i++)
2630     {
2631       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2632       if (glyph == kCGFontIndexInvalid)
2633         break;
2634       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2635     }
2636   if (i == 95)
2637     font->average_width = total_width / 95;
2638   else
2639     font->average_width = font->space_width; /* XXX */
2641   if (!(macfont_info->screen_font
2642         && mac_screen_font_get_metrics (macfont_info->screen_font,
2643                                         &ascent, &descent, &leading)))
2644     {
2645       CFStringRef family_name;
2647       ascent = CTFontGetAscent (macfont);
2648       descent = CTFontGetDescent (macfont);
2649       leading = CTFontGetLeading (macfont);
2650       /* AppKit and WebKit do some adjustment to the heights of
2651          Courier, Helvetica, and Times.  */
2652       family_name = CTFontCopyFamilyName (macfont);
2653       if (family_name)
2654         {
2655           if (CFEqual (family_name, CFSTR ("Courier"))
2656               || CFEqual (family_name, CFSTR ("Helvetica"))
2657               || CFEqual (family_name, CFSTR ("Times")))
2658             ascent += (ascent + descent) * .15f;
2659           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2660             {
2661               leading *= .25f;
2662               ascent += leading;
2663             }
2664           CFRelease (family_name);
2665         }
2666     }
2667   font->ascent = ascent + 0.5f;
2668   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2669   if (CONSP (val) && !NILP (XCDR (val)))
2670     font->descent = descent + 0.5f;
2671   else
2672     font->descent = descent + leading + 0.5f;
2673   font->height = font->ascent + font->descent;
2675   font->underline_position = - CTFontGetUnderlinePosition (macfont) + 0.5f;
2676   font->underline_thickness = CTFontGetUnderlineThickness (macfont) + 0.5f;
2678   unblock_input ();
2680   /* Unfortunately Xft doesn't provide a way to get minimum char
2681      width.  So, we use space_width instead.  */
2682   font->min_width = font->max_width = font->space_width; /* XXX */
2684   font->baseline_offset = 0;
2685   font->relative_compose = 0;
2686   font->default_ascent = 0;
2687   font->vertical_centering = 0;
2689   return font_object;
2692 static void
2693 macfont_close (struct font *font)
2695   struct macfont_info *macfont_info = (struct macfont_info *) font;
2697   if (macfont_info->cache)
2698     {
2699       int i;
2701       block_input ();
2702       CFRelease (macfont_info->macfont);
2703       CGFontRelease (macfont_info->cgfont);
2704       if (macfont_info->screen_font)
2705         CFRelease (macfont_info->screen_font);
2706       macfont_release_cache (macfont_info->cache);
2707       for (i = 0; i < macfont_info->metrics_nrows; i++)
2708         if (macfont_info->metrics[i])
2709           xfree (macfont_info->metrics[i]);
2710       if (macfont_info->metrics)
2711         xfree (macfont_info->metrics);
2712       macfont_info->cache = NULL;
2713       unblock_input ();
2714     }
2717 static int
2718 macfont_has_char (Lisp_Object font, int c)
2720   int result;
2721   CFCharacterSetRef charset;
2723   block_input ();
2724   if (FONT_ENTITY_P (font))
2725     {
2726       Lisp_Object val;
2727       CFStringRef name;
2729       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2730       val = XCDR (val);
2731       name = XSAVE_POINTER (val, 0);
2732       charset = macfont_get_cf_charset_for_name (name);
2733     }
2734   else
2735     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2737   result = CFCharacterSetIsLongCharacterMember (charset, c);
2738   unblock_input ();
2740   return result;
2743 static unsigned
2744 macfont_encode_char (struct font *font, int c)
2746   CGGlyph glyph;
2748   block_input ();
2749   glyph = macfont_get_glyph_for_character (font, c);
2750   unblock_input ();
2752   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2755 static void
2756 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2757                       struct font_metrics *metrics)
2759   int width, i;
2761   block_input ();
2762   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2763   for (i = 1; i < nglyphs; i++)
2764     {
2765       struct font_metrics m;
2766       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2767                                      NULL, 0);
2769       if (metrics)
2770         {
2771           if (width + m.lbearing < metrics->lbearing)
2772             metrics->lbearing = width + m.lbearing;
2773           if (width + m.rbearing > metrics->rbearing)
2774             metrics->rbearing = width + m.rbearing;
2775           if (m.ascent > metrics->ascent)
2776             metrics->ascent = m.ascent;
2777           if (m.descent > metrics->descent)
2778             metrics->descent = m.descent;
2779         }
2780       width += w;
2781     }
2782   unblock_input ();
2784   if (metrics)
2785     metrics->width = width;
2788 static int
2789 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2790               bool with_background)
2792   struct frame * f = s->f;
2793   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2794   CGRect background_rect;
2795   CGPoint text_position;
2796   CGGlyph *glyphs;
2797   CGPoint *positions;
2798   CGFloat font_size = CTFontGetSize (macfont_info->macfont);
2799   bool no_antialias_p =
2800     (NILP (ns_antialias_text)
2801      || macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2802      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2803          && font_size <= macfont_antialias_threshold));
2804   int len = to - from;
2805   struct face *face = s->face;
2806   CGContextRef context;
2808   block_input ();
2810   if (with_background)
2811     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2812                                   s->width, FONT_HEIGHT (s->font));
2813   else
2814     background_rect = CGRectNull;
2816   text_position = CGPointMake (x, -y);
2817   glyphs = xmalloc (sizeof (CGGlyph) * len);
2818   {
2819     CGFloat advance_delta = 0;
2820     int i;
2821     CGFloat total_width = 0;
2823     positions = xmalloc (sizeof (CGPoint) * len);
2824     for (i = 0; i < len; i++)
2825       {
2826         int width;
2828         glyphs[i] = s->char2b[from + i];
2829         width = (s->padding_p ? 1
2830                  : macfont_glyph_extents (s->font, glyphs[i],
2831                                           NULL, &advance_delta,
2832                                           no_antialias_p));
2833         positions[i].x = total_width + advance_delta;
2834         positions[i].y = 0;
2835         total_width += width;
2836       }
2837   }
2839   context = [[NSGraphicsContext currentContext] graphicsPort];
2840   CGContextSaveGState (context);
2842   if (!CGRectIsNull (background_rect))
2843     {
2844       if (s->hl == DRAW_MOUSE_FACE)
2845         {
2846           face = FACE_FROM_ID_OR_NULL (s->f,
2847                                        MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2848           if (!face)
2849             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2850         }
2851       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2852       CGContextFillRects (context, &background_rect, 1);
2853     }
2855   if (macfont_info->cgfont)
2856     {
2857       CGAffineTransform atfm;
2859       CGContextScaleCTM (context, 1, -1);
2860       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2861       if (macfont_info->synthetic_italic_p)
2862         atfm = synthetic_italic_atfm;
2863       else
2864         atfm = CGAffineTransformIdentity;
2865       if (macfont_info->synthetic_bold_p && ! no_antialias_p)
2866         {
2867           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2869           /* Stroke line width for text drawing is not correctly
2870              scaled on Retina display/HiDPI mode when drawn to screen
2871              (whereas it is correctly scaled when drawn to bitmaps),
2872              and synthetic bold looks thinner on such environments.
2873              Apple says there are no plans to address this issue
2874              (rdar://11644870) currently.  So we add a workaround.  */
2875 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
2876           CGContextSetLineWidth (context, synthetic_bold_factor * font_size
2877                                  * [[FRAME_NS_VIEW(f) window] backingScaleFactor]);
2878 #else
2879           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2880 #endif
2881           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2882         }
2883       if (no_antialias_p)
2884         CGContextSetShouldAntialias (context, false);
2886       CGContextSetTextMatrix (context, atfm);
2887       CGContextSetTextPosition (context, text_position.x, text_position.y);
2889 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2890       if (macfont_info->color_bitmap_p
2891 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2892           && CTFontDrawGlyphs != NULL
2893 #endif
2894           )
2895         {
2896           if (len > 0)
2897             {
2898               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2899                                 context);
2900             }
2901         }
2902       else
2903 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2904         {
2905           CGContextSetFont (context, macfont_info->cgfont);
2906           CGContextSetFontSize (context, font_size);
2907           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2908         }
2909     }
2912   xfree (glyphs);
2913   xfree (positions);
2914   CGContextRestoreGState (context);
2916   unblock_input ();
2918   return len;
2921 static Lisp_Object
2922 macfont_shape (Lisp_Object lgstring)
2924   struct font *font = CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring));
2925   struct macfont_info *macfont_info = (struct macfont_info *) font;
2926   CTFontRef macfont = macfont_info->macfont;
2927   ptrdiff_t glyph_len, len, i, j;
2928   CFIndex nonbmp_len;
2929   UniChar *unichars;
2930   CFIndex *nonbmp_indices;
2931   CFStringRef string;
2932   CFIndex used = 0;
2933   struct mac_glyph_layout *glyph_layouts;
2935   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2936   nonbmp_len = 0;
2937   for (i = 0; i < glyph_len; i++)
2938     {
2939       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2941       if (NILP (lglyph))
2942         break;
2943       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2944         nonbmp_len++;
2945     }
2947   len = i;
2949   if (INT_MAX / 2 < len)
2950     memory_full (SIZE_MAX);
2952   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2953   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2954   for (i = j = 0; i < len; i++)
2955     {
2956       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2958       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2959         {
2960           nonbmp_indices[j] = i + j;
2961           j++;
2962         }
2963     }
2964   nonbmp_indices[j] = len + j;  /* sentinel */
2966   block_input ();
2968   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2969                                                kCFAllocatorNull);
2970   if (string)
2971     {
2972       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2973       if (macfont_info->screen_font)
2974         used = mac_screen_font_shape (macfont_info->screen_font, string,
2975                                       glyph_layouts, glyph_len);
2976       else
2977         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2978       CFRelease (string);
2979     }
2981   unblock_input ();
2983   if (used == 0)
2984     return Qnil;
2986   block_input ();
2988   for (i = 0; i < used; i++)
2989     {
2990       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2991       struct mac_glyph_layout *gl = glyph_layouts + i;
2992       EMACS_INT from, to;
2993       struct font_metrics metrics;
2994       int xoff, yoff, wadjust;
2996       if (NILP (lglyph))
2997         {
2998           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2999           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
3000         }
3002       from = gl->comp_range.location;
3003       /* Convert UTF-16 index to UTF-32.  */
3004       j = 0;
3005       while (nonbmp_indices[j] < from)
3006         j++;
3007       from -= j;
3008       LGLYPH_SET_FROM (lglyph, from);
3010       to = gl->comp_range.location + gl->comp_range.length;
3011       /* Convert UTF-16 index to UTF-32.  */
3012       while (nonbmp_indices[j] < to)
3013         j++;
3014       to -= j;
3015       LGLYPH_SET_TO (lglyph, to - 1);
3017       /* LGLYPH_CHAR is used in `describe-char' for checking whether
3018          the composition is trivial.  */
3019       {
3020         UTF32Char c;
3022         if (unichars[gl->string_index] >= 0xD800
3023             && unichars[gl->string_index] < 0xDC00)
3024           c = (((unichars[gl->string_index] - 0xD800) << 10)
3025                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
3026         else
3027           c = unichars[gl->string_index];
3028         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
3029           c = 0;
3030         LGLYPH_SET_CHAR (lglyph, c);
3031       }
3033       {
3034         unsigned long cc = gl->glyph_id;
3035         LGLYPH_SET_CODE (lglyph, cc);
3036       }
3038       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
3039       LGLYPH_SET_WIDTH (lglyph, metrics.width);
3040       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
3041       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
3042       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
3043       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
3045       xoff = lround (gl->advance_delta);
3046       yoff = lround (- gl->baseline_delta);
3047       wadjust = lround (gl->advance);
3048       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
3049         {
3050           Lisp_Object vec;
3052           vec = Fmake_vector (make_number (3), Qnil);
3053           ASET (vec, 0, make_number (xoff));
3054           ASET (vec, 1, make_number (yoff));
3055           ASET (vec, 2, make_number (wadjust));
3056           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
3057         }
3058     }
3060   unblock_input ();
3062   return make_number (used);
3065 /* Structures for the UVS subtable (format 14) in the cmap table.  */
3066 typedef UInt8 UINT24[3];
3068 #pragma pack(push, 1)
3069 struct variation_selector_record
3071   UINT24 var_selector;
3072   UInt32 default_uvs_offset, non_default_uvs_offset;
3074 struct uvs_table
3076   UInt16 format;
3077   UInt32 length, num_var_selector_records;
3078   struct variation_selector_record variation_selector_records[1];
3080 #define SIZEOF_UVS_TABLE_HEADER                                         \
3081   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
3083 struct unicode_value_range
3085   UINT24 start_unicode_value;
3086   UInt8 additional_count;
3088 struct default_uvs_table {
3089   UInt32 num_unicode_value_ranges;
3090   struct unicode_value_range unicode_value_ranges[1];
3092 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3093   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3095 struct uvs_mapping
3097   UINT24 unicode_value;
3098   UInt16 glyph_id;
3100 struct non_default_uvs_table
3102   UInt32 num_uvs_mappings;
3103   struct uvs_mapping uvs_mappings[1];
3105 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3106   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3107 #pragma pack(pop)
3109 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3110 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3111    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3112    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3113 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3114 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3115 /* Succeeding one byte should also be accessible.  */
3116 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3117 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3119 /* Return UVS subtable for the specified FONT.  If the subtable is not
3120    found or ill-formatted, then return NULL.  */
3122 static CFDataRef
3123 mac_font_copy_uvs_table (CTFontRef font)
3125   CFDataRef cmap_table, uvs_table = NULL;
3127   cmap_table = CTFontCopyTable (font, cmapFontTableTag,
3128                                 kCTFontTableOptionNoOptions);
3129   if (cmap_table)
3130     {
3131       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3132       struct uvs_table *uvs;
3133       struct variation_selector_record *records;
3134       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3136 #if __LP64__
3137       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3138         goto finish;
3139 #endif
3141       cmap_len = CFDataGetLength (cmap_table);
3142       if (sizeof_sfntCMapHeader > cmap_len)
3143         goto finish;
3145       ntables = BUINT16_VALUE (cmap->numTables);
3146       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3147                      / sizeof_sfntCMapEncoding))
3148         goto finish;
3150       for (i = 0; i < ntables; i++)
3151         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3152              == kFontUnicodePlatform)
3153             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3154                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3155           {
3156             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3157             break;
3158           }
3159       if (i == ntables
3160           || uvs_offset > cmap_len
3161           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3162         goto finish;
3164       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3165       uvs_len = BUINT32_VALUE (uvs->length);
3166       if (uvs_len > cmap_len - uvs_offset
3167           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3168         goto finish;
3170       if (BUINT16_VALUE (uvs->format) != 14)
3171         goto finish;
3173       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3174       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3175                       / sizeof (struct variation_selector_record)))
3176         goto finish;
3178       records = uvs->variation_selector_records;
3179       for (i = 0; i < nrecords; i++)
3180         {
3181           UInt32 default_uvs_offset, non_default_uvs_offset;
3183           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3184           if (default_uvs_offset)
3185             {
3186               struct default_uvs_table *default_uvs;
3187               UInt32 nranges;
3189               if (default_uvs_offset > uvs_len
3190                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3191                       > uvs_len - default_uvs_offset))
3192                 goto finish;
3194               default_uvs = ((struct default_uvs_table *)
3195                              ((UInt8 *) uvs + default_uvs_offset));
3196               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3197               if (nranges > ((uvs_len - default_uvs_offset
3198                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3199                              / sizeof (struct unicode_value_range)))
3200                 goto finish;
3201               /* Now 2 * nranges can't overflow, so we can safely use
3202                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3203                  mac_font_get_glyphs_for_variants.  */
3204             }
3206           non_default_uvs_offset =
3207             BUINT32_VALUE (records[i].non_default_uvs_offset);
3208           if (non_default_uvs_offset)
3209             {
3210               struct non_default_uvs_table *non_default_uvs;
3211               UInt32 nmappings;
3213               if (non_default_uvs_offset > uvs_len
3214                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3215                       > uvs_len - non_default_uvs_offset))
3216                 goto finish;
3218               non_default_uvs = ((struct non_default_uvs_table *)
3219                                  ((UInt8 *) uvs + non_default_uvs_offset));
3220               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3221               if (nmappings > ((uvs_len - non_default_uvs_offset
3222                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3223                                / sizeof (struct uvs_mapping)))
3224                 goto finish;
3225               /* Now 2 * nmappings can't overflow, so we can safely
3226                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3227                  in mac_font_get_glyphs_for_variants.  */
3228             }
3229         }
3231       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3233     finish:
3234       CFRelease (cmap_table);
3235     }
3237   return uvs_table;
3240 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3241    sequence consisting of the given base character C and each
3242    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3243    result (explained below) into the corresponding GLYPHS[i].  If the
3244    entry is found in the Default UVS Table, then the result is 0.  If
3245    the entry is found in the Non-Default UVS Table, then the result is
3246    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3247    elements in SELECTORS must be sorted in strictly increasing
3248    order.  */
3250 static void
3251 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3252                                   const UTF32Char selectors[], CGGlyph glyphs[],
3253                                   CFIndex count)
3255   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3256   struct variation_selector_record *records = uvs->variation_selector_records;
3257   CFIndex i;
3258   UInt32 ir, nrecords;
3259   dispatch_queue_t queue =
3260     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3261   dispatch_group_t group = dispatch_group_create ();
3263   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3264   i = 0;
3265   ir = 0;
3266   while (i < count && ir < nrecords)
3267     {
3268       UInt32 default_uvs_offset, non_default_uvs_offset;
3270       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3271         {
3272           glyphs[i++] = kCGFontIndexInvalid;
3273           continue;
3274         }
3275       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3276         {
3277           ir++;
3278           continue;
3279         }
3281       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3282       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3283       non_default_uvs_offset =
3284         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3285       dispatch_group_async (group, queue, ^{
3286           glyphs[i] = kCGFontIndexInvalid;
3288           if (default_uvs_offset)
3289             {
3290               struct default_uvs_table *default_uvs =
3291                 (struct default_uvs_table *) ((UInt8 *) uvs
3292                                               + default_uvs_offset);
3293               struct unicode_value_range *ranges =
3294                 default_uvs->unicode_value_ranges;
3295               UInt32 lo, hi;
3297               lo = 0;
3298               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3299               while (lo < hi)
3300                 {
3301                   UInt32 mid = (lo + hi) / 2;
3303                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3304                     hi = mid;
3305                   else
3306                     lo = mid + 1;
3307                 }
3308               if (hi > 0
3309                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3310                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3311                 glyphs[i] = 0;
3312             }
3314           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3315             {
3316               struct non_default_uvs_table *non_default_uvs =
3317                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3318                                                   + non_default_uvs_offset);
3319               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3320               UInt32 lo, hi;
3322               lo = 0;
3323               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3324               while (lo < hi)
3325                 {
3326                   UInt32 mid = (lo + hi) / 2;
3328                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3329                     hi = mid;
3330                   else
3331                     lo = mid + 1;
3332                 }
3333               if (hi > 0 &&
3334                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3335                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3336             }
3337         });
3338       i++;
3339       ir++;
3340     }
3341   while (i < count)
3342     glyphs[i++] = kCGFontIndexInvalid;
3343   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3344   dispatch_release (group);
3347 static int
3348 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3350   CFDataRef uvs_table;
3351   CTCharacterCollection uvs_collection;
3352   int i, n = 0;
3354   block_input ();
3355   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3357   if (uvs_table)
3358     {
3359       UTF32Char selectors[256];
3360       CGGlyph glyphs[256];
3362       for (i = 0; i < 16; i++)
3363         selectors[i] = 0xFE00 + i;
3364       for (; i < 256; i++)
3365         selectors[i] = 0xE0100 + (i - 16);
3366       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3367       for (i = 0; i < 256; i++)
3368         {
3369           CGGlyph glyph = glyphs[i];
3371           if (uvs_collection != kCTCharacterCollectionIdentityMapping
3372               && glyph != kCGFontIndexInvalid)
3373             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3374           if (glyph == kCGFontIndexInvalid)
3375             variations[i] = 0;
3376           else
3377             {
3378               variations[i] = (glyph ? glyph
3379                                : macfont_get_glyph_for_character (font, c));
3380               n++;
3381             }
3382         }
3383     }
3384   unblock_input ();
3386   return n;
3389 static const char *const macfont_booleans[] = {
3390   ":antialias",
3391   ":minspace",
3392   NULL,
3395 static const char *const macfont_non_booleans[] = {
3396   ":lang",
3397   ":script",
3398   ":destination",
3399   NULL,
3402 static void
3403 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3405   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3408 static Boolean
3409 mac_font_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3410                                         CFArrayRef languages)
3412   Boolean result = true;
3413   CFArrayRef desc_languages =
3414     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3416   if (desc_languages == NULL)
3417     result = false;
3418   else
3419     {
3420       CFRange range = CFRangeMake (0, CFArrayGetCount (desc_languages));
3421       CFIndex i, languages_count = CFArrayGetCount (languages);
3423       for (i = 0; i < languages_count; i++)
3424         {
3425           CFStringRef language = CFArrayGetValueAtIndex (languages, i);
3427           if (!CFArrayContainsValue (desc_languages, range, language)
3428               /* PingFang SC contains "zh" and "zh-Hant" as covered
3429                  languages, but does not contain "zh-Hans".  */
3430               && !(CFEqual (language, CFSTR ("zh-Hans"))
3431                    && CFArrayContainsValue (desc_languages, range,
3432                                             CFSTR ("zh"))))
3433             {
3434               result = false;
3435               break;
3436             }
3437         }
3438       CFRelease (desc_languages);
3439     }
3441   return result;
3444 static CFStringRef
3445 mac_font_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3447   CFStringRef result = NULL;
3448   CFStringRef charset_string =
3449     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3451   if (charset_string && CFStringGetLength (charset_string) > 0)
3452     {
3453       CFStringRef keys[] = {
3454 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3455         kCTLanguageAttributeName
3456 #else
3457         CFSTR ("NSLanguage")
3458 #endif
3459       };
3460       CFTypeRef values[] = {NULL};
3461       CFIndex num_values = 0;
3462       CFArrayRef languages
3463         = CFDictionaryGetValue (attributes, kCTFontLanguagesAttribute);
3465       if (languages && CFArrayGetCount (languages) > 0)
3466         {
3467           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3468             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3469           else
3470             {
3471               CFCharacterSetRef charset =
3472                 CFDictionaryGetValue (attributes, kCTFontCharacterSetAttribute);
3474               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3475             }
3476         }
3477       if (result == NULL)
3478         {
3479           CFAttributedStringRef attr_string = NULL;
3480           CTLineRef ctline = NULL;
3481           CFDictionaryRef attrs
3482             = CFDictionaryCreate (NULL, (const void **) keys,
3483                                   (const void **) values, num_values,
3484                                   &kCFTypeDictionaryKeyCallBacks,
3485                                   &kCFTypeDictionaryValueCallBacks);
3487           if (attrs)
3488             {
3489               attr_string = CFAttributedStringCreate (NULL, charset_string,
3490                                                       attrs);
3491               CFRelease (attrs);
3492             }
3493           if (attr_string)
3494             {
3495               ctline = CTLineCreateWithAttributedString (attr_string);
3496               CFRelease (attr_string);
3497             }
3498           if (ctline)
3499             {
3500               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3501               CFIndex i, nruns = CFArrayGetCount (runs);
3502               CTFontRef font;
3504               for (i = 0; i < nruns; i++)
3505                 {
3506                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3507                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3508                   CTFontRef font_in_run;
3510                   if (attributes == NULL)
3511                     break;
3512                   font_in_run =
3513                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3514                   if (font_in_run == NULL)
3515                     break;
3516                   if (i == 0)
3517                     font = font_in_run;
3518                   else if (!mac_font_equal_in_postscript_name (font,
3519                                                                font_in_run))
3520                     break;
3521                 }
3522               if (nruns > 0 && i == nruns)
3523                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3524               CFRelease (ctline);
3525             }
3526         }
3527     }
3529   return result;
3532 static inline double
3533 mac_font_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3535   return CTFontGetAdvancesForGlyphs (font, kCTFontOrientationDefault,
3536                                      &glyph, NULL, 1);
3539 static inline CGRect
3540 mac_font_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3542   return CTFontGetBoundingRectsForGlyphs (font, kCTFontOrientationDefault,
3543                                           &glyph, NULL, 1);
3546 static CFArrayRef
3547 mac_font_create_available_families (void)
3549   CFMutableArrayRef families = NULL;
3550   CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3552   if (orig_families)
3553     {
3554       CFIndex i, count = CFArrayGetCount (orig_families);
3556       families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3557       if (families)
3558         for (i = 0; i < count; i++)
3559           {
3560             CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3562             if (!CFStringHasPrefix (family, CFSTR ("."))
3563                 && (CTFontManagerCompareFontFamilyNames (family,
3564                                                          CFSTR ("LastResort"),
3565                                                          NULL)
3566                     != kCFCompareEqualTo))
3567               CFArrayAppendValue (families, family);
3568           }
3569       CFRelease (orig_families);
3570     }
3572   return families;
3575 static Boolean
3576 mac_font_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3578   Boolean result;
3579   CFStringRef name1, name2;
3581   if (font1 == font2)
3582     return true;
3584   result = false;
3585   name1 = CTFontCopyPostScriptName (font1);
3586   if (name1)
3587     {
3588       name2 = CTFontCopyPostScriptName (font2);
3589       if (name2)
3590         {
3591           result = CFEqual (name1, name2);
3592           CFRelease (name2);
3593         }
3594       CFRelease (name1);
3595     }
3597   return result;
3600 static CTLineRef
3601 mac_font_create_line_with_string_and_font (CFStringRef string,
3602                                            CTFontRef macfont)
3604   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3605   CFTypeRef values[] = {NULL, NULL};
3606   CFDictionaryRef attributes = NULL;
3607   CFAttributedStringRef attr_string = NULL;
3608   CTLineRef ctline = NULL;
3609   float float_zero = 0.0f;
3611   values[0] = macfont;
3612   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3613   if (values[1])
3614     {
3615       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3616                                        (const void **) values,
3617                                        ARRAYELTS (keys),
3618                                        &kCFTypeDictionaryKeyCallBacks,
3619                                        &kCFTypeDictionaryValueCallBacks);
3620       CFRelease (values[1]);
3621     }
3622   if (attributes)
3623     {
3624       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3625       CFRelease (attributes);
3626     }
3627   if (attr_string)
3628     {
3629       ctline = CTLineCreateWithAttributedString (attr_string);
3630       CFRelease (attr_string);
3631     }
3632   if (ctline)
3633     {
3634       /* Abandon if ctline contains some fonts other than the
3635          specified one.  */
3636       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3637       CFIndex i, nruns = CFArrayGetCount (runs);
3639       for (i = 0; i < nruns; i++)
3640         {
3641           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3642           CFDictionaryRef attributes = CTRunGetAttributes (run);
3643           CTFontRef font_in_run;
3645           if (attributes == NULL)
3646             break;
3647           font_in_run =
3648             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3649           if (font_in_run == NULL)
3650             break;
3651           if (!mac_font_equal_in_postscript_name (macfont, font_in_run))
3652             break;
3653         }
3654       if (i < nruns)
3655         {
3656           CFRelease (ctline);
3657           ctline = NULL;
3658         }
3659     }
3661   return ctline;
3664 static CFIndex
3665 mac_font_shape (CTFontRef font, CFStringRef string,
3666                 struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3668   CFIndex used, result = 0;
3669   CTLineRef ctline = mac_font_create_line_with_string_and_font (string, font);
3671   if (ctline == NULL)
3672     return 0;
3674   used = CTLineGetGlyphCount (ctline);
3675   if (used <= glyph_len)
3676     {
3677       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3678       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3679       CGFloat total_advance = 0;
3680       CFIndex total_glyph_count = 0;
3682       for (k = 0; k < ctrun_count; k++)
3683         {
3684           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3685           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3686           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3687           CFRange string_range, comp_range, range;
3688           CFIndex *permutation;
3690           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3691             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3692           else
3693             permutation = NULL;
3695 #define RIGHT_TO_LEFT_P permutation
3697           /* Now the `comp_range' member of struct mac_glyph_layout is
3698              temporarily used as a work area such that:
3699              glbuf[i].comp_range.location =
3700              min {compRange[i + 1].location, ...,
3701                      compRange[glyph_count - 1].location,
3702                      maxRange (stringRangeForCTRun)}
3703              glbuf[i].comp_range.length = maxRange (compRange[i])
3704              where compRange[i] is the range of composed characters
3705              containing i-th glyph.  */
3706           string_range = CTRunGetStringRange (ctrun);
3707           min_location = string_range.location + string_range.length;
3708           for (i = 0; i < glyph_count; i++)
3709             {
3710               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3711               CFIndex glyph_index;
3712               CFRange rng;
3714               if (!RIGHT_TO_LEFT_P)
3715                 glyph_index = glyph_count - i - 1;
3716               else
3717                 glyph_index = i;
3718               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3719                                      &gl->string_index);
3720               rng =
3721                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3722                                                              gl->string_index);
3723               gl->comp_range.location = min_location;
3724               gl->comp_range.length = rng.location + rng.length;
3725               if (rng.location < min_location)
3726                 min_location = rng.location;
3727             }
3729           /* Fill the `comp_range' member of struct mac_glyph_layout,
3730              and setup a permutation for right-to-left text.  */
3731           comp_range = CFRangeMake (string_range.location, 0);
3732           range = CFRangeMake (0, 0);
3733           while (1)
3734             {
3735               struct mac_glyph_layout *gl =
3736                 glbuf + range.location + range.length;
3738               if (gl->comp_range.length
3739                   > comp_range.location + comp_range.length)
3740                 comp_range.length = gl->comp_range.length - comp_range.location;
3741               min_location = gl->comp_range.location;
3742               range.length++;
3744               if (min_location >= comp_range.location + comp_range.length)
3745                 {
3746                   comp_range.length = min_location - comp_range.location;
3747                   for (i = 0; i < range.length; i++)
3748                     {
3749                       glbuf[range.location + i].comp_range = comp_range;
3750                       if (RIGHT_TO_LEFT_P)
3751                         permutation[range.location + i] =
3752                           range.location + range.length - i - 1;
3753                     }
3755                   comp_range = CFRangeMake (min_location, 0);
3756                   range.location += range.length;
3757                   range.length = 0;
3758                   if (range.location == glyph_count)
3759                     break;
3760                 }
3761             }
3763           /* Then fill the remaining members.  */
3764           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3765                range.location++)
3766             {
3767               struct mac_glyph_layout *gl;
3768               CGPoint position;
3769               CGFloat max_x;
3771               if (!RIGHT_TO_LEFT_P)
3772                 gl = glbuf + range.location;
3773               else
3774                 {
3775                   CFIndex src, dest;
3777                   src = glyph_count - 1 - range.location;
3778                   dest = permutation[src];
3779                   gl = glbuf + dest;
3780                   if (src < dest)
3781                     {
3782                       CFIndex tmp = gl->string_index;
3784                       gl->string_index = glbuf[src].string_index;
3785                       glbuf[src].string_index = tmp;
3786                     }
3787                 }
3788               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3790               CTRunGetPositions (ctrun, range, &position);
3791               max_x = position.x + CTRunGetTypographicBounds (ctrun, range,
3792                                                               NULL, NULL, NULL);
3793               max_x = max (max_x, total_advance);
3794               gl->advance_delta = position.x - total_advance;
3795               gl->baseline_delta = position.y;
3796               gl->advance = max_x - total_advance;
3797               total_advance = max_x;
3798             }
3800           if (RIGHT_TO_LEFT_P)
3801             xfree (permutation);
3803 #undef RIGHT_TO_LEFT_P
3805           total_glyph_count += glyph_count;
3806         }
3808       result = used;
3809     }
3810   CFRelease (ctline);
3812   return result;
3815 /* The function below seems to cause a memory leak for the CFString
3816    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3817    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3818 #if USE_CT_GLYPH_INFO
3819 static CGGlyph
3820 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3821                               CGFontIndex cid)
3823   CGGlyph result = kCGFontIndexInvalid;
3824   UniChar characters[] = {0xfffd};
3825   CFStringRef string;
3826   CFAttributedStringRef attr_string = NULL;
3827   CTLineRef ctline = NULL;
3829   string = CFStringCreateWithCharacters (NULL, characters,
3830                                          ARRAYELTS (characters));
3832   if (string)
3833     {
3834       CTGlyphInfoRef glyph_info =
3835         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3836       CFDictionaryRef attributes = NULL;
3838       if (glyph_info)
3839         {
3840           CFStringRef keys[] = {kCTFontAttributeName,
3841                                 kCTGlyphInfoAttributeName};
3842           CFTypeRef values[] = {font, glyph_info};
3844           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3845                                            (const void **) values,
3846                                            ARRAYELTS (keys),
3847                                            &kCFTypeDictionaryKeyCallBacks,
3848                                            &kCFTypeDictionaryValueCallBacks);
3849           CFRelease (glyph_info);
3850         }
3851       if (attributes)
3852         {
3853           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3854           CFRelease (attributes);
3855         }
3856       CFRelease (string);
3857     }
3858   if (attr_string)
3859     {
3860       ctline = CTLineCreateWithAttributedString (attr_string);
3861       CFRelease (attr_string);
3862     }
3863   if (ctline)
3864     {
3865       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3867       if (CFArrayGetCount (runs) > 0)
3868         {
3869           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3870           CFDictionaryRef attributes = CTRunGetAttributes (run);
3872           if (attributes)
3873             {
3874               CTFontRef font_in_run =
3875                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3877               if (font_in_run
3878                   && mac_font_equal_in_postscript_name (font_in_run, font))
3879                 {
3880                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3881                   if (result >= CTFontGetGlyphCount (font))
3882                     result = kCGFontIndexInvalid;
3883                 }
3884             }
3885         }
3886       CFRelease (ctline);
3887     }
3889   return result;
3891 #endif
3893 static CFArrayRef
3894 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3896   CFArrayRef result = NULL;
3898 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3899 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3900   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3901 #endif
3902     {
3903       CTFontRef user_font =
3904         CTFontCreateUIFontForLanguage (kCTFontUIFontUser, 0, language);
3906       if (user_font)
3907         {
3908           CFArrayRef languages =
3909             CFArrayCreate (NULL, (const void **) &language, 1,
3910                            &kCFTypeArrayCallBacks);
3912           if (languages)
3913             {
3914               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3915                                                                  languages);
3916               CFRelease (languages);
3917             }
3918           CFRelease (user_font);
3919         }
3920     }
3921 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3922   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3923 #endif
3924 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3925 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3926     {
3927       CFIndex i;
3929       for (i = 0; macfont_language_default_font_names[i].language; i++)
3930         {
3931           if (CFEqual (macfont_language_default_font_names[i].language,
3932                        language))
3933             {
3934               CFMutableArrayRef descriptors =
3935                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3937               if (descriptors)
3938                 {
3939                   CFIndex j;
3941                   for (j = 0;
3942                        macfont_language_default_font_names[i].font_names[j];
3943                        j++)
3944                     {
3945                       CFDictionaryRef attributes =
3946                         CFDictionaryCreate (NULL,
3947                                             ((const void **)
3948                                              &kCTFontNameAttribute),
3949                                             ((const void **)
3950                                              &macfont_language_default_font_names[i].font_names[j]),
3951                                             1, &kCFTypeDictionaryKeyCallBacks,
3952                                             &kCFTypeDictionaryValueCallBacks);
3954                       if (attributes)
3955                         {
3956                           CTFontDescriptorRef pat_desc =
3957                             CTFontDescriptorCreateWithAttributes (attributes);
3959                           if (pat_desc)
3960                             {
3961                               CTFontDescriptorRef descriptor =
3962                                 CTFontDescriptorCreateMatchingFontDescriptor (pat_desc, NULL);
3964                               if (descriptor)
3965                                 {
3966                                   CFArrayAppendValue (descriptors, descriptor);
3967                                   CFRelease (descriptor);
3968                                 }
3969                               CFRelease (pat_desc);
3970                             }
3971                           CFRelease (attributes);
3972                         }
3973                     }
3974                   result = descriptors;
3975                 }
3976               break;
3977             }
3978         }
3979     }
3980 #endif
3982   return result;
3985 static CFStringRef
3986 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3987                                                       CFArrayRef languages)
3989   CFStringRef result = NULL;
3990   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3991   CFArrayRef descriptors =
3992     mac_font_copy_default_descriptors_for_language (language);
3994   if (descriptors)
3995     {
3996       CFIndex i, count = CFArrayGetCount (descriptors);
3998       for (i = 0; i < count; i++)
3999         {
4000           CTFontDescriptorRef descriptor =
4001             CFArrayGetValueAtIndex (descriptors, i);
4003           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4004                                                         Qnil, languages))
4005             {
4006               CFStringRef family =
4007                 CTFontDescriptorCopyAttribute (descriptor,
4008                                                kCTFontFamilyNameAttribute);
4009               if (family)
4010                 {
4011                   if (!CFStringHasPrefix (family, CFSTR ("."))
4012                       && !CFEqual (family, CFSTR ("LastResort")))
4013                     {
4014                       result = family;
4015                       break;
4016                     }
4017                   else
4018                     CFRelease (family);
4019                 }
4020             }
4021         }
4022       CFRelease (descriptors);
4023     }
4025   return result;
4028 void *
4029 macfont_get_nsctfont (struct font *font)
4031   struct macfont_info *macfont_info = (struct macfont_info *) font;
4032   CTFontRef macfont = macfont_info->macfont;
4034   return (void *) macfont;
4037 void
4038 mac_register_font_driver (struct frame *f)
4040   register_font_driver (&macfont_driver, f);
4044 void
4045 syms_of_macfont (void)
4047   /* Core Text, for macOS.  */
4048   DEFSYM (Qmac_ct, "mac-ct");
4049   register_font_driver (&macfont_driver, NULL);
4051   /* The font property key specifying the font design destination.  The
4052      value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
4053      text.  (See the documentation of X Logical Font Description
4054      Conventions.)  In the Mac font driver, 1 means the screen font is
4055      used for calculating some glyph metrics.  You can see the
4056      difference with Monaco 8pt or 9pt, for example.  */
4057   DEFSYM (QCdestination, ":destination");
4059   /* The boolean-valued font property key specifying the use of leading.  */
4060   DEFSYM (QCminspace, ":minspace");
4062   macfont_family_cache = Qnil;
4063   staticpro (&macfont_family_cache);