Remove unnecessary redisplays in NS port.
[emacs.git] / src / macfont.m
blob9b3cb2c29f653eb8fe1b1c4b94105979cb24b5c3
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   xfree (positions);
2814   CGContextRestoreGState (context);
2816   unblock_input ();
2818   return len;
2821 static Lisp_Object
2822 macfont_shape (Lisp_Object lgstring)
2824   struct font *font;
2825   struct macfont_info *macfont_info;
2826   FontRef macfont;
2827   ptrdiff_t glyph_len, len, i, j;
2828   CFIndex nonbmp_len;
2829   UniChar *unichars;
2830   CFIndex *nonbmp_indices;
2831   CFStringRef string;
2832   CFIndex used = 0;
2833   struct mac_glyph_layout *glyph_layouts;
2835   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
2836   macfont_info = (struct macfont_info *) font;
2837   macfont = macfont_info->macfont;
2839   glyph_len = LGSTRING_GLYPH_LEN (lgstring);
2840   nonbmp_len = 0;
2841   for (i = 0; i < glyph_len; i++)
2842     {
2843       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2845       if (NILP (lglyph))
2846         break;
2847       if (LGLYPH_CHAR (lglyph) >= 0x10000)
2848         nonbmp_len++;
2849     }
2851   len = i;
2853   if (INT_MAX / 2 < len)
2854     memory_full (SIZE_MAX);
2856   unichars = alloca (sizeof (UniChar) * (len + nonbmp_len));
2857   nonbmp_indices = alloca (sizeof (CFIndex) * (nonbmp_len + 1));
2858   for (i = j = 0; i < len; i++)
2859     {
2860       UTF32Char c = LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, i));
2862       if (macfont_store_utf32char_to_unichars (c, unichars + i + j) > 1)
2863         {
2864           nonbmp_indices[j] = i + j;
2865           j++;
2866         }
2867     }
2868   nonbmp_indices[j] = len + j;  /* sentinel */
2870   block_input ();
2872   string = CFStringCreateWithCharactersNoCopy (NULL, unichars, len + nonbmp_len,
2873                                                kCFAllocatorNull);
2874   if (string)
2875     {
2876       glyph_layouts = alloca (sizeof (struct mac_glyph_layout) * glyph_len);
2877       if (macfont_info->screen_font)
2878         used = mac_screen_font_shape (macfont_info->screen_font, string,
2879                                       glyph_layouts, glyph_len);
2880       else
2881         used = mac_font_shape (macfont, string, glyph_layouts, glyph_len);
2882       CFRelease (string);
2883     }
2885   unblock_input ();
2887   if (used == 0)
2888     return Qnil;
2890   block_input ();
2892   for (i = 0; i < used; i++)
2893     {
2894       Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, i);
2895       struct mac_glyph_layout *gl = glyph_layouts + i;
2896       EMACS_INT from, to;
2897       struct font_metrics metrics;
2898       int xoff, yoff, wadjust;
2900       if (NILP (lglyph))
2901         {
2902           lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
2903           LGSTRING_SET_GLYPH (lgstring, i, lglyph);
2904         }
2906       from = gl->comp_range.location;
2907       /* Convert UTF-16 index to UTF-32.  */
2908       j = 0;
2909       while (nonbmp_indices[j] < from)
2910         j++;
2911       from -= j;
2912       LGLYPH_SET_FROM (lglyph, from);
2914       to = gl->comp_range.location + gl->comp_range.length;
2915       /* Convert UTF-16 index to UTF-32.  */
2916       while (nonbmp_indices[j] < to)
2917         j++;
2918       to -= j;
2919       LGLYPH_SET_TO (lglyph, to - 1);
2921       /* LGLYPH_CHAR is used in `describe-char' for checking whether
2922          the composition is trivial.  */
2923       {
2924         UTF32Char c;
2926         if (unichars[gl->string_index] >= 0xD800
2927             && unichars[gl->string_index] < 0xDC00)
2928           c = (((unichars[gl->string_index] - 0xD800) << 10)
2929                + (unichars[gl->string_index + 1] - 0xDC00) + 0x10000);
2930         else
2931           c = unichars[gl->string_index];
2932         if (macfont_get_glyph_for_character (font, c) != gl->glyph_id)
2933           c = 0;
2934         LGLYPH_SET_CHAR (lglyph, c);
2935       }
2937       {
2938         unsigned long cc = gl->glyph_id;
2939         LGLYPH_SET_CODE (lglyph, cc);
2940       }
2942       macfont_glyph_extents (font, gl->glyph_id, &metrics, NULL, 0);
2943       LGLYPH_SET_WIDTH (lglyph, metrics.width);
2944       LGLYPH_SET_LBEARING (lglyph, metrics.lbearing);
2945       LGLYPH_SET_RBEARING (lglyph, metrics.rbearing);
2946       LGLYPH_SET_ASCENT (lglyph, metrics.ascent);
2947       LGLYPH_SET_DESCENT (lglyph, metrics.descent);
2949       xoff = lround (gl->advance_delta);
2950       yoff = lround (- gl->baseline_delta);
2951       wadjust = lround (gl->advance);
2952       if (xoff != 0 || yoff != 0 || wadjust != metrics.width)
2953         {
2954           Lisp_Object vec;
2956           vec = Fmake_vector (make_number (3), Qnil);
2957           ASET (vec, 0, make_number (xoff));
2958           ASET (vec, 1, make_number (yoff));
2959           ASET (vec, 2, make_number (wadjust));
2960           LGLYPH_SET_ADJUSTMENT (lglyph, vec);
2961         }
2962     }
2964   unblock_input ();
2966   return make_number (used);
2969 /* Structures for the UVS subtable (format 14) in the cmap table.  */
2970 typedef UInt8 UINT24[3];
2972 #pragma pack(push, 1)
2973 struct variation_selector_record
2975   UINT24 var_selector;
2976   UInt32 default_uvs_offset, non_default_uvs_offset;
2978 struct uvs_table
2980   UInt16 format;
2981   UInt32 length, num_var_selector_records;
2982   struct variation_selector_record variation_selector_records[1];
2984 #define SIZEOF_UVS_TABLE_HEADER \
2985   (sizeof (struct uvs_table) - sizeof (struct variation_selector_record))
2987 struct unicode_value_range
2989   UINT24 start_unicode_value;
2990   UInt8 additional_count;
2992 struct default_uvs_table {
2993   UInt32 num_unicode_value_ranges;
2994   struct unicode_value_range unicode_value_ranges[1];
2996 #define SIZEOF_DEFAULT_UVS_TABLE_HEADER \
2997   (sizeof (struct default_uvs_table) - sizeof (struct unicode_value_range))
2999 struct uvs_mapping
3001   UINT24 unicode_value;
3002   UInt16 glyph_id;
3004 struct non_default_uvs_table
3006   UInt32 num_uvs_mappings;
3007   struct uvs_mapping uvs_mappings[1];
3009 #define SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER \
3010   (sizeof (struct non_default_uvs_table) - sizeof (struct uvs_mapping))
3011 #pragma pack(pop)
3013 /* Read big endian values.  The argument LVAL must be an lvalue.  */
3014 /* I suppose OSReadBigInt* takes care of unaligned data.  At least, we
3015    can find "... = OSReadBigInt32(cdb, 2);" followed by "... =
3016    OSReadBigInt16(cdb, 7);" in a sample code by Apple.  */
3017 #define BUINT8_VALUE(lval)      (*((UInt8 *) &(lval)))
3018 #define BUINT16_VALUE(lval)     OSReadBigInt16 (&(lval), 0)
3019 /* Succeeding one byte should also be accessible.  */
3020 #define BUINT24_VALUE(lval)     (OSReadBigInt32 (&(lval), 0) >> 8)
3021 #define BUINT32_VALUE(lval)     OSReadBigInt32 (&(lval), 0)
3023 /* Return UVS subtable for the specified FONT.  If the subtable is not
3024    found or ill-formatted, then return NULL.  */
3026 static CFDataRef
3027 mac_font_copy_uvs_table (FontRef font)
3029   CFDataRef cmap_table, uvs_table = NULL;
3031   cmap_table = mac_font_copy_non_synthetic_table (font, cmapFontTableTag);
3032   if (cmap_table)
3033     {
3034       sfntCMapHeader *cmap = (sfntCMapHeader *) CFDataGetBytePtr (cmap_table);
3035       struct uvs_table *uvs;
3036       struct variation_selector_record *records;
3037       UInt32 cmap_len, ntables, i, uvs_offset, uvs_len, nrecords;
3039 #if __LP64__
3040       if (CFDataGetLength (cmap_table) > UINT32_MAX)
3041         goto finish;
3042 #endif
3044       cmap_len = CFDataGetLength (cmap_table);
3045       if (sizeof_sfntCMapHeader > cmap_len)
3046         goto finish;
3048       ntables = BUINT16_VALUE (cmap->numTables);
3049       if (ntables > ((cmap_len - sizeof_sfntCMapHeader)
3050                      / sizeof_sfntCMapEncoding))
3051         goto finish;
3053       for (i = 0; i < ntables; i++)
3054         if ((BUINT16_VALUE (cmap->encoding[i].platformID)
3055              == kFontUnicodePlatform)
3056             && (BUINT16_VALUE (cmap->encoding[i].scriptID)
3057                 == 5)) /* kFontUnicodeV4_0VariationSequenceSemantics */
3058           {
3059             uvs_offset = BUINT32_VALUE (cmap->encoding[i].offset);
3060             break;
3061           }
3062       if (i == ntables
3063           || uvs_offset > cmap_len
3064           || SIZEOF_UVS_TABLE_HEADER > cmap_len - uvs_offset)
3065         goto finish;
3067       uvs = (struct uvs_table *) ((UInt8 *) cmap + uvs_offset);
3068       uvs_len = BUINT32_VALUE (uvs->length);
3069       if (uvs_len > cmap_len - uvs_offset
3070           || SIZEOF_UVS_TABLE_HEADER > uvs_len)
3071         goto finish;
3073       if (BUINT16_VALUE (uvs->format) != 14)
3074         goto finish;
3076       nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3077       if (nrecords > ((uvs_len - SIZEOF_UVS_TABLE_HEADER)
3078                       / sizeof (struct variation_selector_record)))
3079         goto finish;
3081       records = uvs->variation_selector_records;
3082       for (i = 0; i < nrecords; i++)
3083         {
3084           UInt32 default_uvs_offset, non_default_uvs_offset;
3086           default_uvs_offset = BUINT32_VALUE (records[i].default_uvs_offset);
3087           if (default_uvs_offset)
3088             {
3089               struct default_uvs_table *default_uvs;
3090               UInt32 nranges;
3092               if (default_uvs_offset > uvs_len
3093                   || (SIZEOF_DEFAULT_UVS_TABLE_HEADER
3094                       > uvs_len - default_uvs_offset))
3095                 goto finish;
3097               default_uvs = ((struct default_uvs_table *)
3098                              ((UInt8 *) uvs + default_uvs_offset));
3099               nranges = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3100               if (nranges > ((uvs_len - default_uvs_offset
3101                               - SIZEOF_DEFAULT_UVS_TABLE_HEADER)
3102                              / sizeof (struct unicode_value_range)))
3103                 goto finish;
3104               /* Now 2 * nranges can't overflow, so we can safely use
3105                  `(lo + hi) / 2' instead of `lo + (hi - lo) / 2' in
3106                  mac_font_get_glyphs_for_variants.  */
3107             }
3109           non_default_uvs_offset =
3110             BUINT32_VALUE (records[i].non_default_uvs_offset);
3111           if (non_default_uvs_offset)
3112             {
3113               struct non_default_uvs_table *non_default_uvs;
3114               UInt32 nmappings;
3116               if (non_default_uvs_offset > uvs_len
3117                   || (SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER
3118                       > uvs_len - non_default_uvs_offset))
3119                 goto finish;
3121               non_default_uvs = ((struct non_default_uvs_table *)
3122                                  ((UInt8 *) uvs + non_default_uvs_offset));
3123               nmappings = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3124               if (nmappings > ((uvs_len - non_default_uvs_offset
3125                                 - SIZEOF_NON_DEFAULT_UVS_TABLE_HEADER)
3126                                / sizeof (struct uvs_mapping)))
3127                 goto finish;
3128               /* Now 2 * nmappings can't overflow, so we can safely
3129                  use `(lo + hi) / 2' instead of `lo + (hi - lo) / 2'
3130                  in mac_font_get_glyphs_for_variants.  */
3131             }
3132         }
3134       uvs_table = CFDataCreate (NULL, (UInt8 *) uvs, uvs_len);
3136     finish:
3137       CFRelease (cmap_table);
3138     }
3140   return uvs_table;
3143 /* Find an entry in the given UVS subtable UVS_TABLE for a variation
3144    sequence consisting of the given base character C and each
3145    variation selector SELECTORS[i] for 0 <= i < COUNT, and store the
3146    result (explained below) into the corresponding GLYPHS[i].  If the
3147    entry is found in the Default UVS Table, then the result is 0.  If
3148    the entry is found in the Non-Default UVS Table, then the result is
3149    the associated glyph ID.  Otherwise, kCGFontIndexInvalid.  The
3150    elements in SELECTORS must be sorted in strictly increasing
3151    order.  */
3153 static void
3154 mac_font_get_glyphs_for_variants (CFDataRef uvs_table, UTF32Char c,
3155                                   const UTF32Char selectors[], CGGlyph glyphs[],
3156                                   CFIndex count)
3158   struct uvs_table *uvs = (struct uvs_table *) CFDataGetBytePtr (uvs_table);
3159   struct variation_selector_record *records = uvs->variation_selector_records;
3160   CFIndex i;
3161   UInt32 ir, nrecords;
3162 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3163   dispatch_queue_t queue =
3164     dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3165   dispatch_group_t group = dispatch_group_create ();
3166 #endif
3168   nrecords = BUINT32_VALUE (uvs->num_var_selector_records);
3169   i = 0;
3170   ir = 0;
3171   while (i < count && ir < nrecords)
3172     {
3173       UInt32 default_uvs_offset, non_default_uvs_offset;
3175       if (selectors[i] < BUINT24_VALUE (records[ir].var_selector))
3176         {
3177           glyphs[i++] = kCGFontIndexInvalid;
3178           continue;
3179         }
3180       else if (selectors[i] > BUINT24_VALUE (records[ir].var_selector))
3181         {
3182           ir++;
3183           continue;
3184         }
3186       /* selectors[i] == BUINT24_VALUE (records[ir].var_selector) */
3187       default_uvs_offset = BUINT32_VALUE (records[ir].default_uvs_offset);
3188       non_default_uvs_offset =
3189         BUINT32_VALUE (records[ir].non_default_uvs_offset);
3190 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3191       dispatch_group_async (group, queue, ^{
3192 #endif
3193           glyphs[i] = kCGFontIndexInvalid;
3195           if (default_uvs_offset)
3196             {
3197               struct default_uvs_table *default_uvs =
3198                 (struct default_uvs_table *) ((UInt8 *) uvs
3199                                               + default_uvs_offset);
3200               struct unicode_value_range *ranges =
3201                 default_uvs->unicode_value_ranges;
3202               UInt32 lo, hi;
3204               lo = 0;
3205               hi = BUINT32_VALUE (default_uvs->num_unicode_value_ranges);
3206               while (lo < hi)
3207                 {
3208                   UInt32 mid = (lo + hi) / 2;
3210                   if (c < BUINT24_VALUE (ranges[mid].start_unicode_value))
3211                     hi = mid;
3212                   else
3213                     lo = mid + 1;
3214                 }
3215               if (hi > 0
3216                   && (c <= (BUINT24_VALUE (ranges[hi - 1].start_unicode_value)
3217                             + BUINT8_VALUE (ranges[hi - 1].additional_count))))
3218                 glyphs[i] = 0;
3219             }
3221           if (glyphs[i] == kCGFontIndexInvalid && non_default_uvs_offset)
3222             {
3223               struct non_default_uvs_table *non_default_uvs =
3224                 (struct non_default_uvs_table *) ((UInt8 *) uvs
3225                                                   + non_default_uvs_offset);
3226               struct uvs_mapping *mappings = non_default_uvs->uvs_mappings;
3227               UInt32 lo, hi;
3229               lo = 0;
3230               hi = BUINT32_VALUE (non_default_uvs->num_uvs_mappings);
3231               while (lo < hi)
3232                 {
3233                   UInt32 mid = (lo + hi) / 2;
3235                   if (c < BUINT24_VALUE (mappings[mid].unicode_value))
3236                     hi = mid;
3237                   else
3238                     lo = mid + 1;
3239                 }
3240               if (hi > 0 &&
3241                   BUINT24_VALUE (mappings[hi - 1].unicode_value) == c)
3242                 glyphs[i] = BUINT16_VALUE (mappings[hi - 1].glyph_id);
3243             }
3244 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3245         });
3246 #endif
3247       i++;
3248       ir++;
3249     }
3250   while (i < count)
3251     glyphs[i++] = kCGFontIndexInvalid;
3252 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
3253   dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
3254   dispatch_release (group);
3255 #endif
3258 static int
3259 macfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
3261   CFDataRef uvs_table;
3262   CharacterCollection uvs_collection;
3263   int i, n = 0;
3265   block_input ();
3266   uvs_table = macfont_get_uvs_table (font, &uvs_collection);
3268   if (uvs_table)
3269     {
3270       UTF32Char selectors[256];
3271       CGGlyph glyphs[256];
3273       for (i = 0; i < 16; i++)
3274         selectors[i] = 0xFE00 + i;
3275       for (; i < 256; i++)
3276         selectors[i] = 0xE0100 + (i - 16);
3277       mac_font_get_glyphs_for_variants (uvs_table, c, selectors, glyphs, 256);
3278       for (i = 0; i < 256; i++)
3279         {
3280           CGGlyph glyph = glyphs[i];
3282           if (uvs_collection != MAC_CHARACTER_COLLECTION_IDENTITY_MAPPING
3283               && glyph != kCGFontIndexInvalid)
3284             glyph = macfont_get_glyph_for_cid (font, uvs_collection, glyph);
3285           if (glyph == kCGFontIndexInvalid)
3286             variations[i] = 0;
3287           else
3288             {
3289               variations[i] = (glyph ? glyph
3290                                : macfont_get_glyph_for_character (font, c));
3291               n++;
3292             }
3293         }
3294     }
3295   unblock_input ();
3297   return n;
3300 static const char *const macfont_booleans[] = {
3301   ":antialias",
3302   ":minspace",
3303   NULL,
3306 static const char *const macfont_non_booleans[] = {
3307   ":lang",
3308   ":script",
3309   ":destination",
3310   NULL,
3313 static void
3314 macfont_filter_properties (Lisp_Object font, Lisp_Object alist)
3316   font_filter_properties (font, alist, macfont_booleans, macfont_non_booleans);
3319 static Boolean
3320 mac_ctfont_descriptor_supports_languages (CTFontDescriptorRef descriptor,
3321                                           CFArrayRef languages)
3323   Boolean result = true;
3324   CFArrayRef desc_languages =
3325     CTFontDescriptorCopyAttribute (descriptor, kCTFontLanguagesAttribute);
3327   if (desc_languages == NULL)
3328     result = false;
3329   else
3330     {
3331       CFIndex desc_languages_count, i, languages_count;
3333       desc_languages_count = CFArrayGetCount (desc_languages);
3334       languages_count = CFArrayGetCount (languages);
3335       for (i = 0; i < languages_count; i++)
3336         if (!CFArrayContainsValue (desc_languages,
3337                                    CFRangeMake (0, desc_languages_count),
3338                                    CFArrayGetValueAtIndex (languages, i)))
3339           {
3340             result = false;
3341             break;
3342           }
3343       CFRelease (desc_languages);
3344     }
3346   return result;
3349 static CFStringRef
3350 mac_ctfont_create_preferred_family_for_attributes (CFDictionaryRef attributes)
3352   CFStringRef result = NULL;
3353   CFStringRef charset_string =
3354     CFDictionaryGetValue (attributes, MAC_FONT_CHARACTER_SET_STRING_ATTRIBUTE);
3356   if (charset_string && CFStringGetLength (charset_string) > 0)
3357     {
3358       CFStringRef keys[] = {
3359 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
3360         kCTLanguageAttributeName
3361 #else
3362         CFSTR ("NSLanguage")
3363 #endif
3364       };
3365       CFTypeRef values[] = {NULL};
3366       CFIndex num_values = 0;
3367       CFArrayRef languages
3368         = CFDictionaryGetValue (attributes, MAC_FONT_LANGUAGES_ATTRIBUTE);
3370       if (languages && CFArrayGetCount (languages) > 0)
3371         {
3372           if (CTGetCoreTextVersion () >= kCTVersionNumber10_9)
3373             values[num_values++] = CFArrayGetValueAtIndex (languages, 0);
3374           else
3375             {
3376               CFCharacterSetRef charset =
3377                 CFDictionaryGetValue (attributes,
3378                                       MAC_FONT_CHARACTER_SET_ATTRIBUTE);
3380               result = mac_font_copy_default_name_for_charset_and_languages (charset, languages);
3381             }
3382         }
3383       if (result == NULL)
3384         {
3385           CFAttributedStringRef attr_string = NULL;
3386           CTLineRef ctline = NULL;
3387           CFDictionaryRef attrs
3388             = CFDictionaryCreate (NULL, (const void **) keys,
3389                                   (const void **) values, num_values,
3390                                   &kCFTypeDictionaryKeyCallBacks,
3391                                   &kCFTypeDictionaryValueCallBacks);
3393           if (attrs)
3394             {
3395               attr_string = CFAttributedStringCreate (NULL, charset_string,
3396                                                       attrs);
3397               CFRelease (attrs);
3398             }
3399           if (attr_string)
3400             {
3401               ctline = CTLineCreateWithAttributedString (attr_string);
3402               CFRelease (attr_string);
3403             }
3404           if (ctline)
3405             {
3406               CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3407               CFIndex i, nruns = CFArrayGetCount (runs);
3408               CTFontRef font;
3410               for (i = 0; i < nruns; i++)
3411                 {
3412                   CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3413                   CFDictionaryRef attributes = CTRunGetAttributes (run);
3414                   CTFontRef font_in_run;
3416                   if (attributes == NULL)
3417                     break;
3418                   font_in_run =
3419                     CFDictionaryGetValue (attributes, kCTFontAttributeName);
3420                   if (font_in_run == NULL)
3421                     break;
3422                   if (i == 0)
3423                     font = font_in_run;
3424                   else if (!mac_ctfont_equal_in_postscript_name (font,
3425                                                                  font_in_run))
3426                     break;
3427                 }
3428               if (nruns > 0 && i == nruns)
3429                 result = CTFontCopyAttribute (font, kCTFontFamilyNameAttribute);
3430               CFRelease (ctline);
3431             }
3432         }
3433     }
3435   return result;
3438 static inline double
3439 mac_ctfont_get_advance_width_for_glyph (CTFontRef font, CGGlyph glyph)
3441   return CTFontGetAdvancesForGlyphs (font, kCTFontDefaultOrientation,
3442                                      &glyph, NULL, 1);
3445 static inline CGRect
3446 mac_ctfont_get_bounding_rect_for_glyph (CTFontRef font, CGGlyph glyph)
3448   return CTFontGetBoundingRectsForGlyphs (font, kCTFontDefaultOrientation,
3449                                           &glyph, NULL, 1);
3452 static CFArrayRef
3453 mac_ctfont_create_available_families (void)
3455   CFMutableArrayRef families = NULL;
3457 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
3458 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3459   if (CTFontManagerCopyAvailableFontFamilyNames != NULL)
3460 #endif
3461     {
3462       CFArrayRef orig_families = CTFontManagerCopyAvailableFontFamilyNames ();
3464       if (orig_families)
3465         {
3466           CFIndex i, count = CFArrayGetCount (orig_families);
3468           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3469           if (families)
3470             for (i = 0; i < count; i++)
3471               {
3472                 CFStringRef family = CFArrayGetValueAtIndex (orig_families, i);
3474                 if (!CFStringHasPrefix (family, CFSTR ("."))
3475                     && (CTFontManagerCompareFontFamilyNames (family,
3476                                                              CFSTR ("LastResort"),
3477                                                              NULL)
3478                         != kCFCompareEqualTo))
3479                   CFArrayAppendValue (families, family);
3480               }
3481           CFRelease (orig_families);
3482         }
3483     }
3484 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3485   else         /* CTFontManagerCopyAvailableFontFamilyNames == NULL */
3486 #endif
3487 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 */
3488 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3489     {
3490       CTFontCollectionRef collection;
3491       CFArrayRef descs = NULL;
3493       collection = CTFontCollectionCreateFromAvailableFonts (NULL);
3494       if (collection)
3495         {
3496           descs = CTFontCollectionCreateMatchingFontDescriptors (collection);
3497           CFRelease (collection);
3498         }
3499       if (descs)
3500         {
3501           CFIndex i, count = CFArrayGetCount (descs);
3503           families = CFArrayCreateMutable (NULL, count, &kCFTypeArrayCallBacks);
3504           if (families)
3505             for (i = 0; i < count; i++)
3506               {
3507                 FontDescriptorRef desc = CFArrayGetValueAtIndex (descs, i);
3508                 CFStringRef name =
3509                   mac_font_descriptor_copy_attribute (desc,
3510                                                       MAC_FONT_FAMILY_NAME_ATTRIBUTE);
3512                 if (name)
3513                   {
3514                     CFIndex p, limit = CFArrayGetCount (families);
3516                     p = CFArrayBSearchValues (families, CFRangeMake (0, limit),
3517                                               (const void *) name,
3518                                               mac_font_family_compare, NULL);
3519                     if (p >= limit)
3520                       CFArrayAppendValue (families, name);
3521                     else if (mac_font_family_compare
3522                              (CFArrayGetValueAtIndex (families, p),
3523                               name, NULL) != kCFCompareEqualTo)
3524                       CFArrayInsertValueAtIndex (families, p, name);
3525                     CFRelease (name);
3526                   }
3527               }
3528           CFRelease (descs);
3529         }
3530     }
3531 #endif
3533   return families;
3536 static Boolean
3537 mac_ctfont_equal_in_postscript_name (CTFontRef font1, CTFontRef font2)
3539   Boolean result;
3540   CFStringRef name1, name2;
3542   if (font1 == font2)
3543     return true;
3545   result = false;
3546   name1 = CTFontCopyPostScriptName (font1);
3547   if (name1)
3548     {
3549       name2 = CTFontCopyPostScriptName (font2);
3550       if (name2)
3551         {
3552           result = CFEqual (name1, name2);
3553           CFRelease (name2);
3554         }
3555       CFRelease (name1);
3556     }
3558   return result;
3561 static CTLineRef
3562 mac_ctfont_create_line_with_string_and_font (CFStringRef string,
3563                                              CTFontRef macfont)
3565   CFStringRef keys[] = {kCTFontAttributeName, kCTKernAttributeName};
3566   CFTypeRef values[] = {NULL, NULL};
3567   CFDictionaryRef attributes = NULL;
3568   CFAttributedStringRef attr_string = NULL;
3569   CTLineRef ctline = NULL;
3570   float float_zero = 0.0f;
3572   values[0] = macfont;
3573   values[1] = CFNumberCreate (NULL, kCFNumberFloatType, &float_zero);
3574   if (values[1])
3575     {
3576       attributes = CFDictionaryCreate (NULL, (const void **) keys,
3577                                        (const void **) values,
3578                                        ARRAYELTS (keys),
3579                                        &kCFTypeDictionaryKeyCallBacks,
3580                                        &kCFTypeDictionaryValueCallBacks);
3581       CFRelease (values[1]);
3582     }
3583   if (attributes)
3584     {
3585       attr_string = CFAttributedStringCreate (NULL, string, attributes);
3586       CFRelease (attributes);
3587     }
3588   if (attr_string)
3589     {
3590       ctline = CTLineCreateWithAttributedString (attr_string);
3591       CFRelease (attr_string);
3592     }
3593   if (ctline)
3594     {
3595       /* Abandon if ctline contains some fonts other than the
3596          specified one.  */
3597       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3598       CFIndex i, nruns = CFArrayGetCount (runs);
3600       for (i = 0; i < nruns; i++)
3601         {
3602           CTRunRef run = CFArrayGetValueAtIndex (runs, i);
3603           CFDictionaryRef attributes = CTRunGetAttributes (run);
3604           CTFontRef font_in_run;
3606           if (attributes == NULL)
3607             break;
3608           font_in_run =
3609             CFDictionaryGetValue (attributes, kCTFontAttributeName);
3610           if (font_in_run == NULL)
3611             break;
3612           if (!mac_ctfont_equal_in_postscript_name (macfont, font_in_run))
3613             break;
3614         }
3615       if (i < nruns)
3616         {
3617           CFRelease (ctline);
3618           ctline = NULL;
3619         }
3620     }
3622   return ctline;
3625 static CFIndex
3626 mac_ctfont_shape (CTFontRef font, CFStringRef string,
3627                   struct mac_glyph_layout *glyph_layouts, CFIndex glyph_len)
3629   CFIndex used, result = 0;
3630   CTLineRef ctline = mac_ctfont_create_line_with_string_and_font (string, font);
3632   if (ctline == NULL)
3633     return 0;
3635   used = CTLineGetGlyphCount (ctline);
3636   if (used <= glyph_len)
3637     {
3638       CFArrayRef ctruns = CTLineGetGlyphRuns (ctline);
3639       CFIndex k, ctrun_count = CFArrayGetCount (ctruns);
3640       CGFloat total_advance = 0;
3641       CFIndex total_glyph_count = 0;
3643       for (k = 0; k < ctrun_count; k++)
3644         {
3645           CTRunRef ctrun = CFArrayGetValueAtIndex (ctruns, k);
3646           CFIndex i, min_location, glyph_count = CTRunGetGlyphCount (ctrun);
3647           struct mac_glyph_layout *glbuf = glyph_layouts + total_glyph_count;
3648           CFRange string_range, comp_range, range;
3649           CFIndex *permutation;
3651           if (CTRunGetStatus (ctrun) & kCTRunStatusRightToLeft)
3652             permutation = xmalloc (sizeof (CFIndex) * glyph_count);
3653           else
3654             permutation = NULL;
3656 #define RIGHT_TO_LEFT_P permutation
3658           /* Now the `comp_range' member of struct mac_glyph_layout is
3659              temporarily used as a work area such that:
3660               glbuf[i].comp_range.location =
3661                 min {compRange[i + 1].location, ...,
3662                      compRange[glyph_count - 1].location,
3663                      maxRange (stringRangeForCTRun)}
3664               glbuf[i].comp_range.length = maxRange (compRange[i])
3665              where compRange[i] is the range of composed characters
3666              containing i-th glyph.  */
3667           string_range = CTRunGetStringRange (ctrun);
3668           min_location = string_range.location + string_range.length;
3669           for (i = 0; i < glyph_count; i++)
3670             {
3671               struct mac_glyph_layout *gl = glbuf + glyph_count - i - 1;
3672               CFIndex glyph_index;
3673               CFRange rng;
3675               if (!RIGHT_TO_LEFT_P)
3676                 glyph_index = glyph_count - i - 1;
3677               else
3678                 glyph_index = i;
3679               CTRunGetStringIndices (ctrun, CFRangeMake (glyph_index, 1),
3680                                      &gl->string_index);
3681               rng =
3682                 CFStringGetRangeOfComposedCharactersAtIndex (string,
3683                                                              gl->string_index);
3684               gl->comp_range.location = min_location;
3685               gl->comp_range.length = rng.location + rng.length;
3686               if (rng.location < min_location)
3687                 min_location = rng.location;
3688             }
3690           /* Fill the `comp_range' member of struct mac_glyph_layout,
3691              and setup a permutation for right-to-left text.  */
3692           comp_range = CFRangeMake (string_range.location, 0);
3693           range = CFRangeMake (0, 0);
3694           while (1)
3695             {
3696               struct mac_glyph_layout *gl =
3697                 glbuf + range.location + range.length;
3699               if (gl->comp_range.length
3700                   > comp_range.location + comp_range.length)
3701                 comp_range.length = gl->comp_range.length - comp_range.location;
3702               min_location = gl->comp_range.location;
3703               range.length++;
3705               if (min_location >= comp_range.location + comp_range.length)
3706                 {
3707                   comp_range.length = min_location - comp_range.location;
3708                   for (i = 0; i < range.length; i++)
3709                     {
3710                       glbuf[range.location + i].comp_range = comp_range;
3711                       if (RIGHT_TO_LEFT_P)
3712                         permutation[range.location + i] =
3713                           range.location + range.length - i - 1;
3714                     }
3716                   comp_range = CFRangeMake (min_location, 0);
3717                   range.location += range.length;
3718                   range.length = 0;
3719                   if (range.location == glyph_count)
3720                     break;
3721                 }
3722             }
3724           /* Then fill the remaining members.  */
3725           for (range = CFRangeMake (0, 1); range.location < glyph_count;
3726                range.location++)
3727             {
3728               struct mac_glyph_layout *gl;
3729               CGPoint position;
3731               if (!RIGHT_TO_LEFT_P)
3732                 gl = glbuf + range.location;
3733               else
3734                 {
3735                   CFIndex src, dest;
3737                   src = glyph_count - 1 - range.location;
3738                   dest = permutation[src];
3739                   gl = glbuf + dest;
3740                   if (src < dest)
3741                     {
3742                       CFIndex tmp = gl->string_index;
3744                       gl->string_index = glbuf[src].string_index;
3745                       glbuf[src].string_index = tmp;
3746                     }
3747                 }
3748               CTRunGetGlyphs (ctrun, range, &gl->glyph_id);
3750               CTRunGetPositions (ctrun, range, &position);
3751               gl->advance_delta = position.x - total_advance;
3752               gl->baseline_delta = position.y;
3753               gl->advance = (gl->advance_delta
3754                              + CTRunGetTypographicBounds (ctrun, range,
3755                                                           NULL, NULL, NULL));
3756               total_advance += gl->advance;
3757             }
3759           if (RIGHT_TO_LEFT_P)
3760             xfree (permutation);
3762 #undef RIGHT_TO_LEFT_P
3764           total_glyph_count += glyph_count;
3765         }
3767       result = used;
3768     }
3769   CFRelease (ctline);
3771   return result;
3774 /* The function below seems to cause a memory leak for the CFString
3775    created by CFStringCreateWithCharacters as of Mac OS X 10.5.8 and
3776    10.6.3.  For now, we use the NSGlyphInfo version instead.  */
3777 #if USE_CT_GLYPH_INFO
3778 static CGGlyph
3779 mac_ctfont_get_glyph_for_cid (CTFontRef font, CTCharacterCollection collection,
3780                               CGFontIndex cid)
3782   CGGlyph result = kCGFontIndexInvalid;
3783   UniChar characters[] = {0xfffd};
3784   CFStringRef string;
3785   CFAttributedStringRef attr_string = NULL;
3786   CTLineRef ctline = NULL;
3788   string = CFStringCreateWithCharacters (NULL, characters,
3789                                          ARRAYELTS (characters));
3791   if (string)
3792     {
3793       CTGlyphInfoRef glyph_info =
3794         CTGlyphInfoCreateWithCharacterIdentifier (cid, collection, string);
3795       CFDictionaryRef attributes = NULL;
3797       if (glyph_info)
3798         {
3799           CFStringRef keys[] = {kCTFontAttributeName,
3800                                 kCTGlyphInfoAttributeName};
3801           CFTypeRef values[] = {font, glyph_info};
3803           attributes = CFDictionaryCreate (NULL, (const void **) keys,
3804                                            (const void **) values,
3805                                            ARRAYELTS (keys),
3806                                            &kCFTypeDictionaryKeyCallBacks,
3807                                            &kCFTypeDictionaryValueCallBacks);
3808           CFRelease (glyph_info);
3809         }
3810       if (attributes)
3811         {
3812           attr_string = CFAttributedStringCreate (NULL, string, attributes);
3813           CFRelease (attributes);
3814         }
3815       CFRelease (string);
3816     }
3817   if (attr_string)
3818     {
3819       ctline = CTLineCreateWithAttributedString (attr_string);
3820       CFRelease (attr_string);
3821     }
3822   if (ctline)
3823     {
3824       CFArrayRef runs = CTLineGetGlyphRuns (ctline);
3826       if (CFArrayGetCount (runs) > 0)
3827         {
3828           CTRunRef run = CFArrayGetValueAtIndex (runs, 0);
3829           CFDictionaryRef attributes = CTRunGetAttributes (run);
3831           if (attributes)
3832             {
3833               CTFontRef font_in_run =
3834                 CFDictionaryGetValue (attributes, kCTFontAttributeName);
3836               if (font_in_run
3837                   && mac_ctfont_equal_in_postscript_name (font_in_run, font))
3838                 {
3839                   CTRunGetGlyphs (run, CFRangeMake (0, 1), &result);
3840                   if (result >= CTFontGetGlyphCount (font))
3841                     result = kCGFontIndexInvalid;
3842                 }
3843             }
3844         }
3845       CFRelease (ctline);
3846     }
3848   return result;
3850 #endif
3852 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
3853 static inline int
3854 mac_font_family_group (CFStringRef family)
3856   if (CFStringHasPrefix (family, CFSTR ("#")))
3857     return 2;
3858   else
3859     {
3860       CFRange range;
3862       range = CFStringFind (family, CFSTR ("Apple"),
3863                             kCFCompareCaseInsensitive | kCFCompareAnchored);
3864       if (range.location != kCFNotFound)
3865         return 1;
3867       return 0;
3868     }
3871 static CFComparisonResult
3872 mac_font_family_compare (const void *val1, const void *val2, void *context)
3874   CFStringRef family1 = (CFStringRef) val1, family2 = (CFStringRef) val2;
3875   int group1, group2;
3877   group1 = mac_font_family_group (family1);
3878   group2 = mac_font_family_group (family2);
3879   if (group1 < group2)
3880     return kCFCompareLessThan;
3881   if (group1 > group2)
3882     return kCFCompareGreaterThan;
3883   return CFStringCompare (family1, family2, kCFCompareCaseInsensitive);
3885 #endif  /* MAC_OS_X_VERSION_MIN_REQUIRED < 1060 */
3887 static CFArrayRef
3888 mac_font_copy_default_descriptors_for_language (CFStringRef language)
3890   CFArrayRef result = NULL;
3892 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
3893 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3894   if (CTFontCopyDefaultCascadeListForLanguages != NULL)
3895 #endif
3896     {
3897       CTFontRef user_font =
3898         CTFontCreateUIFontForLanguage (kCTFontUserFontType, 0, language);
3900       if (user_font)
3901         {
3902           CFArrayRef languages =
3903             CFArrayCreate (NULL, (const void **) &language, 1,
3904                            &kCFTypeArrayCallBacks);
3906           if (languages)
3907             {
3908               result = CTFontCopyDefaultCascadeListForLanguages (user_font,
3909                                                                  languages);
3910               CFRelease (languages);
3911             }
3912           CFRelease (user_font);
3913         }
3914     }
3915 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3916   else          /* CTFontCopyDefaultCascadeListForLanguages == NULL */
3917 #endif
3918 #endif  /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 */
3919 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
3920     {
3921       CFIndex i;
3923       for (i = 0; macfont_language_default_font_names[i].language; i++)
3924         {
3925           if (CFEqual (macfont_language_default_font_names[i].language,
3926                        language))
3927             {
3928               CFMutableArrayRef descriptors =
3929                 CFArrayCreateMutable (NULL, 0, &kCFTypeArrayCallBacks);
3931               if (descriptors)
3932                 {
3933                   CFIndex j;
3935                   for (j = 0;
3936                        macfont_language_default_font_names[i].font_names[j];
3937                        j++)
3938                     {
3939                       CFDictionaryRef attributes =
3940                         CFDictionaryCreate (NULL,
3941                                             ((const void **)
3942                                              &MAC_FONT_NAME_ATTRIBUTE),
3943                                             ((const void **)
3944                                              &macfont_language_default_font_names[i].font_names[j]),
3945                                             1, &kCFTypeDictionaryKeyCallBacks,
3946                                             &kCFTypeDictionaryValueCallBacks);
3948                       if (attributes)
3949                         {
3950                           FontDescriptorRef pat_desc =
3951                             mac_font_descriptor_create_with_attributes (attributes);
3953                           if (pat_desc)
3954                             {
3955                               FontDescriptorRef descriptor =
3956                                 mac_font_descriptor_create_matching_font_descriptor (pat_desc, NULL);
3958                               if (descriptor)
3959                                 {
3960                                   CFArrayAppendValue (descriptors, descriptor);
3961                                   CFRelease (descriptor);
3962                                 }
3963                               CFRelease (pat_desc);
3964                             }
3965                           CFRelease (attributes);
3966                         }
3967                     }
3968                   result = descriptors;
3969                 }
3970               break;
3971             }
3972         }
3973     }
3974 #endif
3976   return result;
3979 static CFStringRef
3980 mac_font_copy_default_name_for_charset_and_languages (CFCharacterSetRef charset,
3981                                                       CFArrayRef languages)
3983   CFStringRef result = NULL;
3984   CFStringRef language = CFArrayGetValueAtIndex (languages, 0);
3985   CFArrayRef descriptors =
3986     mac_font_copy_default_descriptors_for_language (language);
3988   if (descriptors)
3989     {
3990       CFIndex i, count = CFArrayGetCount (descriptors);
3992       for (i = 0; i < count; i++)
3993         {
3994           FontDescriptorRef descriptor =
3995             CFArrayGetValueAtIndex (descriptors, i);
3997           if (macfont_supports_charset_and_languages_p (descriptor, charset,
3998                                                         Qnil, languages))
3999             {
4000               CFStringRef family =
4001                 mac_font_descriptor_copy_attribute (descriptor,
4002                                                     MAC_FONT_FAMILY_NAME_ATTRIBUTE);
4003               if (family)
4004                 {
4005                   if (!CFStringHasPrefix (family, CFSTR ("."))
4006                       && !CFEqual (family, CFSTR ("LastResort")))
4007                     {
4008                       result = family;
4009                       break;
4010                     }
4011                   else
4012                     CFRelease (family);
4013                 }
4014             }
4015         }
4016       CFRelease (descriptors);
4017     }
4019   return result;
4022 void *
4023 macfont_get_nsctfont (struct font *font)
4025   struct macfont_info *macfont_info = (struct macfont_info *) font;
4026   FontRef macfont = macfont_info->macfont;
4028   return (void *) macfont;
4031 void
4032 mac_register_font_driver (struct frame *f)
4034   register_font_driver (&macfont_driver, f);
4037 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4040 void
4041 syms_of_macfont (void)
4043 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
4044   static struct font_driver mac_font_driver;
4046   DEFSYM (Qmac_ct, "mac-ct");
4047   macfont_driver.type = Qmac_ct;
4048   register_font_driver (&macfont_driver, NULL);
4050   DEFSYM (QCdestination, ":destination");
4051   DEFSYM (QCminspace, ":minspace");
4052 #endif