Remove unused variable EMACS_HEAPSIZE from src/Makefile.in.
[emacs.git] / src / macfont.m
blob4bc58229d6e7ff94d37e02c4fcd928d63a54eb52
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 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 X 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 (CFEqual (key, CFSTR ("LastResort")))
1255             {
1256               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1258               cache->cf_charset =
1259                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1260             }
1261           if (cache->cf_charset == NULL)
1262             cache->cf_charset = mac_font_copy_character_set (macfont);
1263           CFDictionaryAddValue (macfont_cache_dictionary, key,
1264                                 (const void *) cache);
1265           CFRelease (macfont);
1266         }
1267     }
1269   return cache;
1272 static struct macfont_cache *
1273 macfont_retain_cache (struct macfont_cache *cache)
1275   cache->reference_count++;
1277   return cache;
1280 static void
1281 macfont_release_cache (struct macfont_cache *cache)
1283   if (--cache->reference_count == 0)
1284     {
1285       int i;
1287       for (i = 0; i < cache->glyph.nrows; i++)
1288         xfree (cache->glyph.matrix[i]);
1289       xfree (cache->glyph.matrix);
1290       if (cache->glyph.dictionary)
1291         CFRelease (cache->glyph.dictionary);
1292       memset (&cache->glyph, 0, sizeof (cache->glyph));
1293       if (cache->uvs.table)
1294         CFRelease (cache->uvs.table);
1295       memset (&cache->uvs, 0, sizeof (cache->uvs));
1296     }
1299 static CFCharacterSetRef
1300 macfont_get_cf_charset (struct font *font)
1302   struct macfont_info *macfont_info = (struct macfont_info *) font;
1304   return macfont_info->cache->cf_charset;
1307 static CFCharacterSetRef
1308 macfont_get_cf_charset_for_name (CFStringRef name)
1310   struct macfont_cache *cache = macfont_lookup_cache (name);
1312   return cache->cf_charset;
1315 static CGGlyph
1316 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1318   struct macfont_info *macfont_info = (struct macfont_info *) font;
1319   FontRef macfont = macfont_info->macfont;
1320   struct macfont_cache *cache = macfont_info->cache;
1322   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1323     {
1324       int row = c / 256;
1325       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1327       if (nkeys_or_perm < ROW_PERM_OFFSET)
1328         {
1329           UniChar unichars[256], ch;
1330           CGGlyph *glyphs;
1331           int i, len;
1332           int nrows;
1333 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1334           dispatch_queue_t queue;
1335           dispatch_group_t group = NULL;
1336 #else
1337           int nkeys;
1338 #endif
1340           if (row != 0)
1341             {
1342               CFMutableDictionaryRef dictionary;
1343               uintptr_t key, value;
1344               int nshifts;
1345               CGGlyph glyph;
1347               if (cache->glyph.dictionary == NULL)
1348                 cache->glyph.dictionary =
1349                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1350               dictionary = cache->glyph.dictionary;
1351               key = c / NGLYPHS_IN_VALUE;
1352               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1353               value = ((uintptr_t)
1354                        CFDictionaryGetValue (dictionary, (const void *) key));
1355               glyph = (value >> nshifts);
1356               if (glyph)
1357                 return glyph;
1359               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1360                 {
1361                   ch = c;
1362                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1363                                                            &glyph, 1)
1364                       || glyph == 0)
1365                     glyph = kCGFontIndexInvalid;
1367                   if (value == 0)
1368                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1369                   value |= ((uintptr_t) glyph << nshifts);
1370                   CFDictionarySetValue (dictionary, (const void *) key,
1371                                         (const void *) value);
1373                   return glyph;
1374                 }
1376 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1377               queue =
1378                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1379               group = dispatch_group_create ();
1380               dispatch_group_async (group, queue, ^{
1381                   int nkeys;
1382                   uintptr_t key;
1383 #endif
1384                   nkeys = nkeys_or_perm;
1385                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1386                     if (CFDictionaryContainsKey (dictionary,
1387                                                  (const void *) key))
1388                       {
1389                         CFDictionaryRemoveValue (dictionary,
1390                                                  (const void *) key);
1391                         if (--nkeys == 0)
1392                           break;
1393                       }
1394 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1395                 });
1396 #endif
1397             }
1399           len = 0;
1400           for (i = 0; i < 256; i++)
1401             {
1402               ch = row * 256 + i;
1403               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1404                 unichars[len++] = ch;
1405             }
1407           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1408           if (len > 0)
1409             {
1410               mac_font_get_glyphs_for_characters (macfont, unichars,
1411                                                   glyphs, len);
1412               while (i > len)
1413                 {
1414                   int next = unichars[len - 1] % 256;
1416                   while (--i > next)
1417                     glyphs[i] = kCGFontIndexInvalid;
1419                   len--;
1420                   glyphs[i] = glyphs[len];
1421                   if (len == 0)
1422                     break;
1423                 }
1424             }
1425           if (i > len)
1426             while (i-- > 0)
1427               glyphs[i] = kCGFontIndexInvalid;
1429           nrows = cache->glyph.nrows;
1430           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1431           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1432           nrows++;
1433           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1434                                           sizeof (CGGlyph *) * nrows);
1435           cache->glyph.matrix[nrows - 1] = glyphs;
1436           cache->glyph.nrows = nrows;
1438 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1439           if (group)
1440             {
1441               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1442               dispatch_release (group);
1443             }
1444 #endif
1445         }
1447       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1448     }
1449   else
1450     {
1451       uintptr_t key, value;
1452       int nshifts;
1453       CGGlyph glyph;
1455       if (cache->glyph.dictionary == NULL)
1456         cache->glyph.dictionary =
1457           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1458       key = c / NGLYPHS_IN_VALUE;
1459       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1460       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1461                                                 (const void *) key);
1462       glyph = (value >> nshifts);
1463       if (glyph == 0)
1464         {
1465           UniChar unichars[2];
1466           CGGlyph glyphs[2];
1467           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1469           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1470                                                   count))
1471             glyph = glyphs[0];
1472           if (glyph == 0)
1473             glyph = kCGFontIndexInvalid;
1475           value |= ((uintptr_t) glyph << nshifts);
1476           CFDictionarySetValue (cache->glyph.dictionary,
1477                                 (const void *) key, (const void *) value);
1478         }
1480       return glyph;
1481     }
1484 static CGGlyph
1485 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1486                            CGFontIndex cid)
1488   struct macfont_info *macfont_info = (struct macfont_info *) font;
1489   FontRef macfont = macfont_info->macfont;
1491   /* Cache it? */
1492   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1495 static CFDataRef
1496 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1498   struct macfont_info *macfont_info = (struct macfont_info *) font;
1499   FontRef macfont = macfont_info->macfont;
1500   struct macfont_cache *cache = macfont_info->cache;
1501   CFDataRef result = NULL;
1503   if (cache->uvs.table == NULL)
1504     {
1505       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1506       CharacterCollection uvs_collection =
1507         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1509       if (uvs_table == NULL
1510           && mac_font_get_glyph_for_cid (macfont,
1511                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1512                                          6480) != kCGFontIndexInvalid)
1513         {
1514           /* If the glyph for U+4E55 is accessible via its CID 6480,
1515              then we use the Adobe-Japan1 UVS table, which maps a
1516              variation sequence to a CID, as a fallback.  */
1517           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1519           if (mac_uvs_table_adobe_japan1 == NULL)
1520             mac_uvs_table_adobe_japan1 =
1521               CFDataCreateWithBytesNoCopy (NULL,
1522                                            mac_uvs_table_adobe_japan1_bytes,
1523                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1524                                            kCFAllocatorNull);
1525           if (mac_uvs_table_adobe_japan1)
1526             {
1527               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1528               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1529             }
1530         }
1531       if (uvs_table == NULL)
1532         cache->uvs.table = kCFNull;
1533       else
1534         cache->uvs.table = uvs_table;
1535       cache->uvs.collection = uvs_collection;
1536     }
1538   if (cache->uvs.table != kCFNull)
1539     {
1540       result = cache->uvs.table;
1541       *collection = cache->uvs.collection;
1542     }
1544   return result;
1547 static Lisp_Object macfont_get_cache (struct frame *);
1548 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1549 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1550 static Lisp_Object macfont_list_family (struct frame *);
1551 static void macfont_free_entity (Lisp_Object);
1552 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1553 static void macfont_close (struct font *);
1554 static int macfont_has_char (Lisp_Object, int);
1555 static unsigned macfont_encode_char (struct font *, int);
1556 static void macfont_text_extents (struct font *, unsigned int *, int,
1557                                   struct font_metrics *);
1558 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1559 static Lisp_Object macfont_shape (Lisp_Object);
1560 static int macfont_variation_glyphs (struct font *, int c,
1561                                      unsigned variations[256]);
1562 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1564 static struct font_driver macfont_driver =
1565   {
1566     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1567     0,                          /* case insensitive */
1568     macfont_get_cache,
1569     macfont_list,
1570     macfont_match,
1571     macfont_list_family,
1572     macfont_free_entity,
1573     macfont_open,
1574     macfont_close,
1575     NULL,                       /* prepare_face */
1576     NULL,                       /* done_face */
1577     macfont_has_char,
1578     macfont_encode_char,
1579     macfont_text_extents,
1580     macfont_draw,
1581     NULL,                       /* get_bitmap */
1582     NULL,                       /* free_bitmap */
1583     NULL,                       /* anchor_point */
1584     NULL,                       /* otf_capability */
1585     NULL,                       /* otf_drive */
1586     NULL,                       /* start_for_frame */
1587     NULL,                       /* end_for_frame */
1588     macfont_shape,
1589     NULL,                       /* check */
1590     macfont_variation_glyphs,
1591     macfont_filter_properties,
1592   };
1594 static Lisp_Object
1595 macfont_get_cache (struct frame * f)
1597   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1599   return (dpyinfo->name_list_element);
1602 static int
1603 macfont_get_charset (Lisp_Object registry)
1605   char *str = SSDATA (SYMBOL_NAME (registry));
1606   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1607   Lisp_Object regexp;
1608   int i, j;
1610   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1611     {
1612       if (str[i] == '.')
1613         re[j++] = '\\';
1614       else if (str[i] == '*')
1615         re[j++] = '.';
1616       re[j] = str[i];
1617       if (re[j] == '?')
1618         re[j] = '.';
1619     }
1620   re[j] = '\0';
1621   regexp = make_unibyte_string (re, j);
1622   for (i = 0; cf_charset_table[i].name; i++)
1623     if (fast_c_string_match_ignore_case
1624         (regexp, cf_charset_table[i].name,
1625          strlen (cf_charset_table[i].name)) >= 0)
1626       break;
1627   if (! cf_charset_table[i].name)
1628     return -1;
1629   if (! cf_charset_table[i].cf_charset)
1630     {
1631       int *uniquifier = cf_charset_table[i].uniquifier;
1632       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1633       CFIndex count = 0;
1634       CFStringRef string;
1635       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1637       if (! charset)
1638         return -1;
1639       for (j = 0; uniquifier[j]; j++)
1640         {
1641           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1642                                                         unichars + count);
1643           CFCharacterSetAddCharactersInRange (charset,
1644                                               CFRangeMake (uniquifier[j], 1));
1645         }
1647       string = CFStringCreateWithCharacters (NULL, unichars, count);
1648       if (! string)
1649         {
1650           CFRelease (charset);
1651           return -1;
1652         }
1653       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1654                                                                  charset);
1655       CFRelease (charset);
1656       /* CFCharacterSetCreateWithCharactersInString does not handle
1657          surrogate pairs properly as of Mac OS X 10.5.  */
1658      cf_charset_table[i].cf_charset_string = string;
1659     }
1660   return i;
1663 struct OpenTypeSpec
1665   Lisp_Object script;
1666   unsigned int script_tag, langsys_tag;
1667   int nfeatures[2];
1668   unsigned int *features[2];
1671 #define OTF_SYM_TAG(SYM, TAG)                                   \
1672   do {                                                          \
1673     unsigned char *p = SDATA (SYMBOL_NAME (SYM));               \
1674     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1675   } while (0)
1677 #define OTF_TAG_STR(TAG, P)                     \
1678   do {                                          \
1679     (P)[0] = (char) (TAG >> 24);                \
1680     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1681     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1682     (P)[3] = (char) (TAG & 0xFF);               \
1683     (P)[4] = '\0';                              \
1684   } while (0)
1686 static struct OpenTypeSpec *
1687 macfont_get_open_type_spec (Lisp_Object otf_spec)
1689   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1690   Lisp_Object val;
1691   int i, j;
1692   bool negative;
1694   if (! spec)
1695     return NULL;
1696   spec->script = XCAR (otf_spec);
1697   if (! NILP (spec->script))
1698     {
1699       OTF_SYM_TAG (spec->script, spec->script_tag);
1700       val = assq_no_quit (spec->script, Votf_script_alist);
1701       if (CONSP (val) && SYMBOLP (XCDR (val)))
1702         spec->script = XCDR (val);
1703       else
1704         spec->script = Qnil;
1705     }
1706   else
1707     spec->script_tag = 0x44464C54;      /* "DFLT" */
1708   otf_spec = XCDR (otf_spec);
1709   spec->langsys_tag = 0;
1710   if (! NILP (otf_spec))
1711     {
1712       val = XCAR (otf_spec);
1713       if (! NILP (val))
1714         OTF_SYM_TAG (val, spec->langsys_tag);
1715       otf_spec = XCDR (otf_spec);
1716     }
1717   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1718   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1719     {
1720       Lisp_Object len;
1722       val = XCAR (otf_spec);
1723       if (NILP (val))
1724         continue;
1725       len = Flength (val);
1726       spec->features[i] =
1727         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1728          ? 0
1729          : malloc (XINT (len) * sizeof *spec->features[i]));
1730       if (! spec->features[i])
1731         {
1732           if (i > 0 && spec->features[0])
1733             free (spec->features[0]);
1734           free (spec);
1735           return NULL;
1736         }
1737       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1738         {
1739           if (NILP (XCAR (val)))
1740             negative = 1;
1741           else
1742             {
1743               unsigned int tag;
1745               OTF_SYM_TAG (XCAR (val), tag);
1746               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1747             }
1748         }
1749       spec->nfeatures[i] = j;
1750     }
1751   return spec;
1754 static CFMutableDictionaryRef
1755 macfont_create_attributes_with_spec (Lisp_Object spec)
1757   Lisp_Object tmp, extra;
1758   CFMutableArrayRef langarray = NULL;
1759   CFCharacterSetRef charset = NULL;
1760   CFStringRef charset_string = NULL;
1761   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1762   Lisp_Object script = Qnil;
1763   Lisp_Object registry;
1764   int cf_charset_idx, i;
1765   struct OpenTypeSpec *otspec = NULL;
1766   struct {
1767     enum font_property_index index;
1768     CFStringRef trait;
1769     CGPoint points[6];
1770   } numeric_traits[] =
1771       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1772         {{-0.4, 50},            /* light */
1773          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1774          {0, 100},              /* normal */
1775          {0.24, 140},           /* (semi-bold + normal) / 2 */
1776          {0.4, 200},            /* bold */
1777          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1778        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1779         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1780        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1781         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1783   registry = AREF (spec, FONT_REGISTRY_INDEX);
1784   if (NILP (registry)
1785       || EQ (registry, Qascii_0)
1786       || EQ (registry, Qiso10646_1)
1787       || EQ (registry, Qunicode_bmp))
1788     cf_charset_idx = -1;
1789   else
1790     {
1791       CFStringRef lang;
1793       cf_charset_idx = macfont_get_charset (registry);
1794       if (cf_charset_idx < 0)
1795         goto err;
1796       charset = cf_charset_table[cf_charset_idx].cf_charset;
1797       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1798       lang = cf_charset_table[cf_charset_idx].lang;
1799       if (lang)
1800         {
1801           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1802           if (! langarray)
1803             goto err;
1804           CFArrayAppendValue (langarray, lang);
1805         }
1806     }
1808   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1809        CONSP (extra); extra = XCDR (extra))
1810     {
1811       Lisp_Object key, val;
1813       tmp = XCAR (extra);
1814       key = XCAR (tmp), val = XCDR (tmp);
1815       if (EQ (key, QClang))
1816         {
1817           if (! langarray)
1818             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1819           if (! langarray)
1820             goto err;
1821           if (SYMBOLP (val))
1822             val = list1 (val);
1823           for (; CONSP (val); val = XCDR (val))
1824             if (SYMBOLP (XCAR (val)))
1825               {
1826                 CFStringRef lang =
1827                   cfstring_create_with_string_noencode (SYMBOL_NAME
1828                                                         (XCAR (val)));
1830                 if (lang == NULL)
1831                   goto err;
1832                 CFArrayAppendValue (langarray, lang);
1833                 CFRelease (lang);
1834               }
1835         }
1836       else if (EQ (key, QCotf))
1837         {
1838           otspec = macfont_get_open_type_spec (val);
1839           if (! otspec)
1840             goto err;
1841           script = otspec->script;
1842         }
1843       else if (EQ (key, QCscript))
1844         script = val;
1845     }
1847   if (! NILP (script) && ! charset)
1848     {
1849       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1851       if (CONSP (chars) && CONSP (CDR (chars)))
1852         {
1853           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1854           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1856           if (! string || !cs)
1857             {
1858               if (string)
1859                 CFRelease (string);
1860               else if (cs)
1861                 CFRelease (cs);
1862               goto err;
1863             }
1864           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1865             if (CHARACTERP (XCAR (chars)))
1866               {
1867                 UniChar unichars[2];
1868                 CFIndex count =
1869                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1870                                                        unichars);
1871                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1873                 CFStringAppendCharacters (string, unichars, count);
1874                 CFCharacterSetAddCharactersInRange (cs, range);
1875               }
1876           charset = cs;
1877           /* CFCharacterSetCreateWithCharactersInString does not
1878              handle surrogate pairs properly as of Mac OS X 10.5.  */
1879           charset_string = string;
1880         }
1881     }
1883   attributes = CFDictionaryCreateMutable (NULL, 0,
1884                                           &kCFTypeDictionaryKeyCallBacks,
1885                                           &kCFTypeDictionaryValueCallBacks);
1886   if (! attributes)
1887     goto err;
1889   tmp = AREF (spec, FONT_FAMILY_INDEX);
1890   if (SYMBOLP (tmp) && ! NILP (tmp))
1891     {
1892       CFStringRef family = macfont_create_family_with_symbol (tmp);
1894       if (! family)
1895         goto err;
1896       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1897                             family);
1898       CFRelease (family);
1899     }
1901   traits = CFDictionaryCreateMutable (NULL, 4,
1902                                       &kCFTypeDictionaryKeyCallBacks,
1903                                       &kCFTypeDictionaryValueCallBacks);
1904   if (! traits)
1905     goto err;
1907   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1908     {
1909       tmp = AREF (spec, numeric_traits[i].index);
1910       if (INTEGERP (tmp))
1911         {
1912           CGPoint *point = numeric_traits[i].points;
1913           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1914           CFNumberRef num;
1916           while (point->y < floatval)
1917             point++;
1918           if (point == numeric_traits[i].points)
1919             point++;
1920           else if (point->y == CGFLOAT_MAX)
1921             point--;
1922           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1923                                        * ((point->x - (point - 1)->x)
1924                                           / (point->y - (point - 1)->y)));
1925           if (floatval > 1.0)
1926             floatval = 1.0;
1927           else if (floatval < -1.0)
1928             floatval = -1.0;
1929           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1930           if (! num)
1931             goto err;
1932           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1933           CFRelease (num);
1934         }
1935     }
1936   if (CFDictionaryGetCount (traits))
1937     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1939   if (charset)
1940     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1941                           charset);
1942   if (charset_string)
1943     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1944                           charset_string);
1945   if (langarray)
1946     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1948   goto finish;
1950  err:
1951   if (attributes)
1952     {
1953       CFRelease (attributes);
1954       attributes = NULL;
1955     }
1957  finish:
1958   if (langarray) CFRelease (langarray);
1959   if (charset && cf_charset_idx < 0) CFRelease (charset);
1960   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1961   if (traits) CFRelease (traits);
1962   if (otspec)
1963     {
1964       if (otspec->nfeatures[0] > 0)
1965         free (otspec->features[0]);
1966       if (otspec->nfeatures[1] > 0)
1967         free (otspec->features[1]);
1968       free (otspec);
1969     }
1971   return attributes;
1974 static Boolean
1975 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1976                                           CFCharacterSetRef charset,
1977                                           Lisp_Object chars,
1978                                           CFArrayRef languages)
1980   Boolean result = true;
1982   if (charset || VECTORP (chars))
1983     {
1984       CFCharacterSetRef desc_charset =
1985         mac_font_descriptor_copy_attribute (desc,
1986                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1988       if (desc_charset == NULL)
1989         result = false;
1990       else
1991         {
1992           if (charset)
1993             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
1994           else                  /* VECTORP (chars) */
1995             {
1996               ptrdiff_t j;
1998               for (j = 0; j < ASIZE (chars); j++)
1999                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2000                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2001                                                             XFASTINT (AREF (chars, j))))
2002                   break;
2003               if (j == ASIZE (chars))
2004                 result = false;
2005             }
2006           CFRelease (desc_charset);
2007         }
2008     }
2009   if (result && languages)
2010     result = mac_font_descriptor_supports_languages (desc, languages);
2012   return result;
2015 static CFIndex
2016 macfont_closest_traits_index (CFArrayRef traits_array,
2017                               FontSymbolicTraits target)
2019   CFIndex i, result = -1, count = CFArrayGetCount (traits_array);
2020   int min_distance = (1 << 3);
2022   for (i = 0; i < count; i++)
2023     {
2024       FontSymbolicTraits traits, diff;
2025       int distance = 0;
2027       traits = ((FontSymbolicTraits) (uintptr_t)
2028                 CFArrayGetValueAtIndex (traits_array, i));
2029       diff = (target ^ traits);
2030       /* We prefer synthetic bold of italic to synthetic italic of
2031          bold when both bold and italic are available but bold-italic
2032          is not available.  */
2033       if (diff & MAC_FONT_TRAIT_BOLD)
2034         distance |= (1 << 0);
2035       if (diff & MAC_FONT_TRAIT_ITALIC)
2036         distance |= (1 << 1);
2037       if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2038         distance |= (1 << 2);
2039       if (distance < min_distance)
2040         {
2041           min_distance = distance;
2042           result = i;
2043         }
2044     }
2046   return result;
2049 static Lisp_Object
2050 macfont_list (struct frame *f, Lisp_Object spec)
2052   Lisp_Object val = Qnil, family, extra;
2053   int i, n;
2054   CFStringRef family_name = NULL;
2055   CFMutableDictionaryRef attributes = NULL, traits;
2056   Lisp_Object chars = Qnil;
2057   int spacing = -1;
2058   FontSymbolicTraits synth_sym_traits = 0;
2059   CFArrayRef families;
2060   CFIndex families_count;
2061   CFCharacterSetRef charset = NULL;
2062   CFArrayRef languages = NULL;
2064   block_input ();
2066   family = AREF (spec, FONT_FAMILY_INDEX);
2067   if (! NILP (family))
2068     {
2069       family_name = macfont_create_family_with_symbol (family);
2070       if (family_name == NULL)
2071         goto finish;
2072     }
2074   attributes = macfont_create_attributes_with_spec (spec);
2075   if (! attributes)
2076     goto finish;
2078   languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2080   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2081     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2083   traits = ((CFMutableDictionaryRef)
2084             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2086   n = FONT_SLANT_NUMERIC (spec);
2087   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2088     {
2089       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2090       if (traits)
2091         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2092     }
2094   n = FONT_WEIGHT_NUMERIC (spec);
2095   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2096     {
2097       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2098       if (traits)
2099         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2100     }
2102   if (languages
2103       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2104     {
2105       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2107       if (CFStringHasPrefix (language, CFSTR ("ja"))
2108           || CFStringHasPrefix (language, CFSTR ("ko"))
2109           || CFStringHasPrefix (language, CFSTR ("zh")))
2110         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2111     }
2113   /* Create array of families.  */
2114   if (family_name)
2115     families = CFArrayCreate (NULL, (const void **) &family_name,
2116                               1, &kCFTypeArrayCallBacks);
2117   else
2118     {
2119       CFStringRef pref_family;
2120       CFIndex families_count, pref_family_index = -1;
2122       families = mac_font_create_available_families ();
2123       if (families == NULL)
2124         goto err;
2126       families_count = CFArrayGetCount (families);
2128       /* Move preferred family to the front if exists.  */
2129       pref_family =
2130         mac_font_create_preferred_family_for_attributes (attributes);
2131       if (pref_family)
2132         {
2133           pref_family_index =
2134             CFArrayGetFirstIndexOfValue (families,
2135                                          CFRangeMake (0, families_count),
2136                                          pref_family);
2137           CFRelease (pref_family);
2138         }
2139       if (pref_family_index > 0)
2140         {
2141           CFMutableArrayRef mutable_families =
2142             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2144           if (mutable_families)
2145             {
2146               CFArrayAppendValue (mutable_families,
2147                                   CFArrayGetValueAtIndex (families,
2148                                                           pref_family_index));
2149               CFArrayAppendArray (mutable_families, families,
2150                                   CFRangeMake (0, pref_family_index));
2151               if (pref_family_index + 1 < families_count)
2152                 CFArrayAppendArray (mutable_families, families,
2153                                     CFRangeMake (pref_family_index + 1,
2154                                                  families_count
2155                                                  - (pref_family_index + 1)));
2156               CFRelease (families);
2157               families = mutable_families;
2158             }
2159         }
2160     }
2162   charset = CFDictionaryGetValue (attributes,
2163                                   MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2164   if (charset)
2165     {
2166       CFRetain (charset);
2167       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2168     }
2169   else
2170     {
2171       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2172       if (! NILP (val))
2173         {
2174           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2175           if (CONSP (val) && VECTORP (XCDR (val)))
2176             chars = XCDR (val);
2177         }
2178       val = Qnil;
2179     }
2181   if (languages)
2182     {
2183       CFRetain (languages);
2184       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2185     }
2187   val = Qnil;
2188   extra = AREF (spec, FONT_EXTRA_INDEX);
2189   families_count = CFArrayGetCount (families);
2190   for (i = 0; i < families_count; i++)
2191     {
2192       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2193       FontDescriptorRef pat_desc;
2194       CFArrayRef descs;
2195       CFIndex descs_count;
2196       CFMutableArrayRef filtered_descs, traits_array;
2197       Lisp_Object entity;
2198       int j;
2200       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2201                             family_name);
2202       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2203       if (! pat_desc)
2204         goto err;
2206       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2207          10.7 returns NULL if pat_desc represents the LastResort font.
2208          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2209          trailing "s") for such a font.  */
2210       if (!CFEqual (family_name, CFSTR ("LastResort")))
2211        descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2212                                                                      NULL);
2213       else
2214        {
2215          FontDescriptorRef lr_desc =
2216            mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2217                                                                 NULL);
2218          if (lr_desc)
2219            {
2220              descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2221                                     &kCFTypeArrayCallBacks);
2222              CFRelease (lr_desc);
2223            }
2224          else
2225            descs = NULL;
2226        }
2227       CFRelease (pat_desc);
2228       if (! descs)
2229        goto err;
2231       descs_count = CFArrayGetCount (descs);
2232       if (descs_count == 0
2233           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2234                                                         charset, chars,
2235                                                         languages))
2236         {
2237           CFRelease (descs);
2238           continue;
2239         }
2241       filtered_descs =
2242         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2243       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2244       for (j = 0; j < descs_count; j++)
2245         {
2246           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2247           CFDictionaryRef dict;
2248           CFNumberRef num;
2249           FontSymbolicTraits sym_traits;
2251           dict = mac_font_descriptor_copy_attribute (desc,
2252                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2253           if (dict == NULL)
2254             continue;
2256           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2257           CFRelease (dict);
2258           if (num == NULL
2259               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2260             continue;
2262           if (spacing >= 0
2263               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2264               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2265                   != (spacing >= FONT_SPACING_MONO)))
2266             continue;
2268           /* Don't use a color bitmap font unless its family is
2269              explicitly specified.  */
2270           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2271             continue;
2273           if (j > 0
2274               && !macfont_supports_charset_and_languages_p (desc, charset,
2275                                                             chars, languages))
2276             continue;
2278           CFArrayAppendValue (filtered_descs, desc);
2279           CFArrayAppendValue (traits_array,
2280                               (const void *) (uintptr_t) sym_traits);
2281         }
2283       CFRelease (descs);
2284       descs = filtered_descs;
2285       descs_count = CFArrayGetCount (descs);
2287       for (j = 0; j < descs_count; j++)
2288         {
2289           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2290           FontSymbolicTraits sym_traits =
2291             ((FontSymbolicTraits) (uintptr_t)
2292              CFArrayGetValueAtIndex (traits_array, j));
2293           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2295           mask_min = ((synth_sym_traits ^ sym_traits)
2296                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2297           if (FONT_SLANT_NUMERIC (spec) < 0)
2298             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2299           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2300             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2302           mask_max = (synth_sym_traits & ~sym_traits);
2303           /* Synthetic bold does not work for bitmap-only fonts on Mac
2304              OS X 10.6.  */
2305           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2306             {
2307               CFNumberRef format =
2308                 mac_font_descriptor_copy_attribute (desc,
2309                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2311               if (format)
2312                 {
2313                   uint32_t format_val;
2315                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2316                                         &format_val)
2317                       && format_val == MAC_FONT_FORMAT_BITMAP)
2318                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2319                 }
2320             }
2321           if (spacing >= 0)
2322             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2324           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2325                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2326                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2327             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2328                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2329                  bmask += MAC_FONT_TRAIT_BOLD)
2330               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2331                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2332                    imask += MAC_FONT_TRAIT_ITALIC)
2333                 {
2334                   FontSymbolicTraits synth = (imask | bmask | mmask);
2336                   if (synth == 0
2337                       || j == macfont_closest_traits_index (traits_array,
2338                                                             (sym_traits | synth)))
2339                     {
2340                       entity = macfont_descriptor_entity (desc, extra, synth);
2341                       if (! NILP (entity))
2342                         val = Fcons (entity, val);
2343                     }
2344                 }
2345         }
2347       CFRelease (traits_array);
2348       CFRelease (descs);
2349     }
2351   CFRelease (families);
2352   val = Fnreverse (val);
2353   goto finish;
2354  err:
2355   val = Qnil;
2357  finish:
2358   FONT_ADD_LOG ("macfont-list", spec, val);
2359   if (charset) CFRelease (charset);
2360   if (languages) CFRelease (languages);
2361   if (attributes) CFRelease (attributes);
2362   if (family_name) CFRelease (family_name);
2364   unblock_input ();
2366   return val;
2369 static Lisp_Object
2370 macfont_match (struct frame * frame, Lisp_Object spec)
2372   Lisp_Object entity = Qnil;
2373   CFMutableDictionaryRef attributes;
2374   FontDescriptorRef pat_desc = NULL, desc = NULL;
2376   block_input ();
2378   attributes = macfont_create_attributes_with_spec (spec);
2379   if (attributes)
2380     {
2381       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2382       CFRelease (attributes);
2383     }
2384   if (pat_desc)
2385     {
2386       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2387                                                                   NULL);
2388       CFRelease (pat_desc);
2389     }
2390   if (desc)
2391     {
2392       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2393                                           0);
2394       CFRelease (desc);
2395     }
2396   unblock_input ();
2398   FONT_ADD_LOG ("macfont-match", spec, entity);
2399   return entity;
2402 static Lisp_Object
2403 macfont_list_family (struct frame *frame)
2405   Lisp_Object list = Qnil;
2406   CFArrayRef families;
2408   block_input ();
2410   families = mac_font_create_available_families ();
2411   if (families)
2412     {
2413       CFIndex i, count = CFArrayGetCount (families);
2415       for (i = 0; i < count; i++)
2416         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2417       CFRelease (families);
2418     }
2420   unblock_input ();
2422   return list;
2425 static void
2426 macfont_free_entity (Lisp_Object entity)
2428   Lisp_Object val = assq_no_quit (QCfont_entity,
2429                                   AREF (entity, FONT_EXTRA_INDEX));
2430   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2432   block_input ();
2433   CFRelease (name);
2434   unblock_input ();
2437 static Lisp_Object
2438 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2440   Lisp_Object val, font_object;
2441   CFStringRef font_name;
2442   struct macfont_info *macfont_info = NULL;
2443   struct font *font;
2444   int size;
2445   FontRef macfont;
2446   FontSymbolicTraits sym_traits;
2447   int i, total_width;
2448   CGGlyph glyph;
2449   CGFloat ascent, descent, leading;
2451   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2452   if (! CONSP (val)
2453       || XTYPE (XCDR (val)) != Lisp_Misc
2454       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2455     return Qnil;
2456   font_name = XSAVE_POINTER (XCDR (val), 0);
2457   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2459   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2460   if (size == 0)
2461     size = pixel_size;
2463   block_input ();
2464   macfont = mac_font_create_with_name (font_name, size);
2465   if (macfont)
2466     {
2467       int fontsize = (int) [((NSFont *) macfont) pointSize];
2468       if (fontsize != size) size = fontsize;
2469     }
2470   unblock_input ();
2471   if (! macfont)
2472     return Qnil;
2474   font_object = font_build_object (VECSIZE (struct macfont_info),
2475                                    Qmac_ct, entity, size);
2476   font = XFONT_OBJECT (font_object);
2477   font->pixel_size = size;
2478   font->driver = &macfont_driver;
2479   font->encoding_charset = font->repertory_charset = -1;
2481   block_input ();
2483   macfont_info = (struct macfont_info *) font;
2484   macfont_info->macfont = macfont;
2485   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2487   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2488   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2489     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2490                                                                   size);
2491   else
2492     macfont_info->screen_font = NULL;
2493   macfont_info->cache = macfont_lookup_cache (font_name);
2494   macfont_retain_cache (macfont_info->cache);
2495   macfont_info->metrics = NULL;
2496   macfont_info->metrics_nrows = 0;
2497   macfont_info->synthetic_italic_p = 0;
2498   macfont_info->synthetic_bold_p = 0;
2499   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2500   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2501   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2502       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2503     macfont_info->synthetic_italic_p = 1;
2504   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2505       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2506     macfont_info->synthetic_bold_p = 1;
2507   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2508     macfont_info->spacing = MACFONT_SPACING_MONO;
2509   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2510            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2511                == FONT_SPACING_SYNTHETIC_MONO))
2512     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2513   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2514     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2515   else
2516     {
2517       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2518       if (CONSP (val))
2519         macfont_info->antialias =
2520           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2521     }
2522   macfont_info->color_bitmap_p = 0;
2523   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2524     macfont_info->color_bitmap_p = 1;
2526   glyph = macfont_get_glyph_for_character (font, ' ');
2527   if (glyph != kCGFontIndexInvalid)
2528     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2529   else
2530     /* dirty workaround */
2531     font->space_width = pixel_size;
2533   total_width = font->space_width;
2534   for (i = 1; i < 95; i++)
2535     {
2536       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2537       if (glyph == kCGFontIndexInvalid)
2538         break;
2539       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2540     }
2541   if (i == 95)
2542     font->average_width = total_width / 95;
2543   else
2544     font->average_width = font->space_width; /* XXX */
2546   if (!(macfont_info->screen_font
2547         && mac_screen_font_get_metrics (macfont_info->screen_font,
2548                                         &ascent, &descent, &leading)))
2549     {
2550       CFStringRef family_name;
2552       ascent = mac_font_get_ascent (macfont);
2553       descent = mac_font_get_descent (macfont);
2554       leading = mac_font_get_leading (macfont);
2555       /* AppKit and WebKit do some adjustment to the heights of
2556          Courier, Helvetica, and Times.  */
2557       family_name = mac_font_copy_family_name (macfont);
2558       if (family_name)
2559         {
2560           if (CFEqual (family_name, CFSTR ("Courier"))
2561               || CFEqual (family_name, CFSTR ("Helvetica"))
2562               || CFEqual (family_name, CFSTR ("Times")))
2563             ascent += (ascent + descent) * .15f;
2564           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2565             {
2566               leading *= .25f;
2567               ascent += leading;
2568             }
2569           CFRelease (family_name);
2570         }
2571     }
2572   font->ascent = ascent + 0.5f;
2573   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2574   if (CONSP (val) && !NILP (XCDR (val)))
2575     font->descent = descent + 0.5f;
2576   else
2577     font->descent = descent + leading + 0.5f;
2578   font->height = font->ascent + font->descent;
2580   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2581   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2583   unblock_input ();
2585   /* Unfortunately Xft doesn't provide a way to get minimum char
2586      width.  So, we use space_width instead.  */
2587   font->min_width = font->max_width = font->space_width; /* XXX */
2589   font->baseline_offset = 0;
2590   font->relative_compose = 0;
2591   font->default_ascent = 0;
2592   font->vertical_centering = 0;
2594   return font_object;
2597 static void
2598 macfont_close (struct font *font)
2600   struct macfont_info *macfont_info = (struct macfont_info *) font;
2601   int i;
2603   block_input ();
2604   CFRelease (macfont_info->macfont);
2605   CGFontRelease (macfont_info->cgfont);
2606   if (macfont_info->screen_font)
2607     CFRelease (macfont_info->screen_font);
2608   macfont_release_cache (macfont_info->cache);
2609   for (i = 0; i < macfont_info->metrics_nrows; i++)
2610     if (macfont_info->metrics[i])
2611       xfree (macfont_info->metrics[i]);
2612   if (macfont_info->metrics)
2613     xfree (macfont_info->metrics);
2614   unblock_input ();
2617 static int
2618 macfont_has_char (Lisp_Object font, int c)
2620   int result;
2621   CFCharacterSetRef charset;
2623   block_input ();
2624   if (FONT_ENTITY_P (font))
2625     {
2626       Lisp_Object val;
2627       CFStringRef name;
2629       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2630       val = XCDR (val);
2631       name = XSAVE_POINTER (val, 0);
2632       charset = macfont_get_cf_charset_for_name (name);
2633     }
2634   else
2635     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2637   result = CFCharacterSetIsLongCharacterMember (charset, c);
2638   unblock_input ();
2640   return result;
2643 static unsigned
2644 macfont_encode_char (struct font *font, int c)
2646   struct macfont_info *macfont_info = (struct macfont_info *) font;
2647   CGGlyph glyph;
2649   block_input ();
2650   glyph = macfont_get_glyph_for_character (font, c);
2651   unblock_input ();
2653   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2656 static void
2657 macfont_text_extents (struct font *font, unsigned int *code,
2658                       int nglyphs, struct font_metrics *metrics)
2660   int width, i;
2662   block_input ();
2663   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2664   for (i = 1; i < nglyphs; i++)
2665     {
2666       struct font_metrics m;
2667       int w = macfont_glyph_extents (font, code[i], &m, NULL, 0);
2669       if (width + m.lbearing < metrics->lbearing)
2670         metrics->lbearing = width + m.lbearing;
2671       if (width + m.rbearing > metrics->rbearing)
2672         metrics->rbearing = width + m.rbearing;
2673       if (m.ascent > metrics->ascent)
2674         metrics->ascent = m.ascent;
2675       if (m.descent > metrics->descent)
2676         metrics->descent = m.descent;
2677       width += w;
2678     }
2679   unblock_input ();
2681   metrics->width = width;
2684 static int
2685 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2686               bool with_background)
2688   struct frame * f = s->f;
2689   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2690   CGRect background_rect;
2691   CGPoint text_position;
2692   CGGlyph *glyphs;
2693   CGPoint *positions;
2694   CGFloat font_size = mac_font_get_size (macfont_info->macfont);
2695   bool no_antialias_p =
2696     (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2697      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2698          && font_size <= macfont_antialias_threshold));
2699   int len = to - from;
2700   struct face *face = s->face;
2701   CGContextRef context;
2703   block_input ();
2705   if (with_background)
2706     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2707                                   s->width, FONT_HEIGHT (s->font));
2708  else
2709     background_rect = CGRectNull;
2710   
2711   text_position = CGPointMake (x, -y);
2712   glyphs = xmalloc (sizeof (CGGlyph) * len);
2713   {
2714     CGFloat advance_delta;
2715     int i;
2716     CGFloat total_width = 0;
2718     positions = xmalloc (sizeof (CGPoint) * len);
2719     for (i = 0; i < len; i++)
2720       {
2721         int width;
2723         glyphs[i] = s->char2b[from + i];
2724         width = (s->padding_p ? 1
2725                  : macfont_glyph_extents (s->font, glyphs[i],
2726                                           NULL, &advance_delta,
2727                                           no_antialias_p));
2728         positions[i].x = total_width + advance_delta;
2729         positions[i].y = 0;
2730         total_width += width;
2731       }
2732   }
2734   context = [[NSGraphicsContext currentContext] graphicsPort];
2735   CGContextSaveGState (context);
2737   if (!CGRectIsNull (background_rect))
2738     {
2739       if (s->hl == DRAW_MOUSE_FACE) 
2740         {
2741           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2742           if (!face)
2743             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2744         }
2745       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2746       CGContextFillRects (context, &background_rect, 1);
2747     }
2749   if (macfont_info->cgfont)
2750     {
2751       CGAffineTransform atfm;
2752       CGContextScaleCTM (context, 1, -1);
2753       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2754       if (macfont_info->synthetic_italic_p)
2755         atfm = synthetic_italic_atfm;
2756       else
2757         atfm = CGAffineTransformIdentity;
2758       if (macfont_info->synthetic_bold_p)
2759         {
2760           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2761           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2762           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2763         }
2764       if (no_antialias_p)
2765         CGContextSetShouldAntialias (context, false);
2767       CGContextSetTextMatrix (context, atfm);
2768       CGContextSetTextPosition (context, text_position.x, text_position.y);
2770 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2771       if (macfont_info->color_bitmap_p
2772 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2773           && CTFontDrawGlyphs != NULL
2774 #endif
2775           )
2776         {
2777           if (len > 0)
2778             {
2779               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2780                                 context);
2781             }
2782         }
2783       else
2784 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2785         {
2786           CGContextSetFont (context, macfont_info->cgfont);
2787           CGContextSetFontSize (context, font_size);
2788           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2789         }
2790     }
2793   xfree (glyphs);
2794   xfree (positions);
2795   CGContextRestoreGState (context);
2797   unblock_input ();
2799   return len;
2802 static Lisp_Object
2803 macfont_shape (Lisp_Object lgstring)
2805   struct font *font;
2806   struct macfont_info *macfont_info;
2807   FontRef macfont;
2808   ptrdiff_t glyph_len, len, i, j;
2809   CFIndex nonbmp_len;
2810   UniChar *unichars;
2811   CFIndex *nonbmp_indices;
2812   CFStringRef string;
2813   CFIndex used = 0;
2814   struct mac_glyph_layout *glyph_layouts;
2816   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2817   macfont_info = (struct macfont_info *) font;
2818   macfont = macfont_info->macfont;
2820   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2821   nonbmp_len = 0;
2822   for (i = 0; i < glyph_len; i++)
2823     {
2824       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2826       if (NILP (lglyph))
2827         break;
2828       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2829         nonbmp_len++;
2830     }
2832   len = i;
2834   if (INT_MAX / 2 < len)
2835     memory_full (SIZE_MAX);
2837   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2838   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2839   for (i = j = 0; i < len; i++)
2840     {
2841       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2843       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2844         {
2845           nonbmp_indices[j] = i + j;
2846           j++;
2847         }
2848     }
2849   nonbmp_indices[j] = len + j;  /* sentinel */
2851   block_input ();
2853   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2854                                                kCFAllocatorNull);
2855   if (string)
2856     {
2857       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2858       if (macfont_info->screen_font)
2859         used = mac_screen_font_shape (macfont_info->screen_font, string,
2860                                       glyph_layouts, glyph_len);
2861       else
2862         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2863       CFRelease (string);
2864     }
2866   unblock_input ();
2868   if (used == 0)
2869     return Qnil;
2871   block_input ();
2873   for (i = 0; i < used; i++)
2874     {
2875       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2876       struct mac_glyph_layout *gl = glyph_layouts + i;
2877       EMACS_INT from, to;
2878       struct font_metrics metrics;
2879       int xoff, yoff, wadjust;
2881       if (NILP (lglyph))
2882         {
2883           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2884           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2885         }
2887       from = gl->comp_range.location;
2888       /* Convert UTF-16 index to UTF-32.  */
2889       j = 0;
2890       while (nonbmp_indices[j] < from)
2891         j++;
2892       from -= j;
2893       LGLYPH_SET_FROM (lglyph, from);
2895       to = gl->comp_range.location + gl->comp_range.length;
2896       /* Convert UTF-16 index to UTF-32.  */
2897       while (nonbmp_indices[j] < to)
2898         j++;
2899       to -= j;
2900       LGLYPH_SET_TO (lglyph, to - 1);
2902       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2903          the composition is trivial.  */
2904       {
2905         UTF32Char c;
2907         if (unichars[gl->string_index] >= 0xD800
2908             && unichars[gl->string_index] < 0xDC00)
2909           c = (((unichars[gl->string_index] - 0xD800) << 10)
2910                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2911         else
2912           c = unichars[gl->string_index];
2913         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2914           c = 0;
2915         LGLYPH_SET_CHAR (lglyph, c);
2916       }
2918       {
2919         unsigned long cc = gl->glyph_id;
2920         LGLYPH_SET_CODE (lglyph, cc);
2921       }
2923       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2924       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2925       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2926       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2927       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2928       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2930       xoff = lround (gl->advance_delta);
2931       yoff = lround (- gl->baseline_delta);
2932       wadjust = lround (gl->advance);
2933       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2934         {
2935           Lisp_Object vec;
2937           vec = Fmake_vector (make_number (3), Qnil);
2938           ASET (vec, 0, make_number (xoff));
2939           ASET (vec, 1, make_number (yoff));
2940           ASET (vec, 2, make_number (wadjust));
2941           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2942         }
2943     }
2945   unblock_input ();
2947   return make_number (used);
2950 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2951 typedef UInt8 UINT24[3];
2953 #pragma pack(push, 1)
2954 struct variation_selector_record
2956   UINT24 var_selector;
2957   UInt32 default_uvs_offset, non_default_uvs_offset;
2959 struct uvs_table
2961   UInt16 format;
2962   UInt32 length, num_var_selector_records;
2963   struct variation_selector_record variation_selector_records[1];
2965 #define SIZEOF_UVS_TABLE_HEADER \
2966   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2968 struct unicode_value_range
2970   UINT24 start_unicode_value;
2971   UInt8 additional_count;
2973 struct default_uvs_table {
2974   UInt32 num_unicode_value_ranges;
2975   struct unicode_value_range unicode_value_ranges[1];
2977 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
2978   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
2980 struct uvs_mapping
2982   UINT24 unicode_value;
2983   UInt16 glyph_id;
2985 struct non_default_uvs_table
2987   UInt32 num_uvs_mappings;
2988   struct uvs_mapping uvs_mappings[1];
2990 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
2991   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
2992 #pragma pack(pop)
2994 /* Read big endian values.  The argument LVAL must be an lvalue.  */
2995 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
2996    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
2997    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
2998 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
2999 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3000 /* Succeeding one byte should also be accessible.  */
3001 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3002 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3004 /* Return UVS subtable for the specified FONT.  If the subtable is not
3005    found or ill-formatted, then return NULL.  */
3007 static CFDataRef
3008 mac_font_copy_uvs_table (FontRef font)
3010   CFDataRef cmap_table, uvs_table = NULL;
3012   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3013   if (cmap_table)
3014     {
3015       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3016       struct uvs_table *uvs;
3017       struct variation_selector_record *records;
3018       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3020 #if __LP64__
3021       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3022         goto finish;
3023 #endif
3025       cmap_len = CFDataGetLength (cmap_table);
3026       if (sizeof_sfntCMapHeader > cmap_len)
3027         goto finish;
3029       ntables = BUINT16_VALUE (cmap->numTables);
3030       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3031                      / sizeof_sfntCMapEncoding))
3032         goto finish;
3034       for (i = 0; i < ntables; i++)
3035         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3036              == kFontUnicodePlatform)
3037             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3038                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3039           {
3040             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3041             break;
3042           }
3043       if (i == ntables
3044           || uvs_offset > cmap_len
3045           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3046         goto finish;
3048       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3049       uvs_len = BUINT32_VALUE (uvs->length);
3050       if (uvs_len > cmap_len - uvs_offset
3051           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3052         goto finish;
3054       if (BUINT16_VALUE (uvs->format) != 14)
3055         goto finish;
3057       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3058       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3059                       / sizeof (struct variation_selector_record)))
3060         goto finish;
3062       records = uvs->variation_selector_records;
3063       for (i = 0; i < nrecords; i++)
3064         {
3065           UInt32 default_uvs_offset, non_default_uvs_offset;
3067           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3068           if (default_uvs_offset)
3069             {
3070               struct default_uvs_table *default_uvs;
3071               UInt32 nranges;
3073               if (default_uvs_offset > uvs_len
3074                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3075                       > uvs_len - default_uvs_offset))
3076                 goto finish;
3078               default_uvs = ((struct default_uvs_table *)
3079                              ((UInt8 *) uvs + default_uvs_offset));
3080               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3081               if (nranges > ((uvs_len - default_uvs_offset
3082                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3083                              / sizeof (struct unicode_value_range)))
3084                 goto finish;
3085               /* Now 2 * nranges can't overflow, so we can safely use
3086                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3087                  mac_font_get_glyphs_for_variants.  */
3088             }
3090           non_default_uvs_offset =
3091             BUINT32_VALUE (records[i].non_default_uvs_offset);
3092           if (non_default_uvs_offset)
3093             {
3094               struct non_default_uvs_table *non_default_uvs;
3095               UInt32 nmappings;
3097               if (non_default_uvs_offset > uvs_len
3098                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3099                       > uvs_len - non_default_uvs_offset))
3100                 goto finish;
3102               non_default_uvs = ((struct non_default_uvs_table *)
3103                                  ((UInt8 *) uvs + non_default_uvs_offset));
3104               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3105               if (nmappings > ((uvs_len - non_default_uvs_offset
3106                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3107                                / sizeof (struct uvs_mapping)))
3108                 goto finish;
3109               /* Now 2 * nmappings can't overflow, so we can safely
3110                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3111                  in mac_font_get_glyphs_for_variants.  */
3112             }
3113         }
3115       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3117     finish:
3118       CFRelease (cmap_table);
3119     }
3121   return uvs_table;
3124 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3125    sequence consisting of the given base character C and each
3126    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3127    result (explained below) into the corresponding GLYPHS[i].  If the
3128    entry is found in the Default UVS Table, then the result is 0.  If
3129    the entry is found in the Non-Default UVS Table, then the result is
3130    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3131    elements in SELECTORS must be sorted in strictly increasing
3132    order.  */
3134 static void
3135 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3136                                   const UTF32Char selectors[], CGGlyph glyphs[],
3137                                   CFIndex count)
3139   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3140   struct variation_selector_record *records = uvs->variation_selector_records;
3141   CFIndex i;
3142   UInt32 ir, nrecords;
3143 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3144   dispatch_queue_t queue =
3145     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3146   dispatch_group_t group = dispatch_group_create ();
3147 #endif
3149   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3150   i = 0;
3151   ir = 0;
3152   while (i < count && ir < nrecords)
3153     {
3154       UInt32 default_uvs_offset, non_default_uvs_offset;
3156       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3157         {
3158           glyphs[i++] = kCGFontIndexInvalid;
3159           continue;
3160         }
3161       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3162         {
3163           ir++;
3164           continue;
3165         }
3167       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3168       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3169       non_default_uvs_offset =
3170         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3171 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3172       dispatch_group_async (group, queue, ^{
3173 #endif
3174           glyphs[i] = kCGFontIndexInvalid;
3176           if (default_uvs_offset)
3177             {
3178               struct default_uvs_table *default_uvs =
3179                 (struct default_uvs_table *) ((UInt8 *) uvs
3180                                               + default_uvs_offset);
3181               struct unicode_value_range *ranges =
3182                 default_uvs->unicode_value_ranges;
3183               UInt32 lo, hi;
3185               lo = 0;
3186               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3187               while (lo < hi)
3188                 {
3189                   UInt32 mid = (lo + hi) / 2;
3191                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3192                     hi = mid;
3193                   else
3194                     lo = mid + 1;
3195                 }
3196               if (hi > 0
3197                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3198                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3199                 glyphs[i] = 0;
3200             }
3202           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3203             {
3204               struct non_default_uvs_table *non_default_uvs =
3205                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3206                                                   + non_default_uvs_offset);
3207               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3208               UInt32 lo, hi;
3210               lo = 0;
3211               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3212               while (lo < hi)
3213                 {
3214                   UInt32 mid = (lo + hi) / 2;
3216                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3217                     hi = mid;
3218                   else
3219                     lo = mid + 1;
3220                 }
3221               if (hi > 0 &&
3222                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3223                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3224             }
3225 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3226         });
3227 #endif
3228       i++;
3229       ir++;
3230     }
3231   while (i < count)
3232     glyphs[i++] = kCGFontIndexInvalid;
3233 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3234   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3235   dispatch_release (group);
3236 #endif
3239 static int
3240 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3242   CFDataRef uvs_table;
3243   CharacterCollection uvs_collection;
3244   int i, n = 0;
3246   block_input ();
3247   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3249   if (uvs_table)
3250     {
3251       UTF32Char selectors[256];
3252       CGGlyph glyphs[256];
3254       for (i = 0; i < 16; i++)
3255         selectors[i] = 0xFE00 + i;
3256       for (; i < 256; i++)
3257         selectors[i] = 0xE0100 + (i - 16);
3258       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3259       for (i = 0; i < 256; i++)
3260         {
3261           CGGlyph glyph = glyphs[i];
3263           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3264               && glyph != kCGFontIndexInvalid)
3265             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3266           if (glyph == kCGFontIndexInvalid)
3267             variations[i] = 0;
3268           else
3269             {
3270               variations[i] = (glyph ? glyph
3271                                : macfont_get_glyph_for_character (font, c));
3272               n++;
3273             }
3274         }
3275     }
3276   unblock_input ();
3278   return n;
3281 static const char *const macfont_booleans[] = {
3282   ":antialias",
3283   ":minspace",
3284   NULL,
3287 static const char *const macfont_non_booleans[] = {
3288   ":lang",
3289   ":script",
3290   ":destination",
3291   NULL,
3294 static void
3295 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3297   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3300 static Boolean
3301 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3302                                           CFArrayRef languages)
3304   Boolean result = true;
3305   CFArrayRef desc_languages =
3306     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3308   if (desc_languages == NULL)
3309     result = false;
3310   else
3311     {
3312       CFIndex desc_languages_count, i, languages_count;
3314       desc_languages_count = CFArrayGetCount (desc_languages);
3315       languages_count = CFArrayGetCount (languages);
3316       for (i = 0; i < languages_count; i++)
3317         if (!CFArrayContainsValue (desc_languages,
3318                                    CFRangeMake (0, desc_languages_count),
3319                                    CFArrayGetValueAtIndex (languages, i)))
3320           {
3321             result = false;
3322             break;
3323           }
3324       CFRelease (desc_languages);
3325     }
3327   return result;
3330 static CFStringRef
3331 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3333   CFStringRef result = NULL;
3334   CFStringRef charset_string =
3335     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3337   if (charset_string && CFStringGetLength (charset_string) > 0)
3338     {
3339       CFStringRef keys[] = {
3340 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3341         kCTLanguageAttributeName
3342 #else
3343         CFSTR ("NSLanguage")
3344 #endif
3345       };
3346       CFTypeRef values[] = {NULL};
3347       CFIndex num_values = 0;
3348       CFArrayRef languages
3349         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3351       if (languages && CFArrayGetCount (languages) > 0)
3352         {
3353           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3354             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3355           else
3356             {
3357               CFCharacterSetRef charset =
3358                 CFDictionaryGetValue (attributes,
3359                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3361               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3362             }
3363         }
3364       if (result == NULL)
3365         {
3366           CFAttributedStringRef attr_string = NULL;
3367           CTLineRef ctline = NULL;
3368           CFDictionaryRef attrs
3369             = CFDictionaryCreate (NULL, (const void **) keys,
3370                                   (const void **) values, num_values,
3371                                   &kCFTypeDictionaryKeyCallBacks,
3372                                   &kCFTypeDictionaryValueCallBacks);
3374           if (attrs)
3375             {
3376               attr_string = CFAttributedStringCreate (NULL, charset_string,
3377                                                       attrs);
3378               CFRelease (attrs);
3379             }
3380           if (attr_string)
3381             {
3382               ctline = CTLineCreateWithAttributedString (attr_string);
3383               CFRelease (attr_string);
3384             }
3385           if (ctline)
3386             {
3387               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3388               CFIndex i, nruns = CFArrayGetCount (runs);
3389               CTFontRef font;
3391               for (i = 0; i < nruns; i++)
3392                 {
3393                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3394                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3395                   CTFontRef font_in_run;
3397                   if (attributes == NULL)
3398                     break;
3399                   font_in_run =
3400                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3401                   if (font_in_run == NULL)
3402                     break;
3403                   if (i == 0)
3404                     font = font_in_run;
3405                   else if (!mac_ctfont_equal_in_postscript_name (font,
3406                                                                  font_in_run))
3407                     break;
3408                 }
3409               if (nruns > 0 && i == nruns)
3410                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3411               CFRelease (ctline);
3412             }
3413         }
3414     }
3416   return result;
3419 static inline double
3420 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3422   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3423                                      &glyph, NULL, 1);
3426 static inline CGRect
3427 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3429   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3430                                           &glyph, NULL, 1);
3433 static CFArrayRef
3434 mac_ctfont_create_available_families (void)
3436   CFMutableArrayRef families = NULL;
3438 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3439 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3440   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3441 #endif
3442     {
3443       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3445       if (orig_families)
3446         {
3447           CFIndex i, count = CFArrayGetCount (orig_families);
3449           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3450           if (families)
3451             for (i = 0; i < count; i++)
3452               {
3453                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3455                 if (!CFStringHasPrefix (family, CFSTR ("."))
3456                     && (CTFontManagerCompareFontFamilyNames (family,
3457                                                              CFSTR ("LastResort"),
3458                                                              NULL)
3459                         != kCFCompareEqualTo))
3460                   CFArrayAppendValue (families, family);
3461               }
3462           CFRelease (orig_families);
3463         }
3464     }
3465 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3466   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3467 #endif
3468 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3469 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3470     {
3471       CTFontCollectionRef collection;
3472       CFArrayRef descs = NULL;
3474       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3475       if (collection)
3476         {
3477           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3478           CFRelease (collection);
3479         }
3480       if (descs)
3481         {
3482           CFIndex i, count = CFArrayGetCount (descs);
3484           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3485           if (families)
3486             for (i = 0; i < count; i++)
3487               {
3488                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3489                 CFStringRef name =
3490                   mac_font_descriptor_copy_attribute (desc,
3491                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3493                 if (name)
3494                   {
3495                     CFIndex p, limit = CFArrayGetCount (families);
3497                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3498                                               (const void *) name,
3499                                               mac_font_family_compare, NULL);
3500                     if (p >= limit)
3501                       CFArrayAppendValue (families, name);
3502                     else if (mac_font_family_compare
3503                              (CFArrayGetValueAtIndex (families, p),
3504                               name, NULL) != kCFCompareEqualTo)
3505                       CFArrayInsertValueAtIndex (families, p, name);
3506                     CFRelease (name);
3507                   }
3508               }
3509           CFRelease (descs);
3510         }
3511     }
3512 #endif
3514   return families;
3517 static Boolean
3518 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3520   Boolean result;
3521   CFStringRef name1, name2;
3523   if (font1 == font2)
3524     return true;
3526   result = false;
3527   name1 = CTFontCopyPostScriptName (font1);
3528   if (name1)
3529     {
3530       name2 = CTFontCopyPostScriptName (font2);
3531       if (name2)
3532         {
3533           result = CFEqual (name1, name2);
3534           CFRelease (name2);
3535         }
3536       CFRelease (name1);
3537     }
3539   return result;
3542 static CTLineRef
3543 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3544                                              CTFontRef macfont)
3546   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3547   CFTypeRef values[] = {NULL, NULL};
3548   CFDictionaryRef attributes = NULL;
3549   CFAttributedStringRef attr_string = NULL;
3550   CTLineRef ctline = NULL;
3551   float float_zero = 0.0f;
3553   values[0] = macfont;
3554   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3555   if (values[1])
3556     {
3557       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3558                                        (const void **) values,
3559                                        ARRAYELTS (keys),
3560                                        &kCFTypeDictionaryKeyCallBacks,
3561                                        &kCFTypeDictionaryValueCallBacks);
3562       CFRelease (values[1]);
3563     }
3564   if (attributes)
3565     {
3566       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3567       CFRelease (attributes);
3568     }
3569   if (attr_string)
3570     {
3571       ctline = CTLineCreateWithAttributedString (attr_string);
3572       CFRelease (attr_string);
3573     }
3574   if (ctline)
3575     {
3576       /* Abandon if ctline contains some fonts other than the
3577          specified one.  */
3578       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3579       CFIndex i, nruns = CFArrayGetCount (runs);
3581       for (i = 0; i < nruns; i++)
3582         {
3583           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3584           CFDictionaryRef attributes = CTRunGetAttributes (run);
3585           CTFontRef font_in_run;
3587           if (attributes == NULL)
3588             break;
3589           font_in_run =
3590             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3591           if (font_in_run == NULL)
3592             break;
3593           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3594             break;
3595         }
3596       if (i < nruns)
3597         {
3598           CFRelease (ctline);
3599           ctline = NULL;
3600         }
3601     }
3603   return ctline;
3606 static CFIndex
3607 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3608                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3610   CFIndex used, result = 0;
3611   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3613   if (ctline == NULL)
3614     return 0;
3616   used = CTLineGetGlyphCount (ctline);
3617   if (used <= glyph_len)
3618     {
3619       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3620       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3621       CGFloat total_advance = 0;
3622       CFIndex total_glyph_count = 0;
3624       for (k = 0; k < ctrun_count; k++)
3625         {
3626           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3627           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3628           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3629           CFRange string_range, comp_range, range;
3630           CFIndex *permutation;
3632           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3633             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3634           else
3635             permutation = NULL;
3637 #define RIGHT_TO_LEFT_P permutation
3639           /* Now the `comp_range' member of struct mac_glyph_layout is
3640              temporarily used as a work area such that:
3641               glbuf[i].comp_range.location =
3642                 min {compRange[i + 1].location, ...,
3643                      compRange[glyph_count - 1].location,
3644                      maxRange (stringRangeForCTRun)}
3645               glbuf[i].comp_range.length = maxRange (compRange[i])
3646              where compRange[i] is the range of composed characters
3647              containing i-th glyph.  */
3648           string_range = CTRunGetStringRange (ctrun);
3649           min_location = string_range.location + string_range.length;
3650           for (i = 0; i < glyph_count; i++)
3651             {
3652               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3653               CFIndex glyph_index;
3654               CFRange rng;
3656               if (!RIGHT_TO_LEFT_P)
3657                 glyph_index = glyph_count - i - 1;
3658               else
3659                 glyph_index = i;
3660               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3661                                      &gl->string_index);
3662               rng =
3663                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3664                                                              gl->string_index);
3665               gl->comp_range.location = min_location;
3666               gl->comp_range.length = rng.location + rng.length;
3667               if (rng.location < min_location)
3668                 min_location = rng.location;
3669             }
3671           /* Fill the `comp_range' member of struct mac_glyph_layout,
3672              and setup a permutation for right-to-left text.  */
3673           comp_range = CFRangeMake (string_range.location, 0);
3674           range = CFRangeMake (0, 0);
3675           while (1)
3676             {
3677               struct mac_glyph_layout *gl =
3678                 glbuf + range.location + range.length;
3680               if (gl->comp_range.length
3681                   > comp_range.location + comp_range.length)
3682                 comp_range.length = gl->comp_range.length - comp_range.location;
3683               min_location = gl->comp_range.location;
3684               range.length++;
3686               if (min_location >= comp_range.location + comp_range.length)
3687                 {
3688                   comp_range.length = min_location - comp_range.location;
3689                   for (i = 0; i < range.length; i++)
3690                     {
3691                       glbuf[range.location + i].comp_range = comp_range;
3692                       if (RIGHT_TO_LEFT_P)
3693                         permutation[range.location + i] =
3694                           range.location + range.length - i - 1;
3695                     }
3697                   comp_range = CFRangeMake (min_location, 0);
3698                   range.location += range.length;
3699                   range.length = 0;
3700                   if (range.location == glyph_count)
3701                     break;
3702                 }
3703             }
3705           /* Then fill the remaining members.  */
3706           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3707                range.location++)
3708             {
3709               struct mac_glyph_layout *gl;
3710               CGPoint position;
3712               if (!RIGHT_TO_LEFT_P)
3713                 gl = glbuf + range.location;
3714               else
3715                 {
3716                   CFIndex src, dest;
3718                   src = glyph_count - 1 - range.location;
3719                   dest = permutation[src];
3720                   gl = glbuf + dest;
3721                   if (src < dest)
3722                     {
3723                       CFIndex tmp = gl->string_index;
3725                       gl->string_index = glbuf[src].string_index;
3726                       glbuf[src].string_index = tmp;
3727                     }
3728                 }
3729               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3731               CTRunGetPositions (ctrun, range, &position);
3732               gl->advance_delta = position.x - total_advance;
3733               gl->baseline_delta = position.y;
3734               gl->advance = (gl->advance_delta
3735                              + CTRunGetTypographicBounds (ctrun, range,
3736                                                           NULL, NULL, NULL));
3737               total_advance += gl->advance;
3738             }
3740           if (RIGHT_TO_LEFT_P)
3741             xfree (permutation);
3743 #undef RIGHT_TO_LEFT_P
3745           total_glyph_count += glyph_count;
3746         }
3748       result = used;
3749     }
3750   CFRelease (ctline);
3752   return result;
3755 /* The function below seems to cause a memory leak for the CFString
3756    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3757    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3758 #if USE_CT_GLYPH_INFO
3759 static CGGlyph
3760 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3761                               CGFontIndex cid)
3763   CGGlyph result = kCGFontIndexInvalid;
3764   UniChar characters[] = {0xfffd};
3765   CFStringRef string;
3766   CFAttributedStringRef attr_string = NULL;
3767   CTLineRef ctline = NULL;
3769   string = CFStringCreateWithCharacters (NULL, characters,
3770                                          ARRAYELTS (characters));
3772   if (string)
3773     {
3774       CTGlyphInfoRef glyph_info =
3775         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3776       CFDictionaryRef attributes = NULL;
3778       if (glyph_info)
3779         {
3780           CFStringRef keys[] = {kCTFontAttributeName,
3781                                 kCTGlyphInfoAttributeName};
3782           CFTypeRef values[] = {font, glyph_info};
3784           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3785                                            (const void **) values,
3786                                            ARRAYELTS (keys),
3787                                            &kCFTypeDictionaryKeyCallBacks,
3788                                            &kCFTypeDictionaryValueCallBacks);
3789           CFRelease (glyph_info);
3790         }
3791       if (attributes)
3792         {
3793           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3794           CFRelease (attributes);
3795         }
3796       CFRelease (string);
3797     }
3798   if (attr_string)
3799     {
3800       ctline = CTLineCreateWithAttributedString (attr_string);
3801       CFRelease (attr_string);
3802     }
3803   if (ctline)
3804     {
3805       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3807       if (CFArrayGetCount (runs) > 0)
3808         {
3809           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3810           CFDictionaryRef attributes = CTRunGetAttributes (run);
3812           if (attributes)
3813             {
3814               CTFontRef font_in_run =
3815                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3817               if (font_in_run
3818                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3819                 {
3820                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3821                   if (result >= CTFontGetGlyphCount (font))
3822                     result = kCGFontIndexInvalid;
3823                 }
3824             }
3825         }
3826       CFRelease (ctline);
3827     }
3829   return result;
3831 #endif
3833 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3834 static inline int
3835 mac_font_family_group (CFStringRef family)
3837   if (CFStringHasPrefix (family, CFSTR ("#")))
3838     return 2;
3839   else
3840     {
3841       CFRange range;
3843       range = CFStringFind (family, CFSTR ("Apple"),
3844                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3845       if (range.location != kCFNotFound)
3846         return 1;
3848       return 0;
3849     }
3852 static CFComparisonResult
3853 mac_font_family_compare (const void *val1, const void *val2, void *context)
3855   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3856   int group1, group2;
3858   group1 = mac_font_family_group (family1);
3859   group2 = mac_font_family_group (family2);
3860   if (group1 < group2)
3861     return kCFCompareLessThan;
3862   if (group1 > group2)
3863     return kCFCompareGreaterThan;
3864   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3866 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3868 static CFArrayRef
3869 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3871   CFArrayRef result = NULL;
3873 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3874 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3875   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3876 #endif
3877     {
3878       CTFontRef user_font =
3879         CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3881       if (user_font)
3882         {
3883           CFArrayRef languages =
3884             CFArrayCreate (NULL, (const void **) &language, 1,
3885                            &kCFTypeArrayCallBacks);
3887           if (languages)
3888             {
3889               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3890                                                                  languages);
3891               CFRelease (languages);
3892             }
3893           CFRelease (user_font);
3894         }
3895     }
3896 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3897   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3898 #endif
3899 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3900 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3901     {
3902       CFIndex i;
3904       for (i = 0; macfont_language_default_font_names[i].language; i++)
3905         {
3906           if (CFEqual (macfont_language_default_font_names[i].language,
3907                        language))
3908             {
3909               CFMutableArrayRef descriptors =
3910                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3912               if (descriptors)
3913                 {
3914                   CFIndex j;
3916                   for (j = 0;
3917                        macfont_language_default_font_names[i].font_names[j];
3918                        j++)
3919                     {
3920                       CFDictionaryRef attributes =
3921                         CFDictionaryCreate (NULL,
3922                                             ((const void **)
3923                                              &MAC_FONT_NAME_ATTRIBUTE),
3924                                             ((const void **)
3925                                              &macfont_language_default_font_names[i].font_names[j]),
3926                                             1, &kCFTypeDictionaryKeyCallBacks,
3927                                             &kCFTypeDictionaryValueCallBacks);
3929                       if (attributes)
3930                         {
3931                           FontDescriptorRef pat_desc =
3932                             mac_font_descriptor_create_with_attributes (attributes);
3934                           if (pat_desc)
3935                             {
3936                               FontDescriptorRef descriptor =
3937                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3939                               if (descriptor)
3940                                 {
3941                                   CFArrayAppendValue (descriptors, descriptor);
3942                                   CFRelease (descriptor);
3943                                 }
3944                               CFRelease (pat_desc);
3945                             }
3946                           CFRelease (attributes);
3947                         }
3948                     }
3949                   result = descriptors;
3950                 }
3951               break;
3952             }
3953         }
3954     }
3955 #endif
3957   return result;
3960 static CFStringRef
3961 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3962                                                       CFArrayRef languages)
3964   CFStringRef result = NULL;
3965   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3966   CFArrayRef descriptors =
3967     mac_font_copy_default_descriptors_for_language (language);
3969   if (descriptors)
3970     {
3971       CFIndex i, count = CFArrayGetCount (descriptors);
3973       for (i = 0; i < count; i++)
3974         {
3975           FontDescriptorRef descriptor =
3976             CFArrayGetValueAtIndex (descriptors, i);
3978           if (macfont_supports_charset_and_languages_p (descriptor, charset,
3979                                                         Qnil, languages))
3980             {
3981               CFStringRef family =
3982                 mac_font_descriptor_copy_attribute (descriptor,
3983                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3984               if (family)
3985                 {
3986                   if (!CFStringHasPrefix (family, CFSTR ("."))
3987                       && !CFEqual (family, CFSTR ("LastResort")))
3988                     {
3989                       result = family;
3990                       break;
3991                     }
3992                   else
3993                     CFRelease (family);
3994                 }
3995             }
3996         }
3997       CFRelease (descriptors);
3998     }
4000   return result;
4003 void *
4004 macfont_get_nsctfont (struct font *font)
4006   struct macfont_info *macfont_info = (struct macfont_info *) font;
4007   FontRef macfont = macfont_info->macfont;
4009   return (void *) macfont;
4012 void
4013 mac_register_font_driver (struct frame *f)
4015   register_font_driver (&macfont_driver, f);
4018 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4021 void
4022 syms_of_macfont (void)
4024 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4025   static struct font_driver mac_font_driver;
4027   DEFSYM (Qmac_ct, "mac-ct");
4028   macfont_driver.type = Qmac_ct;
4029   register_font_driver (&macfont_driver, NULL);
4031   DEFSYM (QCdestination, ":destination");
4032   DEFSYM (QCminspace, ":minspace");
4033 #endif