* lisp/font-lock.el (font-lock-fontify-buffer): Fix interactive-only markup.
[emacs/old-mirror.git] / src / macfont.m
blobb1fa5a1a41b1bcb83f35cc013f08ba0e7bd94299
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 Boolean macfont_closest_traits_index_p (CFArrayRef, FontSymbolicTraits,
147                                                CFIndex);
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)
654 /* Mac font driver.  */
656 static struct
658   /* registry name */
659   const char *name;
660   /* characters to distinguish the charset from the others */
661   int uniquifier[6];
662   /* additional constraint by language */
663   CFStringRef lang;
664   /* set on demand */
665   CFCharacterSetRef cf_charset;
666   CFStringRef cf_charset_string;
667 } cf_charset_table[] =
668   { { "iso8859-1", { 0x00A0, 0x00A1, 0x00B4, 0x00BC, 0x00D0 } },
669     { "iso8859-2", { 0x00A0, 0x010E }},
670     { "iso8859-3", { 0x00A0, 0x0108 }},
671     { "iso8859-4", { 0x00A0, 0x00AF, 0x0128, 0x0156, 0x02C7 }},
672     { "iso8859-5", { 0x00A0, 0x0401 }},
673     { "iso8859-6", { 0x00A0, 0x060C }},
674     { "iso8859-7", { 0x00A0, 0x0384 }},
675     { "iso8859-8", { 0x00A0, 0x05D0 }},
676     { "iso8859-9", { 0x00A0, 0x00A1, 0x00BC, 0x011E }},
677     { "iso8859-10", { 0x00A0, 0x00D0, 0x0128, 0x2015 }},
678     { "iso8859-11", { 0x00A0, 0x0E01 }},
679     { "iso8859-13", { 0x00A0, 0x201C }},
680     { "iso8859-14", { 0x00A0, 0x0174 }},
681     { "iso8859-15", { 0x00A0, 0x00A1, 0x00D0, 0x0152 }},
682     { "iso8859-16", { 0x00A0, 0x0218}},
683     { "gb2312.1980-0", { 0x4E13 }, CFSTR ("zh-Hans")},
684     { "big5-0", { /* 0xF6B1 in ftfont.c */ 0x4EDC }, CFSTR ("zh-Hant") },
685     { "jisx0208.1983-0", { 0x4E55 }, CFSTR ("ja")},
686     { "ksc5601.1987-0", { 0xAC00 }, CFSTR ("ko")},
687     { "cns11643.1992-1", { 0xFE32 }, CFSTR ("zh-Hant")},
688     { "cns11643.1992-2", { 0x4E33, 0x7934 }},
689     { "cns11643.1992-3", { 0x201A9 }},
690     { "cns11643.1992-4", { 0x20057 }},
691     { "cns11643.1992-5", { 0x20000 }},
692     { "cns11643.1992-6", { 0x20003 }},
693     { "cns11643.1992-7", { 0x20055 }},
694     { "gbk-0", { 0x4E06 }, CFSTR ("zh-Hans")},
695     { "jisx0212.1990-0", { 0x4E44 }},
696     { "jisx0213.2000-1", { 0xFA10 }, CFSTR ("ja")},
697     { "jisx0213.2000-2", { 0xFA49 }},
698     { "jisx0213.2004-1", { 0x20B9F }},
699     { "viscii1.1-1", { 0x1EA0, 0x1EAE, 0x1ED2 }, CFSTR ("vi")},
700     { "tis620.2529-1", { 0x0E01 }, CFSTR ("th")},
701     { "windows-1251", { 0x0401, 0x0490 }, CFSTR ("ru")},
702     { "koi8-r", { 0x0401, 0x2219 }, CFSTR ("ru")},
703     { "mulelao-1", { 0x0E81 }, CFSTR ("lo")},
704     { "unicode-sip", { 0x20000 }},
705     { NULL }
706   };
708 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
709 static const struct
711   CFStringRef language;
712   CFStringRef font_names[3];
713 } macfont_language_default_font_names[] = {
714   { CFSTR ("ja"), { CFSTR ("HiraKakuProN-W3"), /* 10.5 - 10.9 */
715                     CFSTR ("HiraKakuPro-W3"),  /* 10.4 */
716                     NULL }},
717   { CFSTR ("ko"), { CFSTR ("AppleSDGothicNeo-Regular"), /* 10.8 - 10.9 */
718                     CFSTR ("AppleGothic"), /* 10.4 - 10.7 */
719                     NULL }},
720   { CFSTR ("zh-Hans"), { CFSTR ("STHeitiSC-Light"), /* 10.6 - 10.9 */
721                          CFSTR ("STXihei"),         /* 10.4 - 10.5 */
722                          NULL }},
723   { CFSTR ("zh-Hant"), { CFSTR ("STHeitiTC-Light"), /* 10.6 - 10.9 */
724                          CFSTR ("LiHeiPro"),        /* 10.4 - 10.5 */
725                          NULL }},
726   { NULL }
728 #endif
730 static CGFloat macfont_antialias_threshold;
732 void
733 macfont_update_antialias_threshold (void)
735   int threshold;
736   Boolean valid_p;
738   threshold =
739     CFPreferencesGetAppIntegerValue (CFSTR ("AppleAntiAliasingThreshold"),
740                                      kCFPreferencesCurrentApplication,
741                                      &valid_p);
742   if (valid_p)
743     macfont_antialias_threshold = threshold;
746 static inline Lisp_Object
747 macfont_intern_prop_cfstring (CFStringRef cfstring)
749   Lisp_Object string = cfstring_to_lisp_nodecode (cfstring);
751   return font_intern_prop (SSDATA (string), SBYTES (string), 1);
754 static inline CFIndex
755 macfont_store_utf32char_to_unichars (UTF32Char c, UniChar *unichars)
757   if (c < 0x10000)
758     {
759       unichars[0] = c;
761       return 1;
762     }
763   else
764     {
765       c -= 0x10000;
766       unichars[0] = (c >> 10) + 0xD800;
767       unichars[1] = (c & 0x3FF) + 0xDC00;
769       return 2;
770     }
773 static Boolean
774 cfnumber_get_font_symbolic_traits_value (CFNumberRef number,
775                                          FontSymbolicTraits *sym_traits)
777   SInt64 sint64_value;
779   /* Getting symbolic traits with kCFNumberSInt32Type is lossy on Mac
780      OS X 10.6 when the value is greater than or equal to 1 << 31.  */
781   if (CFNumberGetValue (number, kCFNumberSInt64Type, &sint64_value))
782     {
783       *sym_traits = (FontSymbolicTraits) sint64_value;
785       return true;
786     }
788   return false;
791 static void
792 macfont_store_descriptor_attributes (FontDescriptorRef desc,
793                                      Lisp_Object spec_or_entity)
795   CFStringRef str;
796   CFDictionaryRef dict;
797   CFNumberRef num;
798   CGFloat floatval;
800   str = mac_font_descriptor_copy_attribute (desc,
801                                             MAC_FONT_FAMILY_NAME_ATTRIBUTE);
802   if (str)
803     {
804       ASET (spec_or_entity, FONT_FAMILY_INDEX,
805             macfont_intern_prop_cfstring (str));
806       CFRelease (str);
807     }
808   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
809   if (dict)
810     {
811       struct {
812         enum font_property_index index;
813         CFStringRef trait;
814         CGPoint points[6];
815       } numeric_traits[] =
816           {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
817             {{-0.4, 50},        /* light */
818              {-0.24, 87.5},     /* (semi-light + normal) / 2 */
819              {0, 100},          /* normal */
820              {0.24, 140},       /* (semi-bold + normal) / 2 */
821              {0.4, 200},        /* bold */
822              {CGFLOAT_MAX, CGFLOAT_MAX}}},
823            {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
824             {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
825            {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
826             {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
827       int i;
829       for (i = 0; i < ARRAYELTS (numeric_traits); i++)
830         {
831           num = CFDictionaryGetValue (dict, numeric_traits[i].trait);
832           if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
833             {
834               CGPoint *point = numeric_traits[i].points;
836               while (point->x < floatval)
837                 point++;
838               if (point == numeric_traits[i].points)
839                 point++;
840               else if (point->x == CGFLOAT_MAX)
841                 point--;
842               floatval = (point - 1)->y + ((floatval - (point - 1)->x)
843                                            * ((point->y - (point - 1)->y)
844                                               / (point->x - (point - 1)->x)));
845               FONT_SET_STYLE (spec_or_entity, numeric_traits[i].index,
846                               make_number (lround (floatval)));
847             }
848         }
850       num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
851       if (num)
852         {
853           FontSymbolicTraits sym_traits;
854           int spacing;
856           cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
857           spacing = (sym_traits & MAC_FONT_TRAIT_MONO_SPACE
858                      ? FONT_SPACING_MONO : FONT_SPACING_PROPORTIONAL);
859           ASET (spec_or_entity, FONT_SPACING_INDEX, make_number (spacing));
860         }
862       CFRelease (dict);
863     }
864   num = mac_font_descriptor_copy_attribute (desc, MAC_FONT_SIZE_ATTRIBUTE);
865   if (num && CFNumberGetValue (num, kCFNumberCGFloatType, &floatval))
866     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (floatval));
867   else
868     ASET (spec_or_entity, FONT_SIZE_INDEX, make_number (0));
869   if (num)
870     CFRelease (num);
873 static Lisp_Object
874 macfont_descriptor_entity (FontDescriptorRef desc, Lisp_Object extra,
875                            FontSymbolicTraits synth_sym_traits)
877   Lisp_Object entity;
878   CFDictionaryRef dict;
879   FontSymbolicTraits sym_traits = 0;
880   CFStringRef name;
882   entity = font_make_entity ();
884   ASET (entity, FONT_TYPE_INDEX, macfont_driver.type);
885   ASET (entity, FONT_REGISTRY_INDEX, Qiso10646_1);
887   macfont_store_descriptor_attributes (desc, entity);
889   dict = mac_font_descriptor_copy_attribute (desc, MAC_FONT_TRAITS_ATTRIBUTE);
890   if (dict)
891     {
892       CFNumberRef num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
894       if (num)
895         cfnumber_get_font_symbolic_traits_value (num, &sym_traits);
896       CFRelease (dict);
897     }
898   if (EQ (AREF (entity, FONT_SIZE_INDEX), make_number (0)))
899     ASET (entity, FONT_AVGWIDTH_INDEX, make_number (0));
900   ASET (entity, FONT_EXTRA_INDEX, Fcopy_sequence (extra));
901   name = mac_font_descriptor_copy_attribute (desc, MAC_FONT_NAME_ATTRIBUTE);
902   font_put_extra (entity, QCfont_entity,
903                   make_save_ptr_int ((void *) name, sym_traits));
904   if (synth_sym_traits & MAC_FONT_TRAIT_ITALIC)
905     FONT_SET_STYLE (entity, FONT_SLANT_INDEX,
906                     make_number (FONT_SLANT_SYNTHETIC_ITALIC));
907   if (synth_sym_traits & MAC_FONT_TRAIT_BOLD)
908     FONT_SET_STYLE (entity, FONT_WEIGHT_INDEX,
909                     make_number (FONT_WEIGHT_SYNTHETIC_BOLD));
910   if (synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
911     ASET (entity, FONT_SPACING_INDEX,
912           make_number (FONT_SPACING_SYNTHETIC_MONO));
914   return entity;
917 static CFStringRef
918 macfont_create_family_with_symbol (Lisp_Object symbol)
920   static CFArrayRef families = NULL;
921   CFStringRef result = NULL, family_name;
922   int using_cache_p = 1;
923   CFComparatorFunction family_name_comparator;
925   family_name = cfstring_create_with_string_noencode (SYMBOL_NAME (symbol));
926   if (family_name == NULL)
927     return NULL;
929 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
930 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
931   if (CTFontManagerCompareFontFamilyNames != NULL)
932 #endif
933     {
934       family_name_comparator = CTFontManagerCompareFontFamilyNames;
935     }
936 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
937   else               /* CTFontManagerCompareFontFamilyNames == NULL */
938 #endif
939 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
940 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
941     {
942       family_name_comparator = mac_font_family_compare;
943     }
944 #endif
946   if ((*family_name_comparator) (family_name, CFSTR ("LastResort"), NULL)
947       == kCFCompareEqualTo)
948     result = CFSTR ("LastResort");
949   else
950     while (1)
951       {
952         CFIndex i, count;
954         if (families == NULL)
955           {
956             families = mac_font_create_available_families ();
957             using_cache_p = 0;
958             if (families == NULL)
959               break;
960           }
962         count = CFArrayGetCount (families);
963         i = CFArrayBSearchValues (families, CFRangeMake (0, count),
964                                   (const void *) family_name,
965                                   family_name_comparator, NULL);
966         if (i < count)
967           {
968             CFStringRef name = CFArrayGetValueAtIndex (families, i);
970             if ((*family_name_comparator) (name, family_name, NULL)
971                 == kCFCompareEqualTo)
972               result = CFRetain (name);
973           }
975         if (result || !using_cache_p)
976           break;
977         else
978           {
979             CFRelease (families);
980             families = NULL;
981           }
982       }
984   CFRelease (family_name);
986   return result;
989 #define WIDTH_FRAC_BITS         (4)
990 #define WIDTH_FRAC_SCALE        (2 * ((1 << (WIDTH_FRAC_BITS - 1)) - 1))
992 struct macfont_metrics
994   unsigned char lbearing_low, rbearing_low;
995   signed lbearing_high : 4, rbearing_high : 4;
996   unsigned char ascent_low, descent_low;
997   signed ascent_high : 4, descent_high : 4;
999   /* These two members are used for fixed-point representation of
1000      glyph width.  The `width_int' member is an integer that is
1001      closest to the width.  The `width_frac' member is the fractional
1002      adjustment representing a value in [-.5, .5], multiplied by
1003      WIDTH_FRAC_SCALE.  For synthetic monospace fonts, they represent
1004      the advance delta for centering instead of the glyph width.  */
1005   signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS;
1008 #define METRICS_VALUE(metrics, member)                          \
1009   (((metrics)->member##_high << 8) | (metrics)->member##_low)
1010 #define METRICS_SET_VALUE(metrics, member, value)                   \
1011   do {short tmp = (value); (metrics)->member##_low = tmp & 0xff;    \
1012     (metrics)->member##_high = tmp >> 8;} while (0)
1014 enum metrics_status
1016   METRICS_INVALID = -1,    /* metrics entry is invalid */
1017   METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1020 #define METRICS_STATUS(metrics)                                         \
1021   (METRICS_VALUE (metrics, ascent) + METRICS_VALUE (metrics, descent))
1022 #define METRICS_SET_STATUS(metrics, status)                     \
1023   do {METRICS_SET_VALUE (metrics, ascent, 0);                   \
1024     METRICS_SET_VALUE (metrics, descent, status);} while (0)
1026 #define METRICS_NCOLS_PER_ROW   (128)
1027 #define LCD_FONT_SMOOTHING_LEFT_MARGIN  (0.396f)
1028 #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f)
1030 static int
1031 macfont_glyph_extents (struct font *font, CGGlyph glyph,
1032                        struct font_metrics *metrics, CGFloat *advance_delta,
1033                        int force_integral_p)
1035   struct macfont_info *macfont_info = (struct macfont_info *) font;
1036   FontRef macfont = macfont_info->macfont;
1037   int row, col;
1038   struct macfont_metrics *cache;
1039   int width;
1041   row = glyph / METRICS_NCOLS_PER_ROW;
1042   col = glyph % METRICS_NCOLS_PER_ROW;
1043   if (row >= macfont_info->metrics_nrows)
1044     {
1045       macfont_info->metrics =
1046         xrealloc (macfont_info->metrics,
1047                   sizeof (struct macfont_metrics *) * (row + 1));
1048       memset (macfont_info->metrics + macfont_info->metrics_nrows, 0,
1049               (sizeof (struct macfont_metrics *)
1050                * (row + 1 - macfont_info->metrics_nrows)));
1051       macfont_info->metrics_nrows = row + 1;
1052     }
1053   if (macfont_info->metrics[row] == NULL)
1054     {
1055       struct macfont_metrics *new;
1056       int i;
1058       new = xmalloc (sizeof (struct macfont_metrics) * METRICS_NCOLS_PER_ROW);
1059       for (i = 0; i < METRICS_NCOLS_PER_ROW; i++)
1060         METRICS_SET_STATUS (new + i, METRICS_INVALID);
1061       macfont_info->metrics[row] = new;
1062     }
1063   cache = macfont_info->metrics[row] + col;
1065   if (METRICS_STATUS (cache) == METRICS_INVALID)
1066     {
1067       CGFloat fwidth;
1069       if (macfont_info->screen_font)
1070         fwidth = mac_screen_font_get_advance_width_for_glyph (macfont_info->screen_font, glyph);
1071       else
1072         fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph);
1074       /* For synthetic mono fonts, cache->width_{int,frac} holds the
1075          advance delta value.  */
1076       if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1077         fwidth = (font->pixel_size - fwidth) / 2;
1078       cache->width_int = lround (fwidth);
1079       cache->width_frac = lround ((fwidth - cache->width_int)
1080                                   * WIDTH_FRAC_SCALE);
1081       METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID);
1082     }
1083   if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO)
1084     width = font->pixel_size;
1085   else
1086     width = cache->width_int;
1088   if (metrics)
1089     {
1090       if (METRICS_STATUS (cache) == METRICS_WIDTH_VALID)
1091         {
1092           CGRect bounds = mac_font_get_bounding_rect_for_glyph (macfont, glyph);
1094           if (macfont_info->synthetic_italic_p)
1095             {
1096               /* We assume the members a, b, c, and d in
1097                  synthetic_italic_atfm are non-negative.  */
1098               bounds.origin =
1099                 CGPointApplyAffineTransform (bounds.origin,
1100                                              synthetic_italic_atfm);
1101               bounds.size =
1102                 CGSizeApplyAffineTransform (bounds.size, synthetic_italic_atfm);
1103             }
1104           if (macfont_info->synthetic_bold_p)
1105             {
1106               CGFloat d =
1107                 - synthetic_bold_factor * mac_font_get_size (macfont) / 2;
1109                 bounds = CGRectInset (bounds, d, d);
1110             }
1111           switch (macfont_info->spacing)
1112             {
1113             case MACFONT_SPACING_PROPORTIONAL:
1114               bounds.origin.x += - (cache->width_frac
1115                                     / (CGFloat) (WIDTH_FRAC_SCALE * 2));
1116               break;
1117             case MACFONT_SPACING_MONO:
1118               break;
1119             case MACFONT_SPACING_SYNTHETIC_MONO:
1120               bounds.origin.x += (cache->width_int
1121                                   + (cache->width_frac
1122                                      / (CGFloat) WIDTH_FRAC_SCALE));
1123               break;
1124             }
1125           if (bounds.size.width > 0)
1126             {
1127               bounds.origin.x -= LCD_FONT_SMOOTHING_LEFT_MARGIN;
1128               bounds.size.width += (LCD_FONT_SMOOTHING_LEFT_MARGIN
1129                                     + LCD_FONT_SMOOTHING_RIGHT_MARGIN);
1130             }
1131           bounds = CGRectIntegral (bounds);
1132           METRICS_SET_VALUE (cache, lbearing, CGRectGetMinX (bounds));
1133           METRICS_SET_VALUE (cache, rbearing, CGRectGetMaxX (bounds));
1134           METRICS_SET_VALUE (cache, ascent, CGRectGetMaxY (bounds));
1135           METRICS_SET_VALUE (cache, descent, -CGRectGetMinY (bounds));
1136         }
1137       metrics->lbearing = METRICS_VALUE (cache, lbearing);
1138       metrics->rbearing = METRICS_VALUE (cache, rbearing);
1139       metrics->width = width;
1140       metrics->ascent = METRICS_VALUE (cache, ascent);
1141       metrics->descent = METRICS_VALUE (cache, descent);
1142     }
1144   if (advance_delta)
1145     {
1146       switch (macfont_info->spacing)
1147         {
1148         case MACFONT_SPACING_PROPORTIONAL:
1149           *advance_delta = (force_integral_p ? 0
1150                             : - (cache->width_frac
1151                                  / (CGFloat) (WIDTH_FRAC_SCALE * 2)));
1152           break;
1153         case MACFONT_SPACING_MONO:
1154           *advance_delta = 0;
1155           break;
1156         case MACFONT_SPACING_SYNTHETIC_MONO:
1157           *advance_delta = (force_integral_p ? cache->width_int
1158                             : (cache->width_int
1159                                + (cache->width_frac
1160                                   / (CGFloat) WIDTH_FRAC_SCALE)));
1161           break;
1162         }
1163     }
1165   return width;
1168 static CFMutableDictionaryRef macfont_cache_dictionary;
1170 /* Threshold used in row_nkeys_or_perm.  This must be less than or
1171    equal to the number of rows that are invalid as BMP (i.e., from
1172    U+D800 to U+DFFF).  */
1173 #define ROW_PERM_OFFSET (8)
1175 /* The number of glyphs that can be stored in a value for a single
1176    entry of CFDictionary.  */
1177 #define NGLYPHS_IN_VALUE (sizeof (void *) / sizeof (CGGlyph))
1179 struct macfont_cache
1181   int reference_count;
1182   CFCharacterSetRef cf_charset;
1183   struct {
1184     /* The cached glyph for a BMP character c is stored in
1185        matrix[row_nkeys_or_perm[c / 256] - ROW_PERM_OFFSET][c % 256]
1186        if row_nkeys_or_perm[c / 256] >= ROW_PERM_OFFSET.  */
1187     unsigned char row_nkeys_or_perm[256];
1188     CGGlyph **matrix;
1190     /* Number of rows for which the BMP cache is allocated so far.
1191        I.e., matrix[0] ... matrix[nrows - 1] are non-NULL.  */
1192     int nrows;
1194     /* The cached glyph for a character c is stored as the (c %
1195        NGLYPHS_IN_VALUE)-th CGGlyph block of a value for the key (c /
1196        NGLYPHS_IN_VALUE).  However, the glyph for a BMP character c is
1197        not stored here if row_nkeys_or_perm[c / 256] >=
1198        ROW_PERM_OFFSET.  */
1199     CFMutableDictionaryRef dictionary;
1200   } glyph;
1202   struct {
1203     /* UVS (Unicode Variation Sequence) subtable data, which is of
1204        type CFDataRef if available.  NULL means it is not initialized
1205        yet.  kCFNull means the subtable is not found and there is no
1206        suitable fallback table for this font.  */
1207     CFTypeRef table;
1209     /* Character collection specifying the destination of the mapping
1210        provided by `table' above.  If `table' is obtained from the UVS
1211        subtable in the font cmap table, then the value of this member
1212        should be MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING.  */
1213     CharacterCollection collection;
1214   } uvs;
1217 static struct macfont_cache *macfont_lookup_cache (CFStringRef);
1218 static struct macfont_cache *macfont_retain_cache (struct macfont_cache *);
1219 static void macfont_release_cache (struct macfont_cache *);
1220 static CFCharacterSetRef macfont_get_cf_charset (struct font *);
1221 static CFCharacterSetRef macfont_get_cf_charset_for_name (CFStringRef);
1222 static CGGlyph macfont_get_glyph_for_character (struct font *, UTF32Char);
1223 static CGGlyph macfont_get_glyph_for_cid (struct font *font,
1224                                           CharacterCollection, CGFontIndex);
1225 static CFDataRef macfont_get_uvs_table (struct font *, CharacterCollection *);
1227 static struct macfont_cache *
1228 macfont_lookup_cache (CFStringRef key)
1230   struct macfont_cache *cache;
1232   if (macfont_cache_dictionary == NULL)
1233     {
1234       macfont_cache_dictionary =
1235         CFDictionaryCreateMutable (NULL, 0,
1236                                    &kCFTypeDictionaryKeyCallBacks, NULL);
1237       cache = NULL;
1238     }
1239   else
1240     cache = ((struct macfont_cache *)
1241              CFDictionaryGetValue (macfont_cache_dictionary, key));
1243   if (cache == NULL)
1244     {
1245       FontRef macfont = mac_font_create_with_name (key, 0);
1247       if (macfont)
1248         {
1249           cache = xzalloc (sizeof (struct macfont_cache));
1250           /* Treat the LastResort font as if it contained glyphs for
1251              all characters.  This may look too rough, but neither
1252              CTFontCopyCharacterSet nor -[NSFont coveredCharacterSet]
1253              for this font is correct for non-BMP characters on Mac OS
1254              X 10.5, anyway.  */
1255           if (CFEqual (key, CFSTR ("LastResort")))
1256             {
1257               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1259               cache->cf_charset =
1260                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1261             }
1262           if (cache->cf_charset == NULL)
1263             cache->cf_charset = mac_font_copy_character_set (macfont);
1264           CFDictionaryAddValue (macfont_cache_dictionary, key,
1265                                 (const void *) cache);
1266           CFRelease (macfont);
1267         }
1268     }
1270   return cache;
1273 static struct macfont_cache *
1274 macfont_retain_cache (struct macfont_cache *cache)
1276   cache->reference_count++;
1278   return cache;
1281 static void
1282 macfont_release_cache (struct macfont_cache *cache)
1284   if (--cache->reference_count == 0)
1285     {
1286       int i;
1288       for (i = 0; i < cache->glyph.nrows; i++)
1289         xfree (cache->glyph.matrix[i]);
1290       xfree (cache->glyph.matrix);
1291       if (cache->glyph.dictionary)
1292         CFRelease (cache->glyph.dictionary);
1293       memset (&cache->glyph, 0, sizeof (cache->glyph));
1294       if (cache->uvs.table)
1295         CFRelease (cache->uvs.table);
1296       memset (&cache->uvs, 0, sizeof (cache->uvs));
1297     }
1300 static CFCharacterSetRef
1301 macfont_get_cf_charset (struct font *font)
1303   struct macfont_info *macfont_info = (struct macfont_info *) font;
1305   return macfont_info->cache->cf_charset;
1308 static CFCharacterSetRef
1309 macfont_get_cf_charset_for_name (CFStringRef name)
1311   struct macfont_cache *cache = macfont_lookup_cache (name);
1313   return cache->cf_charset;
1316 static CGGlyph
1317 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1319   struct macfont_info *macfont_info = (struct macfont_info *) font;
1320   FontRef macfont = macfont_info->macfont;
1321   struct macfont_cache *cache = macfont_info->cache;
1323   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1324     {
1325       int row = c / 256;
1326       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1328       if (nkeys_or_perm < ROW_PERM_OFFSET)
1329         {
1330           UniChar unichars[256], ch;
1331           CGGlyph *glyphs;
1332           int i, len;
1333           int nrows;
1334 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1335           dispatch_queue_t queue;
1336           dispatch_group_t group = NULL;
1337 #else
1338           int nkeys;
1339 #endif
1341           if (row != 0)
1342             {
1343               CFMutableDictionaryRef dictionary;
1344               uintptr_t key, value;
1345               int nshifts;
1346               CGGlyph glyph;
1348               if (cache->glyph.dictionary == NULL)
1349                 cache->glyph.dictionary =
1350                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1351               dictionary = cache->glyph.dictionary;
1352               key = c / NGLYPHS_IN_VALUE;
1353               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1354               value = ((uintptr_t)
1355                        CFDictionaryGetValue (dictionary, (const void *) key));
1356               glyph = (value >> nshifts);
1357               if (glyph)
1358                 return glyph;
1360               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1361                 {
1362                   ch = c;
1363                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1364                                                            &glyph, 1)
1365                       || glyph == 0)
1366                     glyph = kCGFontIndexInvalid;
1368                   if (value == 0)
1369                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1370                   value |= ((uintptr_t) glyph << nshifts);
1371                   CFDictionarySetValue (dictionary, (const void *) key,
1372                                         (const void *) value);
1374                   return glyph;
1375                 }
1377 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1378               queue =
1379                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1380               group = dispatch_group_create ();
1381               dispatch_group_async (group, queue, ^{
1382                   int nkeys;
1383                   uintptr_t key;
1384 #endif
1385                   nkeys = nkeys_or_perm;
1386                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1387                     if (CFDictionaryContainsKey (dictionary,
1388                                                  (const void *) key))
1389                       {
1390                         CFDictionaryRemoveValue (dictionary,
1391                                                  (const void *) key);
1392                         if (--nkeys == 0)
1393                           break;
1394                       }
1395 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1396                 });
1397 #endif
1398             }
1400           len = 0;
1401           for (i = 0; i < 256; i++)
1402             {
1403               ch = row * 256 + i;
1404               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1405                 unichars[len++] = ch;
1406             }
1408           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1409           if (len > 0)
1410             {
1411               mac_font_get_glyphs_for_characters (macfont, unichars,
1412                                                   glyphs, len);
1413               while (i > len)
1414                 {
1415                   int next = unichars[len - 1] % 256;
1417                   while (--i > next)
1418                     glyphs[i] = kCGFontIndexInvalid;
1420                   len--;
1421                   glyphs[i] = glyphs[len];
1422                   if (len == 0)
1423                     break;
1424                 }
1425             }
1426           if (i > len)
1427             while (i-- > 0)
1428               glyphs[i] = kCGFontIndexInvalid;
1430           nrows = cache->glyph.nrows;
1431           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1432           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1433           nrows++;
1434           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1435                                           sizeof (CGGlyph *) * nrows);
1436           cache->glyph.matrix[nrows - 1] = glyphs;
1437           cache->glyph.nrows = nrows;
1439 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1440           if (group)
1441             {
1442               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1443               dispatch_release (group);
1444             }
1445 #endif
1446         }
1448       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1449     }
1450   else
1451     {
1452       uintptr_t key, value;
1453       int nshifts;
1454       CGGlyph glyph;
1456       if (cache->glyph.dictionary == NULL)
1457         cache->glyph.dictionary =
1458           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1459       key = c / NGLYPHS_IN_VALUE;
1460       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1461       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1462                                                 (const void *) key);
1463       glyph = (value >> nshifts);
1464       if (glyph == 0)
1465         {
1466           UniChar unichars[2];
1467           CGGlyph glyphs[2];
1468           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1470           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1471                                                   count))
1472             glyph = glyphs[0];
1473           if (glyph == 0)
1474             glyph = kCGFontIndexInvalid;
1476           value |= ((uintptr_t) glyph << nshifts);
1477           CFDictionarySetValue (cache->glyph.dictionary,
1478                                 (const void *) key, (const void *) value);
1479         }
1481       return glyph;
1482     }
1485 static CGGlyph
1486 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1487                            CGFontIndex cid)
1489   struct macfont_info *macfont_info = (struct macfont_info *) font;
1490   FontRef macfont = macfont_info->macfont;
1492   /* Cache it? */
1493   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1496 static CFDataRef
1497 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1499   struct macfont_info *macfont_info = (struct macfont_info *) font;
1500   FontRef macfont = macfont_info->macfont;
1501   struct macfont_cache *cache = macfont_info->cache;
1502   CFDataRef result = NULL;
1504   if (cache->uvs.table == NULL)
1505     {
1506       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1507       CharacterCollection uvs_collection =
1508         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1510       if (uvs_table == NULL
1511           && mac_font_get_glyph_for_cid (macfont,
1512                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1513                                          6480) != kCGFontIndexInvalid)
1514         {
1515           /* If the glyph for U+4E55 is accessible via its CID 6480,
1516              then we use the Adobe-Japan1 UVS table, which maps a
1517              variation sequence to a CID, as a fallback.  */
1518           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1520           if (mac_uvs_table_adobe_japan1 == NULL)
1521             mac_uvs_table_adobe_japan1 =
1522               CFDataCreateWithBytesNoCopy (NULL,
1523                                            mac_uvs_table_adobe_japan1_bytes,
1524                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1525                                            kCFAllocatorNull);
1526           if (mac_uvs_table_adobe_japan1)
1527             {
1528               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1529               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1530             }
1531         }
1532       if (uvs_table == NULL)
1533         cache->uvs.table = kCFNull;
1534       else
1535         cache->uvs.table = uvs_table;
1536       cache->uvs.collection = uvs_collection;
1537     }
1539   if (cache->uvs.table != kCFNull)
1540     {
1541       result = cache->uvs.table;
1542       *collection = cache->uvs.collection;
1543     }
1545   return result;
1548 static Lisp_Object macfont_get_cache (struct frame *);
1549 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1550 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1551 static Lisp_Object macfont_list_family (struct frame *);
1552 static void macfont_free_entity (Lisp_Object);
1553 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1554 static void macfont_close (struct font *);
1555 static int macfont_has_char (Lisp_Object, int);
1556 static unsigned macfont_encode_char (struct font *, int);
1557 static void macfont_text_extents (struct font *, unsigned int *, int,
1558                                   struct font_metrics *);
1559 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1560 static Lisp_Object macfont_shape (Lisp_Object);
1561 static int macfont_variation_glyphs (struct font *, int c,
1562                                      unsigned variations[256]);
1563 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1565 static struct font_driver macfont_driver =
1566   {
1567     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1568     0,                          /* case insensitive */
1569     macfont_get_cache,
1570     macfont_list,
1571     macfont_match,
1572     macfont_list_family,
1573     macfont_free_entity,
1574     macfont_open,
1575     macfont_close,
1576     NULL,                       /* prepare_face */
1577     NULL,                       /* done_face */
1578     macfont_has_char,
1579     macfont_encode_char,
1580     macfont_text_extents,
1581     macfont_draw,
1582     NULL,                       /* get_bitmap */
1583     NULL,                       /* free_bitmap */
1584     NULL,                       /* anchor_point */
1585     NULL,                       /* otf_capability */
1586     NULL,                       /* otf_drive */
1587     NULL,                       /* start_for_frame */
1588     NULL,                       /* end_for_frame */
1589     macfont_shape,
1590     NULL,                       /* check */
1591     macfont_variation_glyphs,
1592     macfont_filter_properties,
1593   };
1595 static Lisp_Object
1596 macfont_get_cache (struct frame * f)
1598   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1600   return (dpyinfo->name_list_element);
1603 static int
1604 macfont_get_charset (Lisp_Object registry)
1606   char *str = SSDATA (SYMBOL_NAME (registry));
1607   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1608   Lisp_Object regexp;
1609   int i, j;
1611   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1612     {
1613       if (str[i] == '.')
1614         re[j++] = '\\';
1615       else if (str[i] == '*')
1616         re[j++] = '.';
1617       re[j] = str[i];
1618       if (re[j] == '?')
1619         re[j] = '.';
1620     }
1621   re[j] = '\0';
1622   regexp = make_unibyte_string (re, j);
1623   for (i = 0; cf_charset_table[i].name; i++)
1624     if (fast_c_string_match_ignore_case
1625         (regexp, cf_charset_table[i].name,
1626          strlen (cf_charset_table[i].name)) >= 0)
1627       break;
1628   if (! cf_charset_table[i].name)
1629     return -1;
1630   if (! cf_charset_table[i].cf_charset)
1631     {
1632       int *uniquifier = cf_charset_table[i].uniquifier;
1633       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1634       CFIndex count = 0;
1635       CFStringRef string;
1636       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1638       if (! charset)
1639         return -1;
1640       for (j = 0; uniquifier[j]; j++)
1641         {
1642           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1643                                                         unichars + count);
1644           CFCharacterSetAddCharactersInRange (charset,
1645                                               CFRangeMake (uniquifier[j], 1));
1646         }
1648       string = CFStringCreateWithCharacters (NULL, unichars, count);
1649       if (! string)
1650         {
1651           CFRelease (charset);
1652           return -1;
1653         }
1654       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1655                                                                  charset);
1656       CFRelease (charset);
1657       /* CFCharacterSetCreateWithCharactersInString does not handle
1658          surrogate pairs properly as of Mac OS X 10.5.  */
1659       cf_charset_table[i].cf_charset_string = string;
1660     }
1661   return i;
1664 struct OpenTypeSpec
1666   Lisp_Object script;
1667   unsigned int script_tag, langsys_tag;
1668   int nfeatures[2];
1669   unsigned int *features[2];
1672 #define OTF_SYM_TAG(SYM, TAG)                               \
1673   do {                                                      \
1674     unsigned char *p = SDATA (SYMBOL_NAME (SYM));           \
1675     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1676   } while (0)
1678 #define OTF_TAG_STR(TAG, P)                     \
1679   do {                                          \
1680     (P)[0] = (char) (TAG >> 24);                \
1681     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1682     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1683     (P)[3] = (char) (TAG & 0xFF);               \
1684     (P)[4] = '\0';                              \
1685   } while (0)
1687 static struct OpenTypeSpec *
1688 macfont_get_open_type_spec (Lisp_Object otf_spec)
1690   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1691   Lisp_Object val;
1692   int i, j;
1693   bool negative;
1695   if (! spec)
1696     return NULL;
1697   spec->script = XCAR (otf_spec);
1698   if (! NILP (spec->script))
1699     {
1700       OTF_SYM_TAG (spec->script, spec->script_tag);
1701       val = assq_no_quit (spec->script, Votf_script_alist);
1702       if (CONSP (val) && SYMBOLP (XCDR (val)))
1703         spec->script = XCDR (val);
1704       else
1705         spec->script = Qnil;
1706     }
1707   else
1708     spec->script_tag = 0x44464C54;      /* "DFLT" */
1709   otf_spec = XCDR (otf_spec);
1710   spec->langsys_tag = 0;
1711   if (! NILP (otf_spec))
1712     {
1713       val = XCAR (otf_spec);
1714       if (! NILP (val))
1715         OTF_SYM_TAG (val, spec->langsys_tag);
1716       otf_spec = XCDR (otf_spec);
1717     }
1718   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1719   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1720     {
1721       Lisp_Object len;
1723       val = XCAR (otf_spec);
1724       if (NILP (val))
1725         continue;
1726       len = Flength (val);
1727       spec->features[i] =
1728         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1729          ? 0
1730          : malloc (XINT (len) * sizeof *spec->features[i]));
1731       if (! spec->features[i])
1732         {
1733           if (i > 0 && spec->features[0])
1734             free (spec->features[0]);
1735           free (spec);
1736           return NULL;
1737         }
1738       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1739         {
1740           if (NILP (XCAR (val)))
1741             negative = 1;
1742           else
1743             {
1744               unsigned int tag;
1746               OTF_SYM_TAG (XCAR (val), tag);
1747               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1748             }
1749         }
1750       spec->nfeatures[i] = j;
1751     }
1752   return spec;
1755 static CFMutableDictionaryRef
1756 macfont_create_attributes_with_spec (Lisp_Object spec)
1758   Lisp_Object tmp, extra;
1759   CFMutableArrayRef langarray = NULL;
1760   CFCharacterSetRef charset = NULL;
1761   CFStringRef charset_string = NULL;
1762   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1763   Lisp_Object script = Qnil;
1764   Lisp_Object registry;
1765   int cf_charset_idx, i;
1766   struct OpenTypeSpec *otspec = NULL;
1767   struct {
1768     enum font_property_index index;
1769     CFStringRef trait;
1770     CGPoint points[6];
1771   } numeric_traits[] =
1772       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1773         {{-0.4, 50},            /* light */
1774          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1775          {0, 100},              /* normal */
1776          {0.24, 140},           /* (semi-bold + normal) / 2 */
1777          {0.4, 200},            /* bold */
1778          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1779        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1780         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1781        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1782         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1784   registry = AREF (spec, FONT_REGISTRY_INDEX);
1785   if (NILP (registry)
1786       || EQ (registry, Qascii_0)
1787       || EQ (registry, Qiso10646_1)
1788       || EQ (registry, Qunicode_bmp))
1789     cf_charset_idx = -1;
1790   else
1791     {
1792       CFStringRef lang;
1794       cf_charset_idx = macfont_get_charset (registry);
1795       if (cf_charset_idx < 0)
1796         goto err;
1797       charset = cf_charset_table[cf_charset_idx].cf_charset;
1798       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1799       lang = cf_charset_table[cf_charset_idx].lang;
1800       if (lang)
1801         {
1802           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1803           if (! langarray)
1804             goto err;
1805           CFArrayAppendValue (langarray, lang);
1806         }
1807     }
1809   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1810        CONSP (extra); extra = XCDR (extra))
1811     {
1812       Lisp_Object key, val;
1814       tmp = XCAR (extra);
1815       key = XCAR (tmp), val = XCDR (tmp);
1816       if (EQ (key, QClang))
1817         {
1818           if (! langarray)
1819             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1820           if (! langarray)
1821             goto err;
1822           if (SYMBOLP (val))
1823             val = list1 (val);
1824           for (; CONSP (val); val = XCDR (val))
1825             if (SYMBOLP (XCAR (val)))
1826               {
1827                 CFStringRef lang =
1828                   cfstring_create_with_string_noencode (SYMBOL_NAME
1829                                                         (XCAR (val)));
1831                 if (lang == NULL)
1832                   goto err;
1833                 CFArrayAppendValue (langarray, lang);
1834                 CFRelease (lang);
1835               }
1836         }
1837       else if (EQ (key, QCotf))
1838         {
1839           otspec = macfont_get_open_type_spec (val);
1840           if (! otspec)
1841             goto err;
1842           script = otspec->script;
1843         }
1844       else if (EQ (key, QCscript))
1845         script = val;
1846     }
1848   if (! NILP (script) && ! charset)
1849     {
1850       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1852       if (CONSP (chars) && CONSP (CDR (chars)))
1853         {
1854           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1855           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1857           if (! string || !cs)
1858             {
1859               if (string)
1860                 CFRelease (string);
1861               else if (cs)
1862                 CFRelease (cs);
1863               goto err;
1864             }
1865           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1866             if (CHARACTERP (XCAR (chars)))
1867               {
1868                 UniChar unichars[2];
1869                 CFIndex count =
1870                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1871                                                        unichars);
1872                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1874                 CFStringAppendCharacters (string, unichars, count);
1875                 CFCharacterSetAddCharactersInRange (cs, range);
1876               }
1877           charset = cs;
1878           /* CFCharacterSetCreateWithCharactersInString does not
1879              handle surrogate pairs properly as of Mac OS X 10.5.  */
1880           charset_string = string;
1881         }
1882     }
1884   attributes = CFDictionaryCreateMutable (NULL, 0,
1885                                           &kCFTypeDictionaryKeyCallBacks,
1886                                           &kCFTypeDictionaryValueCallBacks);
1887   if (! attributes)
1888     goto err;
1890   tmp = AREF (spec, FONT_FAMILY_INDEX);
1891   if (SYMBOLP (tmp) && ! NILP (tmp))
1892     {
1893       CFStringRef family = macfont_create_family_with_symbol (tmp);
1895       if (! family)
1896         goto err;
1897       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1898                             family);
1899       CFRelease (family);
1900     }
1902   traits = CFDictionaryCreateMutable (NULL, 4,
1903                                       &kCFTypeDictionaryKeyCallBacks,
1904                                       &kCFTypeDictionaryValueCallBacks);
1905   if (! traits)
1906     goto err;
1908   for (i = 0; i < ARRAYELTS (numeric_traits); i++)
1909     {
1910       tmp = AREF (spec, numeric_traits[i].index);
1911       if (INTEGERP (tmp))
1912         {
1913           CGPoint *point = numeric_traits[i].points;
1914           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1915           CFNumberRef num;
1917           while (point->y < floatval)
1918             point++;
1919           if (point == numeric_traits[i].points)
1920             point++;
1921           else if (point->y == CGFLOAT_MAX)
1922             point--;
1923           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1924                                        * ((point->x - (point - 1)->x)
1925                                           / (point->y - (point - 1)->y)));
1926           if (floatval > 1.0)
1927             floatval = 1.0;
1928           else if (floatval < -1.0)
1929             floatval = -1.0;
1930           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1931           if (! num)
1932             goto err;
1933           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1934           CFRelease (num);
1935         }
1936     }
1937   if (CFDictionaryGetCount (traits))
1938     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1940   if (charset)
1941     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1942                           charset);
1943   if (charset_string)
1944     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1945                           charset_string);
1946   if (langarray)
1947     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1949   goto finish;
1951  err:
1952   if (attributes)
1953     {
1954       CFRelease (attributes);
1955       attributes = NULL;
1956     }
1958  finish:
1959   if (langarray) CFRelease (langarray);
1960   if (charset && cf_charset_idx < 0) CFRelease (charset);
1961   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1962   if (traits) CFRelease (traits);
1963   if (otspec)
1964     {
1965       if (otspec->nfeatures[0] > 0)
1966         free (otspec->features[0]);
1967       if (otspec->nfeatures[1] > 0)
1968         free (otspec->features[1]);
1969       free (otspec);
1970     }
1972   return attributes;
1975 static Boolean
1976 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1977                                           CFCharacterSetRef charset,
1978                                           Lisp_Object chars,
1979                                           CFArrayRef languages)
1981   Boolean result = true;
1983   if (charset || VECTORP (chars))
1984     {
1985       CFCharacterSetRef desc_charset =
1986         mac_font_descriptor_copy_attribute (desc,
1987                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1989       if (desc_charset == NULL)
1990         result = false;
1991       else
1992         {
1993           if (charset)
1994             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
1995           else                  /* VECTORP (chars) */
1996             {
1997               ptrdiff_t j;
1999               for (j = 0; j < ASIZE (chars); j++)
2000                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2001                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2002                                                             XFASTINT (AREF (chars, j))))
2003                   break;
2004               if (j == ASIZE (chars))
2005                 result = false;
2006             }
2007           CFRelease (desc_charset);
2008         }
2009     }
2010   if (result && languages)
2011     result = mac_font_descriptor_supports_languages (desc, languages);
2013   return result;
2016 static int
2017 macfont_traits_distance (FontSymbolicTraits sym_traits1,
2018                          FontSymbolicTraits sym_traits2)
2020   FontSymbolicTraits diff = (sym_traits1 ^ sym_traits2);
2021   int distance = 0;
2023   /* We prefer synthetic bold of italic to synthetic italic of bold
2024      when both bold and italic are available but bold-italic is not
2025      available.  */
2026   if (diff & MAC_FONT_TRAIT_BOLD)
2027     distance |= (1 << 0);
2028   if (diff & MAC_FONT_TRAIT_ITALIC)
2029     distance |= (1 << 1);
2030   if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2031     distance |= (1 << 2);
2033   return distance;
2036 static Boolean
2037 macfont_closest_traits_index_p (CFArrayRef traits_array,
2038                                 FontSymbolicTraits target,
2039                                 CFIndex index)
2041   CFIndex i, count = CFArrayGetCount (traits_array);
2042   FontSymbolicTraits traits;
2043   int my_distance;
2045   traits = ((FontSymbolicTraits) (uintptr_t)
2046             CFArrayGetValueAtIndex (traits_array, index));
2047   my_distance = macfont_traits_distance (target, traits);
2049   for (i = 0; i < count; i++)
2050     if (i != index)
2051       {
2052         traits = ((FontSymbolicTraits) (uintptr_t)
2053                   CFArrayGetValueAtIndex (traits_array, i));
2054         if (macfont_traits_distance (target, traits) < my_distance)
2055           return false;
2056       }
2058   return true;
2061 static Lisp_Object
2062 macfont_list (struct frame *f, Lisp_Object spec)
2064   Lisp_Object val = Qnil, family, extra;
2065   int i, n;
2066   CFStringRef family_name = NULL;
2067   CFMutableDictionaryRef attributes = NULL, traits;
2068   Lisp_Object chars = Qnil;
2069   int spacing = -1;
2070   FontSymbolicTraits synth_sym_traits = 0;
2071   CFArrayRef families;
2072   CFIndex families_count;
2073   CFCharacterSetRef charset = NULL;
2074   CFArrayRef languages = NULL;
2076   block_input ();
2078   family = AREF (spec, FONT_FAMILY_INDEX);
2079   if (! NILP (family))
2080     {
2081       family_name = macfont_create_family_with_symbol (family);
2082       if (family_name == NULL)
2083         goto finish;
2084     }
2086   attributes = macfont_create_attributes_with_spec (spec);
2087   if (! attributes)
2088     goto finish;
2090   languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2092   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2093     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2095   traits = ((CFMutableDictionaryRef)
2096             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2098   n = FONT_SLANT_NUMERIC (spec);
2099   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2100     {
2101       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2102       if (traits)
2103         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2104     }
2106   n = FONT_WEIGHT_NUMERIC (spec);
2107   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2108     {
2109       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2110       if (traits)
2111         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2112     }
2114   if (languages
2115       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2116     {
2117       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2119       if (CFStringHasPrefix (language, CFSTR ("ja"))
2120           || CFStringHasPrefix (language, CFSTR ("ko"))
2121           || CFStringHasPrefix (language, CFSTR ("zh")))
2122         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2123     }
2125   /* Create array of families.  */
2126   if (family_name)
2127     families = CFArrayCreate (NULL, (const void **) &family_name,
2128                               1, &kCFTypeArrayCallBacks);
2129   else
2130     {
2131       CFStringRef pref_family;
2132       CFIndex families_count, pref_family_index = -1;
2134       families = mac_font_create_available_families ();
2135       if (families == NULL)
2136         goto err;
2138       families_count = CFArrayGetCount (families);
2140       /* Move preferred family to the front if exists.  */
2141       pref_family =
2142         mac_font_create_preferred_family_for_attributes (attributes);
2143       if (pref_family)
2144         {
2145           pref_family_index =
2146             CFArrayGetFirstIndexOfValue (families,
2147                                          CFRangeMake (0, families_count),
2148                                          pref_family);
2149           CFRelease (pref_family);
2150         }
2151       if (pref_family_index > 0)
2152         {
2153           CFMutableArrayRef mutable_families =
2154             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2156           if (mutable_families)
2157             {
2158               CFArrayAppendValue (mutable_families,
2159                                   CFArrayGetValueAtIndex (families,
2160                                                           pref_family_index));
2161               CFArrayAppendArray (mutable_families, families,
2162                                   CFRangeMake (0, pref_family_index));
2163               if (pref_family_index + 1 < families_count)
2164                 CFArrayAppendArray (mutable_families, families,
2165                                     CFRangeMake (pref_family_index + 1,
2166                                                  families_count
2167                                                  - (pref_family_index + 1)));
2168               CFRelease (families);
2169               families = mutable_families;
2170             }
2171         }
2172     }
2174   charset = CFDictionaryGetValue (attributes,
2175                                   MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2176   if (charset)
2177     {
2178       CFRetain (charset);
2179       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2180     }
2181   else
2182     {
2183       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2184       if (! NILP (val))
2185         {
2186           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2187           if (CONSP (val) && VECTORP (XCDR (val)))
2188             chars = XCDR (val);
2189         }
2190       val = Qnil;
2191     }
2193   if (languages)
2194     {
2195       CFRetain (languages);
2196       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2197     }
2199   val = Qnil;
2200   extra = AREF (spec, FONT_EXTRA_INDEX);
2201   families_count = CFArrayGetCount (families);
2202   for (i = 0; i < families_count; i++)
2203     {
2204       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2205       FontDescriptorRef pat_desc;
2206       CFArrayRef descs;
2207       CFIndex descs_count;
2208       CFMutableArrayRef filtered_descs, traits_array;
2209       Lisp_Object entity;
2210       int j;
2212       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2213                             family_name);
2214       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2215       if (! pat_desc)
2216         goto err;
2218       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2219          10.7 returns NULL if pat_desc represents the LastResort font.
2220          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2221          trailing "s") for such a font.  */
2222       if (!CFEqual (family_name, CFSTR ("LastResort")))
2223         descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2224                                                                       NULL);
2225       else
2226         {
2227           FontDescriptorRef lr_desc =
2228             mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2229                                                                  NULL);
2230           if (lr_desc)
2231             {
2232               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2233                                      &kCFTypeArrayCallBacks);
2234               CFRelease (lr_desc);
2235             }
2236           else
2237             descs = NULL;
2238         }
2239       CFRelease (pat_desc);
2240       if (! descs)
2241         goto err;
2243       descs_count = CFArrayGetCount (descs);
2244       if (descs_count == 0
2245           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2246                                                         charset, chars,
2247                                                         languages))
2248         {
2249           CFRelease (descs);
2250           continue;
2251         }
2253       filtered_descs =
2254         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2255       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2256       for (j = 0; j < descs_count; j++)
2257         {
2258           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2259           CFDictionaryRef dict;
2260           CFNumberRef num;
2261           FontSymbolicTraits sym_traits;
2263           dict = mac_font_descriptor_copy_attribute (desc,
2264                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2265           if (dict == NULL)
2266             continue;
2268           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2269           CFRelease (dict);
2270           if (num == NULL
2271               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2272             continue;
2274           if (spacing >= 0
2275               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2276               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2277                   != (spacing >= FONT_SPACING_MONO)))
2278             continue;
2280           /* Don't use a color bitmap font unless its family is
2281              explicitly specified.  */
2282           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2283             continue;
2285           if (j > 0
2286               && !macfont_supports_charset_and_languages_p (desc, charset,
2287                                                             chars, languages))
2288             continue;
2290           CFArrayAppendValue (filtered_descs, desc);
2291           CFArrayAppendValue (traits_array,
2292                               (const void *) (uintptr_t) sym_traits);
2293         }
2295       CFRelease (descs);
2296       descs = filtered_descs;
2297       descs_count = CFArrayGetCount (descs);
2299       for (j = 0; j < descs_count; j++)
2300         {
2301           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2302           FontSymbolicTraits sym_traits =
2303             ((FontSymbolicTraits) (uintptr_t)
2304              CFArrayGetValueAtIndex (traits_array, j));
2305           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2307           mask_min = ((synth_sym_traits ^ sym_traits)
2308                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2309           if (FONT_SLANT_NUMERIC (spec) < 0)
2310             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2311           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2312             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2314           mask_max = (synth_sym_traits & ~sym_traits);
2315           /* Synthetic bold does not work for bitmap-only fonts on Mac
2316              OS X 10.6.  */
2317           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2318             {
2319               CFNumberRef format =
2320                 mac_font_descriptor_copy_attribute (desc,
2321                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2323               if (format)
2324                 {
2325                   uint32_t format_val;
2327                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2328                                         &format_val)
2329                       && format_val == MAC_FONT_FORMAT_BITMAP)
2330                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2331                 }
2332             }
2333           if (spacing >= 0)
2334             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2336           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2337                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2338                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2339             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2340                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2341                  bmask += MAC_FONT_TRAIT_BOLD)
2342               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2343                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2344                    imask += MAC_FONT_TRAIT_ITALIC)
2345                 {
2346                   FontSymbolicTraits synth = (imask | bmask | mmask);
2348                   if (synth == 0
2349                       || macfont_closest_traits_index_p (traits_array,
2350                                                          (sym_traits | synth),
2351                                                          j))
2352                     {
2353                       entity = macfont_descriptor_entity (desc, extra, synth);
2354                       if (! NILP (entity))
2355                         val = Fcons (entity, val);
2356                     }
2357                 }
2358         }
2360       CFRelease (traits_array);
2361       CFRelease (descs);
2362     }
2364   CFRelease (families);
2365   val = Fnreverse (val);
2366   goto finish;
2367  err:
2368   val = Qnil;
2370  finish:
2371   FONT_ADD_LOG ("macfont-list", spec, val);
2372   if (charset) CFRelease (charset);
2373   if (languages) CFRelease (languages);
2374   if (attributes) CFRelease (attributes);
2375   if (family_name) CFRelease (family_name);
2377   unblock_input ();
2379   return val;
2382 static Lisp_Object
2383 macfont_match (struct frame * frame, Lisp_Object spec)
2385   Lisp_Object entity = Qnil;
2386   CFMutableDictionaryRef attributes;
2387   FontDescriptorRef pat_desc = NULL, desc = NULL;
2389   block_input ();
2391   attributes = macfont_create_attributes_with_spec (spec);
2392   if (attributes)
2393     {
2394       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2395       CFRelease (attributes);
2396     }
2397   if (pat_desc)
2398     {
2399       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2400                                                                   NULL);
2401       CFRelease (pat_desc);
2402     }
2403   if (desc)
2404     {
2405       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2406                                           0);
2407       CFRelease (desc);
2408     }
2409   unblock_input ();
2411   FONT_ADD_LOG ("macfont-match", spec, entity);
2412   return entity;
2415 static Lisp_Object
2416 macfont_list_family (struct frame *frame)
2418   Lisp_Object list = Qnil;
2419   CFArrayRef families;
2421   block_input ();
2423   families = mac_font_create_available_families ();
2424   if (families)
2425     {
2426       CFIndex i, count = CFArrayGetCount (families);
2428       for (i = 0; i < count; i++)
2429         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2430       CFRelease (families);
2431     }
2433   unblock_input ();
2435   return list;
2438 static void
2439 macfont_free_entity (Lisp_Object entity)
2441   Lisp_Object val = assq_no_quit (QCfont_entity,
2442                                   AREF (entity, FONT_EXTRA_INDEX));
2443   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2445   block_input ();
2446   CFRelease (name);
2447   unblock_input ();
2450 static Lisp_Object
2451 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2453   Lisp_Object val, font_object;
2454   CFStringRef font_name;
2455   struct macfont_info *macfont_info = NULL;
2456   struct font *font;
2457   int size;
2458   FontRef macfont;
2459   FontSymbolicTraits sym_traits;
2460   char name[256];
2461   int len, i, total_width;
2462   CGGlyph glyph;
2463   CGFloat ascent, descent, leading;
2465   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2466   if (! CONSP (val)
2467       || XTYPE (XCDR (val)) != Lisp_Misc
2468       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2469     return Qnil;
2470   font_name = XSAVE_POINTER (XCDR (val), 0);
2471   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2473   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2474   if (size == 0)
2475     size = pixel_size;
2477   block_input ();
2478   macfont = mac_font_create_with_name (font_name, size);
2479   if (macfont)
2480     {
2481       int fontsize = (int) [((NSFont *) macfont) pointSize];
2482       if (fontsize != size) size = fontsize;
2483     }
2484   unblock_input ();
2485   if (! macfont)
2486     return Qnil;
2488   font_object = font_build_object (VECSIZE (struct macfont_info),
2489                                    Qmac_ct, entity, size);
2490   font = XFONT_OBJECT (font_object);
2491   font->pixel_size = size;
2492   font->driver = &macfont_driver;
2493   font->encoding_charset = font->repertory_charset = -1;
2495   block_input ();
2497   macfont_info = (struct macfont_info *) font;
2498   macfont_info->macfont = macfont;
2499   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2501   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2502   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2503     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2504                                                                   size);
2505   else
2506     macfont_info->screen_font = NULL;
2507   macfont_info->cache = macfont_lookup_cache (font_name);
2508   macfont_retain_cache (macfont_info->cache);
2509   macfont_info->metrics = NULL;
2510   macfont_info->metrics_nrows = 0;
2511   macfont_info->synthetic_italic_p = 0;
2512   macfont_info->synthetic_bold_p = 0;
2513   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2514   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2515   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2516       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2517     macfont_info->synthetic_italic_p = 1;
2518   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2519       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2520     macfont_info->synthetic_bold_p = 1;
2521   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2522     macfont_info->spacing = MACFONT_SPACING_MONO;
2523   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2524            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2525                == FONT_SPACING_SYNTHETIC_MONO))
2526     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2527   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2528     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2529   else
2530     {
2531       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2532       if (CONSP (val))
2533         macfont_info->antialias =
2534           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2535     }
2536   macfont_info->color_bitmap_p = 0;
2537   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2538     macfont_info->color_bitmap_p = 1;
2540   glyph = macfont_get_glyph_for_character (font, ' ');
2541   if (glyph != kCGFontIndexInvalid)
2542     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2543   else
2544     /* dirty workaround */
2545     font->space_width = pixel_size;
2547   total_width = font->space_width;
2548   for (i = 1; i < 95; i++)
2549     {
2550       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2551       if (glyph == kCGFontIndexInvalid)
2552         break;
2553       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2554     }
2555   if (i == 95)
2556     font->average_width = total_width / 95;
2557   else
2558     font->average_width = font->space_width; /* XXX */
2560   if (!(macfont_info->screen_font
2561         && mac_screen_font_get_metrics (macfont_info->screen_font,
2562                                         &ascent, &descent, &leading)))
2563     {
2564       CFStringRef family_name;
2566       ascent = mac_font_get_ascent (macfont);
2567       descent = mac_font_get_descent (macfont);
2568       leading = mac_font_get_leading (macfont);
2569       /* AppKit and WebKit do some adjustment to the heights of
2570          Courier, Helvetica, and Times.  */
2571       family_name = mac_font_copy_family_name (macfont);
2572       if (family_name)
2573         {
2574           if (CFEqual (family_name, CFSTR ("Courier"))
2575               || CFEqual (family_name, CFSTR ("Helvetica"))
2576               || CFEqual (family_name, CFSTR ("Times")))
2577             ascent += (ascent + descent) * .15f;
2578           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2579             {
2580               leading *= .25f;
2581               ascent += leading;
2582             }
2583           CFRelease (family_name);
2584         }
2585     }
2586   font->ascent = ascent + 0.5f;
2587   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2588   if (CONSP (val) && !NILP (XCDR (val)))
2589     font->descent = descent + 0.5f;
2590   else
2591     font->descent = descent + leading + 0.5f;
2592   font->height = font->ascent + font->descent;
2594   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2595   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2597   unblock_input ();
2599   /* Unfortunately Xft doesn't provide a way to get minimum char
2600      width.  So, we use space_width instead.  */
2601   font->min_width = font->max_width = font->space_width; /* XXX */
2603   font->baseline_offset = 0;
2604   font->relative_compose = 0;
2605   font->default_ascent = 0;
2606   font->vertical_centering = 0;
2608   return font_object;
2611 static void
2612 macfont_close (struct font *font)
2614   struct macfont_info *macfont_info = (struct macfont_info *) font;
2616   if (macfont_info->cache)
2617     {
2618       int i;
2620       block_input ();
2621       CFRelease (macfont_info->macfont);
2622       CGFontRelease (macfont_info->cgfont);
2623       if (macfont_info->screen_font)
2624         CFRelease (macfont_info->screen_font);
2625       macfont_release_cache (macfont_info->cache);
2626       for (i = 0; i < macfont_info->metrics_nrows; i++)
2627         if (macfont_info->metrics[i])
2628           xfree (macfont_info->metrics[i]);
2629       if (macfont_info->metrics)
2630         xfree (macfont_info->metrics);
2631       macfont_info->cache = NULL;
2632       unblock_input ();
2633     }
2636 static int
2637 macfont_has_char (Lisp_Object font, int c)
2639   int result;
2640   CFCharacterSetRef charset;
2642   block_input ();
2643   if (FONT_ENTITY_P (font))
2644     {
2645       Lisp_Object val;
2646       CFStringRef name;
2648       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2649       val = XCDR (val);
2650       name = XSAVE_POINTER (val, 0);
2651       charset = macfont_get_cf_charset_for_name (name);
2652     }
2653   else
2654     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2656   result = CFCharacterSetIsLongCharacterMember (charset, c);
2657   unblock_input ();
2659   return result;
2662 static unsigned
2663 macfont_encode_char (struct font *font, int c)
2665   struct macfont_info *macfont_info = (struct macfont_info *) font;
2666   CGGlyph glyph;
2668   block_input ();
2669   glyph = macfont_get_glyph_for_character (font, c);
2670   unblock_input ();
2672   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2675 static void
2676 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2677                       struct font_metrics *metrics)
2679   int width, i;
2681   block_input ();
2682   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2683   for (i = 1; i < nglyphs; i++)
2684     {
2685       struct font_metrics m;
2686       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2687                                      NULL, 0);
2689       if (metrics)
2690         {
2691           if (width + m.lbearing < metrics->lbearing)
2692             metrics->lbearing = width + m.lbearing;
2693           if (width + m.rbearing > metrics->rbearing)
2694             metrics->rbearing = width + m.rbearing;
2695           if (m.ascent > metrics->ascent)
2696             metrics->ascent = m.ascent;
2697           if (m.descent > metrics->descent)
2698             metrics->descent = m.descent;
2699         }
2700       width += w;
2701     }
2702   unblock_input ();
2704   if (metrics)
2705     metrics->width = width;
2708 static int
2709 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2710               bool with_background)
2712   struct frame * f = s->f;
2713   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2714   CGRect background_rect;
2715   CGPoint text_position;
2716   CGGlyph *glyphs;
2717   CGPoint *positions;
2718   CGFloat font_size = mac_font_get_size (macfont_info->macfont);
2719   bool no_antialias_p =
2720     (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2721      || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2722          && font_size <= macfont_antialias_threshold));
2723   int len = to - from;
2724   struct face *face = s->face;
2725   CGContextRef context;
2727   block_input ();
2729   if (with_background)
2730     background_rect = CGRectMake (x, y - FONT_BASE (s->font),
2731                                   s->width, FONT_HEIGHT (s->font));
2732   else
2733     background_rect = CGRectNull;
2734   
2735   text_position = CGPointMake (x, -y);
2736   glyphs = xmalloc (sizeof (CGGlyph) * len);
2737   {
2738     CGFloat advance_delta = 0;
2739     int i;
2740     CGFloat total_width = 0;
2742     positions = xmalloc (sizeof (CGPoint) * len);
2743     for (i = 0; i < len; i++)
2744       {
2745         int width;
2747         glyphs[i] = s->char2b[from + i];
2748         width = (s->padding_p ? 1
2749                  : macfont_glyph_extents (s->font, glyphs[i],
2750                                           NULL, &advance_delta,
2751                                           no_antialias_p));
2752         positions[i].x = total_width + advance_delta;
2753         positions[i].y = 0;
2754         total_width += width;
2755       }
2756   }
2758   context = [[NSGraphicsContext currentContext] graphicsPort];
2759   CGContextSaveGState (context);
2761   if (!CGRectIsNull (background_rect))
2762     {
2763       if (s->hl == DRAW_MOUSE_FACE) 
2764         {
2765           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2766           if (!face)
2767             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2768         }
2769       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2770       CGContextFillRects (context, &background_rect, 1);
2771     }
2772   
2773   if (macfont_info->cgfont)
2774     {
2775       CGAffineTransform atfm;
2777       CGContextScaleCTM (context, 1, -1);
2778       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2779       if (macfont_info->synthetic_italic_p)
2780         atfm = synthetic_italic_atfm;
2781       else
2782         atfm = CGAffineTransformIdentity;
2783       if (macfont_info->synthetic_bold_p)
2784         {
2785           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2786           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2787           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2788         }
2789       if (no_antialias_p)
2790         CGContextSetShouldAntialias (context, false);
2792       CGContextSetTextMatrix (context, atfm);
2793       CGContextSetTextPosition (context, text_position.x, text_position.y);
2795 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2796       if (macfont_info->color_bitmap_p
2797 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2798           && CTFontDrawGlyphs != NULL
2799 #endif
2800           )
2801         {
2802           if (len > 0)
2803             {
2804               CTFontDrawGlyphs (macfont_info->macfont, glyphs, positions, len,
2805                                 context);
2806             }
2807         }
2808       else
2809 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2810         {
2811           CGContextSetFont (context, macfont_info->cgfont);
2812           CGContextSetFontSize (context, font_size);
2813           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2814         }
2815     }
2818   xfree (glyphs);
2819   xfree (positions);
2820   CGContextRestoreGState (context);
2822   unblock_input ();
2824   return len;
2827 static Lisp_Object
2828 macfont_shape (Lisp_Object lgstring)
2830   struct font *font;
2831   struct macfont_info *macfont_info;
2832   FontRef macfont;
2833   ptrdiff_t glyph_len, len, i, j;
2834   CFIndex nonbmp_len;
2835   UniChar *unichars;
2836   CFIndex *nonbmp_indices;
2837   CFStringRef string;
2838   CFIndex used = 0;
2839   struct mac_glyph_layout *glyph_layouts;
2841   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2842   macfont_info = (struct macfont_info *) font;
2843   macfont = macfont_info->macfont;
2845   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2846   nonbmp_len = 0;
2847   for (i = 0; i < glyph_len; i++)
2848     {
2849       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2851       if (NILP (lglyph))
2852         break;
2853       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2854         nonbmp_len++;
2855     }
2857   len = i;
2859   if (INT_MAX / 2 < len)
2860     memory_full (SIZE_MAX);
2862   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2863   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2864   for (i = j = 0; i < len; i++)
2865     {
2866       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2868       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2869         {
2870           nonbmp_indices[j] = i + j;
2871           j++;
2872         }
2873     }
2874   nonbmp_indices[j] = len + j;  /* sentinel */
2876   block_input ();
2878   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2879                                                kCFAllocatorNull);
2880   if (string)
2881     {
2882       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2883       if (macfont_info->screen_font)
2884         used = mac_screen_font_shape (macfont_info->screen_font, string,
2885                                       glyph_layouts, glyph_len);
2886       else
2887         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2888       CFRelease (string);
2889     }
2891   unblock_input ();
2893   if (used == 0)
2894     return Qnil;
2896   block_input ();
2898   for (i = 0; i < used; i++)
2899     {
2900       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2901       struct mac_glyph_layout *gl = glyph_layouts + i;
2902       EMACS_INT from, to;
2903       struct font_metrics metrics;
2904       int xoff, yoff, wadjust;
2906       if (NILP (lglyph))
2907         {
2908           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2909           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2910         }
2912       from = gl->comp_range.location;
2913       /* Convert UTF-16 index to UTF-32.  */
2914       j = 0;
2915       while (nonbmp_indices[j] < from)
2916         j++;
2917       from -= j;
2918       LGLYPH_SET_FROM (lglyph, from);
2920       to = gl->comp_range.location + gl->comp_range.length;
2921       /* Convert UTF-16 index to UTF-32.  */
2922       while (nonbmp_indices[j] < to)
2923         j++;
2924       to -= j;
2925       LGLYPH_SET_TO (lglyph, to - 1);
2927       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2928          the composition is trivial.  */
2929       {
2930         UTF32Char c;
2932         if (unichars[gl->string_index] >= 0xD800
2933             && unichars[gl->string_index] < 0xDC00)
2934           c = (((unichars[gl->string_index] - 0xD800) << 10)
2935                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2936         else
2937           c = unichars[gl->string_index];
2938         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2939           c = 0;
2940         LGLYPH_SET_CHAR (lglyph, c);
2941       }
2943       {
2944         unsigned long cc = gl->glyph_id;
2945         LGLYPH_SET_CODE (lglyph, cc);
2946       }
2948       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2949       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2950       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2951       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2952       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2953       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2955       xoff = lround (gl->advance_delta);
2956       yoff = lround (- gl->baseline_delta);
2957       wadjust = lround (gl->advance);
2958       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2959         {
2960           Lisp_Object vec;
2962           vec = Fmake_vector (make_number (3), Qnil);
2963           ASET (vec, 0, make_number (xoff));
2964           ASET (vec, 1, make_number (yoff));
2965           ASET (vec, 2, make_number (wadjust));
2966           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2967         }
2968     }
2970   unblock_input ();
2972   return make_number (used);
2975 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2976 typedef UInt8 UINT24[3];
2978 #pragma pack(push, 1)
2979 struct variation_selector_record
2981   UINT24 var_selector;
2982   UInt32 default_uvs_offset, non_default_uvs_offset;
2984 struct uvs_table
2986   UInt16 format;
2987   UInt32 length, num_var_selector_records;
2988   struct variation_selector_record variation_selector_records[1];
2990 #define SIZEOF_UVS_TABLE_HEADER                                         \
2991   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2993 struct unicode_value_range
2995   UINT24 start_unicode_value;
2996   UInt8 additional_count;
2998 struct default_uvs_table {
2999   UInt32 num_unicode_value_ranges;
3000   struct unicode_value_range unicode_value_ranges[1];
3002 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER                                 \
3003   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3005 struct uvs_mapping
3007   UINT24 unicode_value;
3008   UInt16 glyph_id;
3010 struct non_default_uvs_table
3012   UInt32 num_uvs_mappings;
3013   struct uvs_mapping uvs_mappings[1];
3015 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER                             \
3016   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3017 #pragma pack(pop)
3019 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3020 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3021    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3022    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3023 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3024 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3025 /* Succeeding one byte should also be accessible.  */
3026 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3027 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3029 /* Return UVS subtable for the specified FONT.  If the subtable is not
3030    found or ill-formatted, then return NULL.  */
3032 static CFDataRef
3033 mac_font_copy_uvs_table (FontRef font)
3035   CFDataRef cmap_table, uvs_table = NULL;
3037   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3038   if (cmap_table)
3039     {
3040       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3041       struct uvs_table *uvs;
3042       struct variation_selector_record *records;
3043       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3045 #if __LP64__
3046       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3047         goto finish;
3048 #endif
3050       cmap_len = CFDataGetLength (cmap_table);
3051       if (sizeof_sfntCMapHeader > cmap_len)
3052         goto finish;
3054       ntables = BUINT16_VALUE (cmap->numTables);
3055       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3056                      / sizeof_sfntCMapEncoding))
3057         goto finish;
3059       for (i = 0; i < ntables; i++)
3060         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3061              == kFontUnicodePlatform)
3062             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3063                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3064           {
3065             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3066             break;
3067           }
3068       if (i == ntables
3069           || uvs_offset > cmap_len
3070           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3071         goto finish;
3073       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3074       uvs_len = BUINT32_VALUE (uvs->length);
3075       if (uvs_len > cmap_len - uvs_offset
3076           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3077         goto finish;
3079       if (BUINT16_VALUE (uvs->format) != 14)
3080         goto finish;
3082       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3083       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3084                       / sizeof (struct variation_selector_record)))
3085         goto finish;
3087       records = uvs->variation_selector_records;
3088       for (i = 0; i < nrecords; i++)
3089         {
3090           UInt32 default_uvs_offset, non_default_uvs_offset;
3092           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3093           if (default_uvs_offset)
3094             {
3095               struct default_uvs_table *default_uvs;
3096               UInt32 nranges;
3098               if (default_uvs_offset > uvs_len
3099                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3100                       > uvs_len - default_uvs_offset))
3101                 goto finish;
3103               default_uvs = ((struct default_uvs_table *)
3104                              ((UInt8 *) uvs + default_uvs_offset));
3105               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3106               if (nranges > ((uvs_len - default_uvs_offset
3107                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3108                              / sizeof (struct unicode_value_range)))
3109                 goto finish;
3110               /* Now 2 * nranges can't overflow, so we can safely use
3111                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3112                  mac_font_get_glyphs_for_variants.  */
3113             }
3115           non_default_uvs_offset =
3116             BUINT32_VALUE (records[i].non_default_uvs_offset);
3117           if (non_default_uvs_offset)
3118             {
3119               struct non_default_uvs_table *non_default_uvs;
3120               UInt32 nmappings;
3122               if (non_default_uvs_offset > uvs_len
3123                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3124                       > uvs_len - non_default_uvs_offset))
3125                 goto finish;
3127               non_default_uvs = ((struct non_default_uvs_table *)
3128                                  ((UInt8 *) uvs + non_default_uvs_offset));
3129               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3130               if (nmappings > ((uvs_len - non_default_uvs_offset
3131                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3132                                / sizeof (struct uvs_mapping)))
3133                 goto finish;
3134               /* Now 2 * nmappings can't overflow, so we can safely
3135                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3136                  in mac_font_get_glyphs_for_variants.  */
3137             }
3138         }
3140       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3142     finish:
3143       CFRelease (cmap_table);
3144     }
3146   return uvs_table;
3149 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3150    sequence consisting of the given base character C and each
3151    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3152    result (explained below) into the corresponding GLYPHS[i].  If the
3153    entry is found in the Default UVS Table, then the result is 0.  If
3154    the entry is found in the Non-Default UVS Table, then the result is
3155    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3156    elements in SELECTORS must be sorted in strictly increasing
3157    order.  */
3159 static void
3160 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3161                                   const UTF32Char selectors[], CGGlyph glyphs[],
3162                                   CFIndex count)
3164   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3165   struct variation_selector_record *records = uvs->variation_selector_records;
3166   CFIndex i;
3167   UInt32 ir, nrecords;
3168 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3169   dispatch_queue_t queue =
3170     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3171   dispatch_group_t group = dispatch_group_create ();
3172 #endif
3174   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3175   i = 0;
3176   ir = 0;
3177   while (i < count && ir < nrecords)
3178     {
3179       UInt32 default_uvs_offset, non_default_uvs_offset;
3181       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3182         {
3183           glyphs[i++] = kCGFontIndexInvalid;
3184           continue;
3185         }
3186       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3187         {
3188           ir++;
3189           continue;
3190         }
3192       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3193       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3194       non_default_uvs_offset =
3195         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3196 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3197       dispatch_group_async (group, queue, ^{
3198 #endif
3199           glyphs[i] = kCGFontIndexInvalid;
3201           if (default_uvs_offset)
3202             {
3203               struct default_uvs_table *default_uvs =
3204                 (struct default_uvs_table *) ((UInt8 *) uvs
3205                                               + default_uvs_offset);
3206               struct unicode_value_range *ranges =
3207                 default_uvs->unicode_value_ranges;
3208               UInt32 lo, hi;
3210               lo = 0;
3211               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3212               while (lo < hi)
3213                 {
3214                   UInt32 mid = (lo + hi) / 2;
3216                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3217                     hi = mid;
3218                   else
3219                     lo = mid + 1;
3220                 }
3221               if (hi > 0
3222                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3223                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3224                 glyphs[i] = 0;
3225             }
3227           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3228             {
3229               struct non_default_uvs_table *non_default_uvs =
3230                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3231                                                   + non_default_uvs_offset);
3232               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3233               UInt32 lo, hi;
3235               lo = 0;
3236               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3237               while (lo < hi)
3238                 {
3239                   UInt32 mid = (lo + hi) / 2;
3241                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3242                     hi = mid;
3243                   else
3244                     lo = mid + 1;
3245                 }
3246               if (hi > 0 &&
3247                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3248                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3249             }
3250 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3251         });
3252 #endif
3253       i++;
3254       ir++;
3255     }
3256   while (i < count)
3257     glyphs[i++] = kCGFontIndexInvalid;
3258 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3259   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3260   dispatch_release (group);
3261 #endif
3264 static int
3265 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3267   CFDataRef uvs_table;
3268   CharacterCollection uvs_collection;
3269   int i, n = 0;
3271   block_input ();
3272   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3274   if (uvs_table)
3275     {
3276       UTF32Char selectors[256];
3277       CGGlyph glyphs[256];
3279       for (i = 0; i < 16; i++)
3280         selectors[i] = 0xFE00 + i;
3281       for (; i < 256; i++)
3282         selectors[i] = 0xE0100 + (i - 16);
3283       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3284       for (i = 0; i < 256; i++)
3285         {
3286           CGGlyph glyph = glyphs[i];
3288           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3289               && glyph != kCGFontIndexInvalid)
3290             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3291           if (glyph == kCGFontIndexInvalid)
3292             variations[i] = 0;
3293           else
3294             {
3295               variations[i] = (glyph ? glyph
3296                                : macfont_get_glyph_for_character (font, c));
3297               n++;
3298             }
3299         }
3300     }
3301   unblock_input ();
3303   return n;
3306 static const char *const macfont_booleans[] = {
3307   ":antialias",
3308   ":minspace",
3309   NULL,
3312 static const char *const macfont_non_booleans[] = {
3313   ":lang",
3314   ":script",
3315   ":destination",
3316   NULL,
3319 static void
3320 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3322   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3325 static Boolean
3326 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3327                                           CFArrayRef languages)
3329   Boolean result = true;
3330   CFArrayRef desc_languages =
3331     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3333   if (desc_languages == NULL)
3334     result = false;
3335   else
3336     {
3337       CFIndex desc_languages_count, i, languages_count;
3339       desc_languages_count = CFArrayGetCount (desc_languages);
3340       languages_count = CFArrayGetCount (languages);
3341       for (i = 0; i < languages_count; i++)
3342         if (!CFArrayContainsValue (desc_languages,
3343                                    CFRangeMake (0, desc_languages_count),
3344                                    CFArrayGetValueAtIndex (languages, i)))
3345           {
3346             result = false;
3347             break;
3348           }
3349       CFRelease (desc_languages);
3350     }
3352   return result;
3355 static CFStringRef
3356 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3358   CFStringRef result = NULL;
3359   CFStringRef charset_string =
3360     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3362   if (charset_string && CFStringGetLength (charset_string) > 0)
3363     {
3364       CFStringRef keys[] = {
3365 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3366         kCTLanguageAttributeName
3367 #else
3368         CFSTR ("NSLanguage")
3369 #endif
3370       };
3371       CFTypeRef values[] = {NULL};
3372       CFIndex num_values = 0;
3373       CFArrayRef languages
3374         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3376       if (languages && CFArrayGetCount (languages) > 0)
3377         {
3378           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3379             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3380           else
3381             {
3382               CFCharacterSetRef charset =
3383                 CFDictionaryGetValue (attributes,
3384                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3386               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3387             }
3388         }
3389       if (result == NULL)
3390         {
3391           CFAttributedStringRef attr_string = NULL;
3392           CTLineRef ctline = NULL;
3393           CFDictionaryRef attrs
3394             = CFDictionaryCreate (NULL, (const void **) keys,
3395                                   (const void **) values, num_values,
3396                                   &kCFTypeDictionaryKeyCallBacks,
3397                                   &kCFTypeDictionaryValueCallBacks);
3399           if (attrs)
3400             {
3401               attr_string = CFAttributedStringCreate (NULL, charset_string,
3402                                                       attrs);
3403               CFRelease (attrs);
3404             }
3405           if (attr_string)
3406             {
3407               ctline = CTLineCreateWithAttributedString (attr_string);
3408               CFRelease (attr_string);
3409             }
3410           if (ctline)
3411             {
3412               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3413               CFIndex i, nruns = CFArrayGetCount (runs);
3414               CTFontRef font;
3416               for (i = 0; i < nruns; i++)
3417                 {
3418                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3419                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3420                   CTFontRef font_in_run;
3422                   if (attributes == NULL)
3423                     break;
3424                   font_in_run =
3425                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3426                   if (font_in_run == NULL)
3427                     break;
3428                   if (i == 0)
3429                     font = font_in_run;
3430                   else if (!mac_ctfont_equal_in_postscript_name (font,
3431                                                                  font_in_run))
3432                     break;
3433                 }
3434               if (nruns > 0 && i == nruns)
3435                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3436               CFRelease (ctline);
3437             }
3438         }
3439     }
3441   return result;
3444 static inline double
3445 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3447   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3448                                      &glyph, NULL, 1);
3451 static inline CGRect
3452 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3454   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3455                                           &glyph, NULL, 1);
3458 static CFArrayRef
3459 mac_ctfont_create_available_families (void)
3461   CFMutableArrayRef families = NULL;
3463 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3464 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3465   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3466 #endif
3467     {
3468       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3470       if (orig_families)
3471         {
3472           CFIndex i, count = CFArrayGetCount (orig_families);
3474           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3475           if (families)
3476             for (i = 0; i < count; i++)
3477               {
3478                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3480                 if (!CFStringHasPrefix (family, CFSTR ("."))
3481                     && (CTFontManagerCompareFontFamilyNames (family,
3482                                                              CFSTR ("LastResort"),
3483                                                              NULL)
3484                         != kCFCompareEqualTo))
3485                   CFArrayAppendValue (families, family);
3486               }
3487           CFRelease (orig_families);
3488         }
3489     }
3490 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3491   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3492 #endif
3493 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3494 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3495     {
3496       CTFontCollectionRef collection;
3497       CFArrayRef descs = NULL;
3499       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3500       if (collection)
3501         {
3502           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3503           CFRelease (collection);
3504         }
3505       if (descs)
3506         {
3507           CFIndex i, count = CFArrayGetCount (descs);
3509           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3510           if (families)
3511             for (i = 0; i < count; i++)
3512               {
3513                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3514                 CFStringRef name =
3515                   mac_font_descriptor_copy_attribute (desc,
3516                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3518                 if (name)
3519                   {
3520                     CFIndex p, limit = CFArrayGetCount (families);
3522                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3523                                               (const void *) name,
3524                                               mac_font_family_compare, NULL);
3525                     if (p >= limit)
3526                       CFArrayAppendValue (families, name);
3527                     else if (mac_font_family_compare
3528                              (CFArrayGetValueAtIndex (families, p),
3529                               name, NULL) != kCFCompareEqualTo)
3530                       CFArrayInsertValueAtIndex (families, p, name);
3531                     CFRelease (name);
3532                   }
3533               }
3534           CFRelease (descs);
3535         }
3536     }
3537 #endif
3539   return families;
3542 static Boolean
3543 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3545   Boolean result;
3546   CFStringRef name1, name2;
3548   if (font1 == font2)
3549     return true;
3551   result = false;
3552   name1 = CTFontCopyPostScriptName (font1);
3553   if (name1)
3554     {
3555       name2 = CTFontCopyPostScriptName (font2);
3556       if (name2)
3557         {
3558           result = CFEqual (name1, name2);
3559           CFRelease (name2);
3560         }
3561       CFRelease (name1);
3562     }
3564   return result;
3567 static CTLineRef
3568 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3569                                              CTFontRef macfont)
3571   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3572   CFTypeRef values[] = {NULL, NULL};
3573   CFDictionaryRef attributes = NULL;
3574   CFAttributedStringRef attr_string = NULL;
3575   CTLineRef ctline = NULL;
3576   float float_zero = 0.0f;
3578   values[0] = macfont;
3579   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3580   if (values[1])
3581     {
3582       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3583                                        (const void **) values,
3584                                        ARRAYELTS (keys),
3585                                        &kCFTypeDictionaryKeyCallBacks,
3586                                        &kCFTypeDictionaryValueCallBacks);
3587       CFRelease (values[1]);
3588     }
3589   if (attributes)
3590     {
3591       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3592       CFRelease (attributes);
3593     }
3594   if (attr_string)
3595     {
3596       ctline = CTLineCreateWithAttributedString (attr_string);
3597       CFRelease (attr_string);
3598     }
3599   if (ctline)
3600     {
3601       /* Abandon if ctline contains some fonts other than the
3602          specified one.  */
3603       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3604       CFIndex i, nruns = CFArrayGetCount (runs);
3606       for (i = 0; i < nruns; i++)
3607         {
3608           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3609           CFDictionaryRef attributes = CTRunGetAttributes (run);
3610           CTFontRef font_in_run;
3612           if (attributes == NULL)
3613             break;
3614           font_in_run =
3615             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3616           if (font_in_run == NULL)
3617             break;
3618           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3619             break;
3620         }
3621       if (i < nruns)
3622         {
3623           CFRelease (ctline);
3624           ctline = NULL;
3625         }
3626     }
3628   return ctline;
3631 static CFIndex
3632 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3633                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3635   CFIndex used, result = 0;
3636   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3638   if (ctline == NULL)
3639     return 0;
3641   used = CTLineGetGlyphCount (ctline);
3642   if (used <= glyph_len)
3643     {
3644       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3645       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3646       CGFloat total_advance = 0;
3647       CFIndex total_glyph_count = 0;
3649       for (k = 0; k < ctrun_count; k++)
3650         {
3651           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3652           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3653           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3654           CFRange string_range, comp_range, range;
3655           CFIndex *permutation;
3657           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3658             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3659           else
3660             permutation = NULL;
3662 #define RIGHT_TO_LEFT_P permutation
3664           /* Now the `comp_range' member of struct mac_glyph_layout is
3665              temporarily used as a work area such that:
3666              glbuf[i].comp_range.location =
3667              min {compRange[i + 1].location, ...,
3668                      compRange[glyph_count - 1].location,
3669                      maxRange (stringRangeForCTRun)}
3670              glbuf[i].comp_range.length = maxRange (compRange[i])
3671              where compRange[i] is the range of composed characters
3672              containing i-th glyph.  */
3673           string_range = CTRunGetStringRange (ctrun);
3674           min_location = string_range.location + string_range.length;
3675           for (i = 0; i < glyph_count; i++)
3676             {
3677               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3678               CFIndex glyph_index;
3679               CFRange rng;
3681               if (!RIGHT_TO_LEFT_P)
3682                 glyph_index = glyph_count - i - 1;
3683               else
3684                 glyph_index = i;
3685               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3686                                      &gl->string_index);
3687               rng =
3688                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3689                                                              gl->string_index);
3690               gl->comp_range.location = min_location;
3691               gl->comp_range.length = rng.location + rng.length;
3692               if (rng.location < min_location)
3693                 min_location = rng.location;
3694             }
3696           /* Fill the `comp_range' member of struct mac_glyph_layout,
3697              and setup a permutation for right-to-left text.  */
3698           comp_range = CFRangeMake (string_range.location, 0);
3699           range = CFRangeMake (0, 0);
3700           while (1)
3701             {
3702               struct mac_glyph_layout *gl =
3703                 glbuf + range.location + range.length;
3705               if (gl->comp_range.length
3706                   > comp_range.location + comp_range.length)
3707                 comp_range.length = gl->comp_range.length - comp_range.location;
3708               min_location = gl->comp_range.location;
3709               range.length++;
3711               if (min_location >= comp_range.location + comp_range.length)
3712                 {
3713                   comp_range.length = min_location - comp_range.location;
3714                   for (i = 0; i < range.length; i++)
3715                     {
3716                       glbuf[range.location + i].comp_range = comp_range;
3717                       if (RIGHT_TO_LEFT_P)
3718                         permutation[range.location + i] =
3719                           range.location + range.length - i - 1;
3720                     }
3722                   comp_range = CFRangeMake (min_location, 0);
3723                   range.location += range.length;
3724                   range.length = 0;
3725                   if (range.location == glyph_count)
3726                     break;
3727                 }
3728             }
3730           /* Then fill the remaining members.  */
3731           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3732                range.location++)
3733             {
3734               struct mac_glyph_layout *gl;
3735               CGPoint position;
3737               if (!RIGHT_TO_LEFT_P)
3738                 gl = glbuf + range.location;
3739               else
3740                 {
3741                   CFIndex src, dest;
3743                   src = glyph_count - 1 - range.location;
3744                   dest = permutation[src];
3745                   gl = glbuf + dest;
3746                   if (src < dest)
3747                     {
3748                       CFIndex tmp = gl->string_index;
3750                       gl->string_index = glbuf[src].string_index;
3751                       glbuf[src].string_index = tmp;
3752                     }
3753                 }
3754               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3756               CTRunGetPositions (ctrun, range, &position);
3757               gl->advance_delta = position.x - total_advance;
3758               gl->baseline_delta = position.y;
3759               gl->advance = (gl->advance_delta
3760                              + CTRunGetTypographicBounds (ctrun, range,
3761                                                           NULL, NULL, NULL));
3762               total_advance += gl->advance;
3763             }
3765           if (RIGHT_TO_LEFT_P)
3766             xfree (permutation);
3768 #undef RIGHT_TO_LEFT_P
3770           total_glyph_count += glyph_count;
3771         }
3773       result = used;
3774     }
3775   CFRelease (ctline);
3777   return result;
3780 /* The function below seems to cause a memory leak for the CFString
3781    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3782    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3783 #if USE_CT_GLYPH_INFO
3784 static CGGlyph
3785 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3786                               CGFontIndex cid)
3788   CGGlyph result = kCGFontIndexInvalid;
3789   UniChar characters[] = {0xfffd};
3790   CFStringRef string;
3791   CFAttributedStringRef attr_string = NULL;
3792   CTLineRef ctline = NULL;
3794   string = CFStringCreateWithCharacters (NULL, characters,
3795                                          ARRAYELTS (characters));
3797   if (string)
3798     {
3799       CTGlyphInfoRef glyph_info =
3800         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3801       CFDictionaryRef attributes = NULL;
3803       if (glyph_info)
3804         {
3805           CFStringRef keys[] = {kCTFontAttributeName,
3806                                 kCTGlyphInfoAttributeName};
3807           CFTypeRef values[] = {font, glyph_info};
3809           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3810                                            (const void **) values,
3811                                            ARRAYELTS (keys),
3812                                            &kCFTypeDictionaryKeyCallBacks,
3813                                            &kCFTypeDictionaryValueCallBacks);
3814           CFRelease (glyph_info);
3815         }
3816       if (attributes)
3817         {
3818           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3819           CFRelease (attributes);
3820         }
3821       CFRelease (string);
3822     }
3823   if (attr_string)
3824     {
3825       ctline = CTLineCreateWithAttributedString (attr_string);
3826       CFRelease (attr_string);
3827     }
3828   if (ctline)
3829     {
3830       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3832       if (CFArrayGetCount (runs) > 0)
3833         {
3834           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3835           CFDictionaryRef attributes = CTRunGetAttributes (run);
3837           if (attributes)
3838             {
3839               CTFontRef font_in_run =
3840                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3842               if (font_in_run
3843                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3844                 {
3845                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3846                   if (result >= CTFontGetGlyphCount (font))
3847                     result = kCGFontIndexInvalid;
3848                 }
3849             }
3850         }
3851       CFRelease (ctline);
3852     }
3854   return result;
3856 #endif
3858 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3859 static inline int
3860 mac_font_family_group (CFStringRef family)
3862   if (CFStringHasPrefix (family, CFSTR ("#")))
3863     return 2;
3864   else
3865     {
3866       CFRange range;
3868       range = CFStringFind (family, CFSTR ("Apple"),
3869                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3870       if (range.location != kCFNotFound)
3871         return 1;
3873       return 0;
3874     }
3877 static CFComparisonResult
3878 mac_font_family_compare (const void *val1, const void *val2, void *context)
3880   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3881   int group1, group2;
3883   group1 = mac_font_family_group (family1);
3884   group2 = mac_font_family_group (family2);
3885   if (group1 < group2)
3886     return kCFCompareLessThan;
3887   if (group1 > group2)
3888     return kCFCompareGreaterThan;
3889   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3891 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3893 static CFArrayRef
3894 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3896   CFArrayRef result = NULL;
3898 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3899 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3900   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3901 #endif
3902     {
3903       CTFontRef user_font =
3904         CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3906       if (user_font)
3907         {
3908           CFArrayRef languages =
3909             CFArrayCreate (NULL, (const void **) &language, 1,
3910                            &kCFTypeArrayCallBacks);
3912           if (languages)
3913             {
3914               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3915                                                                  languages);
3916               CFRelease (languages);
3917             }
3918           CFRelease (user_font);
3919         }
3920     }
3921 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3922   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3923 #endif
3924 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3925 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3926     {
3927       CFIndex i;
3929       for (i = 0; macfont_language_default_font_names[i].language; i++)
3930         {
3931           if (CFEqual (macfont_language_default_font_names[i].language,
3932                        language))
3933             {
3934               CFMutableArrayRef descriptors =
3935                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3937               if (descriptors)
3938                 {
3939                   CFIndex j;
3941                   for (j = 0;
3942                        macfont_language_default_font_names[i].font_names[j];
3943                        j++)
3944                     {
3945                       CFDictionaryRef attributes =
3946                         CFDictionaryCreate (NULL,
3947                                             ((const void **)
3948                                              &MAC_FONT_NAME_ATTRIBUTE),
3949                                             ((const void **)
3950                                              &macfont_language_default_font_names[i].font_names[j]),
3951                                             1, &kCFTypeDictionaryKeyCallBacks,
3952                                             &kCFTypeDictionaryValueCallBacks);
3954                       if (attributes)
3955                         {
3956                           FontDescriptorRef pat_desc =
3957                             mac_font_descriptor_create_with_attributes (attributes);
3959                           if (pat_desc)
3960                             {
3961                               FontDescriptorRef descriptor =
3962                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3964                               if (descriptor)
3965                                 {
3966                                   CFArrayAppendValue (descriptors, descriptor);
3967                                   CFRelease (descriptor);
3968                                 }
3969                               CFRelease (pat_desc);
3970                             }
3971                           CFRelease (attributes);
3972                         }
3973                     }
3974                   result = descriptors;
3975                 }
3976               break;
3977             }
3978         }
3979     }
3980 #endif
3982   return result;
3985 static CFStringRef
3986 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3987                                                       CFArrayRef languages)
3989   CFStringRef result = NULL;
3990   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3991   CFArrayRef descriptors =
3992     mac_font_copy_default_descriptors_for_language (language);
3994   if (descriptors)
3995     {
3996       CFIndex i, count = CFArrayGetCount (descriptors);
3998       for (i = 0; i < count; i++)
3999         {
4000           FontDescriptorRef descriptor =
4001             CFArrayGetValueAtIndex (descriptors, i);
4003           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4004                                                         Qnil, languages))
4005             {
4006               CFStringRef family =
4007                 mac_font_descriptor_copy_attribute (descriptor,
4008                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
4009               if (family)
4010                 {
4011                   if (!CFStringHasPrefix (family, CFSTR ("."))
4012                       && !CFEqual (family, CFSTR ("LastResort")))
4013                     {
4014                       result = family;
4015                       break;
4016                     }
4017                   else
4018                     CFRelease (family);
4019                 }
4020             }
4021         }
4022       CFRelease (descriptors);
4023     }
4025   return result;
4028 void *
4029 macfont_get_nsctfont (struct font *font)
4031   struct macfont_info *macfont_info = (struct macfont_info *) font;
4032   FontRef macfont = macfont_info->macfont;
4034   return (void *) macfont;
4037 void
4038 mac_register_font_driver (struct frame *f)
4040   register_font_driver (&macfont_driver, f);
4043 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4046 void
4047 syms_of_macfont (void)
4049 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4050   static struct font_driver mac_font_driver;
4052   DEFSYM (Qmac_ct, "mac-ct");
4053   macfont_driver.type = Qmac_ct;
4054   register_font_driver (&macfont_driver, NULL);
4056   DEFSYM (QCdestination, ":destination");
4057   DEFSYM (QCminspace, ":minspace");
4058 #endif