More GC assertions
[emacs.git] / src / macfont.m
blob7aa1d40b332a7e48af640eec4174b7e7ae8cc341
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2014 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
19 Original author: YAMAMOTO Mitsuharu
22 #include <config.h>
24 #include "lisp.h"
25 #include "dispextern.h"
26 #include "frame.h"
27 #include "blockinput.h"
28 #include "character.h"
29 #include "charset.h"
30 #include "composite.h"
31 #include "fontset.h"
32 #include "font.h"
33 #include "termchar.h"
34 #include "nsgui.h"
35 #include "nsterm.h"
36 #include "macfont.h"
37 #include "macuvs.h"
39 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
41 #include <libkern/OSByteOrder.h>
43 static struct font_driver macfont_driver;
45 /* Core Text, for Mac OS X 10.5 and later.  */
46 static Lisp_Object Qmac_ct;
48 static double mac_ctfont_get_advance_width_for_glyph (CTFontRef, CGGlyph);
49 static CGRect mac_ctfont_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
50 static CFArrayRef mac_ctfont_create_available_families (void);
51 static Boolean mac_ctfont_equal_in_postscript_name (CTFontRef, CTFontRef);
52 static CTLineRef mac_ctfont_create_line_with_string_and_font (CFStringRef,
53                                                               CTFontRef);
54 static CFComparisonResult mac_font_family_compare (const void *,
55                                                    const void *, void *);
56 static Boolean mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef,
57                                                          CFArrayRef);
58 static CFStringRef mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef);
59 static CFIndex mac_ctfont_shape (CTFontRef, CFStringRef,
60                                  struct mac_glyph_layout *, CFIndex);
61 static CFArrayRef
62 mac_font_copy_default_descriptors_for_language (CFStringRef language);
64 static CFStringRef
65 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
66                                                       CFArrayRef languages);
68 #if USE_CT_GLYPH_INFO
69 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef,
70                                              CTCharacterCollection,
71                                              CGFontIndex);
72 #endif
74 /* The font property key specifying the font design destination.  The
75    value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
76    text.  (See the documentation of X Logical Font Description
77    Conventions.)  In the Mac font driver, 1 means the screen font is
78    used for calculating some glyph metrics.  You can see the
79    difference with Monaco 8pt or 9pt, for example.  */
80 static Lisp_Object QCdestination;
82 /* The boolean-valued font property key specifying the use of
83    leading.  */
84 static Lisp_Object QCminspace;
86 struct macfont_metrics;
88 /* The actual structure for Mac font that can be cast to struct font.  */
90 struct macfont_info
92   struct font font;
93   FontRef macfont;
94   CGFontRef cgfont;
95   ScreenFontRef screen_font;
96   struct macfont_cache *cache;
97   struct macfont_metrics **metrics;
98   short metrics_nrows;
99   bool_bf synthetic_italic_p : 1;
100   bool_bf synthetic_bold_p : 1;
101   unsigned spacing : 2;
102   unsigned antialias : 2;
103   bool_bf color_bitmap_p : 1;
106 /* Values for the `spacing' member in `struct macfont_info'.  */
108 enum
109   {
110     MACFONT_SPACING_PROPORTIONAL,
111     MACFONT_SPACING_MONO,
112     MACFONT_SPACING_SYNTHETIC_MONO,
113   };
115 /* Values for the `antialias' member in `struct macfont_info'.  */
117 enum
118   {
119     MACFONT_ANTIALIAS_DEFAULT,
120     MACFONT_ANTIALIAS_OFF,
121     MACFONT_ANTIALIAS_ON,
122   };
124 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
125 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
126 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
128 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
129 static const CGFloat synthetic_bold_factor = 0.024;
131 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
132                                                         FontSymbolicTraits *);
133 static void macfont_store_descriptor_attributes (FontDescriptorRef,
134                                                  Lisp_Object);
135 static Lisp_Object macfont_descriptor_entity (FontDescriptorRef,
136                                               Lisp_Object,
137                                               FontSymbolicTraits);
138 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
139 static int macfont_glyph_extents (struct font *, CGGlyph,
140                                   struct font_metrics *, CGFloat *, int);
141 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
142 static Boolean macfont_supports_charset_and_languages_p (FontDescriptorRef,
143                                                          CFCharacterSetRef,
144                                                          Lisp_Object,
145                                                          CFArrayRef);
146 static CFIndex macfont_closest_traits_index (CFArrayRef,
147                                              FontSymbolicTraits);
148 static CFDataRef mac_font_copy_uvs_table (FontRef);
149 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
150                                               const UTF32Char [],
151                                               CGGlyph [], CFIndex);
153 /* From CFData to a lisp string.  Always returns a unibyte string.  */
155 static Lisp_Object
156 cfdata_to_lisp (CFDataRef data)
158   CFIndex len = CFDataGetLength (data);
159   Lisp_Object result = make_uninit_string (len);
161   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
163   return result;
168 /* From CFString to a lisp string.  Returns a unibyte string
169    containing a UTF-8 byte sequence.  */
171 static Lisp_Object
172 cfstring_to_lisp_nodecode (CFStringRef string)
174   Lisp_Object result = Qnil;
175   CFDataRef data;
176   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
178   if (s)
179     {
180       CFIndex i, length = CFStringGetLength (string);
182       for (i = 0; i < length; i++)
183         if (CFStringGetCharacterAtIndex (string, i) == 0)
184           break;
186       if (i == length)
187         return make_unibyte_string (s, strlen (s));
188     }
190   data = CFStringCreateExternalRepresentation (NULL, string,
191                                                kCFStringEncodingUTF8, '?');
192   if (data)
193     {
194       result = cfdata_to_lisp (data);
195       CFRelease (data);
196     }
198   return result;
201 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
202    cfstring_create_with_utf8_cstring, this function preserves NUL
203    characters.  */
205 static CFStringRef
206 cfstring_create_with_string_noencode (Lisp_Object s)
208   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
209                                                 kCFStringEncodingUTF8, false);
211   if (string == NULL)
212     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
213     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
214                                       kCFStringEncodingMacRoman, false);
216   return string;
219 static CGFloat
220 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
222   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
224   return advancement.width;
227 static CGGlyph
228 mac_font_get_glyph_for_cid (FontRef font, CharacterCollection collection,
229                             CGFontIndex cid)
231 #if USE_CT_GLYPH_INFO
232   return mac_ctfont_get_glyph_for_cid ((CTFontRef) font, collection, cid);
233 #else
234   {
235     CGGlyph result = kCGFontIndexInvalid;
236     NSFont *nsFont = (NSFont *) font;
237     unichar characters[] = {0xfffd};
238     NSString *string =
239       [NSString stringWithCharacters:characters
240                               length:ARRAYELTS (characters)];
241     NSGlyphInfo *glyphInfo =
242       [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
243                                          collection:collection
244                                          baseString:string];
245     NSDictionary *attributes =
246       [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
247                     glyphInfo,NSGlyphInfoAttributeName,nil];
248     NSTextStorage *textStorage =
249       [[NSTextStorage alloc] initWithString:string
250                                  attributes:attributes];
251     NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
252     NSTextContainer *textContainer = [[NSTextContainer alloc] init];
253     NSFont *fontInTextStorage;
255     [layoutManager addTextContainer:textContainer];
256     [textContainer release];
257     [textStorage addLayoutManager:layoutManager];
258     [layoutManager release];
260     /* Force layout.  */
261     (void) [layoutManager glyphRangeForTextContainer:textContainer];
263     fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
264                                 effectiveRange:NULL];
265     if (fontInTextStorage == nsFont
266         || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
267       {
268         NSGlyph glyph = [layoutManager glyphAtIndex:0];
270         if (glyph < [nsFont numberOfGlyphs])
271           result = glyph;
272       }
274     [textStorage release];
276     return result;
277   }
279 #endif
281 static ScreenFontRef
282 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
284   NSFont *result, *font;
286   font = [NSFont fontWithName:((NSString *) name) size:size];
287   result = [font screenFont];
289   return (ScreenFontRef)[result retain];
293 static Boolean
294 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
295                              CGFloat *descent, CGFloat *leading)
297   NSFont *nsFont = [(NSFont *)font printerFont];
298   NSTextStorage *textStorage;
299   NSLayoutManager *layoutManager;
300   NSTextContainer *textContainer;
301   NSRect usedRect;
302   NSPoint spaceLocation;
303   CGFloat descender;
305   textStorage = [[NSTextStorage alloc] initWithString:@" "];
306   layoutManager = [[NSLayoutManager alloc] init];
307   textContainer = [[NSTextContainer alloc] init];
309   [textStorage setFont:nsFont];
310   [textContainer setLineFragmentPadding:0];
311   [layoutManager setUsesScreenFonts:YES];
313   [layoutManager addTextContainer:textContainer];
314   [textContainer release];
315   [textStorage addLayoutManager:layoutManager];
316   [layoutManager release];
318   if (!(textStorage && layoutManager && textContainer))
319     {
320       [textStorage release];
322       return false;
323     }
325   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
326                                                  effectiveRange:NULL];
327   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
328   [textStorage release];
330   *ascent = spaceLocation.y;
331   *descent = NSHeight (usedRect) - spaceLocation.y;
332   *leading = 0;
333   descender = [nsFont descender];
334   if (- descender < *descent)
335     {
336       *leading = *descent + descender;
337       *descent = - descender;
338     }
340   return true;
343 static CFIndex
344 mac_font_shape_1 (NSFont *font, NSString *string,
345                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
346                   BOOL screen_font_p)
348   NSUInteger i;
349   CFIndex result = 0;
350   NSTextStorage *textStorage;
351   NSLayoutManager *layoutManager;
352   NSTextContainer *textContainer;
353   NSUInteger stringLength;
354   NSPoint spaceLocation;
355   NSUInteger used, numberOfGlyphs;
357   textStorage = [[NSTextStorage alloc] initWithString:string];
358   layoutManager = [[NSLayoutManager alloc] init];
359   textContainer = [[NSTextContainer alloc] init];
361   /* Append a trailing space to measure baseline position.  */
362   [textStorage appendAttributedString:([[[NSAttributedString alloc]
363                                           initWithString:@" "] autorelease])];
364   [textStorage setFont:font];
365   [textContainer setLineFragmentPadding:0];
366   [layoutManager setUsesScreenFonts:screen_font_p];
368   [layoutManager addTextContainer:textContainer];
369   [textContainer release];
370   [textStorage addLayoutManager:layoutManager];
371   [layoutManager release];
373   if (!(textStorage && layoutManager && textContainer))
374     {
375       [textStorage release];
377       return 0;
378     }
380   stringLength = [string length];
382   /* Force layout.  */
383   (void) [layoutManager glyphRangeForTextContainer:textContainer];
385   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
387   /* Remove the appended trailing space because otherwise it may
388      generate a wrong result for a right-to-left text.  */
389   [textStorage beginEditing];
390   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
391   [textStorage endEditing];
392   (void) [layoutManager glyphRangeForTextContainer:textContainer];
394   i = 0;
395   while (i < stringLength)
396     {
397       NSRange range;
398       NSFont *fontInTextStorage =
399         [textStorage attribute:NSFontAttributeName atIndex:i
400                      longestEffectiveRange:&range
401                        inRange:(NSMakeRange (0, stringLength))];
403       if (!(fontInTextStorage == font
404             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
405         break;
406       i = NSMaxRange (range);
407     }
408   if (i < stringLength)
409     /* Make the test `used <= glyph_len' below fail if textStorage
410        contained some fonts other than the specified one.  */
411     used = glyph_len + 1;
412   else
413     {
414       NSRange range = NSMakeRange (0, stringLength);
416       range = [layoutManager glyphRangeForCharacterRange:range
417                                     actualCharacterRange:NULL];
418       numberOfGlyphs = NSMaxRange (range);
419       used = numberOfGlyphs;
420       for (i = 0; i < numberOfGlyphs; i++)
421         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
422           used--;
423     }
425   if (0 < used && used <= glyph_len)
426     {
427       NSUInteger glyphIndex, prevGlyphIndex;
428       unsigned char bidiLevel;
429       NSUInteger *permutation;
430       NSRange compRange, range;
431       CGFloat totalAdvance;
433       glyphIndex = 0;
434       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
435         glyphIndex++;
437       /* For now we assume the direction is not changed within the
438          string.  */
439       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
440                                glyphs:NULL characterIndexes:NULL
441                     glyphInscriptions:NULL elasticBits:NULL
442                            bidiLevels:&bidiLevel];
443       if (bidiLevel & 1)
444         permutation = xmalloc (sizeof (NSUInteger) * used);
445       else
446         permutation = NULL;
448 #define RIGHT_TO_LEFT_P permutation
450       /* Fill the `comp_range' member of struct mac_glyph_layout, and
451          setup a permutation for right-to-left text.  */
452       compRange = NSMakeRange (0, 0);
453       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
454            range.length++)
455         {
456           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
457           NSUInteger characterIndex =
458             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
460           gl->string_index = characterIndex;
462           if (characterIndex >= NSMaxRange (compRange))
463             {
464               compRange.location = NSMaxRange (compRange);
465               do
466                 {
467                   NSRange characterRange =
468                     [string
469                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
471                   compRange.length =
472                     NSMaxRange (characterRange) - compRange.location;
473                   [layoutManager glyphRangeForCharacterRange:compRange
474                                         actualCharacterRange:&characterRange];
475                   characterIndex = NSMaxRange (characterRange) - 1;
476                 }
477               while (characterIndex >= NSMaxRange (compRange));
479               if (RIGHT_TO_LEFT_P)
480                 for (i = 0; i < range.length; i++)
481                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
483               range = NSMakeRange (NSMaxRange (range), 0);
484             }
486           gl->comp_range.location = compRange.location;
487           gl->comp_range.length = compRange.length;
489           while (++glyphIndex < numberOfGlyphs)
490             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
491               break;
492         }
493       if (RIGHT_TO_LEFT_P)
494         for (i = 0; i < range.length; i++)
495           permutation[range.location + i] = NSMaxRange (range) - i - 1;
497       /* Then fill the remaining members.  */
498       glyphIndex = prevGlyphIndex = 0;
499       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
500         glyphIndex++;
502       if (!RIGHT_TO_LEFT_P)
503         totalAdvance = 0;
504       else
505         {
506           NSUInteger nrects;
507           NSRect *glyphRects =
508             [layoutManager
509               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
510               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
511                      inTextContainer:textContainer rectCount:&nrects];
513           totalAdvance = NSMaxX (glyphRects[0]);
514         }
516       for (i = 0; i < used; i++)
517         {
518           struct mac_glyph_layout *gl;
519           NSPoint location;
520           NSUInteger nextGlyphIndex;
521           NSRange glyphRange;
522           NSRect *glyphRects;
523           NSUInteger nrects;
525           if (!RIGHT_TO_LEFT_P)
526             gl = glyph_layouts + i;
527           else
528             {
529               NSUInteger dest = permutation[i];
531               gl = glyph_layouts + dest;
532               if (i < dest)
533                 {
534                   CFIndex tmp = gl->string_index;
536                   gl->string_index = glyph_layouts[i].string_index;
537                   glyph_layouts[i].string_index = tmp;
538                 }
539             }
540           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
542           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
543           gl->baseline_delta = spaceLocation.y - location.y;
545           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
546                nextGlyphIndex++)
547             if (![layoutManager
548                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
549               break;
551           if (!RIGHT_TO_LEFT_P)
552             {
553               CGFloat maxX;
555               if (prevGlyphIndex == 0)
556                 glyphRange = NSMakeRange (0, nextGlyphIndex);
557               else
558                 glyphRange = NSMakeRange (glyphIndex,
559                                           nextGlyphIndex - glyphIndex);
560               glyphRects =
561                 [layoutManager
562                   rectArrayForGlyphRange:glyphRange
563                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
564                          inTextContainer:textContainer rectCount:&nrects];
565               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
566               gl->advance_delta = location.x - totalAdvance;
567               gl->advance = maxX - totalAdvance;
568               totalAdvance = maxX;
569             }
570           else
571             {
572               CGFloat minX;
574               if (nextGlyphIndex == numberOfGlyphs)
575                 glyphRange = NSMakeRange (prevGlyphIndex,
576                                           numberOfGlyphs - prevGlyphIndex);
577               else
578                 glyphRange = NSMakeRange (prevGlyphIndex,
579                                           glyphIndex + 1 - prevGlyphIndex);
580               glyphRects =
581                 [layoutManager
582                   rectArrayForGlyphRange:glyphRange
583                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
584                          inTextContainer:textContainer rectCount:&nrects];
585               minX = min (NSMinX (glyphRects[0]), totalAdvance);
586               gl->advance = totalAdvance - minX;
587               totalAdvance = minX;
588               gl->advance_delta = location.x - totalAdvance;
589             }
591           prevGlyphIndex = glyphIndex + 1;
592           glyphIndex = nextGlyphIndex;
593         }
595       if (RIGHT_TO_LEFT_P)
596         xfree (permutation);
598 #undef RIGHT_TO_LEFT_P
600       result = used;
601    }
602  [textStorage release];
604   return result;
607 static CFIndex
608 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
609                        struct mac_glyph_layout *glyph_layouts,
610                        CFIndex glyph_len)
612   return mac_font_shape_1 ([(NSFont *)font printerFont],
613                            (NSString *) string,
614                            glyph_layouts, glyph_len, YES);
617 static CGColorRef
618 get_cgcolor(unsigned long idx, struct frame *f)
620   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
621   [nsColor set];
622   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
623   NSInteger noc = [nsColor numberOfComponents];
624   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
625   CGColorRef cgColor;
627   [nsColor getComponents: components];
628   cgColor = CGColorCreate (colorSpace, components);
629   xfree (components);
630   return cgColor;
633 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
634   do {                                                                  \
635     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
636     CGContextSetFillColorWithColor (context, refcol_) ;                 \
637     CGColorRelease (refcol_);                                           \
638   } while (0)
639 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f)        \
640   do {                                                                  \
641     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f);    \
642     CGContextSetFillColorWithColor (context, refcol_);                  \
643     CGColorRelease (refcol_);                                           \
644   } while (0)
645 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f)      \
646   do {                                                                  \
647     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
648     CGContextSetStrokeColorWithColor (context, refcol_);                \
649     CGColorRelease (refcol_);                                           \
650   } while (0)
653 /* Mac font driver.  */
655 static struct
657   /* registry name */
658   const char *name;
659   /* characters to distinguish the charset from the others */
660   int uniquifier[6];
661   /* additional constraint by language */
662   CFStringRef lang;
663   /* set on demand */
664   CFCharacterSetRef cf_charset;
665   CFStringRef cf_charset_string;
666 } cf_charset_table[] =
667   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
668     { "iso8859-2", { 0x00A0, 0x010E }},
669     { "iso8859-3", { 0x00A0, 0x0108 }},
670     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
671     { "iso8859-5", { 0x00A0, 0x0401 }},
672     { "iso8859-6", { 0x00A0, 0x060C }},
673     { "iso8859-7", { 0x00A0, 0x0384 }},
674     { "iso8859-8", { 0x00A0, 0x05D0 }},
675     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
676     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
677     { "iso8859-11", { 0x00A0, 0x0E01 }},
678     { "iso8859-13", { 0x00A0, 0x201C }},
679     { "iso8859-14", { 0x00A0, 0x0174 }},
680     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
681     { "iso8859-16", { 0x00A0, 0x0218}},
682     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
683     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
684     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
685     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
686     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
687     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
688     { "cns11643.1992-3", { 0x201A9 }},
689     { "cns11643.1992-4", { 0x20057 }},
690     { "cns11643.1992-5", { 0x20000 }},
691     { "cns11643.1992-6", { 0x20003 }},
692     { "cns11643.1992-7", { 0x20055 }},
693     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
694     { "jisx0212.1990-0", { 0x4E44 }},
695     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
696     { "jisx0213.2000-2", { 0xFA49 }},
697     { "jisx0213.2004-1", { 0x20B9F }},
698     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
699     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
700     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
701     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
702     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
703     { "unicode-sip", { 0x20000 }},
704     { NULL }
705   };
707 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
708 static const struct
710   CFStringRef language;
711   CFStringRef font_names[3];
712 } macfont_language_default_font_names[] = {
713   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
714                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
715                     NULL }},
716   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
717                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
718                     NULL }},
719   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
720                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
721                          NULL }},
722   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
723                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
724                          NULL }},
725   { NULL }
727 #endif
729 static CGFloat macfont_antialias_threshold;
731 static void
732 macfont_update_antialias_threshold (void)
734   int threshold;
735   Boolean valid_p;
737   threshold =
738     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
739                                      kCFPreferencesCurrentApplication,
740                                      &valid_p);
741   if (valid_p)
742     macfont_antialias_threshold = threshold;
745 static inline Lisp_Object
746 macfont_intern_prop_cfstring (CFStringRef cfstring)
748   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
750   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
753 static inline CFIndex
754 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
756   if (c < 0x10000)
757     {
758       unichars[0] = c;
760       return 1;
761     }
762   else
763     {
764       c -= 0x10000;
765       unichars[0] = (c >> 10) + 0xD800;
766       unichars[1] = (c & 0x3FF) + 0xDC00;
768       return 2;
769     }
772 static Boolean
773 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
774                                          FontSymbolicTraits *sym_traits)
776   SInt64 sint64_value;
778   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
779      OS 10.6 when the value is greater than or equal to 1 << 31.  */
780   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
781     {
782       *sym_traits = (FontSymbolicTraits) sint64_value;
784       return true;
785     }
787   return false;
790 static void
791 macfont_store_descriptor_attributes (FontDescriptorRef desc,
792                                      Lisp_Object spec_or_entity)
794   CFStringRef str;
795   CFDictionaryRef dict;
796   CFNumberRef num;
797   CGFloat floatval;
799   str = mac_font_descriptor_copy_attribute (desc,
800                                             MAC_FONT_FAMILY_NAME_ATTRIBUTE);
801   if (str)
802     {
803       ASET (spec_or_entity, FONT_FAMILY_INDEX,
804             macfont_intern_prop_cfstring (str));
805       CFRelease (str);
806     }
807   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
808   if (dict)
809     {
810       struct {
811         enum font_property_index index;
812         CFStringRef trait;
813         CGPoint points[6];
814       } numeric_traits[] =
815           {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
816             {{-0.4, 50},        /* light */
817              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
818              {0, 100},          /* normal */
819              {0.24, 140},       /* (semi-bold + normal) / 2 */
820              {0.4, 200},        /* bold */
821              {CGFLOAT_MAX, CGFLOAT_MAX}}},
822            {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
823             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
824            {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
825             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
826       int i;
828       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
829         {
830           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
831           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
832             {
833               CGPoint *point = numeric_traits[i].points;
835               while (point->x < floatval)
836                 point++;
837               if (point == numeric_traits[i].points)
838                 point++;
839               else if (point->x == CGFLOAT_MAX)
840                 point--;
841               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
842                                            * ((point->y - (point - 1)->y)
843                                               / (point->x - (point - 1)->x)));
844               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
845                               make_number (lround (floatval)));
846             }
847         }
849       num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
850       if (num)
851         {
852           FontSymbolicTraits sym_traits;
853           int spacing;
855           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
856           spacing = (sym_traits & MAC_FONT_TRAIT_MONO_SPACE
857                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
858           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
859         }
861       CFRelease (dict);
862     }
863   num = mac_font_descriptor_copy_attribute (desc, MAC_FONT_SIZE_ATTRIBUTE);
864   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
865     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
866   else
867     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
868   if (num)
869     CFRelease (num);
872 static Lisp_Object
873 macfont_descriptor_entity (FontDescriptorRef desc, Lisp_Object extra,
874                            FontSymbolicTraits synth_sym_traits)
876   Lisp_Object entity;
877   CFDictionaryRef dict;
878   FontSymbolicTraits sym_traits = 0;
879   CFStringRef name;
881   entity = font_make_entity ();
883   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
884   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
886   macfont_store_descriptor_attributes (desc, entity);
888   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
889   if (dict)
890     {
891       CFNumberRef num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
893       if (num)
894         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
895       CFRelease (dict);
896     }
897   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
898     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
899   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
900   name = mac_font_descriptor_copy_attribute (desc, MAC_FONT_NAME_ATTRIBUTE);
901   font_put_extra (entity, QCfont_entity,
902                   make_save_ptr_int ((void *) name, sym_traits));
903   if (synth_sym_traits & MAC_FONT_TRAIT_ITALIC)
904     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
905                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
906   if (synth_sym_traits & MAC_FONT_TRAIT_BOLD)
907     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
908                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
909   if (synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
910     ASET (entity, FONT_SPACING_INDEX,
911           make_number (FONT_SPACING_SYNTHETIC_MONO));
913   return entity;
916 static CFStringRef
917 macfont_create_family_with_symbol (Lisp_Object symbol)
919   static CFArrayRef families = NULL;
920   CFStringRef result = NULL, family_name;
921   int using_cache_p = 1;
922   CFComparatorFunction family_name_comparator;
924   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
925   if (family_name == NULL)
926     return NULL;
928 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
929 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
930   if (CTFontManagerCompareFontFamilyNames != NULL)
931 #endif
932     {
933       family_name_comparator = CTFontManagerCompareFontFamilyNames;
934     }
935 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
936   else               /* CTFontManagerCompareFontFamilyNames == NULL */
937 #endif
938 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
939 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
940     {
941       family_name_comparator = mac_font_family_compare;
942     }
943 #endif
945   if ((*family_name_comparator) (family_name, CFSTR ("LastResort"), NULL)
946       == kCFCompareEqualTo)
947     result = CFSTR ("LastResort");
948   else
949     while (1)
950       {
951         CFIndex i, count;
953         if (families == NULL)
954           {
955             families = mac_font_create_available_families ();
956             using_cache_p = 0;
957             if (families == NULL)
958               break;
959           }
961         count = CFArrayGetCount (families);
962         i = CFArrayBSearchValues (families, CFRangeMake (0, count),
963                                   (const void *) family_name,
964                                   family_name_comparator, NULL);
965         if (i < count)
966           {
967             CFStringRef name = CFArrayGetValueAtIndex (families, i);
969             if ((*family_name_comparator) (name, family_name, NULL)
970                 == kCFCompareEqualTo)
971               result = CFRetain (name);
972           }
974         if (result || !using_cache_p)
975           break;
976         else
977           {
978             CFRelease (families);
979             families = NULL;
980           }
981       }
983   CFRelease (family_name);
985   return result;
988 #define WIDTH_FRAC_BITS         (4)
989 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
991 struct macfont_metrics
993   unsigned char lbearing_low, rbearing_low;
994   signed lbearing_high : 4, rbearing_high : 4;
995   unsigned char ascent_low, descent_low;
996   signed ascent_high : 4, descent_high : 4;
998   /* These two members are used for fixed-point representation of
999      glyph width.  The `width_int' member is an integer that is
1000      closest to the width.  The `width_frac' member is the fractional
1001      adjustment representing a value in [-.5, .5], multiplied by
1002      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1003      the advance delta for centering instead of the glyph width.  */
1004   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1007 #define METRICS_VALUE(metrics, member) \
1008   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1009 #define METRICS_SET_VALUE(metrics, member, value) \
1010   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff; \
1011       (metrics)->member##_high = tmp >> 8;} while (0)
1013 enum metrics_status
1014   {
1015     METRICS_INVALID = -1,    /* metrics entry is invalid */
1016     METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1017   };
1019 #define METRICS_STATUS(metrics) \
1020   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1021 #define METRICS_SET_STATUS(metrics, status) \
1022   do {METRICS_SET_VALUE (metrics, ascent, 0); \
1023       METRICS_SET_VALUE (metrics, descent, status);} while (0)
1025 #define METRICS_NCOLS_PER_ROW   (128)
1026 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1027 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1029 static int
1030 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1031                        struct font_metrics *metrics, CGFloat *advance_delta,
1032                        int force_integral_p)
1034   struct macfont_info *macfont_info = (struct macfont_info *) font;
1035   FontRef macfont = macfont_info->macfont;
1036   int row, col;
1037   struct macfont_metrics *cache;
1038   int width;
1040   row = glyph / METRICS_NCOLS_PER_ROW;
1041   col = glyph % METRICS_NCOLS_PER_ROW;
1042   if (row >= macfont_info->metrics_nrows)
1043     {
1044       macfont_info->metrics =
1045         xrealloc (macfont_info->metrics,
1046                   sizeof (struct macfont_metrics *) * (row + 1));
1047       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1048               (sizeof (struct macfont_metrics *)
1049                * (row + 1 - macfont_info->metrics_nrows)));
1050       macfont_info->metrics_nrows = row + 1;
1051     }
1052   if (macfont_info->metrics[row] == NULL)
1053     {
1054       struct macfont_metrics *new;
1055       int i;
1057       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1058       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1059         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1060       macfont_info->metrics[row] = new;
1061     }
1062   cache = macfont_info->metrics[row] + col;
1064   if (METRICS_STATUS (cache) == METRICS_INVALID)
1065     {
1066       CGFloat fwidth;
1068       if (macfont_info->screen_font)
1069         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1070       else
1071         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1073       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1074          advance delta value.  */
1075       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1076         fwidth = (font->pixel_size - fwidth) / 2;
1077       cache->width_int = lround (fwidth);
1078       cache->width_frac = lround ((fwidth - cache->width_int)
1079                                   * WIDTH_FRAC_SCALE);
1080       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1081     }
1082   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1083     width = font->pixel_size;
1084   else
1085     width = cache->width_int;
1087   if (metrics)
1088     {
1089       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1090         {
1091           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1093           if (macfont_info->synthetic_italic_p)
1094             {
1095               /* We assume the members a, b, c, and d in
1096                  synthetic_italic_atfm are non-negative.  */
1097               bounds.origin =
1098                 CGPointApplyAffineTransform (bounds.origin,
1099                                              synthetic_italic_atfm);
1100               bounds.size =
1101                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1102             }
1103           if (macfont_info->synthetic_bold_p)
1104             {
1105               CGFloat d =
1106                 - synthetic_bold_factor * mac_font_get_size (macfont) / 2;
1108               bounds = CGRectInset (bounds, d, d);
1109             }
1110           switch (macfont_info->spacing)
1111             {
1112             case MACFONT_SPACING_PROPORTIONAL:
1113               bounds.origin.x += - (cache->width_frac
1114                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1115               break;
1116             case MACFONT_SPACING_MONO:
1117               break;
1118             case MACFONT_SPACING_SYNTHETIC_MONO:
1119               bounds.origin.x += (cache->width_int
1120                                   + (cache->width_frac
1121                                      / (CGFloat) WIDTH_FRAC_SCALE));
1122               break;
1123             }
1124           if (bounds.size.width > 0)
1125             {
1126               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1127               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1128                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1129             }
1130           bounds = CGRectIntegral (bounds);
1131           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1132           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1133           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1134           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1135         }
1136       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1137       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1138       metrics->width = width;
1139       metrics->ascent = METRICS_VALUE (cache, ascent);
1140       metrics->descent = METRICS_VALUE (cache, descent);
1141     }
1143   if (advance_delta)
1144     {
1145       switch (macfont_info->spacing)
1146         {
1147         case MACFONT_SPACING_PROPORTIONAL:
1148           *advance_delta = (force_integral_p ? 0
1149                             : - (cache->width_frac
1150                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1151           break;
1152         case MACFONT_SPACING_MONO:
1153           *advance_delta = 0;
1154           break;
1155         case MACFONT_SPACING_SYNTHETIC_MONO:
1156           *advance_delta = (force_integral_p ? cache->width_int
1157                             : (cache->width_int
1158                                + (cache->width_frac
1159                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1160           break;
1161         }
1162     }
1164   return width;
1167 static CFMutableDictionaryRef macfont_cache_dictionary;
1169 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1170    equal to the number of rows that are invalid as BMP (i.e., from
1171    U+D800 to U+DFFF).  */
1172 #define ROW_PERM_OFFSET (8)
1174 /* The number of glyphs that can be stored in a value for a single
1175    entry of CFDictionary.  */
1176 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1178 struct macfont_cache
1180   int reference_count;
1181   CFCharacterSetRef cf_charset;
1182   struct {
1183     /* The cached glyph for a BMP character c is stored in
1184        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1185        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1186     unsigned char row_nkeys_or_perm[256];
1187     CGGlyph **matrix;
1189     /* Number of rows for which the BMP cache is allocated so far.
1190        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1191     int nrows;
1193     /* The cached glyph for a character c is stored as the (c %
1194        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1195        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1196        not stored here if row_nkeys_or_perm[c / 256] >=
1197        ROW_PERM_OFFSET.  */
1198     CFMutableDictionaryRef dictionary;
1199   } glyph;
1201   struct {
1202     /* UVS (Unicode Variation Sequence) subtable data, which is of
1203        type CFDataRef if available.  NULL means it is not initialized
1204        yet.  kCFNull means the subtable is not found and there is no
1205        suitable fallback table for this font.  */
1206     CFTypeRef table;
1208     /* Character collection specifying the destination of the mapping
1209        provided by `table' above.  If `table' is obtained from the UVS
1210        subtable in the font cmap table, then the value of this member
1211        should be MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING.  */
1212     CharacterCollection collection;
1213   } uvs;
1216 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1217 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1218 static void macfont_release_cache (struct macfont_cache *);
1219 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1220 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1221 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1222 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1223                                           CharacterCollection, CGFontIndex);
1224 static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1226 static struct macfont_cache *
1227 macfont_lookup_cache (CFStringRef key)
1229   struct macfont_cache *cache;
1231   if (macfont_cache_dictionary == NULL)
1232     {
1233       macfont_cache_dictionary =
1234         CFDictionaryCreateMutable (NULL, 0,
1235                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1236       cache = NULL;
1237     }
1238   else
1239     cache = ((struct macfont_cache *)
1240              CFDictionaryGetValue (macfont_cache_dictionary, key));
1242   if (cache == NULL)
1243     {
1244       FontRef macfont = mac_font_create_with_name (key, 0);
1246       if (macfont)
1247         {
1248           cache = xzalloc (sizeof (struct macfont_cache));
1249           /* Treat the LastResort font as if it contained glyphs for
1250              all characters.  This may look too rough, but neither
1251              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1252              for this font is correct for non-BMP characters on Mac OS
1253              X 10.5, anyway.  */
1254           if (CFStringCompare (key, CFSTR ("LastResort"), 0)
1255               == kCFCompareEqualTo)
1256             {
1257               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1259               cache->cf_charset =
1260                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1261             }
1262           if (cache->cf_charset == NULL)
1263             cache->cf_charset = mac_font_copy_character_set (macfont);
1264           CFDictionaryAddValue (macfont_cache_dictionary, key,
1265                                 (const void *) cache);
1266           CFRelease (macfont);
1267         }
1268     }
1270   return cache;
1273 static struct macfont_cache *
1274 macfont_retain_cache (struct macfont_cache *cache)
1276   cache->reference_count++;
1278   return cache;
1281 static void
1282 macfont_release_cache (struct macfont_cache *cache)
1284   if (--cache->reference_count == 0)
1285     {
1286       int i;
1288       for (i = 0; i < cache->glyph.nrows; i++)
1289         xfree (cache->glyph.matrix[i]);
1290       xfree (cache->glyph.matrix);
1291       if (cache->glyph.dictionary)
1292         CFRelease (cache->glyph.dictionary);
1293       memset (&cache->glyph, 0, sizeof (cache->glyph));
1294       if (cache->uvs.table)
1295         CFRelease (cache->uvs.table);
1296       memset (&cache->uvs, 0, sizeof (cache->uvs));
1297     }
1300 static CFCharacterSetRef
1301 macfont_get_cf_charset (struct font *font)
1303   struct macfont_info *macfont_info = (struct macfont_info *) font;
1305   return macfont_info->cache->cf_charset;
1308 static CFCharacterSetRef
1309 macfont_get_cf_charset_for_name (CFStringRef name)
1311   struct macfont_cache *cache = macfont_lookup_cache (name);
1313   return cache->cf_charset;
1316 static CGGlyph
1317 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1319   struct macfont_info *macfont_info = (struct macfont_info *) font;
1320   FontRef macfont = macfont_info->macfont;
1321   struct macfont_cache *cache = macfont_info->cache;
1323   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1324     {
1325       int row = c / 256;
1326       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1328       if (nkeys_or_perm < ROW_PERM_OFFSET)
1329         {
1330           UniChar unichars[256], ch;
1331           CGGlyph *glyphs;
1332           int i, len;
1333           int nrows;
1334 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1335           dispatch_queue_t queue;
1336           dispatch_group_t group = NULL;
1337 #else
1338           int nkeys;
1339 #endif
1341           if (row != 0)
1342             {
1343               CFMutableDictionaryRef dictionary;
1344               uintptr_t key, value;
1345               int nshifts;
1346               CGGlyph glyph;
1348               if (cache->glyph.dictionary == NULL)
1349                 cache->glyph.dictionary =
1350                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1351               dictionary = cache->glyph.dictionary;
1352               key = c / NGLYPHS_IN_VALUE;
1353               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1354               value = ((uintptr_t)
1355                        CFDictionaryGetValue (dictionary, (const void *) key));
1356               glyph = (value >> nshifts);
1357               if (glyph)
1358                 return glyph;
1360               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1361                 {
1362                   ch = c;
1363                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1364                                                            &glyph, 1)
1365                       || glyph == 0)
1366                     glyph = kCGFontIndexInvalid;
1368                   if (value == 0)
1369                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1370                   value |= ((uintptr_t) glyph << nshifts);
1371                   CFDictionarySetValue (dictionary, (const void *) key,
1372                                         (const void *) value);
1374                   return glyph;
1375                 }
1377 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1378               queue =
1379                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1380               group = dispatch_group_create ();
1381               dispatch_group_async (group, queue, ^{
1382                   int nkeys;
1383                   uintptr_t key;
1384 #endif
1385                   nkeys = nkeys_or_perm;
1386                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1387                     if (CFDictionaryContainsKey (dictionary,
1388                                                  (const void *) key))
1389                       {
1390                         CFDictionaryRemoveValue (dictionary,
1391                                                  (const void *) key);
1392                         if (--nkeys == 0)
1393                           break;
1394                       }
1395 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1396                 });
1397 #endif
1398             }
1400           len = 0;
1401           for (i = 0; i < 256; i++)
1402             {
1403               ch = row * 256 + i;
1404               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1405                 unichars[len++] = ch;
1406             }
1408           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1409           if (len > 0)
1410             {
1411               mac_font_get_glyphs_for_characters (macfont, unichars,
1412                                                   glyphs, len);
1413               while (i > len)
1414                 {
1415                   int next = unichars[len - 1] % 256;
1417                   while (--i > next)
1418                     glyphs[i] = kCGFontIndexInvalid;
1420                   len--;
1421                   glyphs[i] = glyphs[len];
1422                   if (len == 0)
1423                     break;
1424                 }
1425             }
1426           if (i > len)
1427             while (i-- > 0)
1428               glyphs[i] = kCGFontIndexInvalid;
1430           nrows = cache->glyph.nrows;
1431           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1432           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1433           nrows++;
1434           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1435                                           sizeof (CGGlyph *) * nrows);
1436           cache->glyph.matrix[nrows - 1] = glyphs;
1437           cache->glyph.nrows = nrows;
1439 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1440           if (group)
1441             {
1442               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1443               dispatch_release (group);
1444             }
1445 #endif
1446         }
1448       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1449     }
1450   else
1451     {
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       key = c / NGLYPHS_IN_VALUE;
1460       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1461       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1462                                                 (const void *) key);
1463       glyph = (value >> nshifts);
1464       if (glyph == 0)
1465         {
1466           UniChar unichars[2];
1467           CGGlyph glyphs[2];
1468           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1470           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1471                                                   count))
1472             glyph = glyphs[0];
1473           if (glyph == 0)
1474             glyph = kCGFontIndexInvalid;
1476           value |= ((uintptr_t) glyph << nshifts);
1477           CFDictionarySetValue (cache->glyph.dictionary,
1478                                 (const void *) key, (const void *) value);
1479         }
1481       return glyph;
1482     }
1485 static CGGlyph
1486 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1487                            CGFontIndex cid)
1489   struct macfont_info *macfont_info = (struct macfont_info *) font;
1490   FontRef macfont = macfont_info->macfont;
1492   /* Cache it? */
1493   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1496 static CFDataRef
1497 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1499   struct macfont_info *macfont_info = (struct macfont_info *) font;
1500   FontRef macfont = macfont_info->macfont;
1501   struct macfont_cache *cache = macfont_info->cache;
1502   CFDataRef result = NULL;
1504   if (cache->uvs.table == NULL)
1505     {
1506       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1507       CharacterCollection uvs_collection =
1508         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1510       if (uvs_table == NULL
1511           && mac_font_get_glyph_for_cid (macfont,
1512                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1513                                          6480) != kCGFontIndexInvalid)
1514         {
1515           /* If the glyph for U+4E55 is accessible via its CID 6480,
1516              then we use the Adobe-Japan1 UVS table, which maps a
1517              variation sequence to a CID, as a fallback.  */
1518           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1520           if (mac_uvs_table_adobe_japan1 == NULL)
1521             mac_uvs_table_adobe_japan1 =
1522               CFDataCreateWithBytesNoCopy (NULL,
1523                                            mac_uvs_table_adobe_japan1_bytes,
1524                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1525                                            kCFAllocatorNull);
1526           if (mac_uvs_table_adobe_japan1)
1527             {
1528               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1529               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1530             }
1531         }
1532       if (uvs_table == NULL)
1533         cache->uvs.table = kCFNull;
1534       else
1535         cache->uvs.table = uvs_table;
1536       cache->uvs.collection = uvs_collection;
1537     }
1539   if (cache->uvs.table != kCFNull)
1540     {
1541       result = cache->uvs.table;
1542       *collection = cache->uvs.collection;
1543     }
1545   return result;
1548 static Lisp_Object macfont_get_cache (struct frame *);
1549 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1550 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1551 static Lisp_Object macfont_list_family (struct frame *);
1552 static void macfont_free_entity (Lisp_Object);
1553 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1554 static void macfont_close (struct font *);
1555 static int macfont_has_char (Lisp_Object, int);
1556 static unsigned macfont_encode_char (struct font *, int);
1557 static int macfont_text_extents (struct font *, unsigned int *, int,
1558                                  struct font_metrics *);
1559 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1560 static Lisp_Object macfont_shape (Lisp_Object);
1561 static int macfont_variation_glyphs (struct font *, int c,
1562                                      unsigned variations[256]);
1563 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1565 static struct font_driver macfont_driver =
1566   {
1567     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1568     0,                          /* case insensitive */
1569     macfont_get_cache,
1570     macfont_list,
1571     macfont_match,
1572     macfont_list_family,
1573     macfont_free_entity,
1574     macfont_open,
1575     macfont_close,
1576     NULL,                       /* prepare_face */
1577     NULL,                       /* done_face */
1578     macfont_has_char,
1579     macfont_encode_char,
1580     macfont_text_extents,
1581     macfont_draw,
1582     NULL,                       /* get_bitmap */
1583     NULL,                       /* free_bitmap */
1584     NULL,                       /* get_outline */
1585     NULL,                       /* free_outline */
1586     NULL,                       /* anchor_point */
1587     NULL,                       /* otf_capability */
1588     NULL,                       /* otf_drive */
1589     NULL,                       /* start_for_frame */
1590     NULL,                       /* end_for_frame */
1591     macfont_shape,
1592     NULL,                       /* check */
1593     macfont_variation_glyphs,
1594     macfont_filter_properties,
1595   };
1597 static Lisp_Object
1598 macfont_get_cache (struct frame * f)
1600   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1602   return (dpyinfo->name_list_element);
1605 static int
1606 macfont_get_charset (Lisp_Object registry)
1608   char *str = SSDATA (SYMBOL_NAME (registry));
1609   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1610   Lisp_Object regexp;
1611   int i, j;
1613   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1614     {
1615       if (str[i] == '.')
1616         re[j++] = '\\';
1617       else if (str[i] == '*')
1618         re[j++] = '.';
1619       re[j] = str[i];
1620       if (re[j] == '?')
1621         re[j] = '.';
1622     }
1623   re[j] = '\0';
1624   regexp = make_unibyte_string (re, j);
1625   for (i = 0; cf_charset_table[i].name; i++)
1626     if (fast_c_string_match_ignore_case
1627         (regexp, cf_charset_table[i].name,
1628          strlen (cf_charset_table[i].name)) >= 0)
1629       break;
1630   if (! cf_charset_table[i].name)
1631     return -1;
1632   if (! cf_charset_table[i].cf_charset)
1633     {
1634       int *uniquifier = cf_charset_table[i].uniquifier;
1635       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1636       CFIndex count = 0;
1637       CFStringRef string;
1638       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1640       if (! charset)
1641         return -1;
1642       for (j = 0; uniquifier[j]; j++)
1643         {
1644           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1645                                                         unichars + count);
1646           CFCharacterSetAddCharactersInRange (charset,
1647                                               CFRangeMake (uniquifier[j], 1));
1648         }
1650       string = CFStringCreateWithCharacters (NULL, unichars, count);
1651       if (! string)
1652         {
1653           CFRelease (charset);
1654           return -1;
1655         }
1656       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1657                                                                  charset);
1658       CFRelease (charset);
1659       /* CFCharacterSetCreateWithCharactersInString does not handle
1660          surrogate pairs properly as of Mac OS X 10.5.  */
1661      cf_charset_table[i].cf_charset_string = string;
1662     }
1663   return i;
1666 struct OpenTypeSpec
1668   Lisp_Object script;
1669   unsigned int script_tag, langsys_tag;
1670   int nfeatures[2];
1671   unsigned int *features[2];
1674 #define OTF_SYM_TAG(SYM, TAG)                                   \
1675   do {                                                          \
1676     unsigned char *p = SDATA (SYMBOL_NAME (SYM));               \
1677     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1678   } while (0)
1680 #define OTF_TAG_STR(TAG, P)                     \
1681   do {                                          \
1682     (P)[0] = (char) (TAG >> 24);                \
1683     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1684     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1685     (P)[3] = (char) (TAG & 0xFF);               \
1686     (P)[4] = '\0';                              \
1687   } while (0)
1689 static struct OpenTypeSpec *
1690 macfont_get_open_type_spec (Lisp_Object otf_spec)
1692   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1693   Lisp_Object val;
1694   int i, j;
1695   bool negative;
1697   if (! spec)
1698     return NULL;
1699   spec->script = XCAR (otf_spec);
1700   if (! NILP (spec->script))
1701     {
1702       OTF_SYM_TAG (spec->script, spec->script_tag);
1703       val = assq_no_quit (spec->script, Votf_script_alist);
1704       if (CONSP (val) && SYMBOLP (XCDR (val)))
1705         spec->script = XCDR (val);
1706       else
1707         spec->script = Qnil;
1708     }
1709   else
1710     spec->script_tag = 0x44464C54;      /* "DFLT" */
1711   otf_spec = XCDR (otf_spec);
1712   spec->langsys_tag = 0;
1713   if (! NILP (otf_spec))
1714     {
1715       val = XCAR (otf_spec);
1716       if (! NILP (val))
1717         OTF_SYM_TAG (val, spec->langsys_tag);
1718       otf_spec = XCDR (otf_spec);
1719     }
1720   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1721   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1722     {
1723       Lisp_Object len;
1725       val = XCAR (otf_spec);
1726       if (NILP (val))
1727         continue;
1728       len = Flength (val);
1729       spec->features[i] =
1730         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1731          ? 0
1732          : malloc (XINT (len) * sizeof *spec->features[i]));
1733       if (! spec->features[i])
1734         {
1735           if (i > 0 && spec->features[0])
1736             free (spec->features[0]);
1737           free (spec);
1738           return NULL;
1739         }
1740       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1741         {
1742           if (NILP (XCAR (val)))
1743             negative = 1;
1744           else
1745             {
1746               unsigned int tag;
1748               OTF_SYM_TAG (XCAR (val), tag);
1749               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1750             }
1751         }
1752       spec->nfeatures[i] = j;
1753     }
1754   return spec;
1757 static CFMutableDictionaryRef
1758 macfont_create_attributes_with_spec (Lisp_Object spec)
1760   Lisp_Object tmp, extra;
1761   CFMutableArrayRef langarray = NULL;
1762   CFCharacterSetRef charset = NULL;
1763   CFStringRef charset_string = NULL;
1764   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1765   Lisp_Object script = Qnil;
1766   Lisp_Object registry;
1767   int cf_charset_idx, i;
1768   struct OpenTypeSpec *otspec = NULL;
1769   struct {
1770     enum font_property_index index;
1771     CFStringRef trait;
1772     CGPoint points[6];
1773   } numeric_traits[] =
1774       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1775         {{-0.4, 50},            /* light */
1776          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1777          {0, 100},              /* normal */
1778          {0.24, 140},           /* (semi-bold + normal) / 2 */
1779          {0.4, 200},            /* bold */
1780          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1781        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1782         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1783        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1784         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1786   registry = AREF (spec, FONT_REGISTRY_INDEX);
1787   if (NILP (registry)
1788       || EQ (registry, Qascii_0)
1789       || EQ (registry, Qiso10646_1)
1790       || EQ (registry, Qunicode_bmp))
1791     cf_charset_idx = -1;
1792   else
1793     {
1794       CFStringRef lang;
1796       cf_charset_idx = macfont_get_charset (registry);
1797       if (cf_charset_idx < 0)
1798         goto err;
1799       charset = cf_charset_table[cf_charset_idx].cf_charset;
1800       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1801       lang = cf_charset_table[cf_charset_idx].lang;
1802       if (lang)
1803         {
1804           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1805           if (! langarray)
1806             goto err;
1807           CFArrayAppendValue (langarray, lang);
1808         }
1809     }
1811   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1812        CONSP (extra); extra = XCDR (extra))
1813     {
1814       Lisp_Object key, val;
1816       tmp = XCAR (extra);
1817       key = XCAR (tmp), val = XCDR (tmp);
1818       if (EQ (key, QClang))
1819         {
1820           if (! langarray)
1821             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1822           if (! langarray)
1823             goto err;
1824           if (SYMBOLP (val))
1825             val = list1 (val);
1826           for (; CONSP (val); val = XCDR (val))
1827             if (SYMBOLP (XCAR (val)))
1828               {
1829                 CFStringRef lang =
1830                   cfstring_create_with_string_noencode (SYMBOL_NAME
1831                                                         (XCAR (val)));
1833                 if (lang == NULL)
1834                   goto err;
1835                 CFArrayAppendValue (langarray, lang);
1836                 CFRelease (lang);
1837               }
1838         }
1839       else if (EQ (key, QCotf))
1840         {
1841           otspec = macfont_get_open_type_spec (val);
1842           if (! otspec)
1843             goto err;
1844           script = otspec->script;
1845         }
1846       else if (EQ (key, QCscript))
1847         script = val;
1848     }
1850   if (! NILP (script) && ! charset)
1851     {
1852       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1854       if (CONSP (chars) && CONSP (CDR (chars)))
1855         {
1856           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1857           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1859           if (! string || !cs)
1860             {
1861               if (string)
1862                 CFRelease (string);
1863               else if (cs)
1864                 CFRelease (cs);
1865               goto err;
1866             }
1867           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1868             if (CHARACTERP (XCAR (chars)))
1869               {
1870                 UniChar unichars[2];
1871                 CFIndex count =
1872                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1873                                                        unichars);
1874                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1876                 CFStringAppendCharacters (string, unichars, count);
1877                 CFCharacterSetAddCharactersInRange (cs, range);
1878               }
1879           charset = cs;
1880           /* CFCharacterSetCreateWithCharactersInString does not
1881              handle surrogate pairs properly as of Mac OS X 10.5.  */
1882           charset_string = string;
1883         }
1884     }
1886   attributes = CFDictionaryCreateMutable (NULL, 0,
1887                                           &kCFTypeDictionaryKeyCallBacks,
1888                                           &kCFTypeDictionaryValueCallBacks);
1889   if (! attributes)
1890     goto err;
1892   tmp = AREF (spec, FONT_FAMILY_INDEX);
1893   if (SYMBOLP (tmp) && ! NILP (tmp))
1894     {
1895       CFStringRef family = macfont_create_family_with_symbol (tmp);
1897       if (! family)
1898         goto err;
1899       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1900                             family);
1901       CFRelease (family);
1902     }
1904   traits = CFDictionaryCreateMutable (NULL, 4,
1905                                       &kCFTypeDictionaryKeyCallBacks,
1906                                       &kCFTypeDictionaryValueCallBacks);
1907   if (! traits)
1908     goto err;
1910   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1911     {
1912       tmp = AREF (spec, numeric_traits[i].index);
1913       if (INTEGERP (tmp))
1914         {
1915           CGPoint *point = numeric_traits[i].points;
1916           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1917           CFNumberRef num;
1919           while (point->y < floatval)
1920             point++;
1921           if (point == numeric_traits[i].points)
1922             point++;
1923           else if (point->y == CGFLOAT_MAX)
1924             point--;
1925           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1926                                        * ((point->x - (point - 1)->x)
1927                                           / (point->y - (point - 1)->y)));
1928           if (floatval > 1.0)
1929             floatval = 1.0;
1930           else if (floatval < -1.0)
1931             floatval = -1.0;
1932           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1933           if (! num)
1934             goto err;
1935           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1936           CFRelease (num);
1937         }
1938     }
1939   if (CFDictionaryGetCount (traits))
1940     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1942   if (charset)
1943     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1944                           charset);
1945   if (charset_string)
1946     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1947                           charset_string);
1948   if (langarray)
1949     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1951   goto finish;
1953  err:
1954   if (attributes)
1955     {
1956       CFRelease (attributes);
1957       attributes = NULL;
1958     }
1960  finish:
1961   if (langarray) CFRelease (langarray);
1962   if (charset && cf_charset_idx < 0) CFRelease (charset);
1963   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1964   if (traits) CFRelease (traits);
1965   if (otspec)
1966     {
1967       if (otspec->nfeatures[0] > 0)
1968         free (otspec->features[0]);
1969       if (otspec->nfeatures[1] > 0)
1970         free (otspec->features[1]);
1971       free (otspec);
1972     }
1974   return attributes;
1977 static Boolean
1978 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1979                                           CFCharacterSetRef charset,
1980                                           Lisp_Object chars,
1981                                           CFArrayRef languages)
1983   Boolean result = true;
1985   if (charset || VECTORP (chars))
1986     {
1987       CFCharacterSetRef desc_charset =
1988         mac_font_descriptor_copy_attribute (desc,
1989                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1991       if (desc_charset == NULL)
1992         result = false;
1993       else
1994         {
1995           if (charset)
1996             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
1997           else                  /* VECTORP (chars) */
1998             {
1999               ptrdiff_t j;
2001               for (j = 0; j < ASIZE (chars); j++)
2002                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2003                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2004                                                             XFASTINT (AREF (chars, j))))
2005                   break;
2006               if (j == ASIZE (chars))
2007                 result = false;
2008             }
2009           CFRelease (desc_charset);
2010         }
2011     }
2012   if (result && languages)
2013     result = mac_font_descriptor_supports_languages (desc, languages);
2015   return result;
2018 static CFIndex
2019 macfont_closest_traits_index (CFArrayRef traits_array,
2020                               FontSymbolicTraits target)
2022   CFIndex i, result = -1, count = CFArrayGetCount (traits_array);
2023   int min_distance = (1 << 3);
2025   for (i = 0; i < count; i++)
2026     {
2027       FontSymbolicTraits traits, diff;
2028       int distance = 0;
2030       traits = ((FontSymbolicTraits) (uintptr_t)
2031                 CFArrayGetValueAtIndex (traits_array, i));
2032       diff = (target ^ traits);
2033       /* We prefer synthetic bold of italic to synthetic italic of
2034          bold when both bold and italic are available but bold-italic
2035          is not available.  */
2036       if (diff & MAC_FONT_TRAIT_BOLD)
2037         distance |= (1 << 0);
2038       if (diff & MAC_FONT_TRAIT_ITALIC)
2039         distance |= (1 << 1);
2040       if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2041         distance |= (1 << 2);
2042       if (distance < min_distance)
2043         {
2044           min_distance = distance;
2045           result = i;
2046         }
2047     }
2049   return result;
2052 static Lisp_Object
2053 macfont_list (struct frame *f, Lisp_Object spec)
2055   Lisp_Object val = Qnil, family, extra;
2056   int i, n;
2057   CFStringRef family_name = NULL;
2058   CFMutableDictionaryRef attributes = NULL, traits;
2059   Lisp_Object chars = Qnil;
2060   int spacing = -1;
2061   FontSymbolicTraits synth_sym_traits = 0;
2062   CFArrayRef families;
2063   CFIndex families_count;
2064   CFCharacterSetRef charset = NULL;
2065   CFArrayRef languages = NULL;
2067   block_input ();
2069   family = AREF (spec, FONT_FAMILY_INDEX);
2070   if (! NILP (family))
2071     {
2072       family_name = macfont_create_family_with_symbol (family);
2073       if (family_name == NULL)
2074         goto finish;
2075     }
2077   attributes = macfont_create_attributes_with_spec (spec);
2078   if (! attributes)
2079     goto finish;
2081   languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2083   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2084     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2086   traits = ((CFMutableDictionaryRef)
2087             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2089   n = FONT_SLANT_NUMERIC (spec);
2090   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2091     {
2092       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2093       if (traits)
2094         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2095     }
2097   n = FONT_WEIGHT_NUMERIC (spec);
2098   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2099     {
2100       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2101       if (traits)
2102         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2103     }
2105   if (languages
2106       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2107     {
2108       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2110       if (CFStringHasPrefix (language, CFSTR ("ja"))
2111           || CFStringHasPrefix (language, CFSTR ("ko"))
2112           || CFStringHasPrefix (language, CFSTR ("zh")))
2113         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2114     }
2116   /* Create array of families.  */
2117   if (family_name)
2118     families = CFArrayCreate (NULL, (const void **) &family_name,
2119                               1, &kCFTypeArrayCallBacks);
2120   else
2121     {
2122       CFStringRef pref_family;
2123       CFIndex families_count, pref_family_index = -1;
2125       families = mac_font_create_available_families ();
2126       if (families == NULL)
2127         goto err;
2129       families_count = CFArrayGetCount (families);
2131       /* Move preferred family to the front if exists.  */
2132       pref_family =
2133         mac_font_create_preferred_family_for_attributes (attributes);
2134       if (pref_family)
2135         {
2136           pref_family_index =
2137             CFArrayGetFirstIndexOfValue (families,
2138                                          CFRangeMake (0, families_count),
2139                                          pref_family);
2140           CFRelease (pref_family);
2141         }
2142       if (pref_family_index > 0)
2143         {
2144           CFMutableArrayRef mutable_families =
2145             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2147           if (mutable_families)
2148             {
2149               CFArrayAppendValue (mutable_families,
2150                                   CFArrayGetValueAtIndex (families,
2151                                                           pref_family_index));
2152               CFArrayAppendArray (mutable_families, families,
2153                                   CFRangeMake (0, pref_family_index));
2154               if (pref_family_index + 1 < families_count)
2155                 CFArrayAppendArray (mutable_families, families,
2156                                     CFRangeMake (pref_family_index + 1,
2157                                                  families_count
2158                                                  - (pref_family_index + 1)));
2159               CFRelease (families);
2160               families = mutable_families;
2161             }
2162         }
2163     }
2165   charset = CFDictionaryGetValue (attributes,
2166                                   MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2167   if (charset)
2168     {
2169       CFRetain (charset);
2170       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2171     }
2172   else
2173     {
2174       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2175       if (! NILP (val))
2176         {
2177           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2178           if (CONSP (val) && VECTORP (XCDR (val)))
2179             chars = XCDR (val);
2180         }
2181       val = Qnil;
2182     }
2184   if (languages)
2185     {
2186       CFRetain (languages);
2187       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2188     }
2190   val = Qnil;
2191   extra = AREF (spec, FONT_EXTRA_INDEX);
2192   families_count = CFArrayGetCount (families);
2193   for (i = 0; i < families_count; i++)
2194     {
2195       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2196       FontDescriptorRef pat_desc;
2197       CFArrayRef descs;
2198       CFIndex descs_count;
2199       CFMutableArrayRef filtered_descs, traits_array;
2200       Lisp_Object entity;
2201       int j;
2203       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2204                             family_name);
2205       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2206       if (! pat_desc)
2207         goto err;
2209       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2210          10.7 returns NULL if pat_desc represents the LastResort font.
2211          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2212          trailing "s") for such a font.  */
2213       if (CFStringCompare (family_name, CFSTR ("LastResort"), 0)
2214           != kCFCompareEqualTo)
2215         descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2216                                                                       NULL);
2217       else
2218         {
2219           FontDescriptorRef lr_desc =
2220             mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2221                                                                  NULL);
2222           if (lr_desc)
2223             {
2224               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2225                                      &kCFTypeArrayCallBacks);
2226               CFRelease (lr_desc);
2227             }
2228           else
2229             descs = NULL;
2230         }
2231       CFRelease (pat_desc);
2232       if (! descs)
2233         goto err;
2235       descs_count = CFArrayGetCount (descs);
2236       if (descs_count == 0
2237           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2238                                                         charset, chars,
2239                                                         languages))
2240         {
2241           CFRelease (descs);
2242           continue;
2243         }
2245       filtered_descs =
2246         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2247       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2248       for (j = 0; j < descs_count; j++)
2249         {
2250           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2251           CFDictionaryRef dict;
2252           CFNumberRef num;
2253           FontSymbolicTraits sym_traits;
2255           dict = mac_font_descriptor_copy_attribute (desc,
2256                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2257           if (dict == NULL)
2258             continue;
2260           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2261           CFRelease (dict);
2262           if (num == NULL
2263               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2264             continue;
2266           if (spacing >= 0
2267               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2268               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2269                   != (spacing >= FONT_SPACING_MONO)))
2270             continue;
2272           /* Don't use a color bitmap font unless its family is
2273              explicitly specified.  */
2274           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2275             continue;
2277           if (j > 0
2278               && !macfont_supports_charset_and_languages_p (desc, charset,
2279                                                             chars, languages))
2280             continue;
2282           CFArrayAppendValue (filtered_descs, desc);
2283           CFArrayAppendValue (traits_array,
2284                               (const void *) (uintptr_t) sym_traits);
2285         }
2287       CFRelease (descs);
2288       descs = filtered_descs;
2289       descs_count = CFArrayGetCount (descs);
2291       for (j = 0; j < descs_count; j++)
2292         {
2293           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2294           FontSymbolicTraits sym_traits =
2295             ((FontSymbolicTraits) (uintptr_t)
2296              CFArrayGetValueAtIndex (traits_array, j));
2297           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2299           mask_min = ((synth_sym_traits ^ sym_traits)
2300                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2301           if (FONT_SLANT_NUMERIC (spec) < 0)
2302             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2303           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2304             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2306           mask_max = (synth_sym_traits & ~sym_traits);
2307           /* Synthetic bold does not work for bitmap-only fonts on Mac
2308              OS X 10.6.  */
2309           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2310             {
2311               CFNumberRef format =
2312                 mac_font_descriptor_copy_attribute (desc,
2313                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2315               if (format)
2316                 {
2317                   uint32_t format_val;
2319                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2320                                         &format_val)
2321                       && format_val == MAC_FONT_FORMAT_BITMAP)
2322                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2323                 }
2324             }
2325           if (spacing >= 0)
2326             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2328           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2329                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2330                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2331             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2332                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2333                  bmask += MAC_FONT_TRAIT_BOLD)
2334               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2335                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2336                    imask += MAC_FONT_TRAIT_ITALIC)
2337                 {
2338                   FontSymbolicTraits synth = (imask | bmask | mmask);
2340                   if (synth == 0
2341                       || j == macfont_closest_traits_index (traits_array,
2342                                                             (sym_traits | synth)))
2343                     {
2344                       entity = macfont_descriptor_entity (desc, extra, synth);
2345                       if (! NILP (entity))
2346                         val = Fcons (entity, val);
2347                     }
2348                 }
2349         }
2351       CFRelease (traits_array);
2352       CFRelease (descs);
2353     }
2355   CFRelease (families);
2356   val = Fnreverse (val);
2357   goto finish;
2358  err:
2359   val = Qnil;
2361  finish:
2362   FONT_ADD_LOG ("macfont-list", spec, val);
2363   if (charset) CFRelease (charset);
2364   if (languages) CFRelease (languages);
2365   if (attributes) CFRelease (attributes);
2366   if (family_name) CFRelease (family_name);
2368   unblock_input ();
2370   return val;
2373 static Lisp_Object
2374 macfont_match (struct frame * frame, Lisp_Object spec)
2376   Lisp_Object entity = Qnil;
2377   CFMutableDictionaryRef attributes;
2378   FontDescriptorRef pat_desc = NULL, desc = NULL;
2380   block_input ();
2382   attributes = macfont_create_attributes_with_spec (spec);
2383   if (attributes)
2384     {
2385       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2386       CFRelease (attributes);
2387     }
2388   if (pat_desc)
2389     {
2390       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2391                                                                   NULL);
2392       CFRelease (pat_desc);
2393     }
2394   if (desc)
2395     {
2396       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2397                                           0);
2398       CFRelease (desc);
2399     }
2400   unblock_input ();
2402   FONT_ADD_LOG ("macfont-match", spec, entity);
2403   return entity;
2406 static Lisp_Object
2407 macfont_list_family (struct frame *frame)
2409   Lisp_Object list = Qnil;
2410   CFArrayRef families;
2412   block_input ();
2414   families = mac_font_create_available_families ();
2415   if (families)
2416     {
2417       CFIndex i, count = CFArrayGetCount (families);
2419       for (i = 0; i < count; i++)
2420         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2421       CFRelease (families);
2422     }
2424   unblock_input ();
2426   return list;
2429 static void
2430 macfont_free_entity (Lisp_Object entity)
2432   Lisp_Object val = assq_no_quit (QCfont_entity,
2433                                   AREF (entity, FONT_EXTRA_INDEX));
2434   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2436   block_input ();
2437   CFRelease (name);
2438   unblock_input ();
2441 static Lisp_Object
2442 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2444   Lisp_Object val, font_object;
2445   CFStringRef font_name;
2446   struct macfont_info *macfont_info = NULL;
2447   struct font *font;
2448   int size;
2449   FontRef macfont;
2450   FontSymbolicTraits sym_traits;
2451   char name[256];
2452   int len, i, total_width;
2453   CGGlyph glyph;
2454   CGFloat ascent, descent, leading;
2456   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2457   if (! CONSP (val)
2458       || XTYPE (XCDR (val)) != Lisp_Misc
2459       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2460     return Qnil;
2461   font_name = XSAVE_POINTER (XCDR (val), 0);
2462   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2464   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2465   if (size == 0)
2466     size = pixel_size;
2468   block_input ();
2469   macfont = mac_font_create_with_name (font_name, size);
2470   if (macfont)
2471     {
2472       int fontsize = (int) [((NSFont *) macfont) pointSize];
2473       if (fontsize != size) size = fontsize;
2474     }
2475   unblock_input ();
2476   if (! macfont)
2477     return Qnil;
2479   font_object = font_make_object (VECSIZE (struct macfont_info), entity, size);
2480   ASET (font_object, FONT_TYPE_INDEX, macfont_driver.type);
2481   len = font_unparse_xlfd (entity, size, name, 256);
2482   if (len > 0)
2483     ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
2484   len = font_unparse_fcname (entity, size, name, 256);
2485   if (len > 0)
2486     ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
2487   else
2488     ASET (font_object, FONT_FULLNAME_INDEX,
2489           AREF (font_object, FONT_NAME_INDEX));
2490   font = XFONT_OBJECT (font_object);
2491   font->pixel_size = size;
2492   font->driver = &macfont_driver;
2493   font->encoding_charset = font->repertory_charset = -1;
2495   block_input ();
2497   macfont_info = (struct macfont_info *) font;
2498   macfont_info->macfont = macfont;
2499   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2501   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2502   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2503     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2504                                                                   size);
2505   else
2506     macfont_info->screen_font = NULL;
2507   macfont_info->cache = macfont_lookup_cache (font_name);
2508   macfont_retain_cache (macfont_info->cache);
2509   macfont_info->metrics = NULL;
2510   macfont_info->metrics_nrows = 0;
2511   macfont_info->synthetic_italic_p = 0;
2512   macfont_info->synthetic_bold_p = 0;
2513   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2514   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2515   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2516       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2517     macfont_info->synthetic_italic_p = 1;
2518   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2519       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2520     macfont_info->synthetic_bold_p = 1;
2521   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2522     macfont_info->spacing = MACFONT_SPACING_MONO;
2523   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2524            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2525                == FONT_SPACING_SYNTHETIC_MONO))
2526     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2527   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2528     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2529   else
2530     {
2531       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2532       if (CONSP (val))
2533         macfont_info->antialias =
2534           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2535     }
2536   macfont_info->color_bitmap_p = 0;
2537   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2538     macfont_info->color_bitmap_p = 1;
2540   glyph = macfont_get_glyph_for_character (font, ' ');
2541   if (glyph != kCGFontIndexInvalid)
2542     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2543   else
2544     /* dirty workaround */
2545     font->space_width = pixel_size;
2547   total_width = font->space_width;
2548   for (i = 1; i < 95; i++)
2549     {
2550       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2551       if (glyph == kCGFontIndexInvalid)
2552         break;
2553       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2554     }
2555   if (i == 95)
2556     font->average_width = total_width / 95;
2557   else
2558     font->average_width = font->space_width; /* XXX */
2560   if (!(macfont_info->screen_font
2561         && mac_screen_font_get_metrics (macfont_info->screen_font,
2562                                         &ascent, &descent, &leading)))
2563     {
2564       CFStringRef family_name;
2566       ascent = mac_font_get_ascent (macfont);
2567       descent = mac_font_get_descent (macfont);
2568       leading = mac_font_get_leading (macfont);
2569       /* AppKit and WebKit do some adjustment to the heights of
2570          Courier, Helvetica, and Times.  */
2571       family_name = mac_font_copy_family_name (macfont);
2572       if (family_name)
2573         {
2574           if ((CFStringCompare (family_name, CFSTR ("Courier"), 0)
2575                == kCFCompareEqualTo)
2576               || (CFStringCompare (family_name, CFSTR ("Helvetica"), 0)
2577                   == kCFCompareEqualTo)
2578               || (CFStringCompare (family_name, CFSTR ("Times"), 0)
2579                   == kCFCompareEqualTo))
2580             ascent += (ascent + descent) * .15f;
2581           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2582             {
2583               leading *= .25f;
2584               ascent += leading;
2585             }
2586           CFRelease (family_name);
2587         }
2588     }
2589   font->ascent = ascent + 0.5f;
2590   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2591   if (CONSP (val) && !NILP (XCDR (val)))
2592     font->descent = descent + 0.5f;
2593   else
2594     font->descent = descent + leading + 0.5f;
2595   font->height = font->ascent + font->descent;
2597   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2598   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2600   unblock_input ();
2602   /* Unfortunately Xft doesn't provide a way to get minimum char
2603      width.  So, we use space_width instead.  */
2604   font->min_width = font->max_width = font->space_width; /* XXX */
2606   font->baseline_offset = 0;
2607   font->relative_compose = 0;
2608   font->default_ascent = 0;
2609   font->vertical_centering = 0;
2611   return font_object;
2614 static void
2615 macfont_close (struct font *font)
2617   struct macfont_info *macfont_info = (struct macfont_info *) font;
2618   int i;
2620   block_input ();
2621   CFRelease (macfont_info->macfont);
2622   CGFontRelease (macfont_info->cgfont);
2623   if (macfont_info->screen_font)
2624     CFRelease (macfont_info->screen_font);
2625   macfont_release_cache (macfont_info->cache);
2626   for (i = 0; i < macfont_info->metrics_nrows; i++)
2627     if (macfont_info->metrics[i])
2628       xfree (macfont_info->metrics[i]);
2629   if (macfont_info->metrics)
2630     xfree (macfont_info->metrics);
2631   unblock_input ();
2634 static int
2635 macfont_has_char (Lisp_Object font, int c)
2637   int result;
2638   CFCharacterSetRef charset;
2640   block_input ();
2641   if (FONT_ENTITY_P (font))
2642     {
2643       Lisp_Object val;
2644       CFStringRef name;
2646       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2647       val = XCDR (val);
2648       name = XSAVE_POINTER (val, 0);
2649       charset = macfont_get_cf_charset_for_name (name);
2650     }
2651   else
2652     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2654   result = CFCharacterSetIsLongCharacterMember (charset, c);
2655   unblock_input ();
2657   return result;
2660 static unsigned
2661 macfont_encode_char (struct font *font, int c)
2663   struct macfont_info *macfont_info = (struct macfont_info *) font;
2664   CGGlyph glyph;
2666   block_input ();
2667   glyph = macfont_get_glyph_for_character (font, c);
2668   unblock_input ();
2670   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2673 static int
2674 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2675                       struct font_metrics *metrics)
2677   int width, i;
2679   block_input ();
2680   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2681   for (i = 1; i < nglyphs; i++)
2682     {
2683       struct font_metrics m;
2684       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2685                                      NULL, 0);
2687       if (metrics)
2688         {
2689           if (width + m.lbearing < metrics->lbearing)
2690             metrics->lbearing = width + m.lbearing;
2691           if (width + m.rbearing > metrics->rbearing)
2692             metrics->rbearing = width + m.rbearing;
2693           if (m.ascent > metrics->ascent)
2694             metrics->ascent = m.ascent;
2695           if (m.descent > metrics->descent)
2696             metrics->descent = m.descent;
2697         }
2698       width += w;
2699     }
2700   unblock_input ();
2702   if (metrics)
2703     metrics->width = width;
2705   return width;
2708 static int
2709 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2710               bool with_background)
2712   struct frame * f = s->f;
2713   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2714   FontRef macfont = macfont_info->macfont;
2715   CGContextRef context;
2716   BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
2717   int end = isComposite ? s->cmp_to : s->nchars;
2718   int len = end - s->cmp_from;
2719   struct face *face = s->face;
2720   int i;
2722   block_input ();
2724   context = [[NSGraphicsContext currentContext] graphicsPort];
2725   CGContextSaveGState (context);
2727 #if 0
2728   if (s->num_clips > 0)
2729     {
2730       CGRect clips[2];
2732       for (i = 0; i < s->num_clips; i++)
2733         clips[i] = mac_rect_make (f, s->clip[i].left, s->clip[i].top,
2734                                   s->clip[i].right - s->clip[i].left,
2735                                   s->clip[i].bottom - s->clip[i].top);
2736       CGContextClipToRects (context, clips, s->num_clips);
2737     }
2738 #endif
2740   if (with_background)
2741     {
2742       if (s->hl == DRAW_MOUSE_FACE) 
2743         {
2744           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2745           if (!face)
2746             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2747         }
2749       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2750       CGContextFillRect (context,
2751                          CGRectMake (x, y,
2752                                      s->width, FONT_HEIGHT (s->font)));
2753     }
2755   if (macfont_info->cgfont)
2756     {
2757       CGGlyph *glyphs = alloca (sizeof (CGGlyph) * len);
2758       CGPoint *positions = alloca (sizeof (CGPoint) * len);
2759       CGFloat total_width = 0;
2760       CGFloat font_size = mac_font_get_size (macfont);
2761       CGAffineTransform atfm;
2762       CGFloat advance_delta = 0;
2763       int y_draw = -s->ybase;
2764       int no_antialias_p =
2765         (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2766          || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2767              && font_size <= macfont_antialias_threshold));
2769       for (i = 0; i < len; i++)
2770         {
2771           int width;
2773           glyphs[i] = *(s->char2b + s->cmp_from + i);
2774           width = (s->padding_p ? 1
2775                    : macfont_glyph_extents (s->font, glyphs[i],
2776                                             NULL, &advance_delta,
2777                                             no_antialias_p));
2778           positions[i].x = total_width + advance_delta;
2779           positions[i].y = 0;
2780           total_width += width;
2781         }
2783       CGContextScaleCTM (context, 1, -1);
2784       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2785       if (macfont_info->synthetic_italic_p)
2786         atfm = synthetic_italic_atfm;
2787       else
2788         atfm = CGAffineTransformIdentity;
2789       if (macfont_info->synthetic_bold_p)
2790         {
2791           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2792           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2793           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2794         }
2795       if (no_antialias_p)
2796         CGContextSetShouldAntialias (context, false);
2798       CGContextSetTextMatrix (context, atfm);
2799       CGContextSetTextPosition (context, x, y_draw);
2801 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2802       if (macfont_info->color_bitmap_p
2803 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2804           && CTFontDrawGlyphs != NULL
2805 #endif
2806           )
2807         {
2808           if (len > 0)
2809             {
2810               CTFontDrawGlyphs (macfont, glyphs, positions, len, context);
2811             }
2812         }
2813       else
2814 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2815         {
2816           CGContextSetFont (context, macfont_info->cgfont);
2817           CGContextSetFontSize (context, font_size);
2818           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2819         }
2820     }
2822   CGContextRestoreGState (context);
2824   unblock_input ();
2826   return len;
2829 static Lisp_Object
2830 macfont_shape (Lisp_Object lgstring)
2832   struct font *font;
2833   struct macfont_info *macfont_info;
2834   FontRef macfont;
2835   ptrdiff_t glyph_len, len, i, j;
2836   CFIndex nonbmp_len;
2837   UniChar *unichars;
2838   CFIndex *nonbmp_indices;
2839   CFStringRef string;
2840   CFIndex used = 0;
2841   struct mac_glyph_layout *glyph_layouts;
2843   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2844   macfont_info = (struct macfont_info *) font;
2845   macfont = macfont_info->macfont;
2847   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2848   nonbmp_len = 0;
2849   for (i = 0; i < glyph_len; i++)
2850     {
2851       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2853       if (NILP (lglyph))
2854         break;
2855       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2856         nonbmp_len++;
2857     }
2859   len = i;
2861   if (INT_MAX / 2 < len)
2862     memory_full (SIZE_MAX);
2864   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2865   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2866   for (i = j = 0; i < len; i++)
2867     {
2868       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2870       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2871         {
2872           nonbmp_indices[j] = i + j;
2873           j++;
2874         }
2875     }
2876   nonbmp_indices[j] = len + j;  /* sentinel */
2878   block_input ();
2880   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2881                                                kCFAllocatorNull);
2882   if (string)
2883     {
2884       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2885       if (macfont_info->screen_font)
2886         used = mac_screen_font_shape (macfont_info->screen_font, string,
2887                                       glyph_layouts, glyph_len);
2888       else
2889         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2890       CFRelease (string);
2891     }
2893   unblock_input ();
2895   if (used == 0)
2896     return Qnil;
2898   block_input ();
2900   for (i = 0; i < used; i++)
2901     {
2902       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2903       struct mac_glyph_layout *gl = glyph_layouts + i;
2904       EMACS_INT from, to;
2905       struct font_metrics metrics;
2906       int xoff, yoff, wadjust;
2908       if (NILP (lglyph))
2909         {
2910           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2911           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2912         }
2914       from = gl->comp_range.location;
2915       /* Convert UTF-16 index to UTF-32.  */
2916       j = 0;
2917       while (nonbmp_indices[j] < from)
2918         j++;
2919       from -= j;
2920       LGLYPH_SET_FROM (lglyph, from);
2922       to = gl->comp_range.location + gl->comp_range.length;
2923       /* Convert UTF-16 index to UTF-32.  */
2924       while (nonbmp_indices[j] < to)
2925         j++;
2926       to -= j;
2927       LGLYPH_SET_TO (lglyph, to - 1);
2929       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2930          the composition is trivial.  */
2931       {
2932         UTF32Char c;
2934         if (unichars[gl->string_index] >= 0xD800
2935             && unichars[gl->string_index] < 0xDC00)
2936           c = (((unichars[gl->string_index] - 0xD800) << 10)
2937                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2938         else
2939           c = unichars[gl->string_index];
2940         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2941           c = 0;
2942         LGLYPH_SET_CHAR (lglyph, c);
2943       }
2945       {
2946         unsigned long cc = gl->glyph_id;
2947         LGLYPH_SET_CODE (lglyph, cc);
2948       }
2950       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2951       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2952       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2953       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2954       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2955       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2957       xoff = lround (gl->advance_delta);
2958       yoff = lround (- gl->baseline_delta);
2959       wadjust = lround (gl->advance);
2960       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2961         {
2962           Lisp_Object vec;
2964           vec = Fmake_vector (make_number (3), Qnil);
2965           ASET (vec, 0, make_number (xoff));
2966           ASET (vec, 1, make_number (yoff));
2967           ASET (vec, 2, make_number (wadjust));
2968           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2969         }
2970     }
2972   unblock_input ();
2974   return make_number (used);
2977 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2978 typedef UInt8 UINT24[3];
2980 #pragma pack(push, 1)
2981 struct variation_selector_record
2983   UINT24 var_selector;
2984   UInt32 default_uvs_offset, non_default_uvs_offset;
2986 struct uvs_table
2988   UInt16 format;
2989   UInt32 length, num_var_selector_records;
2990   struct variation_selector_record variation_selector_records[1];
2992 #define SIZEOF_UVS_TABLE_HEADER \
2993   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2995 struct unicode_value_range
2997   UINT24 start_unicode_value;
2998   UInt8 additional_count;
3000 struct default_uvs_table {
3001   UInt32 num_unicode_value_ranges;
3002   struct unicode_value_range unicode_value_ranges[1];
3004 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
3005   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3007 struct uvs_mapping
3009   UINT24 unicode_value;
3010   UInt16 glyph_id;
3012 struct non_default_uvs_table
3014   UInt32 num_uvs_mappings;
3015   struct uvs_mapping uvs_mappings[1];
3017 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3018   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3019 #pragma pack(pop)
3021 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3022 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3023    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3024    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3025 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3026 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3027 /* Succeeding one byte should also be accessible.  */
3028 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3029 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3031 /* Return UVS subtable for the specified FONT.  If the subtable is not
3032    found or ill-formatted, then return NULL.  */
3034 static CFDataRef
3035 mac_font_copy_uvs_table (FontRef font)
3037   CFDataRef cmap_table, uvs_table = NULL;
3039   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3040   if (cmap_table)
3041     {
3042       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3043       struct uvs_table *uvs;
3044       struct variation_selector_record *records;
3045       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3047 #if __LP64__
3048       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3049         goto finish;
3050 #endif
3052       cmap_len = CFDataGetLength (cmap_table);
3053       if (sizeof_sfntCMapHeader > cmap_len)
3054         goto finish;
3056       ntables = BUINT16_VALUE (cmap->numTables);
3057       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3058                      / sizeof_sfntCMapEncoding))
3059         goto finish;
3061       for (i = 0; i < ntables; i++)
3062         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3063              == kFontUnicodePlatform)
3064             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3065                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3066           {
3067             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3068             break;
3069           }
3070       if (i == ntables
3071           || uvs_offset > cmap_len
3072           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3073         goto finish;
3075       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3076       uvs_len = BUINT32_VALUE (uvs->length);
3077       if (uvs_len > cmap_len - uvs_offset
3078           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3079         goto finish;
3081       if (BUINT16_VALUE (uvs->format) != 14)
3082         goto finish;
3084       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3085       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3086                       / sizeof (struct variation_selector_record)))
3087         goto finish;
3089       records = uvs->variation_selector_records;
3090       for (i = 0; i < nrecords; i++)
3091         {
3092           UInt32 default_uvs_offset, non_default_uvs_offset;
3094           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3095           if (default_uvs_offset)
3096             {
3097               struct default_uvs_table *default_uvs;
3098               UInt32 nranges;
3100               if (default_uvs_offset > uvs_len
3101                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3102                       > uvs_len - default_uvs_offset))
3103                 goto finish;
3105               default_uvs = ((struct default_uvs_table *)
3106                              ((UInt8 *) uvs + default_uvs_offset));
3107               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3108               if (nranges > ((uvs_len - default_uvs_offset
3109                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3110                              / sizeof (struct unicode_value_range)))
3111                 goto finish;
3112               /* Now 2 * nranges can't overflow, so we can safely use
3113                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3114                  mac_font_get_glyphs_for_variants.  */
3115             }
3117           non_default_uvs_offset =
3118             BUINT32_VALUE (records[i].non_default_uvs_offset);
3119           if (non_default_uvs_offset)
3120             {
3121               struct non_default_uvs_table *non_default_uvs;
3122               UInt32 nmappings;
3124               if (non_default_uvs_offset > uvs_len
3125                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3126                       > uvs_len - non_default_uvs_offset))
3127                 goto finish;
3129               non_default_uvs = ((struct non_default_uvs_table *)
3130                                  ((UInt8 *) uvs + non_default_uvs_offset));
3131               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3132               if (nmappings > ((uvs_len - non_default_uvs_offset
3133                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3134                                / sizeof (struct uvs_mapping)))
3135                 goto finish;
3136               /* Now 2 * nmappings can't overflow, so we can safely
3137                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3138                  in mac_font_get_glyphs_for_variants.  */
3139             }
3140         }
3142       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3144     finish:
3145       CFRelease (cmap_table);
3146     }
3148   return uvs_table;
3151 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3152    sequence consisting of the given base character C and each
3153    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3154    result (explained below) into the corresponding GLYPHS[i].  If the
3155    entry is found in the Default UVS Table, then the result is 0.  If
3156    the entry is found in the Non-Default UVS Table, then the result is
3157    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3158    elements in SELECTORS must be sorted in strictly increasing
3159    order.  */
3161 static void
3162 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3163                                   const UTF32Char selectors[], CGGlyph glyphs[],
3164                                   CFIndex count)
3166   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3167   struct variation_selector_record *records = uvs->variation_selector_records;
3168   CFIndex i;
3169   UInt32 ir, nrecords;
3170 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3171   dispatch_queue_t queue =
3172     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3173   dispatch_group_t group = dispatch_group_create ();
3174 #endif
3176   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3177   i = 0;
3178   ir = 0;
3179   while (i < count && ir < nrecords)
3180     {
3181       UInt32 default_uvs_offset, non_default_uvs_offset;
3183       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3184         {
3185           glyphs[i++] = kCGFontIndexInvalid;
3186           continue;
3187         }
3188       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3189         {
3190           ir++;
3191           continue;
3192         }
3194       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3195       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3196       non_default_uvs_offset =
3197         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3198 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3199       dispatch_group_async (group, queue, ^{
3200 #endif
3201           glyphs[i] = kCGFontIndexInvalid;
3203           if (default_uvs_offset)
3204             {
3205               struct default_uvs_table *default_uvs =
3206                 (struct default_uvs_table *) ((UInt8 *) uvs
3207                                               + default_uvs_offset);
3208               struct unicode_value_range *ranges =
3209                 default_uvs->unicode_value_ranges;
3210               UInt32 lo, hi;
3212               lo = 0;
3213               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3214               while (lo < hi)
3215                 {
3216                   UInt32 mid = (lo + hi) / 2;
3218                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3219                     hi = mid;
3220                   else
3221                     lo = mid + 1;
3222                 }
3223               if (hi > 0
3224                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3225                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3226                 glyphs[i] = 0;
3227             }
3229           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3230             {
3231               struct non_default_uvs_table *non_default_uvs =
3232                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3233                                                   + non_default_uvs_offset);
3234               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3235               UInt32 lo, hi;
3237               lo = 0;
3238               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3239               while (lo < hi)
3240                 {
3241                   UInt32 mid = (lo + hi) / 2;
3243                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3244                     hi = mid;
3245                   else
3246                     lo = mid + 1;
3247                 }
3248               if (hi > 0 &&
3249                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3250                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3251             }
3252 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3253         });
3254 #endif
3255       i++;
3256       ir++;
3257     }
3258   while (i < count)
3259     glyphs[i++] = kCGFontIndexInvalid;
3260 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3261   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3262   dispatch_release (group);
3263 #endif
3266 static int
3267 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3269   CFDataRef uvs_table;
3270   CharacterCollection uvs_collection;
3271   int i, n = 0;
3273   block_input ();
3274   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3276   if (uvs_table)
3277     {
3278       UTF32Char selectors[256];
3279       CGGlyph glyphs[256];
3281       for (i = 0; i < 16; i++)
3282         selectors[i] = 0xFE00 + i;
3283       for (; i < 256; i++)
3284         selectors[i] = 0xE0100 + (i - 16);
3285       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3286       for (i = 0; i < 256; i++)
3287         {
3288           CGGlyph glyph = glyphs[i];
3290           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3291               && glyph != kCGFontIndexInvalid)
3292             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3293           if (glyph == kCGFontIndexInvalid)
3294             variations[i] = 0;
3295           else
3296             {
3297               variations[i] = (glyph ? glyph
3298                                : macfont_get_glyph_for_character (font, c));
3299               n++;
3300             }
3301         }
3302     }
3303   unblock_input ();
3305   return n;
3308 static const char *const macfont_booleans[] = {
3309   ":antialias",
3310   ":minspace",
3311   NULL,
3314 static const char *const macfont_non_booleans[] = {
3315   ":lang",
3316   ":script",
3317   ":destination",
3318   NULL,
3321 static void
3322 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3324   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3327 static Boolean
3328 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3329                                           CFArrayRef languages)
3331   Boolean result = true;
3332   CFArrayRef desc_languages =
3333     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3335   if (desc_languages == NULL)
3336     result = false;
3337   else
3338     {
3339       CFIndex desc_languages_count, i, languages_count;
3341       desc_languages_count = CFArrayGetCount (desc_languages);
3342       languages_count = CFArrayGetCount (languages);
3343       for (i = 0; i < languages_count; i++)
3344         if (!CFArrayContainsValue (desc_languages,
3345                                    CFRangeMake (0, desc_languages_count),
3346                                    CFArrayGetValueAtIndex (languages, i)))
3347           {
3348             result = false;
3349             break;
3350           }
3351       CFRelease (desc_languages);
3352     }
3354   return result;
3357 static CFStringRef
3358 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3360   CFStringRef result = NULL;
3361   CFStringRef charset_string =
3362     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3364   if (charset_string && CFStringGetLength (charset_string) > 0)
3365     {
3366       CFStringRef keys[] = {
3367 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3368         kCTLanguageAttributeName
3369 #else
3370         CFSTR ("NSLanguage")
3371 #endif
3372       };
3373       CFTypeRef values[] = {NULL};
3374       CFIndex num_values = 0;
3375       CFArrayRef languages
3376         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3378       if (languages && CFArrayGetCount (languages) > 0)
3379         {
3380           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3381             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3382           else
3383             {
3384               CFCharacterSetRef charset =
3385                 CFDictionaryGetValue (attributes,
3386                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3388               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3389             }
3390         }
3391       if (result == NULL)
3392         {
3393           CFAttributedStringRef attr_string = NULL;
3394           CTLineRef ctline = NULL;
3395           CFDictionaryRef attrs
3396             = CFDictionaryCreate (NULL, (const void **) keys,
3397                                   (const void **) values, num_values,
3398                                   &kCFTypeDictionaryKeyCallBacks,
3399                                   &kCFTypeDictionaryValueCallBacks);
3401           if (attrs)
3402             {
3403               attr_string = CFAttributedStringCreate (NULL, charset_string,
3404                                                       attrs);
3405               CFRelease (attrs);
3406             }
3407           if (attr_string)
3408             {
3409               ctline = CTLineCreateWithAttributedString (attr_string);
3410               CFRelease (attr_string);
3411             }
3412           if (ctline)
3413             {
3414               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3415               CFIndex i, nruns = CFArrayGetCount (runs);
3416               CTFontRef font;
3418               for (i = 0; i < nruns; i++)
3419                 {
3420                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3421                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3422                   CTFontRef font_in_run;
3424                   if (attributes == NULL)
3425                     break;
3426                   font_in_run =
3427                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3428                   if (font_in_run == NULL)
3429                     break;
3430                   if (i == 0)
3431                     font = font_in_run;
3432                   else if (!mac_ctfont_equal_in_postscript_name (font,
3433                                                                  font_in_run))
3434                     break;
3435                 }
3436               if (nruns > 0 && i == nruns)
3437                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3438               CFRelease (ctline);
3439             }
3440         }
3441     }
3443   return result;
3446 static inline double
3447 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3449   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3450                                      &glyph, NULL, 1);
3453 static inline CGRect
3454 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3456   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3457                                           &glyph, NULL, 1);
3460 static CFArrayRef
3461 mac_ctfont_create_available_families (void)
3463   CFMutableArrayRef families = NULL;
3465 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3466 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3467   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3468 #endif
3469     {
3470       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3472       if (orig_families)
3473         {
3474           CFIndex i, count = CFArrayGetCount (orig_families);
3476           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3477           if (families)
3478             for (i = 0; i < count; i++)
3479               {
3480                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3482                 if (!CFStringHasPrefix (family, CFSTR ("."))
3483                     && (CTFontManagerCompareFontFamilyNames (family,
3484                                                              CFSTR ("LastResort"),
3485                                                              NULL)
3486                         != kCFCompareEqualTo))
3487                   CFArrayAppendValue (families, family);
3488               }
3489           CFRelease (orig_families);
3490         }
3491     }
3492 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3493   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3494 #endif
3495 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3496 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3497     {
3498       CTFontCollectionRef collection;
3499       CFArrayRef descs = NULL;
3501       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3502       if (collection)
3503         {
3504           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3505           CFRelease (collection);
3506         }
3507       if (descs)
3508         {
3509           CFIndex i, count = CFArrayGetCount (descs);
3511           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3512           if (families)
3513             for (i = 0; i < count; i++)
3514               {
3515                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3516                 CFStringRef name =
3517                   mac_font_descriptor_copy_attribute (desc,
3518                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3520                 if (name)
3521                   {
3522                     CFIndex p, limit = CFArrayGetCount (families);
3524                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3525                                               (const void *) name,
3526                                               mac_font_family_compare, NULL);
3527                     if (p >= limit)
3528                       CFArrayAppendValue (families, name);
3529                     else if (mac_font_family_compare
3530                              (CFArrayGetValueAtIndex (families, p),
3531                               name, NULL) != kCFCompareEqualTo)
3532                       CFArrayInsertValueAtIndex (families, p, name);
3533                     CFRelease (name);
3534                   }
3535               }
3536           CFRelease (descs);
3537         }
3538     }
3539 #endif
3541   return families;
3544 static Boolean
3545 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3547   Boolean result;
3548   CFStringRef name1, name2;
3550   if (font1 == font2)
3551     return true;
3553   result = false;
3554   name1 = CTFontCopyPostScriptName (font1);
3555   if (name1)
3556     {
3557       name2 = CTFontCopyPostScriptName (font2);
3558       if (name2)
3559         {
3560           result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3561           CFRelease (name2);
3562         }
3563       CFRelease (name1);
3564     }
3566   return result;
3569 static CTLineRef
3570 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3571                                              CTFontRef macfont)
3573   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3574   CFTypeRef values[] = {NULL, NULL};
3575   CFDictionaryRef attributes = NULL;
3576   CFAttributedStringRef attr_string = NULL;
3577   CTLineRef ctline = NULL;
3578   float float_zero = 0.0f;
3580   values[0] = macfont;
3581   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3582   if (values[1])
3583     {
3584       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3585                                        (const void **) values,
3586                                        ARRAYELTS (keys),
3587                                        &kCFTypeDictionaryKeyCallBacks,
3588                                        &kCFTypeDictionaryValueCallBacks);
3589       CFRelease (values[1]);
3590     }
3591   if (attributes)
3592     {
3593       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3594       CFRelease (attributes);
3595     }
3596   if (attr_string)
3597     {
3598       ctline = CTLineCreateWithAttributedString (attr_string);
3599       CFRelease (attr_string);
3600     }
3601   if (ctline)
3602     {
3603       /* Abandon if ctline contains some fonts other than the
3604          specified one.  */
3605       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3606       CFIndex i, nruns = CFArrayGetCount (runs);
3608       for (i = 0; i < nruns; i++)
3609         {
3610           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3611           CFDictionaryRef attributes = CTRunGetAttributes (run);
3612           CTFontRef font_in_run;
3614           if (attributes == NULL)
3615             break;
3616           font_in_run =
3617             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3618           if (font_in_run == NULL)
3619             break;
3620           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3621             break;
3622         }
3623       if (i < nruns)
3624         {
3625           CFRelease (ctline);
3626           ctline = NULL;
3627         }
3628     }
3630   return ctline;
3633 static CFIndex
3634 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3635                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3637   CFIndex used, result = 0;
3638   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3640   if (ctline == NULL)
3641     return 0;
3643   used = CTLineGetGlyphCount (ctline);
3644   if (used <= glyph_len)
3645     {
3646       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3647       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3648       CGFloat total_advance = 0;
3649       CFIndex total_glyph_count = 0;
3651       for (k = 0; k < ctrun_count; k++)
3652         {
3653           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3654           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3655           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3656           CFRange string_range, comp_range, range;
3657           CFIndex *permutation;
3659           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3660             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3661           else
3662             permutation = NULL;
3664 #define RIGHT_TO_LEFT_P permutation
3666           /* Now the `comp_range' member of struct mac_glyph_layout is
3667              temporarily used as a work area such that:
3668               glbuf[i].comp_range.location =
3669                 min {compRange[i + 1].location, ...,
3670                      compRange[glyph_count - 1].location,
3671                      maxRange (stringRangeForCTRun)}
3672               glbuf[i].comp_range.length = maxRange (compRange[i])
3673              where compRange[i] is the range of composed characters
3674              containing i-th glyph.  */
3675           string_range = CTRunGetStringRange (ctrun);
3676           min_location = string_range.location + string_range.length;
3677           for (i = 0; i < glyph_count; i++)
3678             {
3679               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3680               CFIndex glyph_index;
3681               CFRange rng;
3683               if (!RIGHT_TO_LEFT_P)
3684                 glyph_index = glyph_count - i - 1;
3685               else
3686                 glyph_index = i;
3687               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3688                                      &gl->string_index);
3689               rng =
3690                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3691                                                              gl->string_index);
3692               gl->comp_range.location = min_location;
3693               gl->comp_range.length = rng.location + rng.length;
3694               if (rng.location < min_location)
3695                 min_location = rng.location;
3696             }
3698           /* Fill the `comp_range' member of struct mac_glyph_layout,
3699              and setup a permutation for right-to-left text.  */
3700           comp_range = CFRangeMake (string_range.location, 0);
3701           range = CFRangeMake (0, 0);
3702           while (1)
3703             {
3704               struct mac_glyph_layout *gl =
3705                 glbuf + range.location + range.length;
3707               if (gl->comp_range.length
3708                   > comp_range.location + comp_range.length)
3709                 comp_range.length = gl->comp_range.length - comp_range.location;
3710               min_location = gl->comp_range.location;
3711               range.length++;
3713               if (min_location >= comp_range.location + comp_range.length)
3714                 {
3715                   comp_range.length = min_location - comp_range.location;
3716                   for (i = 0; i < range.length; i++)
3717                     {
3718                       glbuf[range.location + i].comp_range = comp_range;
3719                       if (RIGHT_TO_LEFT_P)
3720                         permutation[range.location + i] =
3721                           range.location + range.length - i - 1;
3722                     }
3724                   comp_range = CFRangeMake (min_location, 0);
3725                   range.location += range.length;
3726                   range.length = 0;
3727                   if (range.location == glyph_count)
3728                     break;
3729                 }
3730             }
3732           /* Then fill the remaining members.  */
3733           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3734                range.location++)
3735             {
3736               struct mac_glyph_layout *gl;
3737               CGPoint position;
3739               if (!RIGHT_TO_LEFT_P)
3740                 gl = glbuf + range.location;
3741               else
3742                 {
3743                   CFIndex src, dest;
3745                   src = glyph_count - 1 - range.location;
3746                   dest = permutation[src];
3747                   gl = glbuf + dest;
3748                   if (src < dest)
3749                     {
3750                       CFIndex tmp = gl->string_index;
3752                       gl->string_index = glbuf[src].string_index;
3753                       glbuf[src].string_index = tmp;
3754                     }
3755                 }
3756               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3758               CTRunGetPositions (ctrun, range, &position);
3759               gl->advance_delta = position.x - total_advance;
3760               gl->baseline_delta = position.y;
3761               gl->advance = (gl->advance_delta
3762                              + CTRunGetTypographicBounds (ctrun, range,
3763                                                           NULL, NULL, NULL));
3764               total_advance += gl->advance;
3765             }
3767           if (RIGHT_TO_LEFT_P)
3768             xfree (permutation);
3770 #undef RIGHT_TO_LEFT_P
3772           total_glyph_count += glyph_count;
3773         }
3775       result = used;
3776     }
3777   CFRelease (ctline);
3779   return result;
3782 /* The function below seems to cause a memory leak for the CFString
3783    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3784    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3785 #if USE_CT_GLYPH_INFO
3786 static CGGlyph
3787 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3788                               CGFontIndex cid)
3790   CGGlyph result = kCGFontIndexInvalid;
3791   UniChar characters[] = {0xfffd};
3792   CFStringRef string;
3793   CFAttributedStringRef attr_string = NULL;
3794   CTLineRef ctline = NULL;
3796   string = CFStringCreateWithCharacters (NULL, characters,
3797                                          ARRAYELTS (characters));
3799   if (string)
3800     {
3801       CTGlyphInfoRef glyph_info =
3802         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3803       CFDictionaryRef attributes = NULL;
3805       if (glyph_info)
3806         {
3807           CFStringRef keys[] = {kCTFontAttributeName,
3808                                 kCTGlyphInfoAttributeName};
3809           CFTypeRef values[] = {font, glyph_info};
3811           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3812                                            (const void **) values,
3813                                            ARRAYELTS (keys),
3814                                            &kCFTypeDictionaryKeyCallBacks,
3815                                            &kCFTypeDictionaryValueCallBacks);
3816           CFRelease (glyph_info);
3817         }
3818       if (attributes)
3819         {
3820           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3821           CFRelease (attributes);
3822         }
3823       CFRelease (string);
3824     }
3825   if (attr_string)
3826     {
3827       ctline = CTLineCreateWithAttributedString (attr_string);
3828       CFRelease (attr_string);
3829     }
3830   if (ctline)
3831     {
3832       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3834       if (CFArrayGetCount (runs) > 0)
3835         {
3836           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3837           CFDictionaryRef attributes = CTRunGetAttributes (run);
3839           if (attributes)
3840             {
3841               CTFontRef font_in_run =
3842                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3844               if (font_in_run
3845                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3846                 {
3847                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3848                   if (result >= CTFontGetGlyphCount (font))
3849                     result = kCGFontIndexInvalid;
3850                 }
3851             }
3852         }
3853       CFRelease (ctline);
3854     }
3856   return result;
3858 #endif
3860 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3861 static inline int
3862 mac_font_family_group (CFStringRef family)
3864   if (CFStringHasPrefix (family, CFSTR ("#")))
3865     return 2;
3866   else
3867     {
3868       CFRange range;
3870       range = CFStringFind (family, CFSTR ("Apple"),
3871                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3872       if (range.location != kCFNotFound)
3873         return 1;
3875       return 0;
3876     }
3879 static CFComparisonResult
3880 mac_font_family_compare (const void *val1, const void *val2, void *context)
3882   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3883   int group1, group2;
3885   group1 = mac_font_family_group (family1);
3886   group2 = mac_font_family_group (family2);
3887   if (group1 < group2)
3888     return kCFCompareLessThan;
3889   if (group1 > group2)
3890     return kCFCompareGreaterThan;
3891   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3893 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3895 static CFArrayRef
3896 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3898   CFArrayRef result = NULL;
3900 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3901 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3902   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3903 #endif
3904     {
3905       CTFontRef user_font =
3906         CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3908       if (user_font)
3909         {
3910           CFArrayRef languages =
3911             CFArrayCreate (NULL, (const void **) &language, 1,
3912                            &kCFTypeArrayCallBacks);
3914           if (languages)
3915             {
3916               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3917                                                                  languages);
3918               CFRelease (languages);
3919             }
3920           CFRelease (user_font);
3921         }
3922     }
3923 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3924   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3925 #endif
3926 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3927 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3928     {
3929       CFIndex i;
3931       for (i = 0; macfont_language_default_font_names[i].language; i++)
3932         {
3933           if (CFStringCompare (macfont_language_default_font_names[i].language,
3934                                language, 0) == kCFCompareEqualTo)
3935             {
3936               CFMutableArrayRef descriptors =
3937                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3939               if (descriptors)
3940                 {
3941                   CFIndex j;
3943                   for (j = 0;
3944                        macfont_language_default_font_names[i].font_names[j];
3945                        j++)
3946                     {
3947                       CFDictionaryRef attributes =
3948                         CFDictionaryCreate (NULL,
3949                                             ((const void **)
3950                                              &MAC_FONT_NAME_ATTRIBUTE),
3951                                             ((const void **)
3952                                              &macfont_language_default_font_names[i].font_names[j]),
3953                                             1, &kCFTypeDictionaryKeyCallBacks,
3954                                             &kCFTypeDictionaryValueCallBacks);
3956                       if (attributes)
3957                         {
3958                           FontDescriptorRef pat_desc =
3959                             mac_font_descriptor_create_with_attributes (attributes);
3961                           if (pat_desc)
3962                             {
3963                               FontDescriptorRef descriptor =
3964                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3966                               if (descriptor)
3967                                 {
3968                                   CFArrayAppendValue (descriptors, descriptor);
3969                                   CFRelease (descriptor);
3970                                 }
3971                               CFRelease (pat_desc);
3972                             }
3973                           CFRelease (attributes);
3974                         }
3975                     }
3976                   result = descriptors;
3977                 }
3978               break;
3979             }
3980         }
3981     }
3982 #endif
3984   return result;
3987 static CFStringRef
3988 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3989                                                       CFArrayRef languages)
3991   CFStringRef result = NULL;
3992   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3993   CFArrayRef descriptors =
3994     mac_font_copy_default_descriptors_for_language (language);
3996   if (descriptors)
3997     {
3998       CFIndex i, count = CFArrayGetCount (descriptors);
4000       for (i = 0; i < count; i++)
4001         {
4002           FontDescriptorRef descriptor =
4003             CFArrayGetValueAtIndex (descriptors, i);
4005           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4006                                                         Qnil, languages))
4007             {
4008               CFStringRef family =
4009                 mac_font_descriptor_copy_attribute (descriptor,
4010                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
4011               if (family)
4012                 {
4013                   if (!CFStringHasPrefix (family, CFSTR ("."))
4014                       && (CFStringCompare (family, CFSTR ("LastResort"), 0)
4015                           != kCFCompareEqualTo))
4016                     {
4017                       result = family;
4018                       break;
4019                     }
4020                   else
4021                     CFRelease (family);
4022                 }
4023             }
4024         }
4025       CFRelease (descriptors);
4026     }
4028   return result;
4031 void *
4032 macfont_get_nsctfont (struct font *font)
4034   struct macfont_info *macfont_info = (struct macfont_info *) font;
4035   FontRef macfont = macfont_info->macfont;
4037   return (void *) macfont;
4040 void
4041 mac_register_font_driver (struct frame *f)
4043   register_font_driver (&macfont_driver, f);
4046 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4049 void
4050 syms_of_macfont (void)
4052 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4053   static struct font_driver mac_font_driver;
4055   DEFSYM (Qmac_ct, "mac-ct");
4056   macfont_driver.type = Qmac_ct;
4057   register_font_driver (&macfont_driver, NULL);
4059   DEFSYM (QCdestination, ":destination");
4060   DEFSYM (QCminspace, ":minspace");
4061 #endif