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