Merge from emacs-24
[emacs.git] / src / macfont.m
blobf1895d1b0a5e04ea6f747becf3fefd5cda54fad0
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;
2602   if (macfont_info->cache)
2603     {
2604       int i;
2606       block_input ();
2607       CFRelease (macfont_info->macfont);
2608       CGFontRelease (macfont_info->cgfont);
2609       if (macfont_info->screen_font)
2610         CFRelease (macfont_info->screen_font);
2611       macfont_release_cache (macfont_info->cache);
2612       for (i = 0; i < macfont_info->metrics_nrows; i++)
2613         if (macfont_info->metrics[i])
2614           xfree (macfont_info->metrics[i]);
2615       if (macfont_info->metrics)
2616         xfree (macfont_info->metrics);
2617       macfont_info->cache = NULL;
2618       unblock_input ();
2619     }
2622 static int
2623 macfont_has_char (Lisp_Object font, int c)
2625   int result;
2626   CFCharacterSetRef charset;
2628   block_input ();
2629   if (FONT_ENTITY_P (font))
2630     {
2631       Lisp_Object val;
2632       CFStringRef name;
2634       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2635       val = XCDR (val);
2636       name = XSAVE_POINTER (val, 0);
2637       charset = macfont_get_cf_charset_for_name (name);
2638     }
2639   else
2640     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2642   result = CFCharacterSetIsLongCharacterMember (charset, c);
2643   unblock_input ();
2645   return result;
2648 static unsigned
2649 macfont_encode_char (struct font *font, int c)
2651   struct macfont_info *macfont_info = (struct macfont_info *) font;
2652   CGGlyph glyph;
2654   block_input ();
2655   glyph = macfont_get_glyph_for_character (font, c);
2656   unblock_input ();
2658   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2661 static void
2662 macfont_text_extents (struct font *font, unsigned int *code,
2663                       int nglyphs, struct font_metrics *metrics)
2665   int width, i;
2667   block_input ();
2668   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2669   for (i = 1; i < nglyphs; i++)
2670     {
2671       struct font_metrics m;
2672       int w = macfont_glyph_extents (font, code[i], &m, NULL, 0);
2674       if (width + m.lbearing < metrics->lbearing)
2675         metrics->lbearing = width + m.lbearing;
2676       if (width + m.rbearing > metrics->rbearing)
2677         metrics->rbearing = width + m.rbearing;
2678       if (m.ascent > metrics->ascent)
2679         metrics->ascent = m.ascent;
2680       if (m.descent > metrics->descent)
2681         metrics->descent = m.descent;
2682       width += w;
2683     }
2684   unblock_input ();
2686   metrics->width = width;
2689 static int
2690 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2691               bool with_background)
2693   struct frame * f = s->f;
2694   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2695   CGRect background_rect;
2696   CGPoint text_position;
2697   CGGlyph *glyphs;
2698   CGPoint *positions;
2699   CGFloat font_size = mac_font_get_size (macfont_info->macfont);
2700   bool no_antialias_p =
2701     (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2702      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2703          && font_size <= macfont_antialias_threshold));
2704   int len = to - from;
2705   struct face *face = s->face;
2706   CGContextRef context;
2708   block_input ();
2710   if (with_background)
2711     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2712                                   s->width, FONT_HEIGHT (s->font));
2713  else
2714     background_rect = CGRectNull;
2715   
2716   text_position = CGPointMake (x, -y);
2717   glyphs = xmalloc (sizeof (CGGlyph) * len);
2718   {
2719     CGFloat advance_delta;
2720     int i;
2721     CGFloat total_width = 0;
2723     positions = xmalloc (sizeof (CGPoint) * len);
2724     for (i = 0; i < len; i++)
2725       {
2726         int width;
2728         glyphs[i] = s->char2b[from + i];
2729         width = (s->padding_p ? 1
2730                  : macfont_glyph_extents (s->font, glyphs[i],
2731                                           NULL, &advance_delta,
2732                                           no_antialias_p));
2733         positions[i].x = total_width + advance_delta;
2734         positions[i].y = 0;
2735         total_width += width;
2736       }
2737   }
2739   context = [[NSGraphicsContext currentContext] graphicsPort];
2740   CGContextSaveGState (context);
2742   if (!CGRectIsNull (background_rect))
2743     {
2744       if (s->hl == DRAW_MOUSE_FACE) 
2745         {
2746           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2747           if (!face)
2748             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2749         }
2750       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2751       CGContextFillRects (context, &background_rect, 1);
2752     }
2754   if (macfont_info->cgfont)
2755     {
2756       CGAffineTransform atfm;
2757       CGContextScaleCTM (context, 1, -1);
2758       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2759       if (macfont_info->synthetic_italic_p)
2760         atfm = synthetic_italic_atfm;
2761       else
2762         atfm = CGAffineTransformIdentity;
2763       if (macfont_info->synthetic_bold_p)
2764         {
2765           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2766           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2767           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2768         }
2769       if (no_antialias_p)
2770         CGContextSetShouldAntialias (context, false);
2772       CGContextSetTextMatrix (context, atfm);
2773       CGContextSetTextPosition (context, text_position.x, text_position.y);
2775 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2776       if (macfont_info->color_bitmap_p
2777 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2778           && CTFontDrawGlyphs != NULL
2779 #endif
2780           )
2781         {
2782           if (len > 0)
2783             {
2784               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2785                                 context);
2786             }
2787         }
2788       else
2789 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2790         {
2791           CGContextSetFont (context, macfont_info->cgfont);
2792           CGContextSetFontSize (context, font_size);
2793           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2794         }
2795     }
2798   xfree (glyphs);
2799   xfree (positions);
2800   CGContextRestoreGState (context);
2802   unblock_input ();
2804   return len;
2807 static Lisp_Object
2808 macfont_shape (Lisp_Object lgstring)
2810   struct font *font;
2811   struct macfont_info *macfont_info;
2812   FontRef macfont;
2813   ptrdiff_t glyph_len, len, i, j;
2814   CFIndex nonbmp_len;
2815   UniChar *unichars;
2816   CFIndex *nonbmp_indices;
2817   CFStringRef string;
2818   CFIndex used = 0;
2819   struct mac_glyph_layout *glyph_layouts;
2821   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2822   macfont_info = (struct macfont_info *) font;
2823   macfont = macfont_info->macfont;
2825   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2826   nonbmp_len = 0;
2827   for (i = 0; i < glyph_len; i++)
2828     {
2829       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2831       if (NILP (lglyph))
2832         break;
2833       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2834         nonbmp_len++;
2835     }
2837   len = i;
2839   if (INT_MAX / 2 < len)
2840     memory_full (SIZE_MAX);
2842   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2843   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2844   for (i = j = 0; i < len; i++)
2845     {
2846       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2848       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2849         {
2850           nonbmp_indices[j] = i + j;
2851           j++;
2852         }
2853     }
2854   nonbmp_indices[j] = len + j;  /* sentinel */
2856   block_input ();
2858   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2859                                                kCFAllocatorNull);
2860   if (string)
2861     {
2862       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2863       if (macfont_info->screen_font)
2864         used = mac_screen_font_shape (macfont_info->screen_font, string,
2865                                       glyph_layouts, glyph_len);
2866       else
2867         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2868       CFRelease (string);
2869     }
2871   unblock_input ();
2873   if (used == 0)
2874     return Qnil;
2876   block_input ();
2878   for (i = 0; i < used; i++)
2879     {
2880       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2881       struct mac_glyph_layout *gl = glyph_layouts + i;
2882       EMACS_INT from, to;
2883       struct font_metrics metrics;
2884       int xoff, yoff, wadjust;
2886       if (NILP (lglyph))
2887         {
2888           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2889           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2890         }
2892       from = gl->comp_range.location;
2893       /* Convert UTF-16 index to UTF-32.  */
2894       j = 0;
2895       while (nonbmp_indices[j] < from)
2896         j++;
2897       from -= j;
2898       LGLYPH_SET_FROM (lglyph, from);
2900       to = gl->comp_range.location + gl->comp_range.length;
2901       /* Convert UTF-16 index to UTF-32.  */
2902       while (nonbmp_indices[j] < to)
2903         j++;
2904       to -= j;
2905       LGLYPH_SET_TO (lglyph, to - 1);
2907       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2908          the composition is trivial.  */
2909       {
2910         UTF32Char c;
2912         if (unichars[gl->string_index] >= 0xD800
2913             && unichars[gl->string_index] < 0xDC00)
2914           c = (((unichars[gl->string_index] - 0xD800) << 10)
2915                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2916         else
2917           c = unichars[gl->string_index];
2918         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2919           c = 0;
2920         LGLYPH_SET_CHAR (lglyph, c);
2921       }
2923       {
2924         unsigned long cc = gl->glyph_id;
2925         LGLYPH_SET_CODE (lglyph, cc);
2926       }
2928       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2929       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2930       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2931       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2932       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2933       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2935       xoff = lround (gl->advance_delta);
2936       yoff = lround (- gl->baseline_delta);
2937       wadjust = lround (gl->advance);
2938       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2939         {
2940           Lisp_Object vec;
2942           vec = Fmake_vector (make_number (3), Qnil);
2943           ASET (vec, 0, make_number (xoff));
2944           ASET (vec, 1, make_number (yoff));
2945           ASET (vec, 2, make_number (wadjust));
2946           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2947         }
2948     }
2950   unblock_input ();
2952   return make_number (used);
2955 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2956 typedef UInt8 UINT24[3];
2958 #pragma pack(push, 1)
2959 struct variation_selector_record
2961   UINT24 var_selector;
2962   UInt32 default_uvs_offset, non_default_uvs_offset;
2964 struct uvs_table
2966   UInt16 format;
2967   UInt32 length, num_var_selector_records;
2968   struct variation_selector_record variation_selector_records[1];
2970 #define SIZEOF_UVS_TABLE_HEADER \
2971   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2973 struct unicode_value_range
2975   UINT24 start_unicode_value;
2976   UInt8 additional_count;
2978 struct default_uvs_table {
2979   UInt32 num_unicode_value_ranges;
2980   struct unicode_value_range unicode_value_ranges[1];
2982 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
2983   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
2985 struct uvs_mapping
2987   UINT24 unicode_value;
2988   UInt16 glyph_id;
2990 struct non_default_uvs_table
2992   UInt32 num_uvs_mappings;
2993   struct uvs_mapping uvs_mappings[1];
2995 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
2996   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
2997 #pragma pack(pop)
2999 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3000 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3001    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3002    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3003 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3004 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3005 /* Succeeding one byte should also be accessible.  */
3006 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3007 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3009 /* Return UVS subtable for the specified FONT.  If the subtable is not
3010    found or ill-formatted, then return NULL.  */
3012 static CFDataRef
3013 mac_font_copy_uvs_table (FontRef font)
3015   CFDataRef cmap_table, uvs_table = NULL;
3017   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3018   if (cmap_table)
3019     {
3020       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3021       struct uvs_table *uvs;
3022       struct variation_selector_record *records;
3023       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3025 #if __LP64__
3026       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3027         goto finish;
3028 #endif
3030       cmap_len = CFDataGetLength (cmap_table);
3031       if (sizeof_sfntCMapHeader > cmap_len)
3032         goto finish;
3034       ntables = BUINT16_VALUE (cmap->numTables);
3035       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3036                      / sizeof_sfntCMapEncoding))
3037         goto finish;
3039       for (i = 0; i < ntables; i++)
3040         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3041              == kFontUnicodePlatform)
3042             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3043                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3044           {
3045             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3046             break;
3047           }
3048       if (i == ntables
3049           || uvs_offset > cmap_len
3050           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3051         goto finish;
3053       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3054       uvs_len = BUINT32_VALUE (uvs->length);
3055       if (uvs_len > cmap_len - uvs_offset
3056           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3057         goto finish;
3059       if (BUINT16_VALUE (uvs->format) != 14)
3060         goto finish;
3062       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3063       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3064                       / sizeof (struct variation_selector_record)))
3065         goto finish;
3067       records = uvs->variation_selector_records;
3068       for (i = 0; i < nrecords; i++)
3069         {
3070           UInt32 default_uvs_offset, non_default_uvs_offset;
3072           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3073           if (default_uvs_offset)
3074             {
3075               struct default_uvs_table *default_uvs;
3076               UInt32 nranges;
3078               if (default_uvs_offset > uvs_len
3079                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3080                       > uvs_len - default_uvs_offset))
3081                 goto finish;
3083               default_uvs = ((struct default_uvs_table *)
3084                              ((UInt8 *) uvs + default_uvs_offset));
3085               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3086               if (nranges > ((uvs_len - default_uvs_offset
3087                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3088                              / sizeof (struct unicode_value_range)))
3089                 goto finish;
3090               /* Now 2 * nranges can't overflow, so we can safely use
3091                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3092                  mac_font_get_glyphs_for_variants.  */
3093             }
3095           non_default_uvs_offset =
3096             BUINT32_VALUE (records[i].non_default_uvs_offset);
3097           if (non_default_uvs_offset)
3098             {
3099               struct non_default_uvs_table *non_default_uvs;
3100               UInt32 nmappings;
3102               if (non_default_uvs_offset > uvs_len
3103                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3104                       > uvs_len - non_default_uvs_offset))
3105                 goto finish;
3107               non_default_uvs = ((struct non_default_uvs_table *)
3108                                  ((UInt8 *) uvs + non_default_uvs_offset));
3109               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3110               if (nmappings > ((uvs_len - non_default_uvs_offset
3111                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3112                                / sizeof (struct uvs_mapping)))
3113                 goto finish;
3114               /* Now 2 * nmappings can't overflow, so we can safely
3115                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3116                  in mac_font_get_glyphs_for_variants.  */
3117             }
3118         }
3120       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3122     finish:
3123       CFRelease (cmap_table);
3124     }
3126   return uvs_table;
3129 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3130    sequence consisting of the given base character C and each
3131    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3132    result (explained below) into the corresponding GLYPHS[i].  If the
3133    entry is found in the Default UVS Table, then the result is 0.  If
3134    the entry is found in the Non-Default UVS Table, then the result is
3135    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3136    elements in SELECTORS must be sorted in strictly increasing
3137    order.  */
3139 static void
3140 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3141                                   const UTF32Char selectors[], CGGlyph glyphs[],
3142                                   CFIndex count)
3144   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3145   struct variation_selector_record *records = uvs->variation_selector_records;
3146   CFIndex i;
3147   UInt32 ir, nrecords;
3148 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3149   dispatch_queue_t queue =
3150     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3151   dispatch_group_t group = dispatch_group_create ();
3152 #endif
3154   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3155   i = 0;
3156   ir = 0;
3157   while (i < count && ir < nrecords)
3158     {
3159       UInt32 default_uvs_offset, non_default_uvs_offset;
3161       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3162         {
3163           glyphs[i++] = kCGFontIndexInvalid;
3164           continue;
3165         }
3166       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3167         {
3168           ir++;
3169           continue;
3170         }
3172       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3173       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3174       non_default_uvs_offset =
3175         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3176 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3177       dispatch_group_async (group, queue, ^{
3178 #endif
3179           glyphs[i] = kCGFontIndexInvalid;
3181           if (default_uvs_offset)
3182             {
3183               struct default_uvs_table *default_uvs =
3184                 (struct default_uvs_table *) ((UInt8 *) uvs
3185                                               + default_uvs_offset);
3186               struct unicode_value_range *ranges =
3187                 default_uvs->unicode_value_ranges;
3188               UInt32 lo, hi;
3190               lo = 0;
3191               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3192               while (lo < hi)
3193                 {
3194                   UInt32 mid = (lo + hi) / 2;
3196                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3197                     hi = mid;
3198                   else
3199                     lo = mid + 1;
3200                 }
3201               if (hi > 0
3202                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3203                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3204                 glyphs[i] = 0;
3205             }
3207           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3208             {
3209               struct non_default_uvs_table *non_default_uvs =
3210                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3211                                                   + non_default_uvs_offset);
3212               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3213               UInt32 lo, hi;
3215               lo = 0;
3216               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3217               while (lo < hi)
3218                 {
3219                   UInt32 mid = (lo + hi) / 2;
3221                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3222                     hi = mid;
3223                   else
3224                     lo = mid + 1;
3225                 }
3226               if (hi > 0 &&
3227                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3228                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3229             }
3230 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3231         });
3232 #endif
3233       i++;
3234       ir++;
3235     }
3236   while (i < count)
3237     glyphs[i++] = kCGFontIndexInvalid;
3238 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3239   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3240   dispatch_release (group);
3241 #endif
3244 static int
3245 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3247   CFDataRef uvs_table;
3248   CharacterCollection uvs_collection;
3249   int i, n = 0;
3251   block_input ();
3252   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3254   if (uvs_table)
3255     {
3256       UTF32Char selectors[256];
3257       CGGlyph glyphs[256];
3259       for (i = 0; i < 16; i++)
3260         selectors[i] = 0xFE00 + i;
3261       for (; i < 256; i++)
3262         selectors[i] = 0xE0100 + (i - 16);
3263       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3264       for (i = 0; i < 256; i++)
3265         {
3266           CGGlyph glyph = glyphs[i];
3268           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3269               && glyph != kCGFontIndexInvalid)
3270             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3271           if (glyph == kCGFontIndexInvalid)
3272             variations[i] = 0;
3273           else
3274             {
3275               variations[i] = (glyph ? glyph
3276                                : macfont_get_glyph_for_character (font, c));
3277               n++;
3278             }
3279         }
3280     }
3281   unblock_input ();
3283   return n;
3286 static const char *const macfont_booleans[] = {
3287   ":antialias",
3288   ":minspace",
3289   NULL,
3292 static const char *const macfont_non_booleans[] = {
3293   ":lang",
3294   ":script",
3295   ":destination",
3296   NULL,
3299 static void
3300 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3302   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3305 static Boolean
3306 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3307                                           CFArrayRef languages)
3309   Boolean result = true;
3310   CFArrayRef desc_languages =
3311     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3313   if (desc_languages == NULL)
3314     result = false;
3315   else
3316     {
3317       CFIndex desc_languages_count, i, languages_count;
3319       desc_languages_count = CFArrayGetCount (desc_languages);
3320       languages_count = CFArrayGetCount (languages);
3321       for (i = 0; i < languages_count; i++)
3322         if (!CFArrayContainsValue (desc_languages,
3323                                    CFRangeMake (0, desc_languages_count),
3324                                    CFArrayGetValueAtIndex (languages, i)))
3325           {
3326             result = false;
3327             break;
3328           }
3329       CFRelease (desc_languages);
3330     }
3332   return result;
3335 static CFStringRef
3336 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3338   CFStringRef result = NULL;
3339   CFStringRef charset_string =
3340     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3342   if (charset_string && CFStringGetLength (charset_string) > 0)
3343     {
3344       CFStringRef keys[] = {
3345 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3346         kCTLanguageAttributeName
3347 #else
3348         CFSTR ("NSLanguage")
3349 #endif
3350       };
3351       CFTypeRef values[] = {NULL};
3352       CFIndex num_values = 0;
3353       CFArrayRef languages
3354         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3356       if (languages && CFArrayGetCount (languages) > 0)
3357         {
3358           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3359             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3360           else
3361             {
3362               CFCharacterSetRef charset =
3363                 CFDictionaryGetValue (attributes,
3364                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3366               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3367             }
3368         }
3369       if (result == NULL)
3370         {
3371           CFAttributedStringRef attr_string = NULL;
3372           CTLineRef ctline = NULL;
3373           CFDictionaryRef attrs
3374             = CFDictionaryCreate (NULL, (const void **) keys,
3375                                   (const void **) values, num_values,
3376                                   &kCFTypeDictionaryKeyCallBacks,
3377                                   &kCFTypeDictionaryValueCallBacks);
3379           if (attrs)
3380             {
3381               attr_string = CFAttributedStringCreate (NULL, charset_string,
3382                                                       attrs);
3383               CFRelease (attrs);
3384             }
3385           if (attr_string)
3386             {
3387               ctline = CTLineCreateWithAttributedString (attr_string);
3388               CFRelease (attr_string);
3389             }
3390           if (ctline)
3391             {
3392               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3393               CFIndex i, nruns = CFArrayGetCount (runs);
3394               CTFontRef font;
3396               for (i = 0; i < nruns; i++)
3397                 {
3398                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3399                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3400                   CTFontRef font_in_run;
3402                   if (attributes == NULL)
3403                     break;
3404                   font_in_run =
3405                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3406                   if (font_in_run == NULL)
3407                     break;
3408                   if (i == 0)
3409                     font = font_in_run;
3410                   else if (!mac_ctfont_equal_in_postscript_name (font,
3411                                                                  font_in_run))
3412                     break;
3413                 }
3414               if (nruns > 0 && i == nruns)
3415                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3416               CFRelease (ctline);
3417             }
3418         }
3419     }
3421   return result;
3424 static inline double
3425 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3427   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3428                                      &glyph, NULL, 1);
3431 static inline CGRect
3432 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3434   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3435                                           &glyph, NULL, 1);
3438 static CFArrayRef
3439 mac_ctfont_create_available_families (void)
3441   CFMutableArrayRef families = NULL;
3443 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3444 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3445   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3446 #endif
3447     {
3448       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3450       if (orig_families)
3451         {
3452           CFIndex i, count = CFArrayGetCount (orig_families);
3454           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3455           if (families)
3456             for (i = 0; i < count; i++)
3457               {
3458                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3460                 if (!CFStringHasPrefix (family, CFSTR ("."))
3461                     && (CTFontManagerCompareFontFamilyNames (family,
3462                                                              CFSTR ("LastResort"),
3463                                                              NULL)
3464                         != kCFCompareEqualTo))
3465                   CFArrayAppendValue (families, family);
3466               }
3467           CFRelease (orig_families);
3468         }
3469     }
3470 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3471   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3472 #endif
3473 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3474 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3475     {
3476       CTFontCollectionRef collection;
3477       CFArrayRef descs = NULL;
3479       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3480       if (collection)
3481         {
3482           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3483           CFRelease (collection);
3484         }
3485       if (descs)
3486         {
3487           CFIndex i, count = CFArrayGetCount (descs);
3489           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3490           if (families)
3491             for (i = 0; i < count; i++)
3492               {
3493                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3494                 CFStringRef name =
3495                   mac_font_descriptor_copy_attribute (desc,
3496                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3498                 if (name)
3499                   {
3500                     CFIndex p, limit = CFArrayGetCount (families);
3502                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3503                                               (const void *) name,
3504                                               mac_font_family_compare, NULL);
3505                     if (p >= limit)
3506                       CFArrayAppendValue (families, name);
3507                     else if (mac_font_family_compare
3508                              (CFArrayGetValueAtIndex (families, p),
3509                               name, NULL) != kCFCompareEqualTo)
3510                       CFArrayInsertValueAtIndex (families, p, name);
3511                     CFRelease (name);
3512                   }
3513               }
3514           CFRelease (descs);
3515         }
3516     }
3517 #endif
3519   return families;
3522 static Boolean
3523 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3525   Boolean result;
3526   CFStringRef name1, name2;
3528   if (font1 == font2)
3529     return true;
3531   result = false;
3532   name1 = CTFontCopyPostScriptName (font1);
3533   if (name1)
3534     {
3535       name2 = CTFontCopyPostScriptName (font2);
3536       if (name2)
3537         {
3538           result = CFEqual (name1, name2);
3539           CFRelease (name2);
3540         }
3541       CFRelease (name1);
3542     }
3544   return result;
3547 static CTLineRef
3548 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3549                                              CTFontRef macfont)
3551   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3552   CFTypeRef values[] = {NULL, NULL};
3553   CFDictionaryRef attributes = NULL;
3554   CFAttributedStringRef attr_string = NULL;
3555   CTLineRef ctline = NULL;
3556   float float_zero = 0.0f;
3558   values[0] = macfont;
3559   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3560   if (values[1])
3561     {
3562       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3563                                        (const void **) values,
3564                                        ARRAYELTS (keys),
3565                                        &kCFTypeDictionaryKeyCallBacks,
3566                                        &kCFTypeDictionaryValueCallBacks);
3567       CFRelease (values[1]);
3568     }
3569   if (attributes)
3570     {
3571       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3572       CFRelease (attributes);
3573     }
3574   if (attr_string)
3575     {
3576       ctline = CTLineCreateWithAttributedString (attr_string);
3577       CFRelease (attr_string);
3578     }
3579   if (ctline)
3580     {
3581       /* Abandon if ctline contains some fonts other than the
3582          specified one.  */
3583       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3584       CFIndex i, nruns = CFArrayGetCount (runs);
3586       for (i = 0; i < nruns; i++)
3587         {
3588           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3589           CFDictionaryRef attributes = CTRunGetAttributes (run);
3590           CTFontRef font_in_run;
3592           if (attributes == NULL)
3593             break;
3594           font_in_run =
3595             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3596           if (font_in_run == NULL)
3597             break;
3598           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3599             break;
3600         }
3601       if (i < nruns)
3602         {
3603           CFRelease (ctline);
3604           ctline = NULL;
3605         }
3606     }
3608   return ctline;
3611 static CFIndex
3612 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3613                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3615   CFIndex used, result = 0;
3616   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3618   if (ctline == NULL)
3619     return 0;
3621   used = CTLineGetGlyphCount (ctline);
3622   if (used <= glyph_len)
3623     {
3624       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3625       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3626       CGFloat total_advance = 0;
3627       CFIndex total_glyph_count = 0;
3629       for (k = 0; k < ctrun_count; k++)
3630         {
3631           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3632           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3633           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3634           CFRange string_range, comp_range, range;
3635           CFIndex *permutation;
3637           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3638             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3639           else
3640             permutation = NULL;
3642 #define RIGHT_TO_LEFT_P permutation
3644           /* Now the `comp_range' member of struct mac_glyph_layout is
3645              temporarily used as a work area such that:
3646               glbuf[i].comp_range.location =
3647                 min {compRange[i + 1].location, ...,
3648                      compRange[glyph_count - 1].location,
3649                      maxRange (stringRangeForCTRun)}
3650               glbuf[i].comp_range.length = maxRange (compRange[i])
3651              where compRange[i] is the range of composed characters
3652              containing i-th glyph.  */
3653           string_range = CTRunGetStringRange (ctrun);
3654           min_location = string_range.location + string_range.length;
3655           for (i = 0; i < glyph_count; i++)
3656             {
3657               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3658               CFIndex glyph_index;
3659               CFRange rng;
3661               if (!RIGHT_TO_LEFT_P)
3662                 glyph_index = glyph_count - i - 1;
3663               else
3664                 glyph_index = i;
3665               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3666                                      &gl->string_index);
3667               rng =
3668                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3669                                                              gl->string_index);
3670               gl->comp_range.location = min_location;
3671               gl->comp_range.length = rng.location + rng.length;
3672               if (rng.location < min_location)
3673                 min_location = rng.location;
3674             }
3676           /* Fill the `comp_range' member of struct mac_glyph_layout,
3677              and setup a permutation for right-to-left text.  */
3678           comp_range = CFRangeMake (string_range.location, 0);
3679           range = CFRangeMake (0, 0);
3680           while (1)
3681             {
3682               struct mac_glyph_layout *gl =
3683                 glbuf + range.location + range.length;
3685               if (gl->comp_range.length
3686                   > comp_range.location + comp_range.length)
3687                 comp_range.length = gl->comp_range.length - comp_range.location;
3688               min_location = gl->comp_range.location;
3689               range.length++;
3691               if (min_location >= comp_range.location + comp_range.length)
3692                 {
3693                   comp_range.length = min_location - comp_range.location;
3694                   for (i = 0; i < range.length; i++)
3695                     {
3696                       glbuf[range.location + i].comp_range = comp_range;
3697                       if (RIGHT_TO_LEFT_P)
3698                         permutation[range.location + i] =
3699                           range.location + range.length - i - 1;
3700                     }
3702                   comp_range = CFRangeMake (min_location, 0);
3703                   range.location += range.length;
3704                   range.length = 0;
3705                   if (range.location == glyph_count)
3706                     break;
3707                 }
3708             }
3710           /* Then fill the remaining members.  */
3711           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3712                range.location++)
3713             {
3714               struct mac_glyph_layout *gl;
3715               CGPoint position;
3717               if (!RIGHT_TO_LEFT_P)
3718                 gl = glbuf + range.location;
3719               else
3720                 {
3721                   CFIndex src, dest;
3723                   src = glyph_count - 1 - range.location;
3724                   dest = permutation[src];
3725                   gl = glbuf + dest;
3726                   if (src < dest)
3727                     {
3728                       CFIndex tmp = gl->string_index;
3730                       gl->string_index = glbuf[src].string_index;
3731                       glbuf[src].string_index = tmp;
3732                     }
3733                 }
3734               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3736               CTRunGetPositions (ctrun, range, &position);
3737               gl->advance_delta = position.x - total_advance;
3738               gl->baseline_delta = position.y;
3739               gl->advance = (gl->advance_delta
3740                              + CTRunGetTypographicBounds (ctrun, range,
3741                                                           NULL, NULL, NULL));
3742               total_advance += gl->advance;
3743             }
3745           if (RIGHT_TO_LEFT_P)
3746             xfree (permutation);
3748 #undef RIGHT_TO_LEFT_P
3750           total_glyph_count += glyph_count;
3751         }
3753       result = used;
3754     }
3755   CFRelease (ctline);
3757   return result;
3760 /* The function below seems to cause a memory leak for the CFString
3761    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3762    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3763 #if USE_CT_GLYPH_INFO
3764 static CGGlyph
3765 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3766                               CGFontIndex cid)
3768   CGGlyph result = kCGFontIndexInvalid;
3769   UniChar characters[] = {0xfffd};
3770   CFStringRef string;
3771   CFAttributedStringRef attr_string = NULL;
3772   CTLineRef ctline = NULL;
3774   string = CFStringCreateWithCharacters (NULL, characters,
3775                                          ARRAYELTS (characters));
3777   if (string)
3778     {
3779       CTGlyphInfoRef glyph_info =
3780         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3781       CFDictionaryRef attributes = NULL;
3783       if (glyph_info)
3784         {
3785           CFStringRef keys[] = {kCTFontAttributeName,
3786                                 kCTGlyphInfoAttributeName};
3787           CFTypeRef values[] = {font, glyph_info};
3789           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3790                                            (const void **) values,
3791                                            ARRAYELTS (keys),
3792                                            &kCFTypeDictionaryKeyCallBacks,
3793                                            &kCFTypeDictionaryValueCallBacks);
3794           CFRelease (glyph_info);
3795         }
3796       if (attributes)
3797         {
3798           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3799           CFRelease (attributes);
3800         }
3801       CFRelease (string);
3802     }
3803   if (attr_string)
3804     {
3805       ctline = CTLineCreateWithAttributedString (attr_string);
3806       CFRelease (attr_string);
3807     }
3808   if (ctline)
3809     {
3810       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3812       if (CFArrayGetCount (runs) > 0)
3813         {
3814           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3815           CFDictionaryRef attributes = CTRunGetAttributes (run);
3817           if (attributes)
3818             {
3819               CTFontRef font_in_run =
3820                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3822               if (font_in_run
3823                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3824                 {
3825                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3826                   if (result >= CTFontGetGlyphCount (font))
3827                     result = kCGFontIndexInvalid;
3828                 }
3829             }
3830         }
3831       CFRelease (ctline);
3832     }
3834   return result;
3836 #endif
3838 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3839 static inline int
3840 mac_font_family_group (CFStringRef family)
3842   if (CFStringHasPrefix (family, CFSTR ("#")))
3843     return 2;
3844   else
3845     {
3846       CFRange range;
3848       range = CFStringFind (family, CFSTR ("Apple"),
3849                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3850       if (range.location != kCFNotFound)
3851         return 1;
3853       return 0;
3854     }
3857 static CFComparisonResult
3858 mac_font_family_compare (const void *val1, const void *val2, void *context)
3860   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3861   int group1, group2;
3863   group1 = mac_font_family_group (family1);
3864   group2 = mac_font_family_group (family2);
3865   if (group1 < group2)
3866     return kCFCompareLessThan;
3867   if (group1 > group2)
3868     return kCFCompareGreaterThan;
3869   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3871 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3873 static CFArrayRef
3874 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3876   CFArrayRef result = NULL;
3878 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3879 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3880   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3881 #endif
3882     {
3883       CTFontRef user_font =
3884         CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3886       if (user_font)
3887         {
3888           CFArrayRef languages =
3889             CFArrayCreate (NULL, (const void **) &language, 1,
3890                            &kCFTypeArrayCallBacks);
3892           if (languages)
3893             {
3894               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3895                                                                  languages);
3896               CFRelease (languages);
3897             }
3898           CFRelease (user_font);
3899         }
3900     }
3901 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3902   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3903 #endif
3904 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3905 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3906     {
3907       CFIndex i;
3909       for (i = 0; macfont_language_default_font_names[i].language; i++)
3910         {
3911           if (CFEqual (macfont_language_default_font_names[i].language,
3912                        language))
3913             {
3914               CFMutableArrayRef descriptors =
3915                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3917               if (descriptors)
3918                 {
3919                   CFIndex j;
3921                   for (j = 0;
3922                        macfont_language_default_font_names[i].font_names[j];
3923                        j++)
3924                     {
3925                       CFDictionaryRef attributes =
3926                         CFDictionaryCreate (NULL,
3927                                             ((const void **)
3928                                              &MAC_FONT_NAME_ATTRIBUTE),
3929                                             ((const void **)
3930                                              &macfont_language_default_font_names[i].font_names[j]),
3931                                             1, &kCFTypeDictionaryKeyCallBacks,
3932                                             &kCFTypeDictionaryValueCallBacks);
3934                       if (attributes)
3935                         {
3936                           FontDescriptorRef pat_desc =
3937                             mac_font_descriptor_create_with_attributes (attributes);
3939                           if (pat_desc)
3940                             {
3941                               FontDescriptorRef descriptor =
3942                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3944                               if (descriptor)
3945                                 {
3946                                   CFArrayAppendValue (descriptors, descriptor);
3947                                   CFRelease (descriptor);
3948                                 }
3949                               CFRelease (pat_desc);
3950                             }
3951                           CFRelease (attributes);
3952                         }
3953                     }
3954                   result = descriptors;
3955                 }
3956               break;
3957             }
3958         }
3959     }
3960 #endif
3962   return result;
3965 static CFStringRef
3966 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3967                                                       CFArrayRef languages)
3969   CFStringRef result = NULL;
3970   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3971   CFArrayRef descriptors =
3972     mac_font_copy_default_descriptors_for_language (language);
3974   if (descriptors)
3975     {
3976       CFIndex i, count = CFArrayGetCount (descriptors);
3978       for (i = 0; i < count; i++)
3979         {
3980           FontDescriptorRef descriptor =
3981             CFArrayGetValueAtIndex (descriptors, i);
3983           if (macfont_supports_charset_and_languages_p (descriptor, charset,
3984                                                         Qnil, languages))
3985             {
3986               CFStringRef family =
3987                 mac_font_descriptor_copy_attribute (descriptor,
3988                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3989               if (family)
3990                 {
3991                   if (!CFStringHasPrefix (family, CFSTR ("."))
3992                       && !CFEqual (family, CFSTR ("LastResort")))
3993                     {
3994                       result = family;
3995                       break;
3996                     }
3997                   else
3998                     CFRelease (family);
3999                 }
4000             }
4001         }
4002       CFRelease (descriptors);
4003     }
4005   return result;
4008 void *
4009 macfont_get_nsctfont (struct font *font)
4011   struct macfont_info *macfont_info = (struct macfont_info *) font;
4012   FontRef macfont = macfont_info->macfont;
4014   return (void *) macfont;
4017 void
4018 mac_register_font_driver (struct frame *f)
4020   register_font_driver (&macfont_driver, f);
4023 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4026 void
4027 syms_of_macfont (void)
4029 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4030   static struct font_driver mac_font_driver;
4032   DEFSYM (Qmac_ct, "mac-ct");
4033   macfont_driver.type = Qmac_ct;
4034   register_font_driver (&macfont_driver, NULL);
4036   DEFSYM (QCdestination, ":destination");
4037   DEFSYM (QCminspace, ":minspace");
4038 #endif