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