Fix bug #18420 with deadlocks communicating with subprocess on MS-Windows.
[emacs.git] / src / macfont.m
blob1bb3fb141349b184045832225cf6f9920beb0d26
1 /* Font driver on Mac OSX Core text.
2    Copyright (C) 2009-2014 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
19 Original author: YAMAMOTO Mitsuharu
22 #include <config.h>
24 #include "lisp.h"
25 #include "dispextern.h"
26 #include "frame.h"
27 #include "blockinput.h"
28 #include "character.h"
29 #include "charset.h"
30 #include "composite.h"
31 #include "fontset.h"
32 #include "font.h"
33 #include "termchar.h"
34 #include "nsgui.h"
35 #include "nsterm.h"
36 #include "macfont.h"
37 #include "macuvs.h"
39 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
41 #include <libkern/OSByteOrder.h>
43 static struct font_driver macfont_driver;
45 /* Core Text, for Mac OS X 10.5 and later.  */
46 static Lisp_Object Qmac_ct;
48 static double mac_ctfont_get_advance_width_for_glyph (CTFontRef, CGGlyph);
49 static CGRect mac_ctfont_get_bounding_rect_for_glyph (CTFontRef, CGGlyph);
50 static CFArrayRef mac_ctfont_create_available_families (void);
51 static Boolean mac_ctfont_equal_in_postscript_name (CTFontRef, CTFontRef);
52 static CTLineRef mac_ctfont_create_line_with_string_and_font (CFStringRef,
53                                                               CTFontRef);
54 static CFComparisonResult mac_font_family_compare (const void *,
55                                                    const void *, void *);
56 static Boolean mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef,
57                                                          CFArrayRef);
58 static CFStringRef mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef);
59 static CFIndex mac_ctfont_shape (CTFontRef, CFStringRef,
60                                  struct mac_glyph_layout *, CFIndex);
61 static CFArrayRef
62 mac_font_copy_default_descriptors_for_language (CFStringRef language);
64 static CFStringRef
65 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
66                                                       CFArrayRef languages);
68 #if USE_CT_GLYPH_INFO
69 static CGGlyph mac_ctfont_get_glyph_for_cid (CTFontRef,
70                                              CTCharacterCollection,
71                                              CGFontIndex);
72 #endif
74 /* The font property key specifying the font design destination.  The
75    value is an unsigned integer code: 0 for WYSIWYG, and 1 for Video
76    text.  (See the documentation of X Logical Font Description
77    Conventions.)  In the Mac font driver, 1 means the screen font is
78    used for calculating some glyph metrics.  You can see the
79    difference with Monaco 8pt or 9pt, for example.  */
80 static Lisp_Object QCdestination;
82 /* The boolean-valued font property key specifying the use of
83    leading.  */
84 static Lisp_Object QCminspace;
86 struct macfont_metrics;
88 /* The actual structure for Mac font that can be cast to struct font.  */
90 struct macfont_info
92   struct font font;
93   FontRef macfont;
94   CGFontRef cgfont;
95   ScreenFontRef screen_font;
96   struct macfont_cache *cache;
97   struct macfont_metrics **metrics;
98   short metrics_nrows;
99   bool_bf synthetic_italic_p : 1;
100   bool_bf synthetic_bold_p : 1;
101   unsigned spacing : 2;
102   unsigned antialias : 2;
103   bool_bf color_bitmap_p : 1;
106 /* Values for the `spacing' member in `struct macfont_info'.  */
108 enum
109   {
110     MACFONT_SPACING_PROPORTIONAL,
111     MACFONT_SPACING_MONO,
112     MACFONT_SPACING_SYNTHETIC_MONO,
113   };
115 /* Values for the `antialias' member in `struct macfont_info'.  */
117 enum
118   {
119     MACFONT_ANTIALIAS_DEFAULT,
120     MACFONT_ANTIALIAS_OFF,
121     MACFONT_ANTIALIAS_ON,
122   };
124 enum {FONT_SLANT_SYNTHETIC_ITALIC = 200}; /* FC_SLANT_ITALIC + 100 */
125 enum {FONT_WEIGHT_SYNTHETIC_BOLD = 200};  /* FC_WEIGHT_BOLD */
126 enum {FONT_SPACING_SYNTHETIC_MONO = FONT_SPACING_MONO};
128 static const CGAffineTransform synthetic_italic_atfm = {1, 0, 0.25, 1, 0, 0};
129 static const CGFloat synthetic_bold_factor = 0.024;
131 static Boolean cfnumber_get_font_symbolic_traits_value (CFNumberRef,
132                                                         FontSymbolicTraits *);
133 static void macfont_store_descriptor_attributes (FontDescriptorRef,
134                                                  Lisp_Object);
135 static Lisp_Object macfont_descriptor_entity (FontDescriptorRef,
136                                               Lisp_Object,
137                                               FontSymbolicTraits);
138 static CFStringRef macfont_create_family_with_symbol (Lisp_Object);
139 static int macfont_glyph_extents (struct font *, CGGlyph,
140                                   struct font_metrics *, CGFloat *, int);
141 static CFMutableDictionaryRef macfont_create_attributes_with_spec (Lisp_Object);
142 static Boolean macfont_supports_charset_and_languages_p (FontDescriptorRef,
143                                                          CFCharacterSetRef,
144                                                          Lisp_Object,
145                                                          CFArrayRef);
146 static CFIndex macfont_closest_traits_index (CFArrayRef,
147                                              FontSymbolicTraits);
148 static CFDataRef mac_font_copy_uvs_table (FontRef);
149 static void mac_font_get_glyphs_for_variants (CFDataRef, UTF32Char,
150                                               const UTF32Char [],
151                                               CGGlyph [], CFIndex);
153 /* From CFData to a lisp string.  Always returns a unibyte string.  */
155 static Lisp_Object
156 cfdata_to_lisp (CFDataRef data)
158   CFIndex len = CFDataGetLength (data);
159   Lisp_Object result = make_uninit_string (len);
161   CFDataGetBytes (data, CFRangeMake (0, len), SDATA (result));
163   return result;
168 /* From CFString to a lisp string.  Returns a unibyte string
169    containing a UTF-8 byte sequence.  */
171 static Lisp_Object
172 cfstring_to_lisp_nodecode (CFStringRef string)
174   Lisp_Object result = Qnil;
175   CFDataRef data;
176   const char *s = CFStringGetCStringPtr (string, kCFStringEncodingUTF8);
178   if (s)
179     {
180       CFIndex i, length = CFStringGetLength (string);
182       for (i = 0; i < length; i++)
183         if (CFStringGetCharacterAtIndex (string, i) == 0)
184           break;
186       if (i == length)
187         return make_unibyte_string (s, strlen (s));
188     }
190   data = CFStringCreateExternalRepresentation (NULL, string,
191                                                kCFStringEncodingUTF8, '?');
192   if (data)
193     {
194       result = cfdata_to_lisp (data);
195       CFRelease (data);
196     }
198   return result;
201 /* Lisp string containing a UTF-8 byte sequence to CFString.  Unlike
202    cfstring_create_with_utf8_cstring, this function preserves NUL
203    characters.  */
205 static CFStringRef
206 cfstring_create_with_string_noencode (Lisp_Object s)
208   CFStringRef string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
209                                                 kCFStringEncodingUTF8, false);
211   if (string == NULL)
212     /* Failed to interpret as UTF 8.  Fall back on Mac Roman.  */
213     string = CFStringCreateWithBytes (NULL, SDATA (s), SBYTES (s),
214                                       kCFStringEncodingMacRoman, false);
216   return string;
219 static CGFloat
220 mac_screen_font_get_advance_width_for_glyph (ScreenFontRef font, CGGlyph glyph)
222   NSSize advancement = [(NSFont *)font advancementForGlyph:glyph];
224   return advancement.width;
227 static CGGlyph
228 mac_font_get_glyph_for_cid (FontRef font, CharacterCollection collection,
229                             CGFontIndex cid)
231 #if USE_CT_GLYPH_INFO
232   return mac_ctfont_get_glyph_for_cid ((CTFontRef) font, collection, cid);
233 #else
234   {
235     CGGlyph result = kCGFontIndexInvalid;
236     NSFont *nsFont = (NSFont *) font;
237     unichar characters[] = {0xfffd};
238     NSString *string =
239       [NSString stringWithCharacters:characters
240                               length:(sizeof (characters)
241                                       / sizeof (characters[0]))];
242     NSGlyphInfo *glyphInfo =
243       [NSGlyphInfo glyphInfoWithCharacterIdentifier:cid
244                                          collection:collection
245                                          baseString:string];
246     NSDictionary *attributes =
247       [NSDictionary dictionaryWithObjectsAndKeys:nsFont,NSFontAttributeName,
248                     glyphInfo,NSGlyphInfoAttributeName,nil];
249     NSTextStorage *textStorage =
250       [[NSTextStorage alloc] initWithString:string
251                                  attributes:attributes];
252     NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
253     NSTextContainer *textContainer = [[NSTextContainer alloc] init];
254     NSFont *fontInTextStorage;
256     [layoutManager addTextContainer:textContainer];
257     [textContainer release];
258     [textStorage addLayoutManager:layoutManager];
259     [layoutManager release];
261     /* Force layout.  */
262     (void) [layoutManager glyphRangeForTextContainer:textContainer];
264     fontInTextStorage = [textStorage attribute:NSFontAttributeName atIndex:0
265                                 effectiveRange:NULL];
266     if (fontInTextStorage == nsFont
267         || [[fontInTextStorage fontName] isEqualToString:[nsFont fontName]])
268       {
269         NSGlyph glyph = [layoutManager glyphAtIndex:0];
271         if (glyph < [nsFont numberOfGlyphs])
272           result = glyph;
273       }
275     [textStorage release];
277     return result;
278   }
280 #endif
282 static ScreenFontRef
283 mac_screen_font_create_with_name (CFStringRef name, CGFloat size)
285   NSFont *result, *font;
287   font = [NSFont fontWithName:((NSString *) name) size:size];
288   result = [font screenFont];
290   return (ScreenFontRef)[result retain];
294 static Boolean
295 mac_screen_font_get_metrics (ScreenFontRef font, CGFloat *ascent,
296                              CGFloat *descent, CGFloat *leading)
298   NSFont *nsFont = [(NSFont *)font printerFont];
299   NSTextStorage *textStorage;
300   NSLayoutManager *layoutManager;
301   NSTextContainer *textContainer;
302   NSRect usedRect;
303   NSPoint spaceLocation;
304   CGFloat descender;
306   textStorage = [[NSTextStorage alloc] initWithString:@" "];
307   layoutManager = [[NSLayoutManager alloc] init];
308   textContainer = [[NSTextContainer alloc] init];
310   [textStorage setFont:nsFont];
311   [textContainer setLineFragmentPadding:0];
312   [layoutManager setUsesScreenFonts:YES];
314   [layoutManager addTextContainer:textContainer];
315   [textContainer release];
316   [textStorage addLayoutManager:layoutManager];
317   [layoutManager release];
319   if (!(textStorage && layoutManager && textContainer))
320     {
321       [textStorage release];
323       return false;
324     }
326   usedRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:0
327                                                  effectiveRange:NULL];
328   spaceLocation = [layoutManager locationForGlyphAtIndex:0];
329   [textStorage release];
331   *ascent = spaceLocation.y;
332   *descent = NSHeight (usedRect) - spaceLocation.y;
333   *leading = 0;
334   descender = [nsFont descender];
335   if (- descender < *descent)
336     {
337       *leading = *descent + descender;
338       *descent = - descender;
339     }
341   return true;
344 static CFIndex
345 mac_font_shape_1 (NSFont *font, NSString *string,
346                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len,
347                   BOOL screen_font_p)
349   NSUInteger i;
350   CFIndex result = 0;
351   NSTextStorage *textStorage;
352   NSLayoutManager *layoutManager;
353   NSTextContainer *textContainer;
354   NSUInteger stringLength;
355   NSPoint spaceLocation;
356   NSUInteger used, numberOfGlyphs;
358   textStorage = [[NSTextStorage alloc] initWithString:string];
359   layoutManager = [[NSLayoutManager alloc] init];
360   textContainer = [[NSTextContainer alloc] init];
362   /* Append a trailing space to measure baseline position.  */
363   [textStorage appendAttributedString:([[[NSAttributedString alloc]
364                                           initWithString:@" "] autorelease])];
365   [textStorage setFont:font];
366   [textContainer setLineFragmentPadding:0];
367   [layoutManager setUsesScreenFonts:screen_font_p];
369   [layoutManager addTextContainer:textContainer];
370   [textContainer release];
371   [textStorage addLayoutManager:layoutManager];
372   [layoutManager release];
374   if (!(textStorage && layoutManager && textContainer))
375     {
376       [textStorage release];
378       return 0;
379     }
381   stringLength = [string length];
383   /* Force layout.  */
384   (void) [layoutManager glyphRangeForTextContainer:textContainer];
386   spaceLocation = [layoutManager locationForGlyphAtIndex:stringLength];
388   /* Remove the appended trailing space because otherwise it may
389      generate a wrong result for a right-to-left text.  */
390   [textStorage beginEditing];
391   [textStorage deleteCharactersInRange:(NSMakeRange (stringLength, 1))];
392   [textStorage endEditing];
393   (void) [layoutManager glyphRangeForTextContainer:textContainer];
395   i = 0;
396   while (i < stringLength)
397     {
398       NSRange range;
399       NSFont *fontInTextStorage =
400         [textStorage attribute:NSFontAttributeName atIndex:i
401                      longestEffectiveRange:&range
402                        inRange:(NSMakeRange (0, stringLength))];
404       if (!(fontInTextStorage == font
405             || [[fontInTextStorage fontName] isEqualToString:[font fontName]]))
406         break;
407       i = NSMaxRange (range);
408     }
409   if (i < stringLength)
410     /* Make the test `used <= glyph_len' below fail if textStorage
411        contained some fonts other than the specified one.  */
412     used = glyph_len + 1;
413   else
414     {
415       NSRange range = NSMakeRange (0, stringLength);
417       range = [layoutManager glyphRangeForCharacterRange:range
418                                     actualCharacterRange:NULL];
419       numberOfGlyphs = NSMaxRange (range);
420       used = numberOfGlyphs;
421       for (i = 0; i < numberOfGlyphs; i++)
422         if ([layoutManager notShownAttributeForGlyphAtIndex:i])
423           used--;
424     }
426   if (0 < used && used <= glyph_len)
427     {
428       NSUInteger glyphIndex, prevGlyphIndex;
429       unsigned char bidiLevel;
430       NSUInteger *permutation;
431       NSRange compRange, range;
432       CGFloat totalAdvance;
434       glyphIndex = 0;
435       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
436         glyphIndex++;
438       /* For now we assume the direction is not changed within the
439          string.  */
440       [layoutManager getGlyphsInRange:(NSMakeRange (glyphIndex, 1))
441                                glyphs:NULL characterIndexes:NULL
442                     glyphInscriptions:NULL elasticBits:NULL
443                            bidiLevels:&bidiLevel];
444       if (bidiLevel & 1)
445         permutation = xmalloc (sizeof (NSUInteger) * used);
446       else
447         permutation = NULL;
449 #define RIGHT_TO_LEFT_P permutation
451       /* Fill the `comp_range' member of struct mac_glyph_layout, and
452          setup a permutation for right-to-left text.  */
453       compRange = NSMakeRange (0, 0);
454       for (range = NSMakeRange (0, 0); NSMaxRange (range) < used;
455            range.length++)
456         {
457           struct mac_glyph_layout *gl = glyph_layouts + NSMaxRange (range);
458           NSUInteger characterIndex =
459             [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
461           gl->string_index = characterIndex;
463           if (characterIndex >= NSMaxRange (compRange))
464             {
465               compRange.location = NSMaxRange (compRange);
466               do
467                 {
468                   NSRange characterRange =
469                     [string
470                       rangeOfComposedCharacterSequenceAtIndex:characterIndex];
472                   compRange.length =
473                     NSMaxRange (characterRange) - compRange.location;
474                   [layoutManager glyphRangeForCharacterRange:compRange
475                                         actualCharacterRange:&characterRange];
476                   characterIndex = NSMaxRange (characterRange) - 1;
477                 }
478               while (characterIndex >= NSMaxRange (compRange));
480               if (RIGHT_TO_LEFT_P)
481                 for (i = 0; i < range.length; i++)
482                   permutation[range.location + i] = NSMaxRange (range) - i - 1;
484               range = NSMakeRange (NSMaxRange (range), 0);
485             }
487           gl->comp_range.location = compRange.location;
488           gl->comp_range.length = compRange.length;
490           while (++glyphIndex < numberOfGlyphs)
491             if (![layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
492               break;
493         }
494       if (RIGHT_TO_LEFT_P)
495         for (i = 0; i < range.length; i++)
496           permutation[range.location + i] = NSMaxRange (range) - i - 1;
498       /* Then fill the remaining members.  */
499       glyphIndex = prevGlyphIndex = 0;
500       while ([layoutManager notShownAttributeForGlyphAtIndex:glyphIndex])
501         glyphIndex++;
503       if (!RIGHT_TO_LEFT_P)
504         totalAdvance = 0;
505       else
506         {
507           NSUInteger nrects;
508           NSRect *glyphRects =
509             [layoutManager
510               rectArrayForGlyphRange:(NSMakeRange (0, numberOfGlyphs))
511               withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
512                      inTextContainer:textContainer rectCount:&nrects];
514           totalAdvance = NSMaxX (glyphRects[0]);
515         }
517       for (i = 0; i < used; i++)
518         {
519           struct mac_glyph_layout *gl;
520           NSPoint location;
521           NSUInteger nextGlyphIndex;
522           NSRange glyphRange;
523           NSRect *glyphRects;
524           NSUInteger nrects;
526           if (!RIGHT_TO_LEFT_P)
527             gl = glyph_layouts + i;
528           else
529             {
530               NSUInteger dest = permutation[i];
532               gl = glyph_layouts + dest;
533               if (i < dest)
534                 {
535                   CFIndex tmp = gl->string_index;
537                   gl->string_index = glyph_layouts[i].string_index;
538                   glyph_layouts[i].string_index = tmp;
539                 }
540             }
541           gl->glyph_id = [layoutManager glyphAtIndex:glyphIndex];
543           location = [layoutManager locationForGlyphAtIndex:glyphIndex];
544           gl->baseline_delta = spaceLocation.y - location.y;
546           for (nextGlyphIndex = glyphIndex + 1; nextGlyphIndex < numberOfGlyphs;
547                nextGlyphIndex++)
548             if (![layoutManager
549                    notShownAttributeForGlyphAtIndex:nextGlyphIndex])
550               break;
552           if (!RIGHT_TO_LEFT_P)
553             {
554               CGFloat maxX;
556               if (prevGlyphIndex == 0)
557                 glyphRange = NSMakeRange (0, nextGlyphIndex);
558               else
559                 glyphRange = NSMakeRange (glyphIndex,
560                                           nextGlyphIndex - glyphIndex);
561               glyphRects =
562                 [layoutManager
563                   rectArrayForGlyphRange:glyphRange
564                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
565                          inTextContainer:textContainer rectCount:&nrects];
566               maxX = max (NSMaxX (glyphRects[0]), totalAdvance);
567               gl->advance_delta = location.x - totalAdvance;
568               gl->advance = maxX - totalAdvance;
569               totalAdvance = maxX;
570             }
571           else
572             {
573               CGFloat minX;
575               if (nextGlyphIndex == numberOfGlyphs)
576                 glyphRange = NSMakeRange (prevGlyphIndex,
577                                           numberOfGlyphs - prevGlyphIndex);
578               else
579                 glyphRange = NSMakeRange (prevGlyphIndex,
580                                           glyphIndex + 1 - prevGlyphIndex);
581               glyphRects =
582                 [layoutManager
583                   rectArrayForGlyphRange:glyphRange
584                   withinSelectedGlyphRange:(NSMakeRange (NSNotFound, 0))
585                          inTextContainer:textContainer rectCount:&nrects];
586               minX = min (NSMinX (glyphRects[0]), totalAdvance);
587               gl->advance = totalAdvance - minX;
588               totalAdvance = minX;
589               gl->advance_delta = location.x - totalAdvance;
590             }
592           prevGlyphIndex = glyphIndex + 1;
593           glyphIndex = nextGlyphIndex;
594         }
596       if (RIGHT_TO_LEFT_P)
597         xfree (permutation);
599 #undef RIGHT_TO_LEFT_P
601       result = used;
602    }
603  [textStorage release];
605   return result;
608 static CFIndex
609 mac_screen_font_shape (ScreenFontRef font, CFStringRef string,
610                        struct mac_glyph_layout *glyph_layouts,
611                        CFIndex glyph_len)
613   return mac_font_shape_1 ([(NSFont *)font printerFont],
614                            (NSString *) string,
615                            glyph_layouts, glyph_len, YES);
618 static CGColorRef
619 get_cgcolor(unsigned long idx, struct frame *f)
621   NSColor *nsColor = ns_lookup_indexed_color (idx, f);
622   [nsColor set];
623   CGColorSpaceRef colorSpace = [[nsColor colorSpace] CGColorSpace];
624   NSInteger noc = [nsColor numberOfComponents];
625   CGFloat *components = xmalloc (sizeof(CGFloat)*(1+noc));
626   CGColorRef cgColor;
628   [nsColor getComponents: components];
629   cgColor = CGColorCreate (colorSpace, components);
630   xfree (components);
631   return cgColor;
634 #define CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND(context, face, f)        \
635   do {                                                                  \
636     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
637     CGContextSetFillColorWithColor (context, refcol_) ;                 \
638     CGColorRelease (refcol_);                                           \
639   } while (0)
640 #define CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND(context, face, f)        \
641   do {                                                                  \
642     CGColorRef refcol_ = get_cgcolor (NS_FACE_BACKGROUND (face), f);    \
643     CGContextSetFillColorWithColor (context, refcol_);                  \
644     CGColorRelease (refcol_);                                           \
645   } while (0)
646 #define CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND(context, face, f)      \
647   do {                                                                  \
648     CGColorRef refcol_ = get_cgcolor (NS_FACE_FOREGROUND (face), f);    \
649     CGContextSetStrokeColorWithColor (context, refcol_);                \
650     CGColorRelease (refcol_);                                           \
651   } 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 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 < sizeof (numeric_traits) / sizeof (numeric_traits[0]); 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
1015   {
1016     METRICS_INVALID = -1,    /* metrics entry is invalid */
1017     METRICS_WIDTH_VALID = -2 /* width is valid but others are invalid */
1018   };
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 (CFStringCompare (key, CFSTR ("LastResort"), 0)
1256               == kCFCompareEqualTo)
1257             {
1258               CFRange range = CFRangeMake (0, MAX_UNICODE_CHAR + 1);
1260               cache->cf_charset =
1261                 CFCharacterSetCreateWithCharactersInRange (NULL, range);
1262             }
1263           if (cache->cf_charset == NULL)
1264             cache->cf_charset = mac_font_copy_character_set (macfont);
1265           CFDictionaryAddValue (macfont_cache_dictionary, key,
1266                                 (const void *) cache);
1267           CFRelease (macfont);
1268         }
1269     }
1271   return cache;
1274 static struct macfont_cache *
1275 macfont_retain_cache (struct macfont_cache *cache)
1277   cache->reference_count++;
1279   return cache;
1282 static void
1283 macfont_release_cache (struct macfont_cache *cache)
1285   if (--cache->reference_count == 0)
1286     {
1287       int i;
1289       for (i = 0; i < cache->glyph.nrows; i++)
1290         xfree (cache->glyph.matrix[i]);
1291       xfree (cache->glyph.matrix);
1292       if (cache->glyph.dictionary)
1293         CFRelease (cache->glyph.dictionary);
1294       memset (&cache->glyph, 0, sizeof (cache->glyph));
1295       if (cache->uvs.table)
1296         CFRelease (cache->uvs.table);
1297       memset (&cache->uvs, 0, sizeof (cache->uvs));
1298     }
1301 static CFCharacterSetRef
1302 macfont_get_cf_charset (struct font *font)
1304   struct macfont_info *macfont_info = (struct macfont_info *) font;
1306   return macfont_info->cache->cf_charset;
1309 static CFCharacterSetRef
1310 macfont_get_cf_charset_for_name (CFStringRef name)
1312   struct macfont_cache *cache = macfont_lookup_cache (name);
1314   return cache->cf_charset;
1317 static CGGlyph
1318 macfont_get_glyph_for_character (struct font *font, UTF32Char c)
1320   struct macfont_info *macfont_info = (struct macfont_info *) font;
1321   FontRef macfont = macfont_info->macfont;
1322   struct macfont_cache *cache = macfont_info->cache;
1324   if (c < 0xD800 || (c > 0xDFFF && c < 0x10000))
1325     {
1326       int row = c / 256;
1327       int nkeys_or_perm = cache->glyph.row_nkeys_or_perm[row];
1329       if (nkeys_or_perm < ROW_PERM_OFFSET)
1330         {
1331           UniChar unichars[256], ch;
1332           CGGlyph *glyphs;
1333           int i, len;
1334           int nrows;
1335 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1336           dispatch_queue_t queue;
1337           dispatch_group_t group = NULL;
1338 #else
1339           int nkeys;
1340 #endif
1342           if (row != 0)
1343             {
1344               CFMutableDictionaryRef dictionary;
1345               uintptr_t key, value;
1346               int nshifts;
1347               CGGlyph glyph;
1349               if (cache->glyph.dictionary == NULL)
1350                 cache->glyph.dictionary =
1351                   CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1352               dictionary = cache->glyph.dictionary;
1353               key = c / NGLYPHS_IN_VALUE;
1354               nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1355               value = ((uintptr_t)
1356                        CFDictionaryGetValue (dictionary, (const void *) key));
1357               glyph = (value >> nshifts);
1358               if (glyph)
1359                 return glyph;
1361               if (nkeys_or_perm + 1 != ROW_PERM_OFFSET)
1362                 {
1363                   ch = c;
1364                   if (!mac_font_get_glyphs_for_characters (macfont, &ch,
1365                                                            &glyph, 1)
1366                       || glyph == 0)
1367                     glyph = kCGFontIndexInvalid;
1369                   if (value == 0)
1370                     cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm + 1;
1371                   value |= ((uintptr_t) glyph << nshifts);
1372                   CFDictionarySetValue (dictionary, (const void *) key,
1373                                         (const void *) value);
1375                   return glyph;
1376                 }
1378 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1379               queue =
1380                 dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1381               group = dispatch_group_create ();
1382               dispatch_group_async (group, queue, ^{
1383                   int nkeys;
1384                   uintptr_t key;
1385 #endif
1386                   nkeys = nkeys_or_perm;
1387                   for (key = row * (256 / NGLYPHS_IN_VALUE); ; key++)
1388                     if (CFDictionaryContainsKey (dictionary,
1389                                                  (const void *) key))
1390                       {
1391                         CFDictionaryRemoveValue (dictionary,
1392                                                  (const void *) key);
1393                         if (--nkeys == 0)
1394                           break;
1395                       }
1396 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1397                 });
1398 #endif
1399             }
1401           len = 0;
1402           for (i = 0; i < 256; i++)
1403             {
1404               ch = row * 256 + i;
1405               if (CFCharacterSetIsLongCharacterMember (cache->cf_charset, ch))
1406                 unichars[len++] = ch;
1407             }
1409           glyphs = xmalloc (sizeof (CGGlyph) * 256);
1410           if (len > 0)
1411             {
1412               mac_font_get_glyphs_for_characters (macfont, unichars,
1413                                                   glyphs, len);
1414               while (i > len)
1415                 {
1416                   int next = unichars[len - 1] % 256;
1418                   while (--i > next)
1419                     glyphs[i] = kCGFontIndexInvalid;
1421                   len--;
1422                   glyphs[i] = glyphs[len];
1423                   if (len == 0)
1424                     break;
1425                 }
1426             }
1427           if (i > len)
1428             while (i-- > 0)
1429               glyphs[i] = kCGFontIndexInvalid;
1431           nrows = cache->glyph.nrows;
1432           nkeys_or_perm = nrows + ROW_PERM_OFFSET;
1433           cache->glyph.row_nkeys_or_perm[row] = nkeys_or_perm;
1434           nrows++;
1435           cache->glyph.matrix = xrealloc (cache->glyph.matrix,
1436                                           sizeof (CGGlyph *) * nrows);
1437           cache->glyph.matrix[nrows - 1] = glyphs;
1438           cache->glyph.nrows = nrows;
1440 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
1441           if (group)
1442             {
1443               dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
1444               dispatch_release (group);
1445             }
1446 #endif
1447         }
1449       return cache->glyph.matrix[nkeys_or_perm - ROW_PERM_OFFSET][c % 256];
1450     }
1451   else
1452     {
1453       uintptr_t key, value;
1454       int nshifts;
1455       CGGlyph glyph;
1457       if (cache->glyph.dictionary == NULL)
1458         cache->glyph.dictionary =
1459           CFDictionaryCreateMutable (NULL, 0, NULL, NULL);
1460       key = c / NGLYPHS_IN_VALUE;
1461       nshifts = ((c % NGLYPHS_IN_VALUE) * sizeof (CGGlyph) * 8);
1462       value = (uintptr_t) CFDictionaryGetValue (cache->glyph.dictionary,
1463                                                 (const void *) key);
1464       glyph = (value >> nshifts);
1465       if (glyph == 0)
1466         {
1467           UniChar unichars[2];
1468           CGGlyph glyphs[2];
1469           CFIndex count = macfont_store_utf32char_to_unichars (c, unichars);
1471           if (mac_font_get_glyphs_for_characters (macfont, unichars, glyphs,
1472                                                   count))
1473             glyph = glyphs[0];
1474           if (glyph == 0)
1475             glyph = kCGFontIndexInvalid;
1477           value |= ((uintptr_t) glyph << nshifts);
1478           CFDictionarySetValue (cache->glyph.dictionary,
1479                                 (const void *) key, (const void *) value);
1480         }
1482       return glyph;
1483     }
1486 static CGGlyph
1487 macfont_get_glyph_for_cid (struct font *font, CharacterCollection collection,
1488                            CGFontIndex cid)
1490   struct macfont_info *macfont_info = (struct macfont_info *) font;
1491   FontRef macfont = macfont_info->macfont;
1493   /* Cache it? */
1494   return mac_font_get_glyph_for_cid (macfont, collection, cid);
1497 static CFDataRef
1498 macfont_get_uvs_table (struct font *font, CharacterCollection *collection)
1500   struct macfont_info *macfont_info = (struct macfont_info *) font;
1501   FontRef macfont = macfont_info->macfont;
1502   struct macfont_cache *cache = macfont_info->cache;
1503   CFDataRef result = NULL;
1505   if (cache->uvs.table == NULL)
1506     {
1507       CFDataRef uvs_table = mac_font_copy_uvs_table (macfont);
1508       CharacterCollection uvs_collection =
1509         MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING;
1511       if (uvs_table == NULL
1512           && mac_font_get_glyph_for_cid (macfont,
1513                                          MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1,
1514                                          6480) != kCGFontIndexInvalid)
1515         {
1516           /* If the glyph for U+4E55 is accessible via its CID 6480,
1517              then we use the Adobe-Japan1 UVS table, which maps a
1518              variation sequence to a CID, as a fallback.  */
1519           static CFDataRef mac_uvs_table_adobe_japan1 = NULL;
1521           if (mac_uvs_table_adobe_japan1 == NULL)
1522             mac_uvs_table_adobe_japan1 =
1523               CFDataCreateWithBytesNoCopy (NULL,
1524                                            mac_uvs_table_adobe_japan1_bytes,
1525                                            sizeof (mac_uvs_table_adobe_japan1_bytes),
1526                                            kCFAllocatorNull);
1527           if (mac_uvs_table_adobe_japan1)
1528             {
1529               uvs_table = CFRetain (mac_uvs_table_adobe_japan1);
1530               uvs_collection = MAC_CHARACTER_COLLECTION_ADOBE_JAPAN1;
1531             }
1532         }
1533       if (uvs_table == NULL)
1534         cache->uvs.table = kCFNull;
1535       else
1536         cache->uvs.table = uvs_table;
1537       cache->uvs.collection = uvs_collection;
1538     }
1540   if (cache->uvs.table != kCFNull)
1541     {
1542       result = cache->uvs.table;
1543       *collection = cache->uvs.collection;
1544     }
1546   return result;
1549 static Lisp_Object macfont_get_cache (struct frame *);
1550 static Lisp_Object macfont_list (struct frame *, Lisp_Object);
1551 static Lisp_Object macfont_match (struct frame *, Lisp_Object);
1552 static Lisp_Object macfont_list_family (struct frame *);
1553 static void macfont_free_entity (Lisp_Object);
1554 static Lisp_Object macfont_open (struct frame *, Lisp_Object, int);
1555 static void macfont_close (struct font *);
1556 static int macfont_has_char (Lisp_Object, int);
1557 static unsigned macfont_encode_char (struct font *, int);
1558 static int macfont_text_extents (struct font *, unsigned int *, int,
1559                                  struct font_metrics *);
1560 static int macfont_draw (struct glyph_string *, int, int, int, int, bool);
1561 static Lisp_Object macfont_shape (Lisp_Object);
1562 static int macfont_variation_glyphs (struct font *, int c,
1563                                      unsigned variations[256]);
1564 static void macfont_filter_properties (Lisp_Object, Lisp_Object);
1566 static struct font_driver macfont_driver =
1567   {
1568     LISP_INITIALLY_ZERO,        /* Qmac_ct */
1569     0,                          /* case insensitive */
1570     macfont_get_cache,
1571     macfont_list,
1572     macfont_match,
1573     macfont_list_family,
1574     macfont_free_entity,
1575     macfont_open,
1576     macfont_close,
1577     NULL,                       /* prepare_face */
1578     NULL,                       /* done_face */
1579     macfont_has_char,
1580     macfont_encode_char,
1581     macfont_text_extents,
1582     macfont_draw,
1583     NULL,                       /* get_bitmap */
1584     NULL,                       /* free_bitmap */
1585     NULL,                       /* get_outline */
1586     NULL,                       /* free_outline */
1587     NULL,                       /* anchor_point */
1588     NULL,                       /* otf_capability */
1589     NULL,                       /* otf_drive */
1590     NULL,                       /* start_for_frame */
1591     NULL,                       /* end_for_frame */
1592     macfont_shape,
1593     NULL,                       /* check */
1594     macfont_variation_glyphs,
1595     macfont_filter_properties,
1596   };
1598 static Lisp_Object
1599 macfont_get_cache (struct frame * f)
1601   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
1603   return (dpyinfo->name_list_element);
1606 static int
1607 macfont_get_charset (Lisp_Object registry)
1609   char *str = SSDATA (SYMBOL_NAME (registry));
1610   char *re = alloca (SBYTES (SYMBOL_NAME (registry)) * 2 + 1);
1611   Lisp_Object regexp;
1612   int i, j;
1614   for (i = j = 0; i < SBYTES (SYMBOL_NAME (registry)); i++, j++)
1615     {
1616       if (str[i] == '.')
1617         re[j++] = '\\';
1618       else if (str[i] == '*')
1619         re[j++] = '.';
1620       re[j] = str[i];
1621       if (re[j] == '?')
1622         re[j] = '.';
1623     }
1624   re[j] = '\0';
1625   regexp = make_unibyte_string (re, j);
1626   for (i = 0; cf_charset_table[i].name; i++)
1627     if (fast_c_string_match_ignore_case
1628         (regexp, cf_charset_table[i].name,
1629          strlen (cf_charset_table[i].name)) >= 0)
1630       break;
1631   if (! cf_charset_table[i].name)
1632     return -1;
1633   if (! cf_charset_table[i].cf_charset)
1634     {
1635       int *uniquifier = cf_charset_table[i].uniquifier;
1636       UniChar *unichars = alloca (sizeof (cf_charset_table[i].uniquifier));
1637       CFIndex count = 0;
1638       CFStringRef string;
1639       CFMutableCharacterSetRef charset = CFCharacterSetCreateMutable (NULL);
1641       if (! charset)
1642         return -1;
1643       for (j = 0; uniquifier[j]; j++)
1644         {
1645           count += macfont_store_utf32char_to_unichars (uniquifier[j],
1646                                                         unichars + count);
1647           CFCharacterSetAddCharactersInRange (charset,
1648                                               CFRangeMake (uniquifier[j], 1));
1649         }
1651       string = CFStringCreateWithCharacters (NULL, unichars, count);
1652       if (! string)
1653         {
1654           CFRelease (charset);
1655           return -1;
1656         }
1657       cf_charset_table[i].cf_charset = CFCharacterSetCreateCopy (NULL,
1658                                                                  charset);
1659       CFRelease (charset);
1660       /* CFCharacterSetCreateWithCharactersInString does not handle
1661          surrogate pairs properly as of Mac OS X 10.5.  */
1662      cf_charset_table[i].cf_charset_string = string;
1663     }
1664   return i;
1667 struct OpenTypeSpec
1669   Lisp_Object script;
1670   unsigned int script_tag, langsys_tag;
1671   int nfeatures[2];
1672   unsigned int *features[2];
1675 #define OTF_SYM_TAG(SYM, TAG)                                   \
1676   do {                                                          \
1677     unsigned char *p = SDATA (SYMBOL_NAME (SYM));               \
1678     TAG = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];     \
1679   } while (0)
1681 #define OTF_TAG_STR(TAG, P)                     \
1682   do {                                          \
1683     (P)[0] = (char) (TAG >> 24);                \
1684     (P)[1] = (char) ((TAG >> 16) & 0xFF);       \
1685     (P)[2] = (char) ((TAG >> 8) & 0xFF);        \
1686     (P)[3] = (char) (TAG & 0xFF);               \
1687     (P)[4] = '\0';                              \
1688   } while (0)
1690 static struct OpenTypeSpec *
1691 macfont_get_open_type_spec (Lisp_Object otf_spec)
1693   struct OpenTypeSpec *spec = xmalloc (sizeof *spec);
1694   Lisp_Object val;
1695   int i, j;
1696   bool negative;
1698   if (! spec)
1699     return NULL;
1700   spec->script = XCAR (otf_spec);
1701   if (! NILP (spec->script))
1702     {
1703       OTF_SYM_TAG (spec->script, spec->script_tag);
1704       val = assq_no_quit (spec->script, Votf_script_alist);
1705       if (CONSP (val) && SYMBOLP (XCDR (val)))
1706         spec->script = XCDR (val);
1707       else
1708         spec->script = Qnil;
1709     }
1710   else
1711     spec->script_tag = 0x44464C54;      /* "DFLT" */
1712   otf_spec = XCDR (otf_spec);
1713   spec->langsys_tag = 0;
1714   if (! NILP (otf_spec))
1715     {
1716       val = XCAR (otf_spec);
1717       if (! NILP (val))
1718         OTF_SYM_TAG (val, spec->langsys_tag);
1719       otf_spec = XCDR (otf_spec);
1720     }
1721   spec->nfeatures[0] = spec->nfeatures[1] = 0;
1722   for (i = 0; i < 2 && ! NILP (otf_spec); i++, otf_spec = XCDR (otf_spec))
1723     {
1724       Lisp_Object len;
1726       val = XCAR (otf_spec);
1727       if (NILP (val))
1728         continue;
1729       len = Flength (val);
1730       spec->features[i] =
1731         (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (int) < XINT (len)
1732          ? 0
1733          : malloc (XINT (len) * sizeof *spec->features[i]));
1734       if (! spec->features[i])
1735         {
1736           if (i > 0 && spec->features[0])
1737             free (spec->features[0]);
1738           free (spec);
1739           return NULL;
1740         }
1741       for (j = 0, negative = 0; CONSP (val); val = XCDR (val))
1742         {
1743           if (NILP (XCAR (val)))
1744             negative = 1;
1745           else
1746             {
1747               unsigned int tag;
1749               OTF_SYM_TAG (XCAR (val), tag);
1750               spec->features[i][j++] = negative ? tag & 0x80000000 : tag;
1751             }
1752         }
1753       spec->nfeatures[i] = j;
1754     }
1755   return spec;
1758 static CFMutableDictionaryRef
1759 macfont_create_attributes_with_spec (Lisp_Object spec)
1761   Lisp_Object tmp, extra;
1762   CFMutableArrayRef langarray = NULL;
1763   CFCharacterSetRef charset = NULL;
1764   CFStringRef charset_string = NULL;
1765   CFMutableDictionaryRef attributes = NULL, traits = NULL;
1766   Lisp_Object script = Qnil;
1767   Lisp_Object registry;
1768   int cf_charset_idx, i;
1769   struct OpenTypeSpec *otspec = NULL;
1770   struct {
1771     enum font_property_index index;
1772     CFStringRef trait;
1773     CGPoint points[6];
1774   } numeric_traits[] =
1775       {{FONT_WEIGHT_INDEX, MAC_FONT_WEIGHT_TRAIT,
1776         {{-0.4, 50},            /* light */
1777          {-0.24, 87.5},         /* (semi-light + normal) / 2 */
1778          {0, 100},              /* normal */
1779          {0.24, 140},           /* (semi-bold + normal) / 2 */
1780          {0.4, 200},            /* bold */
1781          {CGFLOAT_MAX, CGFLOAT_MAX}}},
1782        {FONT_SLANT_INDEX, MAC_FONT_SLANT_TRAIT,
1783         {{0, 100}, {0.1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}},
1784        {FONT_WIDTH_INDEX, MAC_FONT_WIDTH_TRAIT,
1785         {{0, 100}, {1, 200}, {CGFLOAT_MAX, CGFLOAT_MAX}}}};
1787   registry = AREF (spec, FONT_REGISTRY_INDEX);
1788   if (NILP (registry)
1789       || EQ (registry, Qascii_0)
1790       || EQ (registry, Qiso10646_1)
1791       || EQ (registry, Qunicode_bmp))
1792     cf_charset_idx = -1;
1793   else
1794     {
1795       CFStringRef lang;
1797       cf_charset_idx = macfont_get_charset (registry);
1798       if (cf_charset_idx < 0)
1799         goto err;
1800       charset = cf_charset_table[cf_charset_idx].cf_charset;
1801       charset_string = cf_charset_table[cf_charset_idx].cf_charset_string;
1802       lang = cf_charset_table[cf_charset_idx].lang;
1803       if (lang)
1804         {
1805           langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1806           if (! langarray)
1807             goto err;
1808           CFArrayAppendValue (langarray, lang);
1809         }
1810     }
1812   for (extra = AREF (spec, FONT_EXTRA_INDEX);
1813        CONSP (extra); extra = XCDR (extra))
1814     {
1815       Lisp_Object key, val;
1817       tmp = XCAR (extra);
1818       key = XCAR (tmp), val = XCDR (tmp);
1819       if (EQ (key, QClang))
1820         {
1821           if (! langarray)
1822             langarray = CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
1823           if (! langarray)
1824             goto err;
1825           if (SYMBOLP (val))
1826             val = list1 (val);
1827           for (; CONSP (val); val = XCDR (val))
1828             if (SYMBOLP (XCAR (val)))
1829               {
1830                 CFStringRef lang =
1831                   cfstring_create_with_string_noencode (SYMBOL_NAME
1832                                                         (XCAR (val)));
1834                 if (lang == NULL)
1835                   goto err;
1836                 CFArrayAppendValue (langarray, lang);
1837                 CFRelease (lang);
1838               }
1839         }
1840       else if (EQ (key, QCotf))
1841         {
1842           otspec = macfont_get_open_type_spec (val);
1843           if (! otspec)
1844             goto err;
1845           script = otspec->script;
1846         }
1847       else if (EQ (key, QCscript))
1848         script = val;
1849     }
1851   if (! NILP (script) && ! charset)
1852     {
1853       Lisp_Object chars = assq_no_quit (script, Vscript_representative_chars);
1855       if (CONSP (chars) && CONSP (CDR (chars)))
1856         {
1857           CFMutableStringRef string = CFStringCreateMutable (NULL, 0);
1858           CFMutableCharacterSetRef cs = CFCharacterSetCreateMutable (NULL);
1860           if (! string || !cs)
1861             {
1862               if (string)
1863                 CFRelease (string);
1864               else if (cs)
1865                 CFRelease (cs);
1866               goto err;
1867             }
1868           for (chars = XCDR (chars); CONSP (chars); chars = XCDR (chars))
1869             if (CHARACTERP (XCAR (chars)))
1870               {
1871                 UniChar unichars[2];
1872                 CFIndex count =
1873                   macfont_store_utf32char_to_unichars (XFASTINT (XCAR (chars)),
1874                                                        unichars);
1875                 CFRange range = CFRangeMake (XFASTINT (XCAR (chars)), 1);
1877                 CFStringAppendCharacters (string, unichars, count);
1878                 CFCharacterSetAddCharactersInRange (cs, range);
1879               }
1880           charset = cs;
1881           /* CFCharacterSetCreateWithCharactersInString does not
1882              handle surrogate pairs properly as of Mac OS X 10.5.  */
1883           charset_string = string;
1884         }
1885     }
1887   attributes = CFDictionaryCreateMutable (NULL, 0,
1888                                           &kCFTypeDictionaryKeyCallBacks,
1889                                           &kCFTypeDictionaryValueCallBacks);
1890   if (! attributes)
1891     goto err;
1893   tmp = AREF (spec, FONT_FAMILY_INDEX);
1894   if (SYMBOLP (tmp) && ! NILP (tmp))
1895     {
1896       CFStringRef family = macfont_create_family_with_symbol (tmp);
1898       if (! family)
1899         goto err;
1900       CFDictionaryAddValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
1901                             family);
1902       CFRelease (family);
1903     }
1905   traits = CFDictionaryCreateMutable (NULL, 4,
1906                                       &kCFTypeDictionaryKeyCallBacks,
1907                                       &kCFTypeDictionaryValueCallBacks);
1908   if (! traits)
1909     goto err;
1911   for (i = 0; i < sizeof (numeric_traits) / sizeof (numeric_traits[0]); i++)
1912     {
1913       tmp = AREF (spec, numeric_traits[i].index);
1914       if (INTEGERP (tmp))
1915         {
1916           CGPoint *point = numeric_traits[i].points;
1917           CGFloat floatval = (XINT (tmp) >> 8); // XXX
1918           CFNumberRef num;
1920           while (point->y < floatval)
1921             point++;
1922           if (point == numeric_traits[i].points)
1923             point++;
1924           else if (point->y == CGFLOAT_MAX)
1925             point--;
1926           floatval = (point - 1)->x + ((floatval - (point - 1)->y)
1927                                        * ((point->x - (point - 1)->x)
1928                                           / (point->y - (point - 1)->y)));
1929           if (floatval > 1.0)
1930             floatval = 1.0;
1931           else if (floatval < -1.0)
1932             floatval = -1.0;
1933           num = CFNumberCreate (NULL, kCFNumberCGFloatType, &floatval);
1934           if (! num)
1935             goto err;
1936           CFDictionaryAddValue (traits, numeric_traits[i].trait, num);
1937           CFRelease (num);
1938         }
1939     }
1940   if (CFDictionaryGetCount (traits))
1941     CFDictionaryAddValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE, traits);
1943   if (charset)
1944     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE,
1945                           charset);
1946   if (charset_string)
1947     CFDictionaryAddValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE,
1948                           charset_string);
1949   if (langarray)
1950     CFDictionaryAddValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE, langarray);
1952   goto finish;
1954  err:
1955   if (attributes)
1956     {
1957       CFRelease (attributes);
1958       attributes = NULL;
1959     }
1961  finish:
1962   if (langarray) CFRelease (langarray);
1963   if (charset && cf_charset_idx < 0) CFRelease (charset);
1964   if (charset_string && cf_charset_idx < 0) CFRelease (charset_string);
1965   if (traits) CFRelease (traits);
1966   if (otspec)
1967     {
1968       if (otspec->nfeatures[0] > 0)
1969         free (otspec->features[0]);
1970       if (otspec->nfeatures[1] > 0)
1971         free (otspec->features[1]);
1972       free (otspec);
1973     }
1975   return attributes;
1978 static Boolean
1979 macfont_supports_charset_and_languages_p (FontDescriptorRef desc,
1980                                           CFCharacterSetRef charset,
1981                                           Lisp_Object chars,
1982                                           CFArrayRef languages)
1984   Boolean result = true;
1986   if (charset || VECTORP (chars))
1987     {
1988       CFCharacterSetRef desc_charset =
1989         mac_font_descriptor_copy_attribute (desc,
1990                                             MAC_FONT_CHARACTER_SET_ATTRIBUTE);
1992       if (desc_charset == NULL)
1993         result = false;
1994       else
1995         {
1996           if (charset)
1997             result = CFCharacterSetIsSupersetOfSet (desc_charset, charset);
1998           else                  /* VECTORP (chars) */
1999             {
2000               ptrdiff_t j;
2002               for (j = 0; j < ASIZE (chars); j++)
2003                 if (TYPE_RANGED_INTEGERP (UTF32Char, AREF (chars, j))
2004                     && CFCharacterSetIsLongCharacterMember (desc_charset,
2005                                                             XFASTINT (AREF (chars, j))))
2006                   break;
2007               if (j == ASIZE (chars))
2008                 result = false;
2009             }
2010           CFRelease (desc_charset);
2011         }
2012     }
2013   if (result && languages)
2014     result = mac_font_descriptor_supports_languages (desc, languages);
2016   return result;
2019 static CFIndex
2020 macfont_closest_traits_index (CFArrayRef traits_array,
2021                               FontSymbolicTraits target)
2023   CFIndex i, result = -1, count = CFArrayGetCount (traits_array);
2024   int min_distance = (1 << 3);
2026   for (i = 0; i < count; i++)
2027     {
2028       FontSymbolicTraits traits, diff;
2029       int distance = 0;
2031       traits = ((FontSymbolicTraits) (uintptr_t)
2032                 CFArrayGetValueAtIndex (traits_array, i));
2033       diff = (target ^ traits);
2034       /* We prefer synthetic bold of italic to synthetic italic of
2035          bold when both bold and italic are available but bold-italic
2036          is not available.  */
2037       if (diff & MAC_FONT_TRAIT_BOLD)
2038         distance |= (1 << 0);
2039       if (diff & MAC_FONT_TRAIT_ITALIC)
2040         distance |= (1 << 1);
2041       if (diff & MAC_FONT_TRAIT_MONO_SPACE)
2042         distance |= (1 << 2);
2043       if (distance < min_distance)
2044         {
2045           min_distance = distance;
2046           result = i;
2047         }
2048     }
2050   return result;
2053 static Lisp_Object
2054 macfont_list (struct frame *f, Lisp_Object spec)
2056   Lisp_Object val = Qnil, family, extra;
2057   int i, n;
2058   CFStringRef family_name = NULL;
2059   CFMutableDictionaryRef attributes = NULL, traits;
2060   Lisp_Object chars = Qnil;
2061   int spacing = -1;
2062   FontSymbolicTraits synth_sym_traits = 0;
2063   CFArrayRef families;
2064   CFIndex families_count;
2065   CFCharacterSetRef charset = NULL;
2066   CFArrayRef languages = NULL;
2068   block_input ();
2070   family = AREF (spec, FONT_FAMILY_INDEX);
2071   if (! NILP (family))
2072     {
2073       family_name = macfont_create_family_with_symbol (family);
2074       if (family_name == NULL)
2075         goto finish;
2076     }
2078   attributes = macfont_create_attributes_with_spec (spec);
2079   if (! attributes)
2080     goto finish;
2082   languages = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2084   if (INTEGERP (AREF (spec, FONT_SPACING_INDEX)))
2085     spacing = XINT (AREF (spec, FONT_SPACING_INDEX));
2087   traits = ((CFMutableDictionaryRef)
2088             CFDictionaryGetValue (attributes, MAC_FONT_TRAITS_ATTRIBUTE));
2090   n = FONT_SLANT_NUMERIC (spec);
2091   if (n < 0 || n == FONT_SLANT_SYNTHETIC_ITALIC)
2092     {
2093       synth_sym_traits |= MAC_FONT_TRAIT_ITALIC;
2094       if (traits)
2095         CFDictionaryRemoveValue (traits, MAC_FONT_SLANT_TRAIT);
2096     }
2098   n = FONT_WEIGHT_NUMERIC (spec);
2099   if (n < 0 || n == FONT_WEIGHT_SYNTHETIC_BOLD)
2100     {
2101       synth_sym_traits |= MAC_FONT_TRAIT_BOLD;
2102       if (traits)
2103         CFDictionaryRemoveValue (traits, MAC_FONT_WEIGHT_TRAIT);
2104     }
2106   if (languages
2107       && (spacing < 0 || spacing == FONT_SPACING_SYNTHETIC_MONO))
2108     {
2109       CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
2111       if (CFStringHasPrefix (language, CFSTR ("ja"))
2112           || CFStringHasPrefix (language, CFSTR ("ko"))
2113           || CFStringHasPrefix (language, CFSTR ("zh")))
2114         synth_sym_traits |= MAC_FONT_TRAIT_MONO_SPACE;
2115     }
2117   /* Create array of families.  */
2118   if (family_name)
2119     families = CFArrayCreate (NULL, (const void **) &family_name,
2120                               1, &kCFTypeArrayCallBacks);
2121   else
2122     {
2123       CFStringRef pref_family;
2124       CFIndex families_count, pref_family_index = -1;
2126       families = mac_font_create_available_families ();
2127       if (families == NULL)
2128         goto err;
2130       families_count = CFArrayGetCount (families);
2132       /* Move preferred family to the front if exists.  */
2133       pref_family =
2134         mac_font_create_preferred_family_for_attributes (attributes);
2135       if (pref_family)
2136         {
2137           pref_family_index =
2138             CFArrayGetFirstIndexOfValue (families,
2139                                          CFRangeMake (0, families_count),
2140                                          pref_family);
2141           CFRelease (pref_family);
2142         }
2143       if (pref_family_index > 0)
2144         {
2145           CFMutableArrayRef mutable_families =
2146             CFArrayCreateMutable (NULL, families_count, &kCFTypeArrayCallBacks);
2148           if (mutable_families)
2149             {
2150               CFArrayAppendValue (mutable_families,
2151                                   CFArrayGetValueAtIndex (families,
2152                                                           pref_family_index));
2153               CFArrayAppendArray (mutable_families, families,
2154                                   CFRangeMake (0, pref_family_index));
2155               if (pref_family_index + 1 < families_count)
2156                 CFArrayAppendArray (mutable_families, families,
2157                                     CFRangeMake (pref_family_index + 1,
2158                                                  families_count
2159                                                  - (pref_family_index + 1)));
2160               CFRelease (families);
2161               families = mutable_families;
2162             }
2163         }
2164     }
2166   charset = CFDictionaryGetValue (attributes,
2167                                   MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2168   if (charset)
2169     {
2170       CFRetain (charset);
2171       CFDictionaryRemoveValue (attributes, MAC_FONT_CHARACTER_SET_ATTRIBUTE);
2172     }
2173   else
2174     {
2175       val = assq_no_quit (QCscript, AREF (spec, FONT_EXTRA_INDEX));
2176       if (! NILP (val))
2177         {
2178           val = assq_no_quit (XCDR (val), Vscript_representative_chars);
2179           if (CONSP (val) && VECTORP (XCDR (val)))
2180             chars = XCDR (val);
2181         }
2182       val = Qnil;
2183     }
2185   if (languages)
2186     {
2187       CFRetain (languages);
2188       CFDictionaryRemoveValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
2189     }
2191   val = Qnil;
2192   extra = AREF (spec, FONT_EXTRA_INDEX);
2193   families_count = CFArrayGetCount (families);
2194   for (i = 0; i < families_count; i++)
2195     {
2196       CFStringRef family_name = CFArrayGetValueAtIndex (families, i);
2197       FontDescriptorRef pat_desc;
2198       CFArrayRef descs;
2199       CFIndex descs_count;
2200       CFMutableArrayRef filtered_descs, traits_array;
2201       Lisp_Object entity;
2202       int j;
2204       CFDictionarySetValue (attributes, MAC_FONT_FAMILY_NAME_ATTRIBUTE,
2205                             family_name);
2206       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2207       if (! pat_desc)
2208         goto err;
2210       /* CTFontDescriptorCreateMatchingFontDescriptors on Mac OS X
2211          10.7 returns NULL if pat_desc represents the LastResort font.
2212          So we use CTFontDescriptorCreateMatchingFontDescriptor (no
2213          trailing "s") for such a font.  */
2214       if (CFStringCompare (family_name, CFSTR ("LastResort"), 0)
2215           != kCFCompareEqualTo)
2216         descs = mac_font_descriptor_create_matching_font_descriptors (pat_desc,
2217                                                                       NULL);
2218       else
2219         {
2220           FontDescriptorRef lr_desc =
2221             mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2222                                                                  NULL);
2223           if (lr_desc)
2224             {
2225               descs = CFArrayCreate (NULL, (const void **) &lr_desc, 1,
2226                                      &kCFTypeArrayCallBacks);
2227               CFRelease (lr_desc);
2228             }
2229           else
2230             descs = NULL;
2231         }
2232       CFRelease (pat_desc);
2233       if (! descs)
2234         goto err;
2236       descs_count = CFArrayGetCount (descs);
2237       if (descs_count == 0
2238           || !macfont_supports_charset_and_languages_p (CFArrayGetValueAtIndex (descs, 0),
2239                                                         charset, chars,
2240                                                         languages))
2241         {
2242           CFRelease (descs);
2243           continue;
2244         }
2246       filtered_descs =
2247         CFArrayCreateMutable (NULL, descs_count, &kCFTypeArrayCallBacks);
2248       traits_array = CFArrayCreateMutable (NULL, descs_count, NULL);
2249       for (j = 0; j < descs_count; j++)
2250         {
2251           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2252           CFDictionaryRef dict;
2253           CFNumberRef num;
2254           FontSymbolicTraits sym_traits;
2256           dict = mac_font_descriptor_copy_attribute (desc,
2257                                                      MAC_FONT_TRAITS_ATTRIBUTE);
2258           if (dict == NULL)
2259             continue;
2261           num = CFDictionaryGetValue (dict, MAC_FONT_SYMBOLIC_TRAIT);
2262           CFRelease (dict);
2263           if (num == NULL
2264               || !cfnumber_get_font_symbolic_traits_value (num, &sym_traits))
2265             continue;
2267           if (spacing >= 0
2268               && !(synth_sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2269               && (((sym_traits & MAC_FONT_TRAIT_MONO_SPACE) != 0)
2270                   != (spacing >= FONT_SPACING_MONO)))
2271             continue;
2273           /* Don't use a color bitmap font unless its family is
2274              explicitly specified.  */
2275           if ((sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS) && NILP (family))
2276             continue;
2278           if (j > 0
2279               && !macfont_supports_charset_and_languages_p (desc, charset,
2280                                                             chars, languages))
2281             continue;
2283           CFArrayAppendValue (filtered_descs, desc);
2284           CFArrayAppendValue (traits_array,
2285                               (const void *) (uintptr_t) sym_traits);
2286         }
2288       CFRelease (descs);
2289       descs = filtered_descs;
2290       descs_count = CFArrayGetCount (descs);
2292       for (j = 0; j < descs_count; j++)
2293         {
2294           FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, j);
2295           FontSymbolicTraits sym_traits =
2296             ((FontSymbolicTraits) (uintptr_t)
2297              CFArrayGetValueAtIndex (traits_array, j));
2298           FontSymbolicTraits mask_min, mask_max, imask, bmask, mmask;
2300           mask_min = ((synth_sym_traits ^ sym_traits)
2301                       & (MAC_FONT_TRAIT_ITALIC | MAC_FONT_TRAIT_BOLD));
2302           if (FONT_SLANT_NUMERIC (spec) < 0)
2303             mask_min &= ~MAC_FONT_TRAIT_ITALIC;
2304           if (FONT_WEIGHT_NUMERIC (spec) < 0)
2305             mask_min &= ~MAC_FONT_TRAIT_BOLD;
2307           mask_max = (synth_sym_traits & ~sym_traits);
2308           /* Synthetic bold does not work for bitmap-only fonts on Mac
2309              OS X 10.6.  */
2310           if ((mask_min ^ mask_max) & MAC_FONT_TRAIT_BOLD)
2311             {
2312               CFNumberRef format =
2313                 mac_font_descriptor_copy_attribute (desc,
2314                                                     MAC_FONT_FORMAT_ATTRIBUTE);
2316               if (format)
2317                 {
2318                   uint32_t format_val;
2320                   if (CFNumberGetValue (format, kCFNumberSInt32Type,
2321                                         &format_val)
2322                       && format_val == MAC_FONT_FORMAT_BITMAP)
2323                     mask_max &= ~MAC_FONT_TRAIT_BOLD;
2324                 }
2325             }
2326           if (spacing >= 0)
2327             mask_min |= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2329           for (mmask = (mask_min & MAC_FONT_TRAIT_MONO_SPACE);
2330                mmask <= (mask_max & MAC_FONT_TRAIT_MONO_SPACE);
2331                mmask += MAC_FONT_TRAIT_MONO_SPACE)
2332             for (bmask = (mask_min & MAC_FONT_TRAIT_BOLD);
2333                  bmask <= (mask_max & MAC_FONT_TRAIT_BOLD);
2334                  bmask += MAC_FONT_TRAIT_BOLD)
2335               for (imask = (mask_min & MAC_FONT_TRAIT_ITALIC);
2336                    imask <= (mask_max & MAC_FONT_TRAIT_ITALIC);
2337                    imask += MAC_FONT_TRAIT_ITALIC)
2338                 {
2339                   FontSymbolicTraits synth = (imask | bmask | mmask);
2341                   if (synth == 0
2342                       || j == macfont_closest_traits_index (traits_array,
2343                                                             (sym_traits | synth)))
2344                     {
2345                       entity = macfont_descriptor_entity (desc, extra, synth);
2346                       if (! NILP (entity))
2347                         val = Fcons (entity, val);
2348                     }
2349                 }
2350         }
2352       CFRelease (traits_array);
2353       CFRelease (descs);
2354     }
2356   CFRelease (families);
2357   val = Fnreverse (val);
2358   goto finish;
2359  err:
2360   val = Qnil;
2362  finish:
2363   FONT_ADD_LOG ("macfont-list", spec, val);
2364   if (charset) CFRelease (charset);
2365   if (languages) CFRelease (languages);
2366   if (attributes) CFRelease (attributes);
2367   if (family_name) CFRelease (family_name);
2369   unblock_input ();
2371   return val;
2374 static Lisp_Object
2375 macfont_match (struct frame * frame, Lisp_Object spec)
2377   Lisp_Object entity = Qnil;
2378   CFMutableDictionaryRef attributes;
2379   FontDescriptorRef pat_desc = NULL, desc = NULL;
2381   block_input ();
2383   attributes = macfont_create_attributes_with_spec (spec);
2384   if (attributes)
2385     {
2386       pat_desc = mac_font_descriptor_create_with_attributes (attributes);
2387       CFRelease (attributes);
2388     }
2389   if (pat_desc)
2390     {
2391       desc = mac_font_descriptor_create_matching_font_descriptor (pat_desc,
2392                                                                   NULL);
2393       CFRelease (pat_desc);
2394     }
2395   if (desc)
2396     {
2397       entity = macfont_descriptor_entity (desc, AREF (spec, FONT_EXTRA_INDEX),
2398                                           0);
2399       CFRelease (desc);
2400     }
2401   unblock_input ();
2403   FONT_ADD_LOG ("macfont-match", spec, entity);
2404   return entity;
2407 static Lisp_Object
2408 macfont_list_family (struct frame *frame)
2410   Lisp_Object list = Qnil;
2411   CFArrayRef families;
2413   block_input ();
2415   families = mac_font_create_available_families ();
2416   if (families)
2417     {
2418       CFIndex i, count = CFArrayGetCount (families);
2420       for (i = 0; i < count; i++)
2421         list = Fcons (macfont_intern_prop_cfstring (CFArrayGetValueAtIndex (families, i)), list);
2422       CFRelease (families);
2423     }
2425   unblock_input ();
2427   return list;
2430 static void
2431 macfont_free_entity (Lisp_Object entity)
2433   Lisp_Object val = assq_no_quit (QCfont_entity,
2434                                   AREF (entity, FONT_EXTRA_INDEX));
2435   CFStringRef name = XSAVE_POINTER (XCDR (val), 0);
2437   block_input ();
2438   CFRelease (name);
2439   unblock_input ();
2442 static Lisp_Object
2443 macfont_open (struct frame * f, Lisp_Object entity, int pixel_size)
2445   Lisp_Object val, font_object;
2446   CFStringRef font_name;
2447   struct macfont_info *macfont_info = NULL;
2448   struct font *font;
2449   int size;
2450   FontRef macfont;
2451   FontSymbolicTraits sym_traits;
2452   char name[256];
2453   int len, i, total_width;
2454   CGGlyph glyph;
2455   CGFloat ascent, descent, leading;
2457   val = assq_no_quit (QCfont_entity, AREF (entity, FONT_EXTRA_INDEX));
2458   if (! CONSP (val)
2459       || XTYPE (XCDR (val)) != Lisp_Misc
2460       || XMISCTYPE (XCDR (val)) != Lisp_Misc_Save_Value)
2461     return Qnil;
2462   font_name = XSAVE_POINTER (XCDR (val), 0);
2463   sym_traits = XSAVE_INTEGER (XCDR (val), 1);
2465   size = XINT (AREF (entity, FONT_SIZE_INDEX));
2466   if (size == 0)
2467     size = pixel_size;
2469   block_input ();
2470   macfont = mac_font_create_with_name (font_name, size);
2471   if (macfont)
2472     {
2473       int fontsize = (int) [((NSFont *) macfont) pointSize];
2474       if (fontsize != size) size = fontsize;
2475     }
2476   unblock_input ();
2477   if (! macfont)
2478     return Qnil;
2480   font_object = font_make_object (VECSIZE (struct macfont_info), entity, size);
2481   ASET (font_object, FONT_TYPE_INDEX, macfont_driver.type);
2482   len = font_unparse_xlfd (entity, size, name, 256);
2483   if (len > 0)
2484     ASET (font_object, FONT_NAME_INDEX, make_string (name, len));
2485   len = font_unparse_fcname (entity, size, name, 256);
2486   if (len > 0)
2487     ASET (font_object, FONT_FULLNAME_INDEX, make_string (name, len));
2488   else
2489     ASET (font_object, FONT_FULLNAME_INDEX,
2490           AREF (font_object, FONT_NAME_INDEX));
2491   font = XFONT_OBJECT (font_object);
2492   font->pixel_size = size;
2493   font->driver = &macfont_driver;
2494   font->encoding_charset = font->repertory_charset = -1;
2496   block_input ();
2498   macfont_info = (struct macfont_info *) font;
2499   macfont_info->macfont = macfont;
2500   macfont_info->cgfont = mac_font_copy_graphics_font (macfont);
2502   val = assq_no_quit (QCdestination, AREF (entity, FONT_EXTRA_INDEX));
2503   if (CONSP (val) && EQ (XCDR (val), make_number (1)))
2504     macfont_info->screen_font = mac_screen_font_create_with_name (font_name,
2505                                                                   size);
2506   else
2507     macfont_info->screen_font = NULL;
2508   macfont_info->cache = macfont_lookup_cache (font_name);
2509   macfont_retain_cache (macfont_info->cache);
2510   macfont_info->metrics = NULL;
2511   macfont_info->metrics_nrows = 0;
2512   macfont_info->synthetic_italic_p = 0;
2513   macfont_info->synthetic_bold_p = 0;
2514   macfont_info->spacing = MACFONT_SPACING_PROPORTIONAL;
2515   macfont_info->antialias = MACFONT_ANTIALIAS_DEFAULT;
2516   if (!(sym_traits & MAC_FONT_TRAIT_ITALIC)
2517       && FONT_SLANT_NUMERIC (entity) == FONT_SLANT_SYNTHETIC_ITALIC)
2518     macfont_info->synthetic_italic_p = 1;
2519   if (!(sym_traits & MAC_FONT_TRAIT_BOLD)
2520       && FONT_WEIGHT_NUMERIC (entity) == FONT_WEIGHT_SYNTHETIC_BOLD)
2521     macfont_info->synthetic_bold_p = 1;
2522   if (sym_traits & MAC_FONT_TRAIT_MONO_SPACE)
2523     macfont_info->spacing = MACFONT_SPACING_MONO;
2524   else if (INTEGERP (AREF (entity, FONT_SPACING_INDEX))
2525            && (XINT (AREF (entity, FONT_SPACING_INDEX))
2526                == FONT_SPACING_SYNTHETIC_MONO))
2527     macfont_info->spacing = MACFONT_SPACING_SYNTHETIC_MONO;
2528   if (macfont_info->synthetic_italic_p || macfont_info->synthetic_bold_p)
2529     macfont_info->antialias = MACFONT_ANTIALIAS_ON;
2530   else
2531     {
2532       val = assq_no_quit (QCantialias, AREF (entity, FONT_EXTRA_INDEX));
2533       if (CONSP (val))
2534         macfont_info->antialias =
2535           NILP (XCDR (val)) ? MACFONT_ANTIALIAS_OFF : MACFONT_ANTIALIAS_ON;
2536     }
2537   macfont_info->color_bitmap_p = 0;
2538   if (sym_traits & MAC_FONT_TRAIT_COLOR_GLYPHS)
2539     macfont_info->color_bitmap_p = 1;
2541   glyph = macfont_get_glyph_for_character (font, ' ');
2542   if (glyph != kCGFontIndexInvalid)
2543     font->space_width = macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2544   else
2545     /* dirty workaround */
2546     font->space_width = pixel_size;
2548   total_width = font->space_width;
2549   for (i = 1; i < 95; i++)
2550     {
2551       glyph = macfont_get_glyph_for_character (font, ' ' + i);
2552       if (glyph == kCGFontIndexInvalid)
2553         break;
2554       total_width += macfont_glyph_extents (font, glyph, NULL, NULL, 0);
2555     }
2556   if (i == 95)
2557     font->average_width = total_width / 95;
2558   else
2559     font->average_width = font->space_width; /* XXX */
2561   if (!(macfont_info->screen_font
2562         && mac_screen_font_get_metrics (macfont_info->screen_font,
2563                                         &ascent, &descent, &leading)))
2564     {
2565       CFStringRef family_name;
2567       ascent = mac_font_get_ascent (macfont);
2568       descent = mac_font_get_descent (macfont);
2569       leading = mac_font_get_leading (macfont);
2570       /* AppKit and WebKit do some adjustment to the heights of
2571          Courier, Helvetica, and Times.  */
2572       family_name = mac_font_copy_family_name (macfont);
2573       if (family_name)
2574         {
2575           if ((CFStringCompare (family_name, CFSTR ("Courier"), 0)
2576                == kCFCompareEqualTo)
2577               || (CFStringCompare (family_name, CFSTR ("Helvetica"), 0)
2578                   == kCFCompareEqualTo)
2579               || (CFStringCompare (family_name, CFSTR ("Times"), 0)
2580                   == kCFCompareEqualTo))
2581             ascent += (ascent + descent) * .15f;
2582           else if (CFStringHasPrefix (family_name, CFSTR ("Hiragino")))
2583             {
2584               leading *= .25f;
2585               ascent += leading;
2586             }
2587           CFRelease (family_name);
2588         }
2589     }
2590   font->ascent = ascent + 0.5f;
2591   val = assq_no_quit (QCminspace, AREF (entity, FONT_EXTRA_INDEX));
2592   if (CONSP (val) && !NILP (XCDR (val)))
2593     font->descent = descent + 0.5f;
2594   else
2595     font->descent = descent + leading + 0.5f;
2596   font->height = font->ascent + font->descent;
2598   font->underline_position = - mac_font_get_underline_position (macfont) + 0.5f;
2599   font->underline_thickness = mac_font_get_underline_thickness (macfont) + 0.5f;
2601   unblock_input ();
2603   /* Unfortunately Xft doesn't provide a way to get minimum char
2604      width.  So, we use space_width instead.  */
2605   font->min_width = font->max_width = font->space_width; /* XXX */
2607   font->baseline_offset = 0;
2608   font->relative_compose = 0;
2609   font->default_ascent = 0;
2610   font->vertical_centering = 0;
2612   return font_object;
2615 static void
2616 macfont_close (struct font *font)
2618   struct macfont_info *macfont_info = (struct macfont_info *) font;
2619   int i;
2621   block_input ();
2622   CFRelease (macfont_info->macfont);
2623   CGFontRelease (macfont_info->cgfont);
2624   if (macfont_info->screen_font)
2625     CFRelease (macfont_info->screen_font);
2626   macfont_release_cache (macfont_info->cache);
2627   for (i = 0; i < macfont_info->metrics_nrows; i++)
2628     if (macfont_info->metrics[i])
2629       xfree (macfont_info->metrics[i]);
2630   if (macfont_info->metrics)
2631     xfree (macfont_info->metrics);
2632   unblock_input ();
2635 static int
2636 macfont_has_char (Lisp_Object font, int c)
2638   int result;
2639   CFCharacterSetRef charset;
2641   block_input ();
2642   if (FONT_ENTITY_P (font))
2643     {
2644       Lisp_Object val;
2645       CFStringRef name;
2647       val = assq_no_quit (QCfont_entity, AREF (font, FONT_EXTRA_INDEX));
2648       val = XCDR (val);
2649       name = XSAVE_POINTER (val, 0);
2650       charset = macfont_get_cf_charset_for_name (name);
2651     }
2652   else
2653     charset = macfont_get_cf_charset (XFONT_OBJECT (font));
2655   result = CFCharacterSetIsLongCharacterMember (charset, c);
2656   unblock_input ();
2658   return result;
2661 static unsigned
2662 macfont_encode_char (struct font *font, int c)
2664   struct macfont_info *macfont_info = (struct macfont_info *) font;
2665   CGGlyph glyph;
2667   block_input ();
2668   glyph = macfont_get_glyph_for_character (font, c);
2669   unblock_input ();
2671   return glyph != kCGFontIndexInvalid ? glyph : FONT_INVALID_CODE;
2674 static int
2675 macfont_text_extents (struct font *font, unsigned int *code, int nglyphs,
2676                       struct font_metrics *metrics)
2678   int width, i;
2680   block_input ();
2681   width = macfont_glyph_extents (font, code[0], metrics, NULL, 0);
2682   for (i = 1; i < nglyphs; i++)
2683     {
2684       struct font_metrics m;
2685       int w = macfont_glyph_extents (font, code[i], metrics ? &m : NULL,
2686                                      NULL, 0);
2688       if (metrics)
2689         {
2690           if (width + m.lbearing < metrics->lbearing)
2691             metrics->lbearing = width + m.lbearing;
2692           if (width + m.rbearing > metrics->rbearing)
2693             metrics->rbearing = width + m.rbearing;
2694           if (m.ascent > metrics->ascent)
2695             metrics->ascent = m.ascent;
2696           if (m.descent > metrics->descent)
2697             metrics->descent = m.descent;
2698         }
2699       width += w;
2700     }
2701   unblock_input ();
2703   if (metrics)
2704     metrics->width = width;
2706   return width;
2709 static int
2710 macfont_draw (struct glyph_string *s, int from, int to, int x, int y,
2711               bool with_background)
2713   struct frame * f = s->f;
2714   struct macfont_info *macfont_info = (struct macfont_info *) s->font;
2715   FontRef macfont = macfont_info->macfont;
2716   CGContextRef context;
2717   BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
2718   int end = isComposite ? s->cmp_to : s->nchars;
2719   int len = end - s->cmp_from;
2720   struct face *face = s->face;
2721   int i;
2723   block_input ();
2725   context = [[NSGraphicsContext currentContext] graphicsPort];
2726   CGContextSaveGState (context);
2728 #if 0
2729   if (s->num_clips > 0)
2730     {
2731       CGRect clips[2];
2733       for (i = 0; i < s->num_clips; i++)
2734         clips[i] = mac_rect_make (f, s->clip[i].left, s->clip[i].top,
2735                                   s->clip[i].right - s->clip[i].left,
2736                                   s->clip[i].bottom - s->clip[i].top);
2737       CGContextClipToRects (context, clips, s->num_clips);
2738     }
2739 #endif
2741   if (with_background)
2742     {
2743       if (s->hl == DRAW_MOUSE_FACE) 
2744         {
2745           face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2746           if (!face)
2747             face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2748         }
2750       CG_SET_FILL_COLOR_WITH_FACE_BACKGROUND (context, face, f);
2751       CGContextFillRect (context,
2752                          CGRectMake (x, y,
2753                                      s->width, FONT_HEIGHT (s->font)));
2754     }
2756   if (macfont_info->cgfont)
2757     {
2758       CGGlyph *glyphs = alloca (sizeof (CGGlyph) * len);
2759       CGPoint *positions = alloca (sizeof (CGPoint) * len);
2760       CGFloat total_width = 0;
2761       CGFloat font_size = mac_font_get_size (macfont);
2762       CGAffineTransform atfm;
2763       CGFloat advance_delta = 0;
2764       int y_draw = -s->ybase;
2765       int no_antialias_p =
2766         (macfont_info->antialias == MACFONT_ANTIALIAS_OFF
2767          || (macfont_info->antialias == MACFONT_ANTIALIAS_DEFAULT
2768              && font_size <= macfont_antialias_threshold));
2770       for (i = 0; i < len; i++)
2771         {
2772           int width;
2774           glyphs[i] = *(s->char2b + s->cmp_from + i);
2775           width = (s->padding_p ? 1
2776                    : macfont_glyph_extents (s->font, glyphs[i],
2777                                             NULL, &advance_delta,
2778                                             no_antialias_p));
2779           positions[i].x = total_width + advance_delta;
2780           positions[i].y = 0;
2781           total_width += width;
2782         }
2784       CGContextScaleCTM (context, 1, -1);
2785       CG_SET_FILL_COLOR_WITH_FACE_FOREGROUND (context, face, s->f);
2786       if (macfont_info->synthetic_italic_p)
2787         atfm = synthetic_italic_atfm;
2788       else
2789         atfm = CGAffineTransformIdentity;
2790       if (macfont_info->synthetic_bold_p)
2791         {
2792           CGContextSetTextDrawingMode (context, kCGTextFillStroke);
2793           CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
2794           CG_SET_STROKE_COLOR_WITH_FACE_FOREGROUND (context, face, f);
2795         }
2796       if (no_antialias_p)
2797         CGContextSetShouldAntialias (context, false);
2799       CGContextSetTextMatrix (context, atfm);
2800       CGContextSetTextPosition (context, x, y_draw);
2802 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
2803       if (macfont_info->color_bitmap_p
2804 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
2805           && CTFontDrawGlyphs != NULL
2806 #endif
2807           )
2808         {
2809           if (len > 0)
2810             {
2811               CTFontDrawGlyphs (macfont, glyphs, positions, len, context);
2812             }
2813         }
2814       else
2815 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
2816         {
2817           CGContextSetFont (context, macfont_info->cgfont);
2818           CGContextSetFontSize (context, font_size);
2819           CGContextShowGlyphsAtPositions (context, glyphs, positions, len);
2820         }
2821     }
2823   CGContextRestoreGState (context);
2825   unblock_input ();
2827   return len;
2830 static Lisp_Object
2831 macfont_shape (Lisp_Object lgstring)
2833   struct font *font;
2834   struct macfont_info *macfont_info;
2835   FontRef macfont;
2836   ptrdiff_t glyph_len, len, i, j;
2837   CFIndex nonbmp_len;
2838   UniChar *unichars;
2839   CFIndex *nonbmp_indices;
2840   CFStringRef string;
2841   CFIndex used = 0;
2842   struct mac_glyph_layout *glyph_layouts;
2844   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2845   macfont_info = (struct macfont_info *) font;
2846   macfont = macfont_info->macfont;
2848   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2849   nonbmp_len = 0;
2850   for (i = 0; i < glyph_len; i++)
2851     {
2852       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2854       if (NILP (lglyph))
2855         break;
2856       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2857         nonbmp_len++;
2858     }
2860   len = i;
2862   if (INT_MAX / 2 < len)
2863     memory_full (SIZE_MAX);
2865   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2866   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2867   for (i = j = 0; i < len; i++)
2868     {
2869       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2871       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2872         {
2873           nonbmp_indices[j] = i + j;
2874           j++;
2875         }
2876     }
2877   nonbmp_indices[j] = len + j;  /* sentinel */
2879   block_input ();
2881   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2882                                                kCFAllocatorNull);
2883   if (string)
2884     {
2885       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2886       if (macfont_info->screen_font)
2887         used = mac_screen_font_shape (macfont_info->screen_font, string,
2888                                       glyph_layouts, glyph_len);
2889       else
2890         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2891       CFRelease (string);
2892     }
2894   unblock_input ();
2896   if (used == 0)
2897     return Qnil;
2899   block_input ();
2901   for (i = 0; i < used; i++)
2902     {
2903       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2904       struct mac_glyph_layout *gl = glyph_layouts + i;
2905       EMACS_INT from, to;
2906       struct font_metrics metrics;
2907       int xoff, yoff, wadjust;
2909       if (NILP (lglyph))
2910         {
2911           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2912           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2913         }
2915       from = gl->comp_range.location;
2916       /* Convert UTF-16 index to UTF-32.  */
2917       j = 0;
2918       while (nonbmp_indices[j] < from)
2919         j++;
2920       from -= j;
2921       LGLYPH_SET_FROM (lglyph, from);
2923       to = gl->comp_range.location + gl->comp_range.length;
2924       /* Convert UTF-16 index to UTF-32.  */
2925       while (nonbmp_indices[j] < to)
2926         j++;
2927       to -= j;
2928       LGLYPH_SET_TO (lglyph, to - 1);
2930       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2931          the composition is trivial.  */
2932       {
2933         UTF32Char c;
2935         if (unichars[gl->string_index] >= 0xD800
2936             && unichars[gl->string_index] < 0xDC00)
2937           c = (((unichars[gl->string_index] - 0xD800) << 10)
2938                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2939         else
2940           c = unichars[gl->string_index];
2941         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2942           c = 0;
2943         LGLYPH_SET_CHAR (lglyph, c);
2944       }
2946       {
2947         unsigned long cc = gl->glyph_id;
2948         LGLYPH_SET_CODE (lglyph, cc);
2949       }
2951       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2952       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2953       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2954       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2955       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2956       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2958       xoff = lround (gl->advance_delta);
2959       yoff = lround (- gl->baseline_delta);
2960       wadjust = lround (gl->advance);
2961       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2962         {
2963           Lisp_Object vec;
2965           vec = Fmake_vector (make_number (3), Qnil);
2966           ASET (vec, 0, make_number (xoff));
2967           ASET (vec, 1, make_number (yoff));
2968           ASET (vec, 2, make_number (wadjust));
2969           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2970         }
2971     }
2973   unblock_input ();
2975   return make_number (used);
2978 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2979 typedef UInt8 UINT24[3];
2981 #pragma pack(push, 1)
2982 struct variation_selector_record
2984   UINT24 var_selector;
2985   UInt32 default_uvs_offset, non_default_uvs_offset;
2987 struct uvs_table
2989   UInt16 format;
2990   UInt32 length, num_var_selector_records;
2991   struct variation_selector_record variation_selector_records[1];
2993 #define SIZEOF_UVS_TABLE_HEADER \
2994   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2996 struct unicode_value_range
2998   UINT24 start_unicode_value;
2999   UInt8 additional_count;
3001 struct default_uvs_table {
3002   UInt32 num_unicode_value_ranges;
3003   struct unicode_value_range unicode_value_ranges[1];
3005 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
3006   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
3008 struct uvs_mapping
3010   UINT24 unicode_value;
3011   UInt16 glyph_id;
3013 struct non_default_uvs_table
3015   UInt32 num_uvs_mappings;
3016   struct uvs_mapping uvs_mappings[1];
3018 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3019   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3020 #pragma pack(pop)
3022 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3023 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3024    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3025    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3026 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3027 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3028 /* Succeeding one byte should also be accessible.  */
3029 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3030 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3032 /* Return UVS subtable for the specified FONT.  If the subtable is not
3033    found or ill-formatted, then return NULL.  */
3035 static CFDataRef
3036 mac_font_copy_uvs_table (FontRef font)
3038   CFDataRef cmap_table, uvs_table = NULL;
3040   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3041   if (cmap_table)
3042     {
3043       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3044       struct uvs_table *uvs;
3045       struct variation_selector_record *records;
3046       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3048 #if __LP64__
3049       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3050         goto finish;
3051 #endif
3053       cmap_len = CFDataGetLength (cmap_table);
3054       if (sizeof_sfntCMapHeader > cmap_len)
3055         goto finish;
3057       ntables = BUINT16_VALUE (cmap->numTables);
3058       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3059                      / sizeof_sfntCMapEncoding))
3060         goto finish;
3062       for (i = 0; i < ntables; i++)
3063         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3064              == kFontUnicodePlatform)
3065             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3066                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3067           {
3068             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3069             break;
3070           }
3071       if (i == ntables
3072           || uvs_offset > cmap_len
3073           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3074         goto finish;
3076       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3077       uvs_len = BUINT32_VALUE (uvs->length);
3078       if (uvs_len > cmap_len - uvs_offset
3079           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3080         goto finish;
3082       if (BUINT16_VALUE (uvs->format) != 14)
3083         goto finish;
3085       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3086       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3087                       / sizeof (struct variation_selector_record)))
3088         goto finish;
3090       records = uvs->variation_selector_records;
3091       for (i = 0; i < nrecords; i++)
3092         {
3093           UInt32 default_uvs_offset, non_default_uvs_offset;
3095           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3096           if (default_uvs_offset)
3097             {
3098               struct default_uvs_table *default_uvs;
3099               UInt32 nranges;
3101               if (default_uvs_offset > uvs_len
3102                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3103                       > uvs_len - default_uvs_offset))
3104                 goto finish;
3106               default_uvs = ((struct default_uvs_table *)
3107                              ((UInt8 *) uvs + default_uvs_offset));
3108               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3109               if (nranges > ((uvs_len - default_uvs_offset
3110                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3111                              / sizeof (struct unicode_value_range)))
3112                 goto finish;
3113               /* Now 2 * nranges can't overflow, so we can safely use
3114                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3115                  mac_font_get_glyphs_for_variants.  */
3116             }
3118           non_default_uvs_offset =
3119             BUINT32_VALUE (records[i].non_default_uvs_offset);
3120           if (non_default_uvs_offset)
3121             {
3122               struct non_default_uvs_table *non_default_uvs;
3123               UInt32 nmappings;
3125               if (non_default_uvs_offset > uvs_len
3126                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3127                       > uvs_len - non_default_uvs_offset))
3128                 goto finish;
3130               non_default_uvs = ((struct non_default_uvs_table *)
3131                                  ((UInt8 *) uvs + non_default_uvs_offset));
3132               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3133               if (nmappings > ((uvs_len - non_default_uvs_offset
3134                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3135                                / sizeof (struct uvs_mapping)))
3136                 goto finish;
3137               /* Now 2 * nmappings can't overflow, so we can safely
3138                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3139                  in mac_font_get_glyphs_for_variants.  */
3140             }
3141         }
3143       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3145     finish:
3146       CFRelease (cmap_table);
3147     }
3149   return uvs_table;
3152 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3153    sequence consisting of the given base character C and each
3154    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3155    result (explained below) into the corresponding GLYPHS[i].  If the
3156    entry is found in the Default UVS Table, then the result is 0.  If
3157    the entry is found in the Non-Default UVS Table, then the result is
3158    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3159    elements in SELECTORS must be sorted in strictly increasing
3160    order.  */
3162 static void
3163 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3164                                   const UTF32Char selectors[], CGGlyph glyphs[],
3165                                   CFIndex count)
3167   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3168   struct variation_selector_record *records = uvs->variation_selector_records;
3169   CFIndex i;
3170   UInt32 ir, nrecords;
3171 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3172   dispatch_queue_t queue =
3173     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3174   dispatch_group_t group = dispatch_group_create ();
3175 #endif
3177   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3178   i = 0;
3179   ir = 0;
3180   while (i < count && ir < nrecords)
3181     {
3182       UInt32 default_uvs_offset, non_default_uvs_offset;
3184       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3185         {
3186           glyphs[i++] = kCGFontIndexInvalid;
3187           continue;
3188         }
3189       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3190         {
3191           ir++;
3192           continue;
3193         }
3195       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3196       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3197       non_default_uvs_offset =
3198         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3199 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3200       dispatch_group_async (group, queue, ^{
3201 #endif
3202           glyphs[i] = kCGFontIndexInvalid;
3204           if (default_uvs_offset)
3205             {
3206               struct default_uvs_table *default_uvs =
3207                 (struct default_uvs_table *) ((UInt8 *) uvs
3208                                               + default_uvs_offset);
3209               struct unicode_value_range *ranges =
3210                 default_uvs->unicode_value_ranges;
3211               UInt32 lo, hi;
3213               lo = 0;
3214               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3215               while (lo < hi)
3216                 {
3217                   UInt32 mid = (lo + hi) / 2;
3219                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3220                     hi = mid;
3221                   else
3222                     lo = mid + 1;
3223                 }
3224               if (hi > 0
3225                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3226                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3227                 glyphs[i] = 0;
3228             }
3230           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3231             {
3232               struct non_default_uvs_table *non_default_uvs =
3233                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3234                                                   + non_default_uvs_offset);
3235               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3236               UInt32 lo, hi;
3238               lo = 0;
3239               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3240               while (lo < hi)
3241                 {
3242                   UInt32 mid = (lo + hi) / 2;
3244                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3245                     hi = mid;
3246                   else
3247                     lo = mid + 1;
3248                 }
3249               if (hi > 0 &&
3250                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3251                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3252             }
3253 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3254         });
3255 #endif
3256       i++;
3257       ir++;
3258     }
3259   while (i < count)
3260     glyphs[i++] = kCGFontIndexInvalid;
3261 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3262   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3263   dispatch_release (group);
3264 #endif
3267 static int
3268 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3270   CFDataRef uvs_table;
3271   CharacterCollection uvs_collection;
3272   int i, n = 0;
3274   block_input ();
3275   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3277   if (uvs_table)
3278     {
3279       UTF32Char selectors[256];
3280       CGGlyph glyphs[256];
3282       for (i = 0; i < 16; i++)
3283         selectors[i] = 0xFE00 + i;
3284       for (; i < 256; i++)
3285         selectors[i] = 0xE0100 + (i - 16);
3286       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3287       for (i = 0; i < 256; i++)
3288         {
3289           CGGlyph glyph = glyphs[i];
3291           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3292               && glyph != kCGFontIndexInvalid)
3293             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3294           if (glyph == kCGFontIndexInvalid)
3295             variations[i] = 0;
3296           else
3297             {
3298               variations[i] = (glyph ? glyph
3299                                : macfont_get_glyph_for_character (font, c));
3300               n++;
3301             }
3302         }
3303     }
3304   unblock_input ();
3306   return n;
3309 static const char *const macfont_booleans[] = {
3310   ":antialias",
3311   ":minspace",
3312   NULL,
3315 static const char *const macfont_non_booleans[] = {
3316   ":lang",
3317   ":script",
3318   ":destination",
3319   NULL,
3322 static void
3323 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3325   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3328 static Boolean
3329 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3330                                           CFArrayRef languages)
3332   Boolean result = true;
3333   CFArrayRef desc_languages =
3334     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3336   if (desc_languages == NULL)
3337     result = false;
3338   else
3339     {
3340       CFIndex desc_languages_count, i, languages_count;
3342       desc_languages_count = CFArrayGetCount (desc_languages);
3343       languages_count = CFArrayGetCount (languages);
3344       for (i = 0; i < languages_count; i++)
3345         if (!CFArrayContainsValue (desc_languages,
3346                                    CFRangeMake (0, desc_languages_count),
3347                                    CFArrayGetValueAtIndex (languages, i)))
3348           {
3349             result = false;
3350             break;
3351           }
3352       CFRelease (desc_languages);
3353     }
3355   return result;
3358 static CFStringRef
3359 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3361   CFStringRef result = NULL;
3362   CFStringRef charset_string =
3363     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3365   if (charset_string && CFStringGetLength (charset_string) > 0)
3366     {
3367       CFStringRef keys[] = {
3368 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3369         kCTLanguageAttributeName
3370 #else
3371         CFSTR ("NSLanguage")
3372 #endif
3373       };
3374       CFTypeRef values[] = {NULL};
3375       CFIndex num_values = 0;
3376       CFArrayRef languages
3377         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3379       if (languages && CFArrayGetCount (languages) > 0)
3380         {
3381           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3382             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3383           else
3384             {
3385               CFCharacterSetRef charset =
3386                 CFDictionaryGetValue (attributes,
3387                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3389               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3390             }
3391         }
3392       if (result == NULL)
3393         {
3394           CFAttributedStringRef attr_string = NULL;
3395           CTLineRef ctline = NULL;
3396           CFDictionaryRef attrs
3397             = CFDictionaryCreate (NULL, (const void **) keys,
3398                                   (const void **) values, num_values,
3399                                   &kCFTypeDictionaryKeyCallBacks,
3400                                   &kCFTypeDictionaryValueCallBacks);
3402           if (attrs)
3403             {
3404               attr_string = CFAttributedStringCreate (NULL, charset_string,
3405                                                       attrs);
3406               CFRelease (attrs);
3407             }
3408           if (attr_string)
3409             {
3410               ctline = CTLineCreateWithAttributedString (attr_string);
3411               CFRelease (attr_string);
3412             }
3413           if (ctline)
3414             {
3415               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3416               CFIndex i, nruns = CFArrayGetCount (runs);
3417               CTFontRef font;
3419               for (i = 0; i < nruns; i++)
3420                 {
3421                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3422                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3423                   CTFontRef font_in_run;
3425                   if (attributes == NULL)
3426                     break;
3427                   font_in_run =
3428                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3429                   if (font_in_run == NULL)
3430                     break;
3431                   if (i == 0)
3432                     font = font_in_run;
3433                   else if (!mac_ctfont_equal_in_postscript_name (font,
3434                                                                  font_in_run))
3435                     break;
3436                 }
3437               if (nruns > 0 && i == nruns)
3438                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3439               CFRelease (ctline);
3440             }
3441         }
3442     }
3444   return result;
3447 static inline double
3448 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3450   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3451                                      &glyph, NULL, 1);
3454 static inline CGRect
3455 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3457   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3458                                           &glyph, NULL, 1);
3461 static CFArrayRef
3462 mac_ctfont_create_available_families (void)
3464   CFMutableArrayRef families = NULL;
3466 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3467 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3468   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3469 #endif
3470     {
3471       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3473       if (orig_families)
3474         {
3475           CFIndex i, count = CFArrayGetCount (orig_families);
3477           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3478           if (families)
3479             for (i = 0; i < count; i++)
3480               {
3481                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3483                 if (!CFStringHasPrefix (family, CFSTR ("."))
3484                     && (CTFontManagerCompareFontFamilyNames (family,
3485                                                              CFSTR ("LastResort"),
3486                                                              NULL)
3487                         != kCFCompareEqualTo))
3488                   CFArrayAppendValue (families, family);
3489               }
3490           CFRelease (orig_families);
3491         }
3492     }
3493 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3494   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3495 #endif
3496 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3497 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3498     {
3499       CTFontCollectionRef collection;
3500       CFArrayRef descs = NULL;
3502       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3503       if (collection)
3504         {
3505           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3506           CFRelease (collection);
3507         }
3508       if (descs)
3509         {
3510           CFIndex i, count = CFArrayGetCount (descs);
3512           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3513           if (families)
3514             for (i = 0; i < count; i++)
3515               {
3516                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3517                 CFStringRef name =
3518                   mac_font_descriptor_copy_attribute (desc,
3519                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3521                 if (name)
3522                   {
3523                     CFIndex p, limit = CFArrayGetCount (families);
3525                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3526                                               (const void *) name,
3527                                               mac_font_family_compare, NULL);
3528                     if (p >= limit)
3529                       CFArrayAppendValue (families, name);
3530                     else if (mac_font_family_compare
3531                              (CFArrayGetValueAtIndex (families, p),
3532                               name, NULL) != kCFCompareEqualTo)
3533                       CFArrayInsertValueAtIndex (families, p, name);
3534                     CFRelease (name);
3535                   }
3536               }
3537           CFRelease (descs);
3538         }
3539     }
3540 #endif
3542   return families;
3545 static Boolean
3546 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3548   Boolean result;
3549   CFStringRef name1, name2;
3551   if (font1 == font2)
3552     return true;
3554   result = false;
3555   name1 = CTFontCopyPostScriptName (font1);
3556   if (name1)
3557     {
3558       name2 = CTFontCopyPostScriptName (font2);
3559       if (name2)
3560         {
3561           result = (CFStringCompare (name1, name2, 0) == kCFCompareEqualTo);
3562           CFRelease (name2);
3563         }
3564       CFRelease (name1);
3565     }
3567   return result;
3570 static CTLineRef
3571 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3572                                              CTFontRef macfont)
3574   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3575   CFTypeRef values[] = {NULL, NULL};
3576   CFDictionaryRef attributes = NULL;
3577   CFAttributedStringRef attr_string = NULL;
3578   CTLineRef ctline = NULL;
3579   float float_zero = 0.0f;
3581   values[0] = macfont;
3582   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3583   if (values[1])
3584     {
3585       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3586                                        (const void **) values,
3587                                        sizeof (keys) / sizeof (keys[0]),
3588                                        &kCFTypeDictionaryKeyCallBacks,
3589                                        &kCFTypeDictionaryValueCallBacks);
3590       CFRelease (values[1]);
3591     }
3592   if (attributes)
3593     {
3594       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3595       CFRelease (attributes);
3596     }
3597   if (attr_string)
3598     {
3599       ctline = CTLineCreateWithAttributedString (attr_string);
3600       CFRelease (attr_string);
3601     }
3602   if (ctline)
3603     {
3604       /* Abandon if ctline contains some fonts other than the
3605          specified one.  */
3606       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3607       CFIndex i, nruns = CFArrayGetCount (runs);
3609       for (i = 0; i < nruns; i++)
3610         {
3611           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3612           CFDictionaryRef attributes = CTRunGetAttributes (run);
3613           CTFontRef font_in_run;
3615           if (attributes == NULL)
3616             break;
3617           font_in_run =
3618             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3619           if (font_in_run == NULL)
3620             break;
3621           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3622             break;
3623         }
3624       if (i < nruns)
3625         {
3626           CFRelease (ctline);
3627           ctline = NULL;
3628         }
3629     }
3631   return ctline;
3634 static CFIndex
3635 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3636                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3638   CFIndex used, result = 0;
3639   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3641   if (ctline == NULL)
3642     return 0;
3644   used = CTLineGetGlyphCount (ctline);
3645   if (used <= glyph_len)
3646     {
3647       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3648       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3649       CGFloat total_advance = 0;
3650       CFIndex total_glyph_count = 0;
3652       for (k = 0; k < ctrun_count; k++)
3653         {
3654           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3655           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3656           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3657           CFRange string_range, comp_range, range;
3658           CFIndex *permutation;
3660           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3661             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3662           else
3663             permutation = NULL;
3665 #define RIGHT_TO_LEFT_P permutation
3667           /* Now the `comp_range' member of struct mac_glyph_layout is
3668              temporarily used as a work area such that:
3669               glbuf[i].comp_range.location =
3670                 min {compRange[i + 1].location, ...,
3671                      compRange[glyph_count - 1].location,
3672                      maxRange (stringRangeForCTRun)}
3673               glbuf[i].comp_range.length = maxRange (compRange[i])
3674              where compRange[i] is the range of composed characters
3675              containing i-th glyph.  */
3676           string_range = CTRunGetStringRange (ctrun);
3677           min_location = string_range.location + string_range.length;
3678           for (i = 0; i < glyph_count; i++)
3679             {
3680               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3681               CFIndex glyph_index;
3682               CFRange rng;
3684               if (!RIGHT_TO_LEFT_P)
3685                 glyph_index = glyph_count - i - 1;
3686               else
3687                 glyph_index = i;
3688               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3689                                      &gl->string_index);
3690               rng =
3691                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3692                                                              gl->string_index);
3693               gl->comp_range.location = min_location;
3694               gl->comp_range.length = rng.location + rng.length;
3695               if (rng.location < min_location)
3696                 min_location = rng.location;
3697             }
3699           /* Fill the `comp_range' member of struct mac_glyph_layout,
3700              and setup a permutation for right-to-left text.  */
3701           comp_range = CFRangeMake (string_range.location, 0);
3702           range = CFRangeMake (0, 0);
3703           while (1)
3704             {
3705               struct mac_glyph_layout *gl =
3706                 glbuf + range.location + range.length;
3708               if (gl->comp_range.length
3709                   > comp_range.location + comp_range.length)
3710                 comp_range.length = gl->comp_range.length - comp_range.location;
3711               min_location = gl->comp_range.location;
3712               range.length++;
3714               if (min_location >= comp_range.location + comp_range.length)
3715                 {
3716                   comp_range.length = min_location - comp_range.location;
3717                   for (i = 0; i < range.length; i++)
3718                     {
3719                       glbuf[range.location + i].comp_range = comp_range;
3720                       if (RIGHT_TO_LEFT_P)
3721                         permutation[range.location + i] =
3722                           range.location + range.length - i - 1;
3723                     }
3725                   comp_range = CFRangeMake (min_location, 0);
3726                   range.location += range.length;
3727                   range.length = 0;
3728                   if (range.location == glyph_count)
3729                     break;
3730                 }
3731             }
3733           /* Then fill the remaining members.  */
3734           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3735                range.location++)
3736             {
3737               struct mac_glyph_layout *gl;
3738               CGPoint position;
3740               if (!RIGHT_TO_LEFT_P)
3741                 gl = glbuf + range.location;
3742               else
3743                 {
3744                   CFIndex src, dest;
3746                   src = glyph_count - 1 - range.location;
3747                   dest = permutation[src];
3748                   gl = glbuf + dest;
3749                   if (src < dest)
3750                     {
3751                       CFIndex tmp = gl->string_index;
3753                       gl->string_index = glbuf[src].string_index;
3754                       glbuf[src].string_index = tmp;
3755                     }
3756                 }
3757               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3759               CTRunGetPositions (ctrun, range, &position);
3760               gl->advance_delta = position.x - total_advance;
3761               gl->baseline_delta = position.y;
3762               gl->advance = (gl->advance_delta
3763                              + CTRunGetTypographicBounds (ctrun, range,
3764                                                           NULL, NULL, NULL));
3765               total_advance += gl->advance;
3766             }
3768           if (RIGHT_TO_LEFT_P)
3769             xfree (permutation);
3771 #undef RIGHT_TO_LEFT_P
3773           total_glyph_count += glyph_count;
3774         }
3776       result = used;
3777     }
3778   CFRelease (ctline);
3780   return result;
3783 /* The function below seems to cause a memory leak for the CFString
3784    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3785    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3786 #if USE_CT_GLYPH_INFO
3787 static CGGlyph
3788 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3789                               CGFontIndex cid)
3791   CGGlyph result = kCGFontIndexInvalid;
3792   UniChar characters[] = {0xfffd};
3793   CFStringRef string;
3794   CFAttributedStringRef attr_string = NULL;
3795   CTLineRef ctline = NULL;
3797   string = CFStringCreateWithCharacters (NULL, characters,
3798                                          sizeof (characters)
3799                                          / sizeof (characters[0]));
3800   if (string)
3801     {
3802       CTGlyphInfoRef glyph_info =
3803         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3804       CFDictionaryRef attributes = NULL;
3806       if (glyph_info)
3807         {
3808           CFStringRef keys[] = {kCTFontAttributeName,
3809                                 kCTGlyphInfoAttributeName};
3810           CFTypeRef values[] = {font, glyph_info};
3812           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3813                                            (const void **) values,
3814                                            sizeof (keys) / sizeof (keys[0]),
3815                                            &kCFTypeDictionaryKeyCallBacks,
3816                                            &kCFTypeDictionaryValueCallBacks);
3817           CFRelease (glyph_info);
3818         }
3819       if (attributes)
3820         {
3821           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3822           CFRelease (attributes);
3823         }
3824       CFRelease (string);
3825     }
3826   if (attr_string)
3827     {
3828       ctline = CTLineCreateWithAttributedString (attr_string);
3829       CFRelease (attr_string);
3830     }
3831   if (ctline)
3832     {
3833       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3835       if (CFArrayGetCount (runs) > 0)
3836         {
3837           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3838           CFDictionaryRef attributes = CTRunGetAttributes (run);
3840           if (attributes)
3841             {
3842               CTFontRef font_in_run =
3843                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3845               if (font_in_run
3846                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3847                 {
3848                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3849                   if (result >= CTFontGetGlyphCount (font))
3850                     result = kCGFontIndexInvalid;
3851                 }
3852             }
3853         }
3854       CFRelease (ctline);
3855     }
3857   return result;
3859 #endif
3861 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3862 static inline int
3863 mac_font_family_group (CFStringRef family)
3865   if (CFStringHasPrefix (family, CFSTR ("#")))
3866     return 2;
3867   else
3868     {
3869       CFRange range;
3871       range = CFStringFind (family, CFSTR ("Apple"),
3872                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3873       if (range.location != kCFNotFound)
3874         return 1;
3876       return 0;
3877     }
3880 static CFComparisonResult
3881 mac_font_family_compare (const void *val1, const void *val2, void *context)
3883   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3884   int group1, group2;
3886   group1 = mac_font_family_group (family1);
3887   group2 = mac_font_family_group (family2);
3888   if (group1 < group2)
3889     return kCFCompareLessThan;
3890   if (group1 > group2)
3891     return kCFCompareGreaterThan;
3892   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3894 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3896 static CFArrayRef
3897 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3899   CFArrayRef result = NULL;
3901 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3902 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3903   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3904 #endif
3905     {
3906       CTFontRef user_font =
3907         CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3909       if (user_font)
3910         {
3911           CFArrayRef languages =
3912             CFArrayCreate (NULL, (const void **) &language, 1,
3913                            &kCFTypeArrayCallBacks);
3915           if (languages)
3916             {
3917               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3918                                                                  languages);
3919               CFRelease (languages);
3920             }
3921           CFRelease (user_font);
3922         }
3923     }
3924 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3925   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3926 #endif
3927 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3928 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3929     {
3930       CFIndex i;
3932       for (i = 0; macfont_language_default_font_names[i].language; i++)
3933         {
3934           if (CFStringCompare (macfont_language_default_font_names[i].language,
3935                                language, 0) == kCFCompareEqualTo)
3936             {
3937               CFMutableArrayRef descriptors =
3938                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3940               if (descriptors)
3941                 {
3942                   CFIndex j;
3944                   for (j = 0;
3945                        macfont_language_default_font_names[i].font_names[j];
3946                        j++)
3947                     {
3948                       CFDictionaryRef attributes =
3949                         CFDictionaryCreate (NULL,
3950                                             ((const void **)
3951                                              &MAC_FONT_NAME_ATTRIBUTE),
3952                                             ((const void **)
3953                                              &macfont_language_default_font_names[i].font_names[j]),
3954                                             1, &kCFTypeDictionaryKeyCallBacks,
3955                                             &kCFTypeDictionaryValueCallBacks);
3957                       if (attributes)
3958                         {
3959                           FontDescriptorRef pat_desc =
3960                             mac_font_descriptor_create_with_attributes (attributes);
3962                           if (pat_desc)
3963                             {
3964                               FontDescriptorRef descriptor =
3965                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3967                               if (descriptor)
3968                                 {
3969                                   CFArrayAppendValue (descriptors, descriptor);
3970                                   CFRelease (descriptor);
3971                                 }
3972                               CFRelease (pat_desc);
3973                             }
3974                           CFRelease (attributes);
3975                         }
3976                     }
3977                   result = descriptors;
3978                 }
3979               break;
3980             }
3981         }
3982     }
3983 #endif
3985   return result;
3988 static CFStringRef
3989 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3990                                                       CFArrayRef languages)
3992   CFStringRef result = NULL;
3993   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3994   CFArrayRef descriptors =
3995     mac_font_copy_default_descriptors_for_language (language);
3997   if (descriptors)
3998     {
3999       CFIndex i, count = CFArrayGetCount (descriptors);
4001       for (i = 0; i < count; i++)
4002         {
4003           FontDescriptorRef descriptor =
4004             CFArrayGetValueAtIndex (descriptors, i);
4006           if (macfont_supports_charset_and_languages_p (descriptor, charset,
4007                                                         Qnil, languages))
4008             {
4009               CFStringRef family =
4010                 mac_font_descriptor_copy_attribute (descriptor,
4011                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
4012               if (family)
4013                 {
4014                   if (!CFStringHasPrefix (family, CFSTR ("."))
4015                       && (CFStringCompare (family, CFSTR ("LastResort"), 0)
4016                           != kCFCompareEqualTo))
4017                     {
4018                       result = family;
4019                       break;
4020                     }
4021                   else
4022                     CFRelease (family);
4023                 }
4024             }
4025         }
4026       CFRelease (descriptors);
4027     }
4029   return result;
4032 void *
4033 macfont_get_nsctfont (struct font *font)
4035   struct macfont_info *macfont_info = (struct macfont_info *) font;
4036   FontRef macfont = macfont_info->macfont;
4038   return (void *) macfont;
4041 void
4042 mac_register_font_driver (struct frame *f)
4044   register_font_driver (&macfont_driver, f);
4047 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4050 void
4051 syms_of_macfont (void)
4053 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4054   static struct font_driver mac_font_driver;
4056   DEFSYM (Qmac_ct, "mac-ct");
4057   macfont_driver.type = Qmac_ct;
4058   register_font_driver (&macfont_driver, NULL);
4060   DEFSYM (QCdestination, ":destination");
4061   DEFSYM (QCminspace, ":minspace");
4062 #endif